diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..b1346a8792f --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,19 @@ +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "prettier"], + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + rules: { + "comma-spacing": ["error", { before: false, after: true }], + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", // or "error" + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "prettier/prettier": "error", + }, +}; diff --git a/.github/ISSUE_TEMPLATE/idea_action_plan.yml b/.github/ISSUE_TEMPLATE/idea_action_plan.yml new file mode 100644 index 00000000000..02fed1fc48b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/idea_action_plan.yml @@ -0,0 +1,54 @@ +name: Idea Action Plan +description: Outline the scope and steps for implementing an enhancement. Start with "Ideas" instead to request and discuss new features. +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + ## Description + Thanks for taking the time to create the Issue, and welcome to the Noirot family! + - type: textarea + id: problem + attributes: + label: Problem + description: Describe what you feel lacking. Supply code / step-by-step examples if applicable. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Happy Case + description: Describe how you think it should work. Supply pseudocode / step-by-step examples if applicable. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Describe less-happy cases you have considered, if any. + - type: textarea + id: additional + attributes: + label: Additional Context + description: Supplement further information if applicable. + - type: markdown + attributes: + value: | + ## Pull Request + - type: dropdown + id: pr-preference + attributes: + label: Would you like to submit a PR for this Issue? + description: Fellow contributors are happy to provide support where applicable. + multiple: false + options: + - "No" + - "Maybe" + - "Yes" + validations: + required: true + - type: textarea + id: pr-support + attributes: + label: Support Needs + description: Support from other contributors you are looking for to create a PR for this Issue. diff --git a/.github/NIGHTLY_TEST_FAILURE.md b/.github/NIGHTLY_TEST_FAILURE.md index e86c01b25b7..05772d82a51 100644 --- a/.github/NIGHTLY_TEST_FAILURE.md +++ b/.github/NIGHTLY_TEST_FAILURE.md @@ -1,6 +1,6 @@ --- title: "nightly test-integration failed" -assignees: kobyhallx, phated, tomafrench, jonybur +assignees: kobyhallx, tomafrench, jonybur labels: bug --- diff --git a/.github/workflows/abi_wasm.yml b/.github/workflows/abi_wasm.yml deleted file mode 100644 index 8f219a77977..00000000000 --- a/.github/workflows/abi_wasm.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: ABI Wasm test - -on: - pull_request: - merge_group: - push: - branches: - - master - -# This will cancel previous runs when a branch or PR is updated -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - build: - runs-on: ubuntu-latest - env: - CACHED_PATH: /tmp/nix-cache - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - uses: cachix/install-nix-action@v20 - with: - nix_path: nixpkgs=channel:nixos-23.05 - github_access_token: ${{ secrets.GITHUB_TOKEN }} - - - name: Restore nix store cache - uses: actions/cache/restore@v3 - id: cache - with: - path: ${{ env.CACHED_PATH }} - key: ${{ runner.os }}-flake-abi-wasm-${{ hashFiles('*.lock') }} - - # Based on https://github.com/marigold-dev/deku/blob/b5016f0cf4bf6ac48db9111b70dd7fb49b969dfd/.github/workflows/build.yml#L26 - - name: Copy cache into nix store - if: steps.cache.outputs.cache-hit == 'true' - # We don't check the signature because we're the one that created the cache - run: | - for narinfo in ${{ env.CACHED_PATH }}/*.narinfo; do - path=$(head -n 1 "$narinfo" | awk '{print $2}') - nix copy --no-check-sigs --from "file://${{ env.CACHED_PATH }}" "$path" - done - - - name: Build noirc_abi_wasm - run: | - nix build -L .#noirc_abi_wasm - cp -r ./result/nodejs ./tooling/noirc_abi_wasm - cp -r ./result/web ./tooling/noirc_abi_wasm - - - name: Export cache from nix store - if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} - run: | - nix copy --to "file://${{ env.CACHED_PATH }}?compression=zstd¶llel-compression=true" .#noirc-abi-wasm-cargo-artifacts - - - uses: actions/cache/save@v3 - # Don't create cache entries for the merge queue. - if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} - with: - path: ${{ env.CACHED_PATH }} - key: ${{ steps.cache.outputs.cache-primary-key }} - - - name: Dereference symlink - run: echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: noirc_abi_wasm - path: ${{ env.UPLOAD_PATH }} - retention-days: 10 - - test: - runs-on: ubuntu-latest - needs: [build] - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Download wasm package artifact - uses: actions/download-artifact@v3 - with: - name: noirc_abi_wasm - path: ./tooling/noirc_abi_wasm - - - name: Install Yarn dependencies - uses: ./.github/actions/setup - - - name: Run node tests - run: yarn workspace @noir-lang/noirc_abi test - - - name: Install Playwright - uses: ./.github/actions/install-playwright - - - name: Run browser tests - run: yarn workspace @noir-lang/noirc_abi test:browser - diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index bdc95b40bd5..07ae535a454 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -1,4 +1,4 @@ -name: Clippy +name: Formatting on: pull_request: @@ -48,3 +48,18 @@ jobs: - name: Run `cargo fmt` run: cargo fmt --all --check + + eslint: + name: eslint + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Run `yarn lint` + run: yarn lint diff --git a/.github/workflows/publish-abi_wasm.yml b/.github/workflows/publish-abi_wasm.yml index 3ca7b77f747..feca0e58ff8 100644 --- a/.github/workflows/publish-abi_wasm.yml +++ b/.github/workflows/publish-abi_wasm.yml @@ -36,7 +36,7 @@ jobs: nix build -L .#noirc_abi_wasm - name: Discover Build Output Path - run: echo "BUILD_OUTPUT_PATH=$(readlink -f ./result)" >> $GITHUB_ENV + run: echo "BUILD_OUTPUT_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV - name: Copy Build Output to Temporary Directory run: | @@ -46,6 +46,6 @@ jobs: - name: Publish to npm working-directory: ./temp_publish_dir run: | - npm publish --tag latest + yarn npm publish --tag latest env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-acvm-js.yml b/.github/workflows/publish-acvm-js.yml new file mode 100644 index 00000000000..b2145085a02 --- /dev/null +++ b/.github/workflows/publish-acvm-js.yml @@ -0,0 +1,54 @@ +name: Publish acvm_js + +on: + workflow_dispatch: + inputs: + acvm-ref: + description: The acvm reference to checkout + required: true + +jobs: + publish-acvm-js-package: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + with: + ref: ${{ inputs.acvm-ref }} + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + registry-url: "https://registry.npmjs.org" + node-version: 18.15 + + - uses: cachix/install-nix-action@v22 + with: + nix_path: nixpkgs=channel:nixos-23.05 + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: cachix/cachix-action@v12 + with: + name: barretenberg + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Build acvm-js + working-directory: acvm-repo + run: | + nix build .# + + - name: Discover Build Output Path + working-directory: acvm-repo + run: echo "BUILD_OUTPUT_PATH=$(readlink -f ./result)" >> $GITHUB_ENV + + - name: Copy Build Output to Temporary Directory + working-directory: acvm-repo + run: | + mkdir temp_publish_dir + cp -r ${{ env.BUILD_OUTPUT_PATH }}/* temp_publish_dir/ + + - name: Publish to NPM + working-directory: ./acvm-repo/temp_publish_dir + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-acvm.yml b/.github/workflows/publish-acvm.yml new file mode 100644 index 00000000000..3f4641a690c --- /dev/null +++ b/.github/workflows/publish-acvm.yml @@ -0,0 +1,72 @@ +name: Publish ACVM crates + +on: + workflow_dispatch: + inputs: + acvm-ref: + description: The acvm reference to checkout + required: true + +jobs: + publish: + name: Publish in order + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + with: + ref: ${{ inputs.acvm-ref }} + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.66.0 + + # These steps are in a specific order so crate dependencies are updated first + - name: Publish acir_field + run: | + cargo publish --package acir_field + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish brillig + run: | + cargo publish --package brillig + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish acir + run: | + cargo publish --package acir + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish acvm_blackbox_solver + run: | + cargo publish --package acvm_blackbox_solver + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish barretenberg_blackbox_solver + run: | + cargo publish --package barretenberg_blackbox_solver + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish acvm_stdlib + run: | + cargo publish --package acvm_stdlib + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish brillig_vm + run: | + cargo publish --package brillig_vm + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} + + - name: Publish acvm + run: | + cargo publish --package acvm + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.ACVM_CRATES_IO_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish-nargo.yml similarity index 78% rename from .github/workflows/publish.yml rename to .github/workflows/publish-nargo.yml index f39f35775f7..9d3ff9423ea 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish-nargo.yml @@ -95,6 +95,24 @@ jobs: overwrite: true tag: ${{ inputs.tag || 'nightly' }} # This will fail if `inputs.tag` is not a tag (e.g. testing a branch) + - name: Get formatted date + id: date + if: ${{ inputs.tag == '' && inputs.publish || github.event_name == 'schedule' }} + run: echo "date=$(date '+%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Upload binaries to release with date tag + uses: svenstaro/upload-release-action@v2 + if: ${{ inputs.tag == '' && inputs.publish || github.event_name == 'schedule' }} + with: + repo_name: noir-lang/noir + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ./nargo-${{ matrix.target }}.tar.gz + asset_name: nargo-${{ matrix.target }}.tar.gz + prerelease: true + make_latest: false + overwrite: true + tag: ${{ format('{0}-{1}', 'nightly', steps.date.outputs.date) }} + build-linux: runs-on: ubuntu-22.04 env: @@ -162,3 +180,21 @@ jobs: asset_name: nargo-${{ matrix.target }}.tar.gz overwrite: true tag: ${{ inputs.tag || 'nightly' }} # This will fail if `inputs.tag` is not a tag (e.g. testing a branch) + + - name: Get formatted date + id: date + if: ${{ inputs.tag == '' && inputs.publish || github.event_name == 'schedule' }} + run: echo "date=$(date '+%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Upload binaries to release with date tag + uses: svenstaro/upload-release-action@v2 + if: ${{ inputs.tag == '' && inputs.publish || github.event_name == 'schedule' }} + with: + repo_name: noir-lang/noir + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: ./nargo-${{ matrix.target }}.tar.gz + asset_name: nargo-${{ matrix.target }}.tar.gz + prerelease: true + make_latest: false + overwrite: true + tag: ${{ format('{0}-{1}', 'nightly', steps.date.outputs.date) }} diff --git a/.github/workflows/noir-js.yml b/.github/workflows/publish-noir-js.yml similarity index 84% rename from .github/workflows/noir-js.yml rename to .github/workflows/publish-noir-js.yml index e8b210feb06..4614390e053 100644 --- a/.github/workflows/noir-js.yml +++ b/.github/workflows/publish-noir-js.yml @@ -23,11 +23,6 @@ jobs: source $HOME/.cargo/env cargo install -f wasm-bindgen-cli --version 0.2.86 - - name: Install toml2json - run: | - source $HOME/.cargo/env - cargo install toml2json - - name: Install wasm-opt run: | npm i wasm-opt -g @@ -47,6 +42,6 @@ jobs: - name: Publish to NPM working-directory: ./tooling/noir_js - run: npm publish --access public + run: yarn npm publish --access public env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release-noir-wasm.yml b/.github/workflows/publish-noir-wasm.yml similarity index 100% rename from .github/workflows/release-noir-wasm.yml rename to .github/workflows/publish-noir-wasm.yml diff --git a/.github/workflows/release-source-resolver.yml b/.github/workflows/publish-source-resolver.yml similarity index 80% rename from .github/workflows/release-source-resolver.yml rename to .github/workflows/publish-source-resolver.yml index aad9ec9618c..f1f7574cc2b 100644 --- a/.github/workflows/release-source-resolver.yml +++ b/.github/workflows/publish-source-resolver.yml @@ -1,11 +1,11 @@ -name: Release and Publish Source Resolver +name: Publish Source Resolver on: workflow_dispatch: jobs: release-source-resolver: - name: Release and Publish Source Resolver + name: Publish Source Resolver runs-on: ubuntu-latest steps: - name: Checkout @@ -19,6 +19,6 @@ jobs: - name: Publish to NPM working-directory: ./compiler/source-resolver - run: npm publish + run: yarn npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request-title.yml similarity index 100% rename from .github/workflows/pull-request.yml rename to .github/workflows/pull-request-title.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5842e041285..5a1aba712f2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,7 @@ jobs: - name: Dispatch to publish workflow uses: benc-uk/workflow-dispatch@v1 with: - workflow: publish.yml + workflow: publish-nargo.yml repo: noir-lang/noir ref: master token: ${{ secrets.GITHUB_TOKEN }} @@ -74,7 +74,7 @@ jobs: - name: Dispatch to noir_wasm uses: benc-uk/workflow-dispatch@v1 with: - workflow: release-noir-wasm.yml + workflow: publish-noir-wasm.yml ref: master token: ${{ secrets.NOIR_REPO_TOKEN }} @@ -87,7 +87,7 @@ jobs: - name: Dispatch to noir_wasm uses: benc-uk/workflow-dispatch@v1 with: - workflow: noir-js.yml + workflow: publish-noir-js.yml ref: master token: ${{ secrets.NOIR_REPO_TOKEN }} @@ -100,11 +100,11 @@ jobs: - name: Dispatch to source resolver uses: benc-uk/workflow-dispatch@v1 with: - workflow: release-source-resolver.yml + workflow: publish-source-resolver.yml ref: master token: ${{ secrets.NOIR_REPO_TOKEN }} - dispatch-publish-abi-wasm: + publish-abi-wasm: name: Dispatch to publish-abi_wasm workflow needs: [release-please] if: ${{ needs.release-please.outputs.tag-name }} @@ -117,3 +117,29 @@ jobs: repo: ${{ github.repository }} token: ${{ secrets.GITHUB_TOKEN }} inputs: '{ "noir-ref": "${{ needs.release-please.outputs.tag-name }}" }' + + publish-acvm: + name: Publish crates + needs: [release-please] + if: ${{ needs.release-please.outputs.tag-name }} + runs-on: ubuntu-latest + steps: + - name: Dispatch to publish workflow + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: publish-acvm.yml + ref: master + inputs: '{ "acvm-ref": "${{ needs.release-please.outputs.tag-name }}" }' + + publish-acvm-js: + name: Dispatch to publish-acvm-js workflow + needs: [release-please] + if: ${{ needs.release-please.outputs.tag-name }} + runs-on: ubuntu-latest + steps: + - name: Trigger publish-acvm-js.yml workflow + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: publish-acvm-js.yml + ref: master + inputs: '{ "acvm-ref": "${{ needs.release-please.outputs.tag-name }}" }' diff --git a/.github/workflows/test-abi_wasm.yml b/.github/workflows/test-abi_wasm.yml new file mode 100644 index 00000000000..7fecb66fd7f --- /dev/null +++ b/.github/workflows/test-abi_wasm.yml @@ -0,0 +1,77 @@ +name: ABI Wasm test + +on: + pull_request: + merge_group: + push: + branches: + - master + +# This will cancel previous runs when a branch or PR is updated +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + env: + CACHED_PATH: /tmp/nix-cache + + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Setup Nix + uses: cachix/install-nix-action@v22 + with: + nix_path: nixpkgs=channel:nixos-23.05 + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: cachix/cachix-action@v12 + with: + name: barretenberg + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Build noirc_abi_wasm + run: | + nix build -L .#noirc_abi_wasm + cp -r ./result/noirc_abi_wasm/nodejs ./tooling/noirc_abi_wasm + cp -r ./result/noirc_abi_wasm/web ./tooling/noirc_abi_wasm + + - name: Dereference symlink + run: echo "UPLOAD_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: noirc_abi_wasm + path: ${{ env.UPLOAD_PATH }} + retention-days: 10 + + test: + runs-on: ubuntu-latest + needs: [build] + + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Download wasm package artifact + uses: actions/download-artifact@v3 + with: + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Run node tests + run: yarn workspace @noir-lang/noirc_abi test + + - name: Install Playwright + uses: ./.github/actions/install-playwright + + - name: Run browser tests + run: yarn workspace @noir-lang/noirc_abi test:browser + diff --git a/.github/workflows/test-acvm-js.yml b/.github/workflows/test-acvm-js.yml new file mode 100644 index 00000000000..8a469f6ff1e --- /dev/null +++ b/.github/workflows/test-acvm-js.yml @@ -0,0 +1,97 @@ +name: Test acvm_js + +on: [push, pull_request] + +# This will cancel previous runs when a branch or PR is updated +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + build-acvm-js-package: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - uses: cachix/install-nix-action@v20 + with: + nix_path: nixpkgs=channel:nixos-22.11 + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: cachix/cachix-action@v12 + with: + name: barretenberg + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Build acvm-js + run: | + nix build -L .#acvm_js + + - name: Dereference symlink + run: echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: acvm-js + path: ${{ env.UPLOAD_PATH }} + retention-days: 3 + + test-acvm_js-node: + needs: [build-acvm-js-package] + name: Node.js Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: acvm-js + path: ./result + + - name: Move build artifacts + run: | + mv ./result/acvm_js/nodejs ./acvm-repo/acvm_js/nodejs + mv ./result/acvm_js/web ./acvm-repo/acvm_js/web + + - name: Set up test environment + uses: ./.github/actions/setup + + - name: Run node tests + run: yarn workspace @noir-lang/acvm_js test + + test-acvm_js-browser: + needs: [build-acvm-js-package] + name: Browser Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: acvm-js + path: ./result + + - name: Move build artifacts + run: | + mv ./result/acvm_js/nodejs ./acvm-repo/acvm_js/nodejs + mv ./result/acvm_js/web ./acvm-repo/acvm_js/web + + - name: Set up test environment + uses: ./.github/actions/setup + + - name: Install playwright deps + run: | + npx playwright install + npx playwright install-deps + + - name: Run browser tests + working-directory: ./acvm-repo/acvm_js + run: yarn workspace @noir-lang/acvm_js test:browser diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index 46606ace966..ebc2136f514 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -4,25 +4,100 @@ on: workflow_dispatch: pull_request: paths: - - ./compiler/integration-tests + - ./compiler/integration-tests/** schedule: - cron: "0 2 * * *" # Run nightly at 2 AM UTC jobs: - wasm-packages-build-test: + build-nargo: + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64-unknown-linux-gnu] + + steps: + - name: Checkout Noir repo + uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.66.0 + + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} + + - name: Build Nargo + run: cargo build --package nargo_cli --release + + - name: Package artifacts + run: | + mkdir dist + cp ./target/release/nargo ./dist/nargo + 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-x86_64-unknown-linux-gnu.tar.gz + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: nargo + path: ./dist/* + retention-days: 3 + + build-wasm: runs-on: ubuntu-latest env: CACHED_PATH: /tmp/nix-cache steps: - - name: Checkout noir sources + - name: Checkout sources uses: actions/checkout@v4 - - name: Checkout acvm sources - uses: actions/checkout@v3 # v3 is needed here otherwise this fails in local execution + - name: Setup Nix + uses: cachix/install-nix-action@v22 + with: + nix_path: nixpkgs=channel:nixos-23.05 + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: cachix/cachix-action@v12 + with: + name: barretenberg + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Build wasm package + run: | + nix build -L .#noir_wasm + + - name: Export cache from nix store + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} + run: | + nix copy --to "file://${{ env.CACHED_PATH }}?compression=zstd¶llel-compression=true" .#noir-wasm-cargo-artifacts + + - uses: actions/cache/save@v3 + # Don't create cache entries for the merge queue. + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} with: - repository: noir-lang/acvm - path: acvm + path: ${{ env.CACHED_PATH }} + key: ${{ steps.cache.outputs.cache-primary-key }} + + - name: Dereference symlink + run: echo "UPLOAD_PATH=$(readlink -f ./result/noir_wasm)" >> $GITHUB_ENV + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: noir_wasm + path: ${{ env.UPLOAD_PATH }} + retention-days: 3 + + build-noirc: + runs-on: ubuntu-latest + env: + CACHED_PATH: /tmp/nix-cache + + steps: + - name: Checkout sources + uses: actions/checkout@v3 - name: Setup Nix uses: cachix/install-nix-action@v22 @@ -40,7 +115,7 @@ jobs: id: cache with: path: ${{ env.CACHED_PATH }} - key: ${{ runner.os }}-flake-wasm-${{ hashFiles('*.lock') }} + key: ${{ runner.os }}-flake-abi-wasm-${{ hashFiles('*.lock') }} # Based on https://github.com/marigold-dev/deku/blob/b5016f0cf4bf6ac48db9111b70dd7fb49b969dfd/.github/workflows/build.yml#L26 - name: Copy cache into nix store @@ -52,46 +127,133 @@ jobs: nix copy --no-check-sigs --from "file://${{ env.CACHED_PATH }}" "$path" done - - name: Build noir_wasm package + - name: Build noirc_abi_wasm run: | - nix build -L .#wasm - echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV - cp -r ./result/nodejs ./compiler/wasm - cp -r ./result/web ./compiler/wasm + nix build -L .#noirc_abi_wasm + cp -r ./result/noirc_abi_wasm/nodejs ./tooling/noirc_abi_wasm + cp -r ./result/noirc_abi_wasm/web ./tooling/noirc_abi_wasm - - name: Upload `noir_wasm` artifact - uses: actions/upload-artifact@v3 + - name: Export cache from nix store + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} + run: | + nix copy --to "file://${{ env.CACHED_PATH }}?compression=zstd¶llel-compression=true" .#noirc-abi-wasm-cargo-artifacts + + - uses: actions/cache/save@v3 + # Don't create cache entries for the merge queue. + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} with: - name: noir_wasm - path: ${{ env.UPLOAD_PATH }} - retention-days: 3 + path: ${{ env.CACHED_PATH }} + key: ${{ steps.cache.outputs.cache-primary-key }} - - name: Build noirc_abi_wasm package - run: | - nix build -L .#noirc_abi_wasm - echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV - cp -r ./result/nodejs ./tooling/noirc_abi_wasm - cp -r ./result/web ./tooling/noirc_abi_wasm + - name: Dereference symlink + run: echo "UPLOAD_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV - - name: Upload `noirc_abi_wasm` artifact + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: noirc_abi_wasm path: ${{ env.UPLOAD_PATH }} - retention-days: 3 + retention-days: 10 + + test-solidity-verifier: + runs-on: ubuntu-latest + needs: [build-wasm, build-nargo, build-noirc] + env: + CACHED_PATH: /tmp/nix-cache + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download nargo binary + uses: actions/download-artifact@v3 + with: + name: nargo + path: ./nargo + + - name: Download wasm package artifact + uses: actions/download-artifact@v3 + with: + name: noir_wasm + path: ./compiler/wasm + + - name: Download noirc package artifact + uses: actions/download-artifact@v3 + with: + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm + + - name: Set nargo on PATH + run: | + nargo_binary="${{ github.workspace }}/nargo/nargo" + chmod +x $nargo_binary + echo "$(dirname $nargo_binary)" >> $GITHUB_PATH + export PATH="$PATH:$(dirname $nargo_binary)" + nargo -V - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Install jq + run: sudo apt-get install jq + + - name: Install wasm-bindgen-cli + uses: taiki-e/install-action@v2 + with: + tool: wasm-bindgen-cli@0.2.86 + + - name: Install wasm-opt + run: | + npm i wasm-opt -g + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Anvil + run: | + anvil > /dev/null 2>&1 & + sleep 10 + + - name: Create new Foundry project + run: forge init --no-git --no-commit --force foundry-project + + - name: Run codegen-verifier for 1_mul + working-directory: tooling/nargo_cli/tests/execution_success/1_mul + run: nargo codegen-verifier + + - name: Run codegen-verifier for main + working-directory: compiler/integration-tests/test/circuits/main + run: nargo codegen-verifier + + - name: Copy compiled contracts + run: | + cp tooling/nargo_cli/tests/execution_success/1_mul/contract/1_mul/plonk_vk.sol foundry-project/src/1_mul.sol + cp compiler/integration-tests/test/circuits/main/contract/main/plonk_vk.sol foundry-project/src/main.sol + + - name: Forge build + working-directory: foundry-project + run: forge build + + - name: Forge deploy + working-directory: foundry-project + run: | + forge create --rpc-url http://127.0.0.1:8545 --mnemonic "test test test test test test test test test test test junk" src/1_mul.sol:UltraVerifier --json > mul_output.json + forge create --rpc-url http://127.0.0.1:8545 --mnemonic "test test test test test test test test test test test junk" src/main.sol:UltraVerifier --json > main_output.json + + - name: Setup `integration-tests` run: | - yarn workspace @noir-lang/noir-source-resolver build + yarn workspace @noir-lang/source-resolver build + yarn workspace @noir-lang/acvm_js build + yarn workspace @noir-lang/noir_js build - name: Run `integration-tests` run: | yarn test:integration - - - name: Alert on nightly test failure + + - name: Alert on nightly test failure uses: JasonEtco/create-an-issue@v2 if: ${{ failure() && github.event_name == 'schedule' }} env: diff --git a/.github/workflows/test-noir-js.yml b/.github/workflows/test-noir-js.yml new file mode 100644 index 00000000000..1dac0200027 --- /dev/null +++ b/.github/workflows/test-noir-js.yml @@ -0,0 +1,54 @@ +name: Noir JS + +on: + pull_request: + merge_group: + push: + branches: + - master + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.66.0 + with: + targets: wasm32-unknown-unknown + + - uses: Swatinem/rust-cache@v2 + with: + key: wasm32-unknown-unknown-noir-js + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} + + - name: Install jq + run: sudo apt-get install jq + + - name: Install wasm-bindgen-cli + uses: taiki-e/install-action@v2 + with: + tool: wasm-bindgen-cli@0.2.86 + + - name: Install wasm-opt + run: | + npm i wasm-opt -g + + - name: Build acvm_js + run: yarn workspace @noir-lang/acvm_js build + + - name: Build noirc_abi + run: yarn workspace @noir-lang/noirc_abi build + + - name: Run noir_js tests + run: | + yarn workspace @noir-lang/noir_js build + yarn workspace @noir-lang/noir_js test diff --git a/.github/workflows/wasm.yml b/.github/workflows/test-noir_wasm.yml similarity index 67% rename from .github/workflows/wasm.yml rename to .github/workflows/test-noir_wasm.yml index f7b36738482..82c094959bc 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/test-noir_wasm.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: target: [x86_64-unknown-linux-gnu] - + steps: - name: Checkout Noir repo uses: actions/checkout@v4 @@ -59,44 +59,20 @@ jobs: - name: Setup Nix uses: cachix/install-nix-action@v22 with: - nix_path: nixpkgs=channel:nixos-22.11 + nix_path: nixpkgs=channel:nixos-23.05 github_access_token: ${{ secrets.GITHUB_TOKEN }} - - name: Restore nix store cache - uses: actions/cache/restore@v3 - id: cache + - uses: cachix/cachix-action@v12 with: - path: ${{ env.CACHED_PATH }} - key: ${{ runner.os }}-flake-wasm-${{ hashFiles('*.lock') }} - - # Based on https://github.com/marigold-dev/deku/blob/b5016f0cf4bf6ac48db9111b70dd7fb49b969dfd/.github/workflows/build.yml#L26 - - name: Copy cache into nix store - if: steps.cache.outputs.cache-hit == 'true' - # We don't check the signature because we're the one that created the cache - run: | - for narinfo in ${{ env.CACHED_PATH }}/*.narinfo; do - path=$(head -n 1 "$narinfo" | awk '{print $2}') - nix copy --no-check-sigs --from "file://${{ env.CACHED_PATH }}" "$path" - done + name: barretenberg + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: Build wasm package run: | - nix build -L .#wasm - - - name: Export cache from nix store - if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} - run: | - nix copy --to "file://${{ env.CACHED_PATH }}?compression=zstd¶llel-compression=true" .#noir-wasm-cargo-artifacts - - - uses: actions/cache/save@v3 - # Don't create cache entries for the merge queue. - if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} - with: - path: ${{ env.CACHED_PATH }} - key: ${{ steps.cache.outputs.cache-primary-key }} + nix build -L .#noir_wasm - name: Dereference symlink - run: echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV + run: echo "UPLOAD_PATH=$(readlink -f ./result/noir_wasm)" >> $GITHUB_ENV - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/.github/workflows/test.yml b/.github/workflows/test-rust-workspace.yml similarity index 100% rename from .github/workflows/test.yml rename to .github/workflows/test-rust-workspace.yml diff --git a/.gitignore b/.gitignore index e36a7458e7b..94e8f1a8db0 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ compiler/wasm/nodejs compiler/wasm/web tooling/noirc_abi_wasm/nodejs tooling/noirc_abi_wasm/web +tooling/noir_js/lib diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8032c17e87a..baa3067f372 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,4 @@ { - ".": "0.12.0" -} + ".": "0.14.1", + "acvm-repo": "0.27.3" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 749c7cfd0a9..8be4206c9c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,83 @@ # Changelog +## [0.14.1](https://github.com/noir-lang/noir/compare/v0.14.0...v0.14.1) (2023-09-27) + + +### Bug Fixes + +* Remove cast for field comparisons in brillig ([#2874](https://github.com/noir-lang/noir/issues/2874)) ([1fc1fdb](https://github.com/noir-lang/noir/commit/1fc1fdb4e15d2ce625ea79d458c5346fab418e49)) +* Remove duplication of code to load stdlib files ([#2868](https://github.com/noir-lang/noir/issues/2868)) ([b694aab](https://github.com/noir-lang/noir/commit/b694aab87c4665a3a89715c9d4096eeb3efb9944)) + +## [0.14.0](https://github.com/noir-lang/noir/compare/v0.13.0...v0.14.0) (2023-09-26) + + +### ⚠ BREAKING CHANGES + +* **noir_js:** Rename inner and outer proof methods ([#2845](https://github.com/noir-lang/noir/issues/2845)) +* `generateWitness` now returns a serialized witness file ([#2842](https://github.com/noir-lang/noir/issues/2842)) +* Issue an error when a module is declared twice & fix module search path ([#2801](https://github.com/noir-lang/noir/issues/2801)) +* Default integers to u64 ([#2764](https://github.com/noir-lang/noir/issues/2764)) + +### Features + +* **abi:** Throw errors rather than returning string from `noirc_abi_wasm` ([#2817](https://github.com/noir-lang/noir/issues/2817)) ([df7b42c](https://github.com/noir-lang/noir/commit/df7b42cd253d1b908a42c367b116813f9999d93b)) +* **acir:** Enable dynamic indices on non-homogenous arrays ([#2703](https://github.com/noir-lang/noir/issues/2703)) ([622d2e4](https://github.com/noir-lang/noir/commit/622d2e436992c23e6d0885b591bd1072ca57b307)) +* Default integers to u64 ([#2764](https://github.com/noir-lang/noir/issues/2764)) ([01cb041](https://github.com/noir-lang/noir/commit/01cb041a92ef6043dd5a160e0a56a63400801980)) +* Implement string escape sequences ([#2803](https://github.com/noir-lang/noir/issues/2803)) ([f7529b8](https://github.com/noir-lang/noir/commit/f7529b80f0958fd47a525f25a123f16438bbb892)) +* Remove redundant predicate from brillig quotients ([#2784](https://github.com/noir-lang/noir/issues/2784)) ([a8f18c5](https://github.com/noir-lang/noir/commit/a8f18c55b35f47c6fa3ebfebcd827aeb55e5c850)) +* **traits:** Implement trait bounds typechecker + monomorphizer passes ([#2717](https://github.com/noir-lang/noir/issues/2717)) ([5ca99b1](https://github.com/noir-lang/noir/commit/5ca99b128e9991b5272c00292208d85415e70edf)) + + +### Bug Fixes + +* **acvm:** Return false rather than panicking on invalid ECDSA signatures ([#2783](https://github.com/noir-lang/noir/issues/2783)) ([155abc0](https://github.com/noir-lang/noir/commit/155abc0d99fff41c79163c16bf297d41e5dff0fa)) +* Conditionally run the "Create or Update PR" step in acir artifacts rebuild workflow ([#2849](https://github.com/noir-lang/noir/issues/2849)) ([63da875](https://github.com/noir-lang/noir/commit/63da875a85a2ad4ad3038443ba52eb28ea44ad10)) +* Error message for assigning the wrong type is backwards [#2804](https://github.com/noir-lang/noir/issues/2804) ([#2805](https://github.com/noir-lang/noir/issues/2805)) ([b2d62bf](https://github.com/noir-lang/noir/commit/b2d62bff3b7958b3ed62c285a7ebd45045ac2e05)) +* Fix panic in some cases when calling a private function ([#2799](https://github.com/noir-lang/noir/issues/2799)) ([078d5df](https://github.com/noir-lang/noir/commit/078d5df691d4ea48e83c9530cd40b64917eba0a7)) +* Fix subtract with underflow in flattening pass ([#2796](https://github.com/noir-lang/noir/issues/2796)) ([f2ed505](https://github.com/noir-lang/noir/commit/f2ed5054b0b0335dd3ecb17369b0d2e6eafb1171)) +* **frontend:** Error on unsupported integer annotation ([#2778](https://github.com/noir-lang/noir/issues/2778)) ([90c3d8b](https://github.com/noir-lang/noir/commit/90c3d8baa3b7ae10bc99f6a767121f556ff75967)) +* Issue an error when a module is declared twice & fix module search path ([#2801](https://github.com/noir-lang/noir/issues/2801)) ([7f76910](https://github.com/noir-lang/noir/commit/7f76910ebbd20e3d7a1db7541f2b7f43cd9b546d)) +* Lack of cjs package version ([#2848](https://github.com/noir-lang/noir/issues/2848)) ([adc2d59](https://github.com/noir-lang/noir/commit/adc2d597536b52c690dceb14ea5f8e30a493452c)) +* Silence unused variable warnings in stdlib ([#2795](https://github.com/noir-lang/noir/issues/2795)) ([5747bfe](https://github.com/noir-lang/noir/commit/5747bfed256f9179321ec0bd1e02f5f82723a4c7)) +* Split conditional_regression tests ([#2774](https://github.com/noir-lang/noir/issues/2774)) ([8ed8832](https://github.com/noir-lang/noir/commit/8ed8832c7b475cd28ae697a09f1ad07c539736db)) +* **ssa:** Do not replace previously constrained values ([#2647](https://github.com/noir-lang/noir/issues/2647)) ([d528844](https://github.com/noir-lang/noir/commit/d5288449a10d162a0340818a6beab54dd985a11a)) + + +### Miscellaneous Chores + +* `generateWitness` now returns a serialized witness file ([#2842](https://github.com/noir-lang/noir/issues/2842)) ([57d3f37](https://github.com/noir-lang/noir/commit/57d3f376d9ceadb75caf37a2bfc0e9394f76bfe6)) +* **noir_js:** Rename inner and outer proof methods ([#2845](https://github.com/noir-lang/noir/issues/2845)) ([71dbbb8](https://github.com/noir-lang/noir/commit/71dbbb863a6f262da4804c17965ace627bf3a278)) + +## [0.13.0](https://github.com/noir-lang/noir/compare/v0.12.0...v0.13.0) (2023-09-21) + + +### ⚠ BREAKING CHANGES + +* constrain is now a hard error ([#2758](https://github.com/noir-lang/noir/issues/2758)) + +### Features + +* Add `pub` modifier ([#2754](https://github.com/noir-lang/noir/issues/2754)) ([dda964e](https://github.com/noir-lang/noir/commit/dda964e82e170a59c328908117677c16f691be7b)) +* Add support for attributes on structs ([#2733](https://github.com/noir-lang/noir/issues/2733)) ([7b3df8e](https://github.com/noir-lang/noir/commit/7b3df8e8be11fe4288ed865951ef88566160f4af)) +* Add wrapping functions in stdlib and use them in relevant test cases ([#2725](https://github.com/noir-lang/noir/issues/2725)) ([49ab121](https://github.com/noir-lang/noir/commit/49ab121ef21819e028d407999a689b92c67d8df7)) +* **aztec-noir:** Abstract storage ([#2750](https://github.com/noir-lang/noir/issues/2750)) ([5481344](https://github.com/noir-lang/noir/commit/5481344feaa0403e1f6a499ff1e8e4dbbd0297aa)) +* Constrain is now a hard error ([#2758](https://github.com/noir-lang/noir/issues/2758)) ([388a2b1](https://github.com/noir-lang/noir/commit/388a2b1659b2a07bde1bc376fc4669f855780858)) +* Refine Noir.js API ([#2732](https://github.com/noir-lang/noir/issues/2732)) ([e79f1ed](https://github.com/noir-lang/noir/commit/e79f1ed357bf7002f14001689fb4b33e0346e679)) +* Short-circuit compilation and read build artifacts from file if program is unchanged ([#2743](https://github.com/noir-lang/noir/issues/2743)) ([87fea4b](https://github.com/noir-lang/noir/commit/87fea4b447596bdd11ab461f847e03d4f1cc45f2)) +* Signed arithmetic ([#2748](https://github.com/noir-lang/noir/issues/2748)) ([a84216d](https://github.com/noir-lang/noir/commit/a84216dd23513b008739ae0a749e48d0dd262a28)) +* **traits:** Implement trait bounds def collector + resolver passes ([#2716](https://github.com/noir-lang/noir/issues/2716)) ([e3d18bb](https://github.com/noir-lang/noir/commit/e3d18bb9889d84fa78eecf3783bac446eac5adef)) +* **traits:** Type checking for Trait impl method signatures ([#2652](https://github.com/noir-lang/noir/issues/2652)) ([8617008](https://github.com/noir-lang/noir/commit/8617008d572c22fd9c830c233bfc0088fe0bafe4)) +* Variable liveness analysis for brillig ([#2715](https://github.com/noir-lang/noir/issues/2715)) ([ddb05ab](https://github.com/noir-lang/noir/commit/ddb05ab8d30ea2b60c06f3cd7d36d5bf1b21b3ef)) + + +### Bug Fixes + +* Add error message for a contract package with no contracts ([#2762](https://github.com/noir-lang/noir/issues/2762)) ([9701a0c](https://github.com/noir-lang/noir/commit/9701a0cc2cde3b3e8fa55c3f8d09343f8861f2f8)) +* Check for literal overflows in expressions ([#2742](https://github.com/noir-lang/noir/issues/2742)) ([4009f30](https://github.com/noir-lang/noir/commit/4009f30e18b17b5e7ef5af324bb9eaea5ed3780a)) +* Keep the correct type for bitshift ([#2739](https://github.com/noir-lang/noir/issues/2739)) ([04fc2ea](https://github.com/noir-lang/noir/commit/04fc2ea5bc2490cdd2cb4ec90e34986fa91f43d4)) +* Make `Vec::get` accept immutable `Vec`s ([#2776](https://github.com/noir-lang/noir/issues/2776)) ([f168a54](https://github.com/noir-lang/noir/commit/f168a5407b303d2e13d5975e9dc18ec13ff68c5f)) +* Nightly js test ([#2740](https://github.com/noir-lang/noir/issues/2740)) ([36dcd48](https://github.com/noir-lang/noir/commit/36dcd4883313faabefe201be3645dcad79dc7970)) + ## [0.12.0](https://github.com/noir-lang/noir/compare/v0.11.1...v0.12.0) (2023-09-15) diff --git a/Cargo.lock b/Cargo.lock index 8cccc14d393..1538bed2fb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,24 +4,25 @@ version = 3 [[package]] name = "acir" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfd6bb6cb07ac4869c58d6e0219f447c2d550a9b2f135f27a6bc6ae0178c379" +version = "0.27.3" dependencies = [ "acir_field", "bincode", "brillig", "flate2", + "rmp-serde", "serde", + "serde_json", + "strum", + "strum_macros", "thiserror", ] [[package]] name = "acir_field" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f41bc6e6dab8bd68516970371d7dd897d09e9bf0aa17a72c5e51cefcdad6573" +version = "0.27.3" dependencies = [ + "ark-bls12-381", "ark-bn254", "ark-ff", "cfg-if", @@ -32,9 +33,7 @@ dependencies = [ [[package]] name = "acvm" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79eb3b6adc177c907e03b9414a45ef5b37100eb51503c573b3eaf383e93a7543" +version = "0.27.3" dependencies = [ "acir", "acvm_blackbox_solver", @@ -43,58 +42,49 @@ dependencies = [ "indexmap 1.9.3", "num-bigint", "num-traits", - "thiserror", -] - -[[package]] -name = "acvm-backend-barretenberg" -version = "0.11.0" -dependencies = [ - "acvm", - "build-target", - "const_format", - "dirs", - "flate2", - "reqwest", - "serde", - "serde_json", - "tar", - "tempfile", - "test-binary", + "paste", + "proptest", + "rand", "thiserror", ] [[package]] name = "acvm_blackbox_solver" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aac4ad683de5aebb590168405c46cdfd76dc7706a7d2c51d029258772d1933e" +version = "0.27.3" dependencies = [ "acir", "blake2", - "flate2", - "getrandom", - "hex", - "js-sys", "k256", - "num-bigint", "p256", - "pkg-config", - "reqwest", - "rust-embed", "sha2", "sha3", - "tar", "thiserror", +] + +[[package]] +name = "acvm_js" +version = "0.27.3" +dependencies = [ + "acvm", + "barretenberg_blackbox_solver", + "build-data", + "cfg-if", + "console_error_panic_hook", + "const-str", + "gloo-utils", + "js-sys", + "log", + "pkg-config", + "serde", + "wasm-bindgen", "wasm-bindgen-futures", - "wasmer", + "wasm-bindgen-test", + "wasm-logger", ] [[package]] name = "acvm_stdlib" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3344180fe2a59d57cdb0e6251cdc7d9978f15c06eace1af7d82bab12dd3ced9" +version = "0.27.3" dependencies = [ "acir", ] @@ -218,11 +208,23 @@ dependencies = [ [[package]] name = "arena" -version = "0.12.0" +version = "0.14.1" dependencies = [ "generational-arena", ] +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + [[package]] name = "ark-bn254" version = "0.4.0" @@ -402,6 +404,25 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backend-interface" +version = "0.11.0" +dependencies = [ + "acvm", + "bb_abstraction_leaks", + "build-target", + "const_format", + "dirs", + "flate2", + "reqwest", + "serde", + "serde_json", + "tar", + "tempfile", + "test-binary", + "thiserror", +] + [[package]] name = "backtrace" version = "0.3.68" @@ -417,6 +438,26 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "barretenberg_blackbox_solver" +version = "0.27.3" +dependencies = [ + "acir", + "acvm_blackbox_solver", + "flate2", + "getrandom", + "hex", + "js-sys", + "num-bigint", + "pkg-config", + "reqwest", + "rust-embed", + "tar", + "thiserror", + "wasm-bindgen-futures", + "wasmer", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -435,6 +476,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bb_abstraction_leaks" +version = "0.11.0" +dependencies = [ + "acvm", + "build-target", + "const_format", +] + [[package]] name = "bincode" version = "1.3.3" @@ -444,6 +494,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -497,9 +562,7 @@ dependencies = [ [[package]] name = "brillig" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448a380e86405ad785c235907654bea2080386d03c77a2003063ddabb853d744" +version = "0.27.3" dependencies = [ "acir_field", "serde", @@ -507,9 +570,7 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1097a496ff44eb2b8f01789dfefb5bbd9364b132d9c2446a4ca18090259bf6" +version = "0.27.3" dependencies = [ "acir", "acvm_blackbox_solver", @@ -813,6 +874,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" +[[package]] +name = "const-str" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aca749d3d3f5b87a0d6100509879f9cf486ab510803a4a4e1001da1ff61c2bd6" + [[package]] name = "const_format" version = "0.2.31" @@ -841,9 +908,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "corosensei" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" +checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" dependencies = [ "autocfg", "cfg-if", @@ -1121,9 +1188,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.0", @@ -1436,7 +1503,7 @@ dependencies = [ [[package]] name = "fm" -version = "0.12.0" +version = "0.14.1" dependencies = [ "cfg-if", "codespan-reporting", @@ -1969,7 +2036,7 @@ dependencies = [ [[package]] name = "iter-extended" -version = "0.12.0" +version = "0.14.1" [[package]] name = "itertools" @@ -2034,6 +2101,12 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -2164,7 +2237,7 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "nargo" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "base64", @@ -2183,13 +2256,15 @@ dependencies = [ [[package]] name = "nargo_cli" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", - "acvm-backend-barretenberg", "assert_cmd", "assert_fs", "async-lsp", + "backend-interface", + "barretenberg_blackbox_solver", + "bb_abstraction_leaks", "build-data", "clap", "color-eyre", @@ -2227,7 +2302,7 @@ dependencies = [ [[package]] name = "nargo_toml" -version = "0.12.0" +version = "0.14.1" dependencies = [ "dirs", "fm", @@ -2253,10 +2328,11 @@ dependencies = [ [[package]] name = "noir_lsp" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "async-lsp", + "barretenberg_blackbox_solver", "codespan-lsp", "codespan-reporting", "fm", @@ -2275,12 +2351,13 @@ dependencies = [ [[package]] name = "noir_wasm" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "build-data", "console_error_panic_hook", "fm", + "getrandom", "gloo-utils", "log", "nargo", @@ -2293,7 +2370,7 @@ dependencies = [ [[package]] name = "noirc_abi" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "iter-extended", @@ -2310,11 +2387,12 @@ dependencies = [ [[package]] name = "noirc_abi_wasm" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "build-data", "console_error_panic_hook", + "getrandom", "gloo-utils", "iter-extended", "js-sys", @@ -2326,12 +2404,13 @@ dependencies = [ [[package]] name = "noirc_driver" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "base64", "clap", "fm", + "fxhash", "noirc_abi", "noirc_errors", "noirc_evaluator", @@ -2341,7 +2420,7 @@ dependencies = [ [[package]] name = "noirc_errors" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "chumsky", @@ -2354,7 +2433,7 @@ dependencies = [ [[package]] name = "noirc_evaluator" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "fxhash", @@ -2369,7 +2448,7 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "arena", @@ -2390,7 +2469,7 @@ dependencies = [ [[package]] name = "noirc_printable_type" -version = "0.12.0" +version = "0.14.1" dependencies = [ "acvm", "iter-extended", @@ -2444,6 +2523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2702,6 +2782,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.6.29", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -2722,6 +2822,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-xml" version = "0.26.0" @@ -2752,6 +2858,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core", ] @@ -2775,6 +2882,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -2856,7 +2972,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax", + "regex-syntax 0.7.4", ] [[package]] @@ -2867,9 +2983,15 @@ checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.4" @@ -3000,6 +3122,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rmp" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rust-embed" version = "6.8.1" @@ -3121,6 +3265,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.15" @@ -3586,9 +3742,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.10" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" @@ -3904,6 +4060,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -4140,9 +4302,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.31.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a3d1b4a575ffb873679402b2aedb3117555eb65c27b1b86c8a91e574bc2a2a" +checksum = "b39de0723a53d3c8f54bed106cfbc0d06b3e4d945c5c5022115a61e3b29183ae" dependencies = [ "leb128", ] @@ -4303,9 +4465,9 @@ dependencies = [ [[package]] name = "wast" -version = "62.0.0" +version = "65.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f7ee878019d69436895f019b65f62c33da63595d8e857cbdc87c13ecb29a32" +checksum = "5fd8c1cbadf94a0b0d1071c581d3cfea1b7ed5192c79808dd15406e508dd0afb" dependencies = [ "leb128", "memchr", @@ -4315,9 +4477,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.68" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295572bf24aa5b685a971a83ad3e8b6e684aaad8a9be24bc7bf59bed84cc1c08" +checksum = "3209e35eeaf483714f4c6be93f4a03e69aad5f304e3fa66afa7cb90fe1c8051f" dependencies = [ "wast", ] diff --git a/Cargo.toml b/Cargo.toml index dac1c15e0a5..f87f3b3d01a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,27 +12,39 @@ members = [ "compiler/utils/arena", "compiler/utils/iter-extended", # Crates related to tooling built ontop of the Noir compiler - "tooling/acvm_backend_barretenberg", + "tooling/backend_interface", + "tooling/bb_abstraction_leaks", + "tooling/lsp", "tooling/nargo", "tooling/nargo_cli", "tooling/nargo_toml", "tooling/noirc_abi", "tooling/noirc_abi_wasm", + # ACVM + "acvm-repo/acir_field", + "acvm-repo/acir", + "acvm-repo/acvm", + "acvm-repo/acvm_js", + "acvm-repo/stdlib", + "acvm-repo/brillig", + "acvm-repo/brillig_vm", + "acvm-repo/blackbox_solver", + "acvm-repo/barretenberg_blackbox_solver", ] default-members = ["tooling/nargo_cli"] resolver = "2" [workspace.package] # x-release-please-start-version -version = "0.12.0" +version = "0.14.1" # x-release-please-end authors = ["The Noir Team "] edition = "2021" rust-version = "1.66" license = "MIT OR Apache-2.0" +repository = "https://github.com/noir-lang/noir/" [workspace.dependencies] -acvm = "0.26.1" arena = { path = "compiler/utils/arena" } fm = { path = "compiler/fm" } iter-extended = { path = "compiler/utils/iter-extended" } @@ -41,6 +53,7 @@ nargo_cli = { path = "tooling/nargo_cli" } nargo_toml = { path = "tooling/nargo_toml" } noir_lsp = { path = "tooling/lsp" } noirc_abi = { path = "tooling/noirc_abi" } +bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } noirc_driver = { path = "compiler/noirc_driver" } noirc_errors = { path = "compiler/noirc_errors" } noirc_evaluator = { path = "compiler/noirc_evaluator" } @@ -68,3 +81,23 @@ url = "2.2.0" wasm-bindgen = { version = "=0.2.86", features = ["serde-serialize"] } wasm-bindgen-test = "0.3.33" base64 = "0.21.2" +fxhash = "0.2.1" +acir = { path = "acvm-repo/acir", default-features = false } +acvm = { path = "acvm-repo/acvm" } +acir_field = { path = "acvm-repo/acir_field", default-features = false } +stdlib = { package = "acvm_stdlib", path = "acvm-repo/stdlib", default-features = false } +brillig = { path = "acvm-repo/brillig", default-features = false } +brillig_vm = { path = "acvm-repo/brillig_vm", default-features = false } +acvm_blackbox_solver = { path = "acvm-repo/blackbox_solver", default-features = false } +barretenberg_blackbox_solver = { path = "acvm-repo/barretenberg_blackbox_solver", default-features = false } + +bincode = "1.3.3" + +hex = "0.4.2" +num-bigint = "0.4" +num-traits = "0.2" + +[profile.dev] +# This is required to be able to run `cargo test` in acvm_js due to the `locals exceeds maximum` error. +# See https://ritik-mishra.medium.com/resolving-the-wasm-pack-error-locals-exceed-maximum-ec3a9d96685b +opt-level = 1 diff --git a/SUPPORT.md b/SUPPORT.md index 82d585937e4..fcf17b9891f 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -4,7 +4,7 @@ Thank you for your interest in Noir! There are many ways to participate in the c ## Asking Questions -The best place to ask general questions about Noir is in the #noir channel on the [Aztec discord](https://discord.gg/aztec). +The best place to ask general questions about Noir is in the #noir channel on the [Noir discord](https://discord.gg/YpCUTkzTC7). It might also be helpful to review existing and previous Github issues to see if your question has been answered already. @@ -21,7 +21,7 @@ When submitting an issue, please include as much detail as possible about the er ## Contributing to the Standard Library -Noir is still very new and there are many cryptographic primitives that we have yet to build that will be useful for the community. If you have other ideas, please reach out on the [Aztec Discord](https://discord.gg/aztec) to discuss. You can find the current list of requested primitives in the [issues section](https://github.com/noir-lang/noir/labels/noir-stdlib) marked with the label `noir-stdlib`. +Noir is still very new and there are many cryptographic primitives that we have yet to build that will be useful for the community. If you have other ideas, please reach out on the [Noir Discord](https://discord.gg/YpCUTkzTC7) to discuss. You can find the current list of requested primitives in the [issues section](https://github.com/noir-lang/noir/labels/noir-stdlib) marked with the label `noir-stdlib`. ## Funding Opportunities diff --git a/acvm-repo/CHANGELOG.md b/acvm-repo/CHANGELOG.md new file mode 100644 index 00000000000..681e9119543 --- /dev/null +++ b/acvm-repo/CHANGELOG.md @@ -0,0 +1,757 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.27.3](https://github.com/noir-lang/noir/compare/v0.27.2...v0.27.3) (2023-09-27) + + +### Bug Fixes + +* **acvm:** Return false rather than panicking on invalid ECDSA signatures ([#2783](https://github.com/noir-lang/noir/issues/2783)) ([155abc0](https://github.com/noir-lang/noir/commit/155abc0d99fff41c79163c16bf297d41e5dff0fa)) + +## [0.27.2](https://github.com/noir-lang/noir/compare/v0.27.1...v0.27.2) (2023-09-27) + + +### Bug Fixes + +* **acvm:** Return false rather than panicking on invalid ECDSA signatures ([#2783](https://github.com/noir-lang/noir/issues/2783)) ([155abc0](https://github.com/noir-lang/noir/commit/155abc0d99fff41c79163c16bf297d41e5dff0fa)) + +## [0.27.1](https://github.com/noir-lang/noir/compare/v0.27.0...v0.27.1) (2023-09-26) + + +### Bug Fixes + +* **acvm:** Return false rather than panicking on invalid ECDSA signatures ([#2783](https://github.com/noir-lang/noir/issues/2783)) ([155abc0](https://github.com/noir-lang/noir/commit/155abc0d99fff41c79163c16bf297d41e5dff0fa)) + +## [0.27.0](https://github.com/noir-lang/acvm/compare/root-v0.26.1...root-v0.27.0) (2023-09-19) + + +### ⚠ BREAKING CHANGES + +* Separate barretenberg solver from generic blackbox solver code ([#554](https://github.com/noir-lang/acvm/issues/554)) + +### Features + +* **acir:** add method on `Circuit` to return assert message ([#551](https://github.com/noir-lang/acvm/issues/551)) ([ee18cde](https://github.com/noir-lang/acvm/commit/ee18cde3537b2be6714061af0bc9ef3793929f7f)) + + +### Bug Fixes + +* bump brillig_vm version in release please ([#556](https://github.com/noir-lang/acvm/issues/556)) ([f6c7823](https://github.com/noir-lang/acvm/commit/f6c7823b3be2b85a6ce8dc4af7a3b57ee7a577db)) +* use the exact version for the hex crate ([#546](https://github.com/noir-lang/acvm/issues/546)) ([2a546e5](https://github.com/noir-lang/acvm/commit/2a546e5b5cc9f39737ad81f8e96d58313a74eced)) + + +### Miscellaneous Chores + +* Separate barretenberg solver from generic blackbox solver code ([#554](https://github.com/noir-lang/acvm/issues/554)) ([a4b9772](https://github.com/noir-lang/acvm/commit/a4b97722a0892fe379ff075e6080675adafdce0e)) + +## [0.26.1](https://github.com/noir-lang/acvm/compare/root-v0.26.0...root-v0.26.1) (2023-09-12) + + +### Bug Fixes + +* Implements handling of the high limb during fixed base scalar multiplication ([#535](https://github.com/noir-lang/acvm/issues/535)) ([551504a](https://github.com/noir-lang/acvm/commit/551504aa572d3f9d56b5576d25ce1211296ee488)) + +## [0.26.0](https://github.com/noir-lang/acvm/compare/root-v0.25.0...root-v0.26.0) (2023-09-07) + + +### ⚠ BREAKING CHANGES + +* Add a low and high limb to scalar mul opcode ([#532](https://github.com/noir-lang/acvm/issues/532)) + +### Miscellaneous Chores + +* Add a low and high limb to scalar mul opcode ([#532](https://github.com/noir-lang/acvm/issues/532)) ([b054f66](https://github.com/noir-lang/acvm/commit/b054f66be9c73d4e02dbecdab80874a907f19242)) + +## [0.25.0](https://github.com/noir-lang/acvm/compare/root-v0.24.1...root-v0.25.0) (2023-09-04) + + +### ⚠ BREAKING CHANGES + +* Provide runtime callstacks for brillig failures and return errors in acvm_js ([#523](https://github.com/noir-lang/acvm/issues/523)) + +### Features + +* Provide runtime callstacks for brillig failures and return errors in acvm_js ([#523](https://github.com/noir-lang/acvm/issues/523)) ([7ab7cff](https://github.com/noir-lang/acvm/commit/7ab7cff48a9aba61a97fad2a759fc8e55740b098)) + + +### Bug Fixes + +* initialize recursive proof output to zero ([#524](https://github.com/noir-lang/acvm/issues/524)) ([5453074](https://github.com/noir-lang/acvm/commit/545307457dd7634b20ea3977e2d2cc751eba06d2)) + +## [0.24.1](https://github.com/noir-lang/acvm/compare/root-v0.24.0...root-v0.24.1) (2023-09-03) + + +### Bug Fixes + +* Add WASI 20 `_initialize` call to `acvm_backend.wasm` binary ([#518](https://github.com/noir-lang/acvm/issues/518)) ([ec6ab0c](https://github.com/noir-lang/acvm/commit/ec6ab0c6fb2753209abe1e03a449873e255ffd76)) + +## [0.24.0](https://github.com/noir-lang/acvm/compare/root-v0.23.0...root-v0.24.0) (2023-08-31) + + +### ⚠ BREAKING CHANGES + +* **acvm:** Remove the `Backend` trait ([#514](https://github.com/noir-lang/acvm/issues/514)) +* **acir:** Remove unused `Directive` opcodes ([#510](https://github.com/noir-lang/acvm/issues/510)) +* **acir:** Add predicate to MemoryOp ([#503](https://github.com/noir-lang/acvm/issues/503)) +* **acvm:** Remove unused arguments from `Backend` trait ([#511](https://github.com/noir-lang/acvm/issues/511)) +* Assertion messages embedded in the circuit ([#484](https://github.com/noir-lang/acvm/issues/484)) + +### Features + +* **acir:** Add predicate to MemoryOp ([#503](https://github.com/noir-lang/acvm/issues/503)) ([ca9eebe](https://github.com/noir-lang/acvm/commit/ca9eebe34e61adabf97318c8ccaf60c8a424aafd)) +* Assertion messages embedded in the circuit ([#484](https://github.com/noir-lang/acvm/issues/484)) ([06b97c5](https://github.com/noir-lang/acvm/commit/06b97c51041e16651cf8b2be8bc18214e276c6c9)) + + +### Miscellaneous Chores + +* **acir:** Remove unused `Directive` opcodes ([#510](https://github.com/noir-lang/acvm/issues/510)) ([cfd8cbf](https://github.com/noir-lang/acvm/commit/cfd8cbf58307511ac0cc9106c299695c2ca779de)) +* **acvm:** Remove the `Backend` trait ([#514](https://github.com/noir-lang/acvm/issues/514)) ([681535d](https://github.com/noir-lang/acvm/commit/681535da52815a4a164ee4f48f7b48329664af98)) +* **acvm:** Remove unused arguments from `Backend` trait ([#511](https://github.com/noir-lang/acvm/issues/511)) ([ae65355](https://github.com/noir-lang/acvm/commit/ae65355afb7df98c71f81d5a54e89f39f9333920)) + +## [0.23.0](https://github.com/noir-lang/acvm/compare/root-v0.22.0...root-v0.23.0) (2023-08-30) + + +### ⚠ BREAKING CHANGES + +* Return an iterator from `new_locations()` instead of collecting ([#507](https://github.com/noir-lang/acvm/issues/507)) +* **acvm:** remove `CommonReferenceString` trait and preprocess method ([#508](https://github.com/noir-lang/acvm/issues/508)) +* **acvm:** Remove `BlackBoxFunctionSolver` from `Backend` trait ([#494](https://github.com/noir-lang/acvm/issues/494)) +* **acvm:** Pass `BlackBoxFunctionSolver` to `ACVM` by reference + +### Features + +* **acvm_js:** Add `execute_circuit_with_black_box_solver` to prevent reinitialization of `BlackBoxFunctionSolver` ([3877e0e](https://github.com/noir-lang/acvm/commit/3877e0e438a8d0e5545a4da7210767dec05c342f)) +* Expose a `BlackBoxFunctionSolver` containing a barretenberg wasm from `blackbox_solver` ([#494](https://github.com/noir-lang/acvm/issues/494)) ([a1d4b71](https://github.com/noir-lang/acvm/commit/a1d4b71256dfbf1e883e770dd9c45479235aa860)) + + +### Miscellaneous Chores + +* **acvm:** Pass `BlackBoxFunctionSolver` to `ACVM` by reference ([3877e0e](https://github.com/noir-lang/acvm/commit/3877e0e438a8d0e5545a4da7210767dec05c342f)) +* **acvm:** Remove `BlackBoxFunctionSolver` from `Backend` trait ([#494](https://github.com/noir-lang/acvm/issues/494)) ([a1d4b71](https://github.com/noir-lang/acvm/commit/a1d4b71256dfbf1e883e770dd9c45479235aa860)) +* **acvm:** remove `CommonReferenceString` trait and preprocess method ([#508](https://github.com/noir-lang/acvm/issues/508)) ([3827dd3](https://github.com/noir-lang/acvm/commit/3827dd3ce487650843ba4df8337b423e39f97edf)) +* Return an iterator from `new_locations()` instead of collecting ([#507](https://github.com/noir-lang/acvm/issues/507)) ([8d49a5c](https://github.com/noir-lang/acvm/commit/8d49a5c15b1e962cd59252467a20a922edadc2f2)) + +## [0.22.0](https://github.com/noir-lang/acvm/compare/root-v0.21.0...root-v0.22.0) (2023-08-18) + + +### ⚠ BREAKING CHANGES + +* Switched from OpcodeLabel to OpcodeLocation and ErrorLocation ([#493](https://github.com/noir-lang/acvm/issues/493)) +* **acvm:** check for index out-of-bounds on memory operations ([#468](https://github.com/noir-lang/acvm/issues/468)) + +### Features + +* **acvm:** check for index out-of-bounds on memory operations ([#468](https://github.com/noir-lang/acvm/issues/468)) ([740468c](https://github.com/noir-lang/acvm/commit/740468c0a144f7179c38f615cfda31b2fcc77359)) +* print error location with fmt ([#497](https://github.com/noir-lang/acvm/issues/497)) ([575a9e5](https://github.com/noir-lang/acvm/commit/575a9e50e97afb04a7b91799e06752cec3093f0b)) +* Switched from OpcodeLabel to OpcodeLocation and ErrorLocation ([#493](https://github.com/noir-lang/acvm/issues/493)) ([27a5a93](https://github.com/noir-lang/acvm/commit/27a5a935849f8904e10056b08089f532a06962b8)) + + +### Bug Fixes + +* add opcode label to unsatisfied constrain string ([#482](https://github.com/noir-lang/acvm/issues/482)) ([cbbbe67](https://github.com/noir-lang/acvm/commit/cbbbe67b9a19a4a560b2dfa8f27ea1c6ebd61f28)) + +## [0.21.0](https://github.com/noir-lang/acvm/compare/root-v0.20.1...root-v0.21.0) (2023-07-26) + + +### ⚠ BREAKING CHANGES + +* **acir:** Remove `Block`, `RAM` and `ROM` opcodes ([#457](https://github.com/noir-lang/acvm/issues/457)) +* **acvm:** Remove `OpcodeResolution` enum ([#400](https://github.com/noir-lang/acvm/issues/400)) +* **acvm:** Support stepwise execution of ACIR ([#399](https://github.com/noir-lang/acvm/issues/399)) + +### Features + +* **acvm:** Remove `OpcodeResolution` enum ([#400](https://github.com/noir-lang/acvm/issues/400)) ([d0ce48c](https://github.com/noir-lang/acvm/commit/d0ce48c506619a5560412ef6693bfa11036b501e)) +* **acvm:** Support stepwise execution of ACIR ([#399](https://github.com/noir-lang/acvm/issues/399)) ([6a03950](https://github.com/noir-lang/acvm/commit/6a0395021779a2711353c2fe2948e09b5b538fc0)) + + +### Miscellaneous Chores + +* **acir:** Remove `Block`, `RAM` and `ROM` opcodes ([#457](https://github.com/noir-lang/acvm/issues/457)) ([8dd220a](https://github.com/noir-lang/acvm/commit/8dd220ae127baf6cc5a31d8ab7ffdeeb161f6109)) + +## [0.20.1](https://github.com/noir-lang/acvm/compare/root-v0.20.0...root-v0.20.1) (2023-07-26) + + +### Features + +* add optimisations to fallback black box functions on booleans ([#446](https://github.com/noir-lang/acvm/issues/446)) ([2cfb2a8](https://github.com/noir-lang/acvm/commit/2cfb2a8cf911a81eedbd9da13ab2c616abd67f83)) +* **stdlib:** Add fallback implementation of `Keccak256` black box function ([#445](https://github.com/noir-lang/acvm/issues/445)) ([f7ebb03](https://github.com/noir-lang/acvm/commit/f7ebb03653c971f119700ff8126d9eb5ff01be0f)) + +## [0.20.0](https://github.com/noir-lang/acvm/compare/root-v0.19.1...root-v0.20.0) (2023-07-20) + + +### ⚠ BREAKING CHANGES + +* atomic memory opcodes ([#447](https://github.com/noir-lang/acvm/issues/447)) + +### Features + +* atomic memory opcodes ([#447](https://github.com/noir-lang/acvm/issues/447)) ([3261c7a](https://github.com/noir-lang/acvm/commit/3261c7a2fd4f3a300bc5f39ef4febccd8a853560)) +* **brillig:** Support integers which fit inside a `FieldElement` ([#403](https://github.com/noir-lang/acvm/issues/403)) ([f992412](https://github.com/noir-lang/acvm/commit/f992412617ade875fa26fe3a2cc3c06dbcad503b)) +* **stdlib:** Add fallback implementation of `HashToField128Security` black box function ([#435](https://github.com/noir-lang/acvm/issues/435)) ([ed40f22](https://github.com/noir-lang/acvm/commit/ed40f228529e888d1960bfa70cb92b277e24b37f)) + +## [0.19.1](https://github.com/noir-lang/acvm/compare/root-v0.19.0...root-v0.19.1) (2023-07-17) + + +### Bug Fixes + +* Remove panic when we divide 0/0 in quotient directive ([#437](https://github.com/noir-lang/acvm/issues/437)) ([9c8ff64](https://github.com/noir-lang/acvm/commit/9c8ff64ebf27a86787ae184e10ed9581041ec0ff)) + +## [0.19.0](https://github.com/noir-lang/acvm/compare/root-v0.18.2...root-v0.19.0) (2023-07-15) + + +### ⚠ BREAKING CHANGES + +* move to bincode and GzEncoding for artifacts ([#436](https://github.com/noir-lang/acvm/issues/436)) + +### Features + +* move to bincode and GzEncoding for artifacts ([#436](https://github.com/noir-lang/acvm/issues/436)) ([4683240](https://github.com/noir-lang/acvm/commit/46832400a8bc20135a8a895ab9477b14449734d9)) + +## [0.18.2](https://github.com/noir-lang/acvm/compare/root-v0.18.1...root-v0.18.2) (2023-07-12) + + +### Features + +* **acvm:** reexport `blackbox_solver` crate from `acvm` ([#431](https://github.com/noir-lang/acvm/issues/431)) ([517e942](https://github.com/noir-lang/acvm/commit/517e942b732d7107f6e064c6791917d1508229b3)) +* **stdlib:** Add fallback implementation of `Blake2s` black box function ([#424](https://github.com/noir-lang/acvm/issues/424)) ([982d940](https://github.com/noir-lang/acvm/commit/982d94087d46092ce7a5e94dbd7e732195f58e42)) + +## [0.18.1](https://github.com/noir-lang/acvm/compare/root-v0.18.0...root-v0.18.1) (2023-07-12) + + +### Bug Fixes + +* Crate publishing order ([#428](https://github.com/noir-lang/acvm/issues/428)) ([4f69cb5](https://github.com/noir-lang/acvm/commit/4f69cb5782435a2fcf45bb0985e1bb0eb944b194)) + +## [0.18.0](https://github.com/noir-lang/acvm/compare/root-v0.17.0...root-v0.18.0) (2023-07-12) + + +### ⚠ BREAKING CHANGES + +* add backend-solvable blackboxes to brillig & unify implementations ([#422](https://github.com/noir-lang/acvm/issues/422)) +* **acvm:** Remove `CircuitSimplifer` ([#421](https://github.com/noir-lang/acvm/issues/421)) +* **acvm:** Add `circuit: &Circuit` to `eth_contract_from_vk` function signature ([#420](https://github.com/noir-lang/acvm/issues/420)) +* Returns index of failing opcode and transformation mapping ([#412](https://github.com/noir-lang/acvm/issues/412)) + +### Features + +* **acvm:** Add `circuit: &Circuit` to `eth_contract_from_vk` function signature ([#420](https://github.com/noir-lang/acvm/issues/420)) ([744e9da](https://github.com/noir-lang/acvm/commit/744e9da71f7ca477a5390a63f47211dd4dffb8b3)) +* add backend-solvable blackboxes to brillig & unify implementations ([#422](https://github.com/noir-lang/acvm/issues/422)) ([093342e](https://github.com/noir-lang/acvm/commit/093342ea9481a311fa71343b8b7a22774788838a)) +* derive PartialOrd, Ord, and Hash on RegisterIndex ([#425](https://github.com/noir-lang/acvm/issues/425)) ([7f6b0dc](https://github.com/noir-lang/acvm/commit/7f6b0dc138c4e11d2b5847f0c9603979cc43493a)) +* Returns index of failing opcode and transformation mapping ([#412](https://github.com/noir-lang/acvm/issues/412)) ([79950e9](https://github.com/noir-lang/acvm/commit/79950e943f60e4082e1cf5ec4442aa67ea91aade)) +* **stdlib:** Add fallback implementation of `SHA256` black box function ([#407](https://github.com/noir-lang/acvm/issues/407)) ([040369a](https://github.com/noir-lang/acvm/commit/040369adc8749fa5ec2edd255ff54c105c3140f5)) + + +### Miscellaneous Chores + +* **acvm:** Remove `CircuitSimplifer` ([#421](https://github.com/noir-lang/acvm/issues/421)) ([e07a56d](https://github.com/noir-lang/acvm/commit/e07a56d9c542a7f03ce156761054cd403de0bd23)) + +## [0.17.0](https://github.com/noir-lang/acvm/compare/root-v0.16.0...root-v0.17.0) (2023-07-07) + + +### ⚠ BREAKING CHANGES + +* **acir:** add `EcdsaSecp256r1` blackbox function ([#408](https://github.com/noir-lang/acvm/issues/408)) + +### Features + +* **acir:** add `EcdsaSecp256r1` blackbox function ([#408](https://github.com/noir-lang/acvm/issues/408)) ([9895817](https://github.com/noir-lang/acvm/commit/98958170c9fa9b4731e33b31cb494a72bb90549e)) + +## [0.16.0](https://github.com/noir-lang/acvm/compare/root-v0.15.1...root-v0.16.0) (2023-07-06) + + +### ⚠ BREAKING CHANGES + +* **acvm:** replace `PartialWitnessGeneratorStatus` with `ACVMStatus` ([#410](https://github.com/noir-lang/acvm/issues/410)) +* **acir:** revert changes to `SchnorrVerify` opcode ([#409](https://github.com/noir-lang/acvm/issues/409)) +* **acvm:** Replace `PartialWitnessGenerator` trait with `BlackBoxFunctionSolver` ([#378](https://github.com/noir-lang/acvm/issues/378)) +* **acvm:** Encapsulate internal state of ACVM within a struct ([#384](https://github.com/noir-lang/acvm/issues/384)) +* remove unused `OpcodeResolutionError::IncorrectNumFunctionArguments` variant ([#397](https://github.com/noir-lang/acvm/issues/397)) +* **acir:** Remove `Oracle` opcode ([#368](https://github.com/noir-lang/acvm/issues/368)) +* **acir:** Use fixed length data structures in black box function inputs/outputs where possible. ([#386](https://github.com/noir-lang/acvm/issues/386)) +* **acir:** Implement `Add` trait for `Witness` & make output of `Mul` on `Expression` optional ([#393](https://github.com/noir-lang/acvm/issues/393)) + +### Features + +* **acir:** Implement `Add` trait for `Witness` & make output of `Mul` on `Expression` optional ([#393](https://github.com/noir-lang/acvm/issues/393)) ([5bcdfc6](https://github.com/noir-lang/acvm/commit/5bcdfc62e4936922135add171d60a948922581ff)) +* **acir:** Remove `Oracle` opcode ([#368](https://github.com/noir-lang/acvm/issues/368)) ([63354df](https://github.com/noir-lang/acvm/commit/63354df1fe47a4f1128b91641d1b66dfc1281794)) +* **acir:** Use fixed length data structures in black box function inputs/outputs where possible. ([#386](https://github.com/noir-lang/acvm/issues/386)) ([b139d4d](https://github.com/noir-lang/acvm/commit/b139d4d566c715009465a430aab0fb819aacab4f)) +* **acvm:** Derive `Copy` for `Language` ([#406](https://github.com/noir-lang/acvm/issues/406)) ([69a6c22](https://github.com/noir-lang/acvm/commit/69a6c224d80be556ac5388ffeb7a02424df22031)) +* **acvm:** Encapsulate internal state of ACVM within a struct ([#384](https://github.com/noir-lang/acvm/issues/384)) ([84d4867](https://github.com/noir-lang/acvm/commit/84d4867b2d97097d451d59174781555dafd2591f)) +* **acvm:** Replace `PartialWitnessGenerator` trait with `BlackBoxFunctionSolver` ([#378](https://github.com/noir-lang/acvm/issues/378)) ([73fbc95](https://github.com/noir-lang/acvm/commit/73fbc95942b0039565c93719809975f66dc9ec53)) +* **acvm:** replace `PartialWitnessGeneratorStatus` with `ACVMStatus` ([#410](https://github.com/noir-lang/acvm/issues/410)) ([fc3240d](https://github.com/noir-lang/acvm/commit/fc3240d456d0128f6eb42096beb8b7a586ea48da)) +* **brillig:** implemented first blackbox functions ([#401](https://github.com/noir-lang/acvm/issues/401)) ([62d40f7](https://github.com/noir-lang/acvm/commit/62d40f7c03cd1102f615b8d565f82496962db637)) + + +### Bug Fixes + +* **acir:** revert changes to `SchnorrVerify` opcode ([#409](https://github.com/noir-lang/acvm/issues/409)) ([f1c7940](https://github.com/noir-lang/acvm/commit/f1c7940f4ac618c7b440b6ed30199f85cbe72cca)) + + +### Miscellaneous Chores + +* remove unused `OpcodeResolutionError::IncorrectNumFunctionArguments` variant ([#397](https://github.com/noir-lang/acvm/issues/397)) ([d1368d0](https://github.com/noir-lang/acvm/commit/d1368d041eb42d265a4ef385e066b82bc36d0743)) + +## [0.15.1](https://github.com/noir-lang/acvm/compare/root-v0.15.0...root-v0.15.1) (2023-06-20) + + +### Features + +* **brillig:** Allow dynamic-size foreign calls ([#370](https://github.com/noir-lang/acvm/issues/370)) ([5ba0349](https://github.com/noir-lang/acvm/commit/5ba0349420cc1b20113cb5e96490a0808a769757)) + + +### Bug Fixes + +* **brillig:** remove register initialization check ([#392](https://github.com/noir-lang/acvm/issues/392)) ([1a53143](https://github.com/noir-lang/acvm/commit/1a531438b5c1ab7ce8c4bd599dda3515bdd5cfcd)) + +## [0.15.0](https://github.com/noir-lang/acvm/compare/root-v0.14.2...root-v0.15.0) (2023-06-15) + + +### ⚠ BREAKING CHANGES + +* **brillig:** Accept multiple inputs/outputs for foreign calls ([#367](https://github.com/noir-lang/acvm/issues/367)) +* **acvm:** Make internals of ACVM private ([#353](https://github.com/noir-lang/acvm/issues/353)) + +### Features + +* Add method to generate updated `Brillig` opcode from `UnresolvedBrilligCall` ([#363](https://github.com/noir-lang/acvm/issues/363)) ([fda5dbe](https://github.com/noir-lang/acvm/commit/fda5dbe57c28dc4bc28dfd8fe0a4a8ba29635393)) +* **brillig:** Accept multiple inputs/outputs for foreign calls ([#367](https://github.com/noir-lang/acvm/issues/367)) ([78d62b2](https://github.com/noir-lang/acvm/commit/78d62b2d7c1c8b884e1f3fe7983e6e5029700e70)) +* **brillig:** Set `VMStatus` to `Failure` rather than panicking on invalid foreign call response ([#375](https://github.com/noir-lang/acvm/issues/375)) ([c49d82c](https://github.com/noir-lang/acvm/commit/c49d82c99c73c60e264585ed201af2b6a2b7ee0f)) + + +### Bug Fixes + +* **brillig:** Correct signed division implementation ([#356](https://github.com/noir-lang/acvm/issues/356)) ([4eefda0](https://github.com/noir-lang/acvm/commit/4eefda01e7b371035314f77631df4687608b4782)) +* **brillig:** Explicitly wrap on arithmetic operations ([#365](https://github.com/noir-lang/acvm/issues/365)) ([c0544a9](https://github.com/noir-lang/acvm/commit/c0544a99930d3c8d534376c8f8a91645a39aecf8)) + + +### Miscellaneous Chores + +* **acvm:** Make internals of ACVM private ([#353](https://github.com/noir-lang/acvm/issues/353)) ([c902a01](https://github.com/noir-lang/acvm/commit/c902a01639033665d106e2d9f4e5c7070af8c0bb)) + +## [0.14.2](https://github.com/noir-lang/acvm/compare/root-v0.14.1...root-v0.14.2) (2023-06-08) + + +### Bug Fixes + +* **brillig:** expand memory with zeroes on store ([#350](https://github.com/noir-lang/acvm/issues/350)) ([4d2dadd](https://github.com/noir-lang/acvm/commit/4d2dadd3acd9dc25f0feae865b74cbaea7250f3d)) + +## [0.14.1](https://github.com/noir-lang/acvm/compare/root-v0.14.0...root-v0.14.1) (2023-06-07) + + +### Features + +* Re-use intermediate variables created during width reduction, with proper scale. ([#343](https://github.com/noir-lang/acvm/issues/343)) ([6bd0baa](https://github.com/noir-lang/acvm/commit/6bd0baa4bc9ac204e7710ec6d17d1752d2e924c0)) + +## [0.14.0](https://github.com/noir-lang/acvm/compare/root-v0.13.3...root-v0.14.0) (2023-06-06) + + +### ⚠ BREAKING CHANGES + +* **acir:** Verify Proof ([#291](https://github.com/noir-lang/acvm/issues/291)) + +### Features + +* **acir:** Verify Proof ([#291](https://github.com/noir-lang/acvm/issues/291)) ([9f34428](https://github.com/noir-lang/acvm/commit/9f34428b7084c7c38de401a16ca76e748d8b1d77)) + +## [0.13.3](https://github.com/noir-lang/acvm/compare/root-v0.13.2...root-v0.13.3) (2023-06-05) + + +### Bug Fixes + +* Empty commit to trigger release-please ([e8f0748](https://github.com/noir-lang/acvm/commit/e8f0748042ef505d59ab63266d3c36c5358ee30d)) + +## [0.13.2](https://github.com/noir-lang/acvm/compare/root-v0.13.1...root-v0.13.2) (2023-06-02) + + +### Bug Fixes + +* re-use intermediate vars during width reduction ([#278](https://github.com/noir-lang/acvm/issues/278)) ([5b32920](https://github.com/noir-lang/acvm/commit/5b32920263c4481c60faf0b84f0031aa8149b6b2)) + +## [0.13.1](https://github.com/noir-lang/acvm/compare/root-v0.13.0...root-v0.13.1) (2023-06-01) + + +### Bug Fixes + +* **brillig:** Proper error handling for Brillig failures ([#329](https://github.com/noir-lang/acvm/issues/329)) ([cffa110](https://github.com/noir-lang/acvm/commit/cffa110c8df30ee3dd8b635d38b17b1fcd54b03e)) +* **ci:** Add brillig_vm to release-please & link versions ([#332](https://github.com/noir-lang/acvm/issues/332)) ([84bd22e](https://github.com/noir-lang/acvm/commit/84bd22eea46cdfef3a5dbf534b878e819d44f755)) +* **ci:** Correct typo to avoid `undefined` in changelogs ([#333](https://github.com/noir-lang/acvm/issues/333)) ([d3424c0](https://github.com/noir-lang/acvm/commit/d3424c04fd303c9cbe25d03118d8b358cbb84b83)) + +## [0.13.0](https://github.com/noir-lang/acvm/compare/root-v0.12.0...root-v0.13.0) (2023-06-01) + + +### ⚠ BREAKING CHANGES + +* added hash index to pedersen ([#281](https://github.com/noir-lang/acvm/issues/281)) +* Add variable length keccak opcode ([#314](https://github.com/noir-lang/acvm/issues/314)) +* Remove AES opcode ([#302](https://github.com/noir-lang/acvm/issues/302)) +* **acir, acvm:** Remove ComputeMerkleRoot opcode #296 +* Remove manual serialization of `Opcode`s in favour of `serde` ([#286](https://github.com/noir-lang/acvm/issues/286)) +* Remove backend solvable methods from the interface and solve them in ACVM ([#264](https://github.com/noir-lang/acvm/issues/264)) +* Reorganize code related to `PartialWitnessGenerator` ([#287](https://github.com/noir-lang/acvm/issues/287)) + +### Features + +* **acir, acvm:** Remove ComputeMerkleRoot opcode [#296](https://github.com/noir-lang/acvm/issues/296) ([8b3923e](https://github.com/noir-lang/acvm/commit/8b3923e191e4ac399400025496e8bb4453734040)) +* Add `Brillig` opcode to introduce custom non-determinism to ACVM ([#152](https://github.com/noir-lang/acvm/issues/152)) ([3c6740a](https://github.com/noir-lang/acvm/commit/3c6740af75125afc8ebb4379f781f8274015e2e2)) +* Add variable length keccak opcode ([#314](https://github.com/noir-lang/acvm/issues/314)) ([7bfd169](https://github.com/noir-lang/acvm/commit/7bfd1695b6f119cd70fce4866314c9bb4991eaab)) +* added hash index to pedersen ([#281](https://github.com/noir-lang/acvm/issues/281)) ([61820b6](https://github.com/noir-lang/acvm/commit/61820b651900aac8d9557b4b9477ed0e1763c124)) +* Remove backend solvable methods from the interface and solve them in ACVM ([#264](https://github.com/noir-lang/acvm/issues/264)) ([69916cb](https://github.com/noir-lang/acvm/commit/69916cbdd928875b2e8fe4775f2251f71c3f3c92)) + + +### Bug Fixes + +* Allow async functions without send on async trait ([#292](https://github.com/noir-lang/acvm/issues/292)) ([9f9fc21](https://github.com/noir-lang/acvm/commit/9f9fc216a6d09ca97352ffd365bfd347e94ad8eb)) + + +### Miscellaneous Chores + +* Remove AES opcode ([#302](https://github.com/noir-lang/acvm/issues/302)) ([a429a54](https://github.com/noir-lang/acvm/commit/a429a5422d6f001b6db0d0a0f30c79ec0f96de89)) +* Remove manual serialization of `Opcode`s in favour of `serde` ([#286](https://github.com/noir-lang/acvm/issues/286)) ([8a3812f](https://github.com/noir-lang/acvm/commit/8a3812fe6ed3b267692284bdcd909d9dd32b9747)) +* Reorganize code related to `PartialWitnessGenerator` ([#287](https://github.com/noir-lang/acvm/issues/287)) ([b9d61a1](https://github.com/noir-lang/acvm/commit/b9d61a16210d70e350a7e953951362c94f497f89)) + +## [0.12.0](https://github.com/noir-lang/acvm/compare/root-v0.11.0...root-v0.12.0) (2023-05-17) + + +### ⚠ BREAKING CHANGES + +* remove deprecated circuit hash functions ([#288](https://github.com/noir-lang/acvm/issues/288)) +* allow backends to specify support for all opcode variants ([#273](https://github.com/noir-lang/acvm/issues/273)) +* **acvm:** Add CommonReferenceString backend trait ([#231](https://github.com/noir-lang/acvm/issues/231)) +* Introduce WitnessMap data structure to avoid leaking internal structure ([#252](https://github.com/noir-lang/acvm/issues/252)) +* use struct variants for blackbox function calls ([#269](https://github.com/noir-lang/acvm/issues/269)) +* **acvm:** Backend trait must implement Debug ([#275](https://github.com/noir-lang/acvm/issues/275)) +* remove `OpcodeResolutionError::UnexpectedOpcode` ([#274](https://github.com/noir-lang/acvm/issues/274)) +* **acvm:** rename `hash_to_field128_security` to `hash_to_field_128_security` ([#271](https://github.com/noir-lang/acvm/issues/271)) +* **acvm:** update black box solver interfaces to match `pwg:black_box::solve` ([#268](https://github.com/noir-lang/acvm/issues/268)) +* **acvm:** expose separate solvers for AND and XOR opcodes ([#266](https://github.com/noir-lang/acvm/issues/266)) +* **acvm:** Simplification pass for ACIR ([#151](https://github.com/noir-lang/acvm/issues/151)) +* Remove `solve` from PWG trait & introduce separate solvers for each blackbox ([#257](https://github.com/noir-lang/acvm/issues/257)) + +### Features + +* **acvm:** Add CommonReferenceString backend trait ([#231](https://github.com/noir-lang/acvm/issues/231)) ([eeddcf1](https://github.com/noir-lang/acvm/commit/eeddcf179880f246383f7f67a11e589269c4e3ff)) +* **acvm:** Simplification pass for ACIR ([#151](https://github.com/noir-lang/acvm/issues/151)) ([7bc42c6](https://github.com/noir-lang/acvm/commit/7bc42c62b6e095f838b781c87cbb1ecd2af5f179)) +* **acvm:** update black box solver interfaces to match `pwg:black_box::solve` ([#268](https://github.com/noir-lang/acvm/issues/268)) ([0098b7d](https://github.com/noir-lang/acvm/commit/0098b7d9640076d970e6c15d5fd6f368eb1513ff)) +* Introduce WitnessMap data structure to avoid leaking internal structure ([#252](https://github.com/noir-lang/acvm/issues/252)) ([b248e60](https://github.com/noir-lang/acvm/commit/b248e606dd69c25d33ae77c5c5c0541adbf80cd6)) +* Remove `solve` from PWG trait & introduce separate solvers for each blackbox ([#257](https://github.com/noir-lang/acvm/issues/257)) ([3f3dd74](https://github.com/noir-lang/acvm/commit/3f3dd7460b27ab06b55dfc3fe5dd733f08e30a9f)) +* use struct variants for blackbox function calls ([#269](https://github.com/noir-lang/acvm/issues/269)) ([a83333b](https://github.com/noir-lang/acvm/commit/a83333b9e270dfcfd40a36271896840ec0201bc4)) + + +### Bug Fixes + +* **acir:** Hide variants of WitnessMapError and export it from package ([#283](https://github.com/noir-lang/acvm/issues/283)) ([bbd9ab7](https://github.com/noir-lang/acvm/commit/bbd9ab7ca5be3fb31f3e141fee2522704852f5de)) + + +### Miscellaneous Chores + +* **acvm:** Backend trait must implement Debug ([#275](https://github.com/noir-lang/acvm/issues/275)) ([3288b4c](https://github.com/noir-lang/acvm/commit/3288b4c7eb01f5621e577d5ff9e7c92c7757e021)) +* **acvm:** expose separate solvers for AND and XOR opcodes ([#266](https://github.com/noir-lang/acvm/issues/266)) ([84b5d18](https://github.com/noir-lang/acvm/commit/84b5d18d29a111a42bfc1c3d122129c8f062c3db)) +* **acvm:** rename `hash_to_field128_security` to `hash_to_field_128_security` ([#271](https://github.com/noir-lang/acvm/issues/271)) ([fad9af2](https://github.com/noir-lang/acvm/commit/fad9af27fb102fa34bf7511f8ed7b16b3ec2d115)) +* allow backends to specify support for all opcode variants ([#273](https://github.com/noir-lang/acvm/issues/273)) ([efd37fe](https://github.com/noir-lang/acvm/commit/efd37fedcbbabb3fac810e662731439e07fef49a)) +* remove `OpcodeResolutionError::UnexpectedOpcode` ([#274](https://github.com/noir-lang/acvm/issues/274)) ([0e71aac](https://github.com/noir-lang/acvm/commit/0e71aac7aa85b3e9142972a26ba122c2c7c51d9b)) +* remove deprecated circuit hash functions ([#288](https://github.com/noir-lang/acvm/issues/288)) ([1a22c75](https://github.com/noir-lang/acvm/commit/1a22c752de3354a2a6d34892331ab6623b24c0b0)) + +## [0.11.0](https://github.com/noir-lang/acvm/compare/root-v0.10.3...root-v0.11.0) (2023-05-04) + + +### ⚠ BREAKING CHANGES + +* **acvm:** Introduce Error type for fallible Backend traits ([#248](https://github.com/noir-lang/acvm/issues/248)) + +### Features + +* **acvm:** Add generic error for failing to solve an opcode ([#251](https://github.com/noir-lang/acvm/issues/251)) ([bc89528](https://github.com/noir-lang/acvm/commit/bc8952820de610e585d505decfac6e590bbb1a35)) +* **acvm:** Introduce Error type for fallible Backend traits ([#248](https://github.com/noir-lang/acvm/issues/248)) ([45c45f7](https://github.com/noir-lang/acvm/commit/45c45f7cdb79c3ccb0373ca0e698b282d4dabc39)) +* Add Keccak Hash function ([#259](https://github.com/noir-lang/acvm/issues/259)) ([443c734](https://github.com/noir-lang/acvm/commit/443c73482eeef6cc42a1a254bf0d7706698ee353)) + + +### Bug Fixes + +* **acir:** Fix `Expression` multiplication to correctly handle degree 1 terms ([#255](https://github.com/noir-lang/acvm/issues/255)) ([e399396](https://github.com/noir-lang/acvm/commit/e399396f7e06deb6b831517af17018607df3f252)) + +## [0.10.3](https://github.com/noir-lang/acvm/compare/root-v0.10.2...root-v0.10.3) (2023-04-28) + + +### Bug Fixes + +* add default feature flag to ACVM crate ([#245](https://github.com/noir-lang/acvm/issues/245)) ([455fddb](https://github.com/noir-lang/acvm/commit/455fddbc19af81cb01d54e29cad199691e1a1d98)) + +## [0.10.2](https://github.com/noir-lang/acvm/compare/root-v0.10.1...root-v0.10.2) (2023-04-28) + + +### Bug Fixes + +* add default flag to `acvm_stdlib` ([#242](https://github.com/noir-lang/acvm/issues/242)) ([83b6fa8](https://github.com/noir-lang/acvm/commit/83b6fa8302569add7e3ac8481b2fd2a6a1ff3576)) + +## [0.10.1](https://github.com/noir-lang/acvm/compare/root-v0.10.0...root-v0.10.1) (2023-04-28) + + +### Bug Fixes + +* **acir:** add `bn254` as default feature flag ([#240](https://github.com/noir-lang/acvm/issues/240)) ([e56973d](https://github.com/noir-lang/acvm/commit/e56973d8dc1745fe9bb844ec8347acd4d836d42f)) + +## [0.10.0](https://github.com/noir-lang/acvm/compare/root-v0.9.0...root-v0.10.0) (2023-04-26) + + +### ⚠ BREAKING CHANGES + +* return `Result` from `solve_range_opcode` ([#238](https://github.com/noir-lang/acvm/issues/238)) +* **acvm:** have all black box functions return `Result` ([#237](https://github.com/noir-lang/acvm/issues/237)) +* **acvm:** implement `hash_to_field_128_security` ([#230](https://github.com/noir-lang/acvm/issues/230)) +* replace `MerkleMembership` opcode with `ComputeMerkleRoot` ([#233](https://github.com/noir-lang/acvm/issues/233)) +* require `Backend` to implement `Default` trait ([#223](https://github.com/noir-lang/acvm/issues/223)) +* Make GeneralOptimizer crate visible ([#220](https://github.com/noir-lang/acvm/issues/220)) +* return `PartialWitnessGeneratorStatus` from `PartialWitnessGenerator.solve` ([#213](https://github.com/noir-lang/acvm/issues/213)) +* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) + +### Features + +* **acvm:** have all black box functions return `Result<OpcodeResolution, OpcodeResolutionError>` ([#237](https://github.com/noir-lang/acvm/issues/237)) ([e8e93fd](https://github.com/noir-lang/acvm/commit/e8e93fda0db18f0d266dd1aacbb53ec787992dc9)) +* **acvm:** implement `hash_to_field_128_security` ([#230](https://github.com/noir-lang/acvm/issues/230)) ([198fb69](https://github.com/noir-lang/acvm/commit/198fb69e90a5ed3c0a8716d888b4dc6c2f9b18aa)) +* Add range opcode optimization ([#219](https://github.com/noir-lang/acvm/issues/219)) ([7abe6e5](https://github.com/noir-lang/acvm/commit/7abe6e5f6d6fea379c3748a910afd00db066eb45)) +* implement `add_mul` on `Expression` ([#207](https://github.com/noir-lang/acvm/issues/207)) ([f156e18](https://github.com/noir-lang/acvm/commit/f156e18cf7a0f1a99bbe1683b8e75fec8325e6dd)) +* implement `FieldElement::from<bool>()` ([#203](https://github.com/noir-lang/acvm/issues/203)) ([476cfa2](https://github.com/noir-lang/acvm/commit/476cfa247fddb515c64c2801c6868357c9375294)) +* replace `MerkleMembership` opcode with `ComputeMerkleRoot` ([#233](https://github.com/noir-lang/acvm/issues/233)) ([74bfee8](https://github.com/noir-lang/acvm/commit/74bfee80e0ff0d205aee1eea548c97ade8bd0e41)) +* require `Backend` to implement `Default` trait ([#223](https://github.com/noir-lang/acvm/issues/223)) ([00282dc](https://github.com/noir-lang/acvm/commit/00282dc5e2b03947bf709a088d829f3e0ba80eed)) +* return `PartialWitnessGeneratorStatus` from `PartialWitnessGenerator.solve` ([#213](https://github.com/noir-lang/acvm/issues/213)) ([e877bed](https://github.com/noir-lang/acvm/commit/e877bed2cca76bd486e9bed66b4230e65a01f0a2)) +* return `Result<OpcodeResolution, OpcodeResolutionError>` from `solve_range_opcode` ([#238](https://github.com/noir-lang/acvm/issues/238)) ([15d3c5a](https://github.com/noir-lang/acvm/commit/15d3c5a9be2dd92f266fcb7e672da17cada9fec5)) + + +### Bug Fixes + +* prevent `bn254` feature flag always being enabled ([#225](https://github.com/noir-lang/acvm/issues/225)) ([82eee6a](https://github.com/noir-lang/acvm/commit/82eee6ab08ae480f04904ca8571fd88f4466c000)) + + +### Miscellaneous Chores + +* Make GeneralOptimizer crate visible ([#220](https://github.com/noir-lang/acvm/issues/220)) ([64bb346](https://github.com/noir-lang/acvm/commit/64bb346524428a0ce196826ea1e5ccde08ad6201)) +* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) ([a619df6](https://github.com/noir-lang/acvm/commit/a619df614bbb9b2518b788b42a7553b069823a0f)) + +## [0.9.0](https://github.com/noir-lang/acvm/compare/root-v0.8.1...root-v0.9.0) (2023-04-07) + + +### ⚠ BREAKING CHANGES + +* **acvm:** Remove deprecated eth_contract_from_cs from SmartContract trait ([#185](https://github.com/noir-lang/acvm/issues/185)) +* **acvm:** make `Backend` trait object safe ([#180](https://github.com/noir-lang/acvm/issues/180)) + +### Features + +* **acvm:** make `Backend` trait object safe ([#180](https://github.com/noir-lang/acvm/issues/180)) ([fd28657](https://github.com/noir-lang/acvm/commit/fd28657426260ce3c53517b75a27eb5c4a74e234)) + + +### Bug Fixes + +* Add test for Out of Memory ([#188](https://github.com/noir-lang/acvm/issues/188)) ([c3db985](https://github.com/noir-lang/acvm/commit/c3db985893e7e59ea04005bb3a57eda5c6ce28c7)) + + +### Miscellaneous Chores + +* **acvm:** Remove deprecated eth_contract_from_cs from SmartContract trait ([#185](https://github.com/noir-lang/acvm/issues/185)) ([ee59c9e](https://github.com/noir-lang/acvm/commit/ee59c9efe9a54ff6b97e4daaebf64f3e327e97d9)) + +## [0.8.1](https://github.com/noir-lang/acvm/compare/root-v0.8.0...root-v0.8.1) (2023-03-30) + + +### Bug Fixes + +* unwraps if inputs is zero ([#171](https://github.com/noir-lang/acvm/issues/171)) ([10a3bb2](https://github.com/noir-lang/acvm/commit/10a3bb2a9930ccf422b3f08227aae07775686860)) + +## [0.8.0](https://github.com/noir-lang/acvm/compare/root-v0.7.1...root-v0.8.0) (2023-03-28) + + +### ⚠ BREAKING CHANGES + +* **acir:** Read Log Directive ([#156](https://github.com/noir-lang/acvm/issues/156)) + +### Bug Fixes + +* **acir:** Read Log Directive ([#156](https://github.com/noir-lang/acvm/issues/156)) ([1cc2b7f](https://github.com/noir-lang/acvm/commit/1cc2b7f2179cecc338fe0def72bb2dd17eaed0cd)) + +## [0.7.1](https://github.com/noir-lang/acvm/compare/root-v0.7.0...root-v0.7.1) (2023-03-27) + + +### Bug Fixes + +* **pwg:** stall instead of fail for unassigned black box ([#154](https://github.com/noir-lang/acvm/issues/154)) ([412a1a6](https://github.com/noir-lang/acvm/commit/412a1a60b434bef53e12d37c3b2bb3d51a317994)) + +## [0.7.0](https://github.com/noir-lang/acvm/compare/root-v0.6.0...root-v0.7.0) (2023-03-23) + + +### ⚠ BREAKING CHANGES + +* Add initial oracle opcode ([#149](https://github.com/noir-lang/acvm/issues/149)) +* **acir:** Add RAM and ROM opcodes +* **acir:** Add a public outputs field ([#56](https://github.com/noir-lang/acvm/issues/56)) +* **acir:** remove `Linear` struct ([#145](https://github.com/noir-lang/acvm/issues/145)) +* **acvm:** remove `prove_with_meta` and `verify_from_cs` from `ProofSystemCompiler` ([#140](https://github.com/noir-lang/acvm/issues/140)) +* **acvm:** Remove truncate and oddrange directives ([#142](https://github.com/noir-lang/acvm/issues/142)) + +### Features + +* **acir:** Add a public outputs field ([#56](https://github.com/noir-lang/acvm/issues/56)) ([5f358a9](https://github.com/noir-lang/acvm/commit/5f358a97aaa81d87956e182cd8a6d60de75f9752)) +* **acir:** Add RAM and ROM opcodes ([73e9f25](https://github.com/noir-lang/acvm/commit/73e9f25dd87b2ca91245e93d2445eadc0f522fac)) +* Add initial oracle opcode ([#149](https://github.com/noir-lang/acvm/issues/149)) ([88ee2f8](https://github.com/noir-lang/acvm/commit/88ee2f89f37abf5dd1d9f91b4d2eed44dc651348)) + + +### Miscellaneous Chores + +* **acir:** remove `Linear` struct ([#145](https://github.com/noir-lang/acvm/issues/145)) ([bbb6d92](https://github.com/noir-lang/acvm/commit/bbb6d92e25c43dd33b12f5fcd639fc9ad2a9c9d8)) +* **acvm:** remove `prove_with_meta` and `verify_from_cs` from `ProofSystemCompiler` ([#140](https://github.com/noir-lang/acvm/issues/140)) ([35dd181](https://github.com/noir-lang/acvm/commit/35dd181102203df17eef510666b327ef41f4b036)) +* **acvm:** Remove truncate and oddrange directives ([#142](https://github.com/noir-lang/acvm/issues/142)) ([85dd6e8](https://github.com/noir-lang/acvm/commit/85dd6e85bfba85bfb97651f7e30e1f75deb986d5)) + +## [0.6.0](https://github.com/noir-lang/acvm/compare/root-v0.5.0...root-v0.6.0) (2023-03-03) + + +### ⚠ BREAKING CHANGES + +* **acir:** rename `term_addition` to `push_addition_term` +* **acir:** rename `term_multiplication` to `push_multiplication_term` ([#122](https://github.com/noir-lang/acvm/issues/122)) +* **acir:** remove `UnknownWitness` ([#123](https://github.com/noir-lang/acvm/issues/123)) +* add block opcode ([#114](https://github.com/noir-lang/acvm/issues/114)) + +### Features + +* **acir:** add useful methods from `noirc_evaluator` onto `Expression` ([#125](https://github.com/noir-lang/acvm/issues/125)) ([d3d5f89](https://github.com/noir-lang/acvm/commit/d3d5f8917482ce5649602695829862a5df4ea712)) +* add block opcode ([#114](https://github.com/noir-lang/acvm/issues/114)) ([097cfb0](https://github.com/noir-lang/acvm/commit/097cfb069291705ddb4bf1fca77ddcef21dbbd08)) + + +### Bug Fixes + +* **acir:** correctly display expressions with non-unit coefficients ([d3d5f89](https://github.com/noir-lang/acvm/commit/d3d5f8917482ce5649602695829862a5df4ea712)) +* **ci:** publish acvm_stdlib before acvm ([#117](https://github.com/noir-lang/acvm/issues/117)) ([ca6defc](https://github.com/noir-lang/acvm/commit/ca6defc9bb5f51241b2fc4d9cd732f9678b4688f)) + + +### Miscellaneous Chores + +* **acir:** remove `UnknownWitness` ([#123](https://github.com/noir-lang/acvm/issues/123)) ([9f002c7](https://github.com/noir-lang/acvm/commit/9f002c7b49a5cf222d4a01732cc4917a47690863)) +* **acir:** rename `term_addition` to `push_addition_term` ([d389385](https://github.com/noir-lang/acvm/commit/d38938542851a97dc01727438391e6a65e44c689)) +* **acir:** rename `term_multiplication` to `push_multiplication_term` ([#122](https://github.com/noir-lang/acvm/issues/122)) ([d389385](https://github.com/noir-lang/acvm/commit/d38938542851a97dc01727438391e6a65e44c689)) + +## [0.5.0](https://github.com/noir-lang/acvm/compare/root-v0.4.1...root-v0.5.0) (2023-02-22) + + +### ⚠ BREAKING CHANGES + +* **acvm:** switch to accepting public inputs as a map ([#96](https://github.com/noir-lang/acvm/issues/96)) +* **acvm:** add `eth_contract_from_vk` to `SmartContract +* update `ProofSystemCompiler` to not take ownership of keys ([#111](https://github.com/noir-lang/acvm/issues/111)) +* update `ProofSystemCompiler` methods to take `&Circuit` ([#108](https://github.com/noir-lang/acvm/issues/108)) +* **acir:** make PublicInputs use a BTreeSet rather than Vec ([#99](https://github.com/noir-lang/acvm/issues/99)) +* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) +* **acir:** Add keccak256 Opcode ([#91](https://github.com/noir-lang/acvm/issues/91)) +* reorganise compiler in terms of optimisers and transformers ([#88](https://github.com/noir-lang/acvm/issues/88)) + +### Features + +* **acir:** Add keccak256 Opcode ([#91](https://github.com/noir-lang/acvm/issues/91)) ([b909146](https://github.com/noir-lang/acvm/commit/b9091461e199bacdd073cc9b31f03dade0b4fb2d)) +* **acir:** make PublicInputs use a BTreeSet rather than Vec ([#99](https://github.com/noir-lang/acvm/issues/99)) ([53666b7](https://github.com/noir-lang/acvm/commit/53666b782d89c65cd755f9e4ded2c9cf5a141e46)) +* **acvm:** add `eth_contract_from_vk` to `SmartContract ([#113](https://github.com/noir-lang/acvm/issues/113)) ([373c18f](https://github.com/noir-lang/acvm/commit/373c18fc05edf673cfec9e8bbb78bd7d7514999e)) +* **acvm:** switch to accepting public inputs as a map ([#96](https://github.com/noir-lang/acvm/issues/96)) ([f57ba57](https://github.com/noir-lang/acvm/commit/f57ba57c2bb2597edf2b02fb1321c69cf11993ee)) +* **ci:** Add release workflow ([#89](https://github.com/noir-lang/acvm/issues/89)) ([db8e828](https://github.com/noir-lang/acvm/commit/db8e828341f59241ef7f437c908277fb8fbca9e3)) +* **ci:** Publish crates upon release ([#104](https://github.com/noir-lang/acvm/issues/104)) ([b265920](https://github.com/noir-lang/acvm/commit/b265920bc1b0c776d20326a0b74fc635c22af4b9)) +* update `ProofSystemCompiler` methods to take `&Circuit` ([#108](https://github.com/noir-lang/acvm/issues/108)) ([af56ca9](https://github.com/noir-lang/acvm/commit/af56ca9da06068c650c66e76bfd09e65eb0ec213)) +* update `ProofSystemCompiler` to not take ownership of keys ([#111](https://github.com/noir-lang/acvm/issues/111)) ([39b8a41](https://github.com/noir-lang/acvm/commit/39b8a41293e567971f700f61103852cb987a8d16)) +* Update Arkworks' dependencies on `acir_field` ([#69](https://github.com/noir-lang/acvm/issues/69)) ([65d6130](https://github.com/noir-lang/acvm/commit/65d61307a12f25e04afad2d50e4c4db5ce97dd8c)) + + +### Bug Fixes + +* **ci:** Update dependency versions in the workspace file ([#103](https://github.com/noir-lang/acvm/issues/103)) ([9acc266](https://github.com/noir-lang/acvm/commit/9acc266c7dc5a6ad2fa9c466cc82cb81d984b7ed)) +* Clean up Log Directive hex output ([#97](https://github.com/noir-lang/acvm/issues/97)) ([d23c735](https://github.com/noir-lang/acvm/commit/d23c7352523ffb42f3e8f4229b61f9803ab78a7e)) + + +### Miscellaneous Chores + +* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) ([2427a27](https://github.com/noir-lang/acvm/commit/2427a275048e598c6d651cce8348a4c55148f235)) +* reorganise compiler in terms of optimisers and transformers ([#88](https://github.com/noir-lang/acvm/issues/88)) ([9329307](https://github.com/noir-lang/acvm/commit/9329307e054de202cfc55207162ad952b70d515e)) + +## [0.4.1] - 2023-02-08 + +### Added + +### Fixed + +- Removed duplicated logic in match branch + +### Changed + +### Removed + +## [0.4.0] - 2023-02-08 + +### Added + +- Add log directive +- Expose `acir_field` through `acir` crate +- Add permutation directive +- Add preprocess methods to ACVM interface + +### Fixed + +### Changed + +- Changed spellings of many functions to be correct using spellchecker + +### Removed + +## [0.3.1] - 2023-01-18 + +### Added + +### Fixed + +### Changed + +- ACVM compile method now returns an Error for when a function cannot be reduced to arithmetic gates + +- Backtrack changes from noir-lang/noir/587 + +### Removed + +## [0.3.0] - 2022-12-31 + +### Added + +- Added stdlib module to hold all of the standard opcodes +- added `read` , `write` methods for circuit + +### Fixed + +### Changed + +- XOR, Range and AND gates are no longer special case. They are now another opcode in the GadgetCall +- Move fallback module to `stdlib` +- Optimizer code and any other passes will live in acvm. acir is solely for defining the IR now. +- ACIR passes now live under the compiler parent module +- Moved opcode module in acir crate to circuit/opcode +- Rename GadgetCall to BlackBoxFuncCall +- Rename opcode file to blackbox_functions . Similarly OPCODE is now BlackBoxFunc +- Renamed GateResolution::UnsupportedOpcode to GateResolution::UnsupportedBlackBoxFunc +- Renamed GadgetDefinition to FuncDefinition +- Rename GadgetInput to FunctionInput +- Rename Gate -> Opcode . Similarly gate.rs is now opcodes.rs +- Rename CustomGate::supports_gate -> CustomGate::supports_opcode +- Rename GateResolution to OpcodeResolution +- Rename Split directive to ToBits +- Field element printing function was modified to uses ascii superscript numbers and ascii multiplication +- Refactor the way we print ACIR (This is a first draft and will change with more feedback) +- Rename `solve_gadget_call` trait method on ProofSystemCompile to `solve_blackbox_function_call` +- API for `compile` now requires a function pointer which tells us whether a blackbox function is supported +- Renamed Directive::Oddrange to Directive::OddRange +- Renamed FieldElement::to_bytes to FieldElement::to_be_bytes + +### Removed + +- Selector struct has been removed as it is no longer being used. It is also not being used by Noir. +- CustomGate trait -- There is a method in the ProofSystemCompiler Trait that backends can use to indicate whether +they support a particular black box function +- Remove OpcodeResolution enum from pwg. The happy case is strictly when the witness has been solved + +## [0.2.1] - 2022-12-23 + +- Removed ToBits and ToBytes opcode diff --git a/acvm-repo/README.md b/acvm-repo/README.md new file mode 100644 index 00000000000..96353252f27 --- /dev/null +++ b/acvm-repo/README.md @@ -0,0 +1,20 @@ +# ACIR - Abstract Circuit Intermediate Representation + +ACIR is an NP complete language that generalizes R1CS and arithmetic circuits while not losing proving system specific optimizations through the use of black box functions. + +# ACVM - Abstract Circuit Virtual Machine + +This can be seen as the ACIR compiler. It will take an ACIR instance and convert it to the format required +by a particular proving system to create a proof. + +# How to add a new crate to the workspace + +- Create the new crate with the current version of the other crates. +- In root `Cargo.toml`, add the new crate to the workspace members list. +- If you want to import it from multiple packages, you can add it as a dependency in the root `Cargo.toml`. +- In `release-please-config.json`: + - Add a package entry + - Add the crate name to the `linked-versions` plugin list + - If you added the new crate as a dependency in the root `Cargo.toml`, add it to the extra-files of the root package. +- In `.release-please-manifest.json`, add the new crate with the same version of the others. +- In [publish.yml](.github/workflows/publish.yml), add the new crate to the `publish` job after its dependencies. diff --git a/acvm-repo/acir/CHANGELOG.md b/acvm-repo/acir/CHANGELOG.md new file mode 100644 index 00000000000..e31ee66379a --- /dev/null +++ b/acvm-repo/acir/CHANGELOG.md @@ -0,0 +1,521 @@ +# Changelog + +## [0.27.0](https://github.com/noir-lang/acvm/compare/acir-v0.26.1...acir-v0.27.0) (2023-09-19) + + +### Features + +* **acir:** add method on `Circuit` to return assert message ([#551](https://github.com/noir-lang/acvm/issues/551)) ([ee18cde](https://github.com/noir-lang/acvm/commit/ee18cde3537b2be6714061af0bc9ef3793929f7f)) + +## [0.26.1](https://github.com/noir-lang/acvm/compare/acir-v0.26.0...acir-v0.26.1) (2023-09-12) + + +### Bug Fixes + +* Implements handling of the high limb during fixed base scalar multiplication ([#535](https://github.com/noir-lang/acvm/issues/535)) ([551504a](https://github.com/noir-lang/acvm/commit/551504aa572d3f9d56b5576d25ce1211296ee488)) + +## [0.26.0](https://github.com/noir-lang/acvm/compare/acir-v0.25.0...acir-v0.26.0) (2023-09-07) + + +### ⚠ BREAKING CHANGES + +* Add a low and high limb to scalar mul opcode ([#532](https://github.com/noir-lang/acvm/issues/532)) + +### Miscellaneous Chores + +* Add a low and high limb to scalar mul opcode ([#532](https://github.com/noir-lang/acvm/issues/532)) ([b054f66](https://github.com/noir-lang/acvm/commit/b054f66be9c73d4e02dbecdab80874a907f19242)) + +## [0.25.0](https://github.com/noir-lang/acvm/compare/acir-v0.24.1...acir-v0.25.0) (2023-09-04) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.24.1](https://github.com/noir-lang/acvm/compare/acir-v0.24.0...acir-v0.24.1) (2023-09-03) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.24.0](https://github.com/noir-lang/acvm/compare/acir-v0.23.0...acir-v0.24.0) (2023-08-31) + + +### ⚠ BREAKING CHANGES + +* **acir:** Remove unused `Directive` opcodes ([#510](https://github.com/noir-lang/acvm/issues/510)) +* **acir:** Add predicate to MemoryOp ([#503](https://github.com/noir-lang/acvm/issues/503)) +* Assertion messages embedded in the circuit ([#484](https://github.com/noir-lang/acvm/issues/484)) + +### Features + +* **acir:** Add predicate to MemoryOp ([#503](https://github.com/noir-lang/acvm/issues/503)) ([ca9eebe](https://github.com/noir-lang/acvm/commit/ca9eebe34e61adabf97318c8ccaf60c8a424aafd)) +* Assertion messages embedded in the circuit ([#484](https://github.com/noir-lang/acvm/issues/484)) ([06b97c5](https://github.com/noir-lang/acvm/commit/06b97c51041e16651cf8b2be8bc18214e276c6c9)) + + +### Miscellaneous Chores + +* **acir:** Remove unused `Directive` opcodes ([#510](https://github.com/noir-lang/acvm/issues/510)) ([cfd8cbf](https://github.com/noir-lang/acvm/commit/cfd8cbf58307511ac0cc9106c299695c2ca779de)) + +## [0.23.0](https://github.com/noir-lang/acvm/compare/acir-v0.22.0...acir-v0.23.0) (2023-08-30) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.22.0](https://github.com/noir-lang/acvm/compare/acir-v0.21.0...acir-v0.22.0) (2023-08-18) + + +### ⚠ BREAKING CHANGES + +* Switched from OpcodeLabel to OpcodeLocation and ErrorLocation ([#493](https://github.com/noir-lang/acvm/issues/493)) + +### Features + +* Switched from OpcodeLabel to OpcodeLocation and ErrorLocation ([#493](https://github.com/noir-lang/acvm/issues/493)) ([27a5a93](https://github.com/noir-lang/acvm/commit/27a5a935849f8904e10056b08089f532a06962b8)) + +## [0.21.0](https://github.com/noir-lang/acvm/compare/acir-v0.20.1...acir-v0.21.0) (2023-07-26) + + +### ⚠ BREAKING CHANGES + +* **acir:** Remove `Block`, `RAM` and `ROM` opcodes ([#457](https://github.com/noir-lang/acvm/issues/457)) +* **acvm:** Support stepwise execution of ACIR ([#399](https://github.com/noir-lang/acvm/issues/399)) + +### Features + +* **acvm:** Support stepwise execution of ACIR ([#399](https://github.com/noir-lang/acvm/issues/399)) ([6a03950](https://github.com/noir-lang/acvm/commit/6a0395021779a2711353c2fe2948e09b5b538fc0)) + + +### Miscellaneous Chores + +* **acir:** Remove `Block`, `RAM` and `ROM` opcodes ([#457](https://github.com/noir-lang/acvm/issues/457)) ([8dd220a](https://github.com/noir-lang/acvm/commit/8dd220ae127baf6cc5a31d8ab7ffdeeb161f6109)) + +## [0.20.1](https://github.com/noir-lang/acvm/compare/acir-v0.20.0...acir-v0.20.1) (2023-07-26) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.20.0](https://github.com/noir-lang/acvm/compare/acir-v0.19.1...acir-v0.20.0) (2023-07-20) + + +### ⚠ BREAKING CHANGES + +* atomic memory opcodes ([#447](https://github.com/noir-lang/acvm/issues/447)) + +### Features + +* atomic memory opcodes ([#447](https://github.com/noir-lang/acvm/issues/447)) ([3261c7a](https://github.com/noir-lang/acvm/commit/3261c7a2fd4f3a300bc5f39ef4febccd8a853560)) + +## [0.19.1](https://github.com/noir-lang/acvm/compare/acir-v0.19.0...acir-v0.19.1) (2023-07-17) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.19.0](https://github.com/noir-lang/acvm/compare/acir-v0.18.2...acir-v0.19.0) (2023-07-15) + + +### ⚠ BREAKING CHANGES + +* move to bincode and GzEncoding for artifacts ([#436](https://github.com/noir-lang/acvm/issues/436)) + +### Features + +* move to bincode and GzEncoding for artifacts ([#436](https://github.com/noir-lang/acvm/issues/436)) ([4683240](https://github.com/noir-lang/acvm/commit/46832400a8bc20135a8a895ab9477b14449734d9)) + +## [0.18.2](https://github.com/noir-lang/acvm/compare/acir-v0.18.1...acir-v0.18.2) (2023-07-12) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.18.1](https://github.com/noir-lang/acvm/compare/acir-v0.18.0...acir-v0.18.1) (2023-07-12) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.18.0](https://github.com/noir-lang/acvm/compare/acir-v0.17.0...acir-v0.18.0) (2023-07-12) + + +### ⚠ BREAKING CHANGES + +* add backend-solvable blackboxes to brillig & unify implementations ([#422](https://github.com/noir-lang/acvm/issues/422)) +* Returns index of failing opcode and transformation mapping ([#412](https://github.com/noir-lang/acvm/issues/412)) + +### Features + +* add backend-solvable blackboxes to brillig & unify implementations ([#422](https://github.com/noir-lang/acvm/issues/422)) ([093342e](https://github.com/noir-lang/acvm/commit/093342ea9481a311fa71343b8b7a22774788838a)) +* Returns index of failing opcode and transformation mapping ([#412](https://github.com/noir-lang/acvm/issues/412)) ([79950e9](https://github.com/noir-lang/acvm/commit/79950e943f60e4082e1cf5ec4442aa67ea91aade)) + +## [0.17.0](https://github.com/noir-lang/acvm/compare/acir-v0.16.0...acir-v0.17.0) (2023-07-07) + + +### ⚠ BREAKING CHANGES + +* **acir:** add `EcdsaSecp256r1` blackbox function ([#408](https://github.com/noir-lang/acvm/issues/408)) + +### Features + +* **acir:** add `EcdsaSecp256r1` blackbox function ([#408](https://github.com/noir-lang/acvm/issues/408)) ([9895817](https://github.com/noir-lang/acvm/commit/98958170c9fa9b4731e33b31cb494a72bb90549e)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.16.0 to 0.17.0 + +## [0.16.0](https://github.com/noir-lang/acvm/compare/acir-v0.15.1...acir-v0.16.0) (2023-07-06) + + +### ⚠ BREAKING CHANGES + +* **acir:** revert changes to `SchnorrVerify` opcode ([#409](https://github.com/noir-lang/acvm/issues/409)) +* **acir:** Remove `Oracle` opcode ([#368](https://github.com/noir-lang/acvm/issues/368)) +* **acir:** Use fixed length data structures in black box function inputs/outputs where possible. ([#386](https://github.com/noir-lang/acvm/issues/386)) +* **acir:** Implement `Add` trait for `Witness` & make output of `Mul` on `Expression` optional ([#393](https://github.com/noir-lang/acvm/issues/393)) + +### Features + +* **acir:** Implement `Add` trait for `Witness` & make output of `Mul` on `Expression` optional ([#393](https://github.com/noir-lang/acvm/issues/393)) ([5bcdfc6](https://github.com/noir-lang/acvm/commit/5bcdfc62e4936922135add171d60a948922581ff)) +* **acir:** Remove `Oracle` opcode ([#368](https://github.com/noir-lang/acvm/issues/368)) ([63354df](https://github.com/noir-lang/acvm/commit/63354df1fe47a4f1128b91641d1b66dfc1281794)) +* **acir:** Use fixed length data structures in black box function inputs/outputs where possible. ([#386](https://github.com/noir-lang/acvm/issues/386)) ([b139d4d](https://github.com/noir-lang/acvm/commit/b139d4d566c715009465a430aab0fb819aacab4f)) + + +### Bug Fixes + +* **acir:** revert changes to `SchnorrVerify` opcode ([#409](https://github.com/noir-lang/acvm/issues/409)) ([f1c7940](https://github.com/noir-lang/acvm/commit/f1c7940f4ac618c7b440b6ed30199f85cbe72cca)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.15.1 to 0.16.0 + +## [0.15.1](https://github.com/noir-lang/acvm/compare/acir-v0.15.0...acir-v0.15.1) (2023-06-20) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.15.0 to 0.15.1 + +## [0.15.0](https://github.com/noir-lang/acvm/compare/acir-v0.14.2...acir-v0.15.0) (2023-06-15) + + +### Features + +* Add method to generate updated `Brillig` opcode from `UnresolvedBrilligCall` ([#363](https://github.com/noir-lang/acvm/issues/363)) ([fda5dbe](https://github.com/noir-lang/acvm/commit/fda5dbe57c28dc4bc28dfd8fe0a4a8ba29635393)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.14.2 to 0.15.0 + +## [0.14.2](https://github.com/noir-lang/acvm/compare/acir-v0.14.1...acir-v0.14.2) (2023-06-08) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.14.1 to 0.14.2 + +## [0.14.1](https://github.com/noir-lang/acvm/compare/acir-v0.14.0...acir-v0.14.1) (2023-06-07) + + +### Features + +* Re-use intermediate variables created during width reduction, with proper scale. ([#343](https://github.com/noir-lang/acvm/issues/343)) ([6bd0baa](https://github.com/noir-lang/acvm/commit/6bd0baa4bc9ac204e7710ec6d17d1752d2e924c0)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.14.0 to 0.14.1 + +## [0.14.0](https://github.com/noir-lang/acvm/compare/acir-v0.13.3...acir-v0.14.0) (2023-06-06) + + +### ⚠ BREAKING CHANGES + +* **acir:** Verify Proof ([#291](https://github.com/noir-lang/acvm/issues/291)) + +### Features + +* **acir:** Verify Proof ([#291](https://github.com/noir-lang/acvm/issues/291)) ([9f34428](https://github.com/noir-lang/acvm/commit/9f34428b7084c7c38de401a16ca76e748d8b1d77)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.13.3 to 0.14.0 + +## [0.13.3](https://github.com/noir-lang/acvm/compare/acir-v0.13.2...acir-v0.13.3) (2023-06-05) + + +### Bug Fixes + +* Empty commit to trigger release-please ([e8f0748](https://github.com/noir-lang/acvm/commit/e8f0748042ef505d59ab63266d3c36c5358ee30d)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.13.2 to 0.13.3 + +## [0.13.2](https://github.com/noir-lang/acvm/compare/acir-v0.13.1...acir-v0.13.2) (2023-06-02) + + +### Bug Fixes + +* re-use intermediate vars during width reduction ([#278](https://github.com/noir-lang/acvm/issues/278)) ([5b32920](https://github.com/noir-lang/acvm/commit/5b32920263c4481c60faf0b84f0031aa8149b6b2)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.13.1 to 0.13.2 + +## [0.13.1](https://github.com/noir-lang/acvm/compare/acir-v0.13.0...acir-v0.13.1) (2023-06-01) + + +### Bug Fixes + +* **ci:** Correct typo to avoid `undefined` in changelogs ([#333](https://github.com/noir-lang/acvm/issues/333)) ([d3424c0](https://github.com/noir-lang/acvm/commit/d3424c04fd303c9cbe25d03118d8b358cbb84b83)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.1.1 to 0.13.1 + +## [0.13.0](https://github.com/noir-lang/acvm/compare/acir-v0.12.0...acir-v0.13.0) (2023-06-01) + + +### ⚠ BREAKING CHANGES + +* added hash index to pedersen ([#281](https://github.com/noir-lang/acvm/issues/281)) +* Add variable length keccak opcode ([#314](https://github.com/noir-lang/acvm/issues/314)) +* Remove AES opcode ([#302](https://github.com/noir-lang/acvm/issues/302)) +* **acir, acvm:** Remove ComputeMerkleRoot opcode #296 +* Remove manual serialization of `Opcode`s in favour of `serde` ([#286](https://github.com/noir-lang/acvm/issues/286)) + +### Features + +* **acir, acvm:** Remove ComputeMerkleRoot opcode [#296](https://github.com/noir-lang/acvm/issues/296) ([8b3923e](https://github.com/noir-lang/acvm/commit/8b3923e191e4ac399400025496e8bb4453734040)) +* Add `Brillig` opcode to introduce custom non-determinism to ACVM ([#152](https://github.com/noir-lang/acvm/issues/152)) ([3c6740a](https://github.com/noir-lang/acvm/commit/3c6740af75125afc8ebb4379f781f8274015e2e2)) +* Add variable length keccak opcode ([#314](https://github.com/noir-lang/acvm/issues/314)) ([7bfd169](https://github.com/noir-lang/acvm/commit/7bfd1695b6f119cd70fce4866314c9bb4991eaab)) +* added hash index to pedersen ([#281](https://github.com/noir-lang/acvm/issues/281)) ([61820b6](https://github.com/noir-lang/acvm/commit/61820b651900aac8d9557b4b9477ed0e1763c124)) + + +### Miscellaneous Chores + +* Remove AES opcode ([#302](https://github.com/noir-lang/acvm/issues/302)) ([a429a54](https://github.com/noir-lang/acvm/commit/a429a5422d6f001b6db0d0a0f30c79ec0f96de89)) +* Remove manual serialization of `Opcode`s in favour of `serde` ([#286](https://github.com/noir-lang/acvm/issues/286)) ([8a3812f](https://github.com/noir-lang/acvm/commit/8a3812fe6ed3b267692284bdcd909d9dd32b9747)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.1.0 to 0.1.1 + +## [0.12.0](https://github.com/noir-lang/acvm/compare/acir-v0.11.0...acir-v0.12.0) (2023-05-17) + + +### ⚠ BREAKING CHANGES + +* Introduce WitnessMap data structure to avoid leaking internal structure ([#252](https://github.com/noir-lang/acvm/issues/252)) +* use struct variants for blackbox function calls ([#269](https://github.com/noir-lang/acvm/issues/269)) +* **acvm:** Simplification pass for ACIR ([#151](https://github.com/noir-lang/acvm/issues/151)) + +### Features + +* **acvm:** Simplification pass for ACIR ([#151](https://github.com/noir-lang/acvm/issues/151)) ([7bc42c6](https://github.com/noir-lang/acvm/commit/7bc42c62b6e095f838b781c87cbb1ecd2af5f179)) +* Introduce WitnessMap data structure to avoid leaking internal structure ([#252](https://github.com/noir-lang/acvm/issues/252)) ([b248e60](https://github.com/noir-lang/acvm/commit/b248e606dd69c25d33ae77c5c5c0541adbf80cd6)) +* use struct variants for blackbox function calls ([#269](https://github.com/noir-lang/acvm/issues/269)) ([a83333b](https://github.com/noir-lang/acvm/commit/a83333b9e270dfcfd40a36271896840ec0201bc4)) + + +### Bug Fixes + +* **acir:** Hide variants of WitnessMapError and export it from package ([#283](https://github.com/noir-lang/acvm/issues/283)) ([bbd9ab7](https://github.com/noir-lang/acvm/commit/bbd9ab7ca5be3fb31f3e141fee2522704852f5de)) + +## [0.11.0](https://github.com/noir-lang/acvm/compare/acir-v0.10.3...acir-v0.11.0) (2023-05-04) + + +### Bug Fixes + +* **acir:** Fix `Expression` multiplication to correctly handle degree 1 terms ([#255](https://github.com/noir-lang/acvm/issues/255)) ([e399396](https://github.com/noir-lang/acvm/commit/e399396f7e06deb6b831517af17018607df3f252)) + +## [0.10.3](https://github.com/noir-lang/acvm/compare/acir-v0.10.2...acir-v0.10.3) (2023-04-28) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.10.2](https://github.com/noir-lang/acvm/compare/acir-v0.10.1...acir-v0.10.2) (2023-04-28) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.10.1](https://github.com/noir-lang/acvm/compare/acir-v0.10.0...acir-v0.10.1) (2023-04-28) + + +### Bug Fixes + +* **acir:** add `bn254` as default feature flag ([#240](https://github.com/noir-lang/acvm/issues/240)) ([e56973d](https://github.com/noir-lang/acvm/commit/e56973d8dc1745fe9bb844ec8347acd4d836d42f)) + +## [0.10.0](https://github.com/noir-lang/acvm/compare/acir-v0.9.0...acir-v0.10.0) (2023-04-26) + + +### ⚠ BREAKING CHANGES + +* replace `MerkleMembership` opcode with `ComputeMerkleRoot` ([#233](https://github.com/noir-lang/acvm/issues/233)) +* return `PartialWitnessGeneratorStatus` from `PartialWitnessGenerator.solve` ([#213](https://github.com/noir-lang/acvm/issues/213)) +* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) + +### Features + +* implement `add_mul` on `Expression` ([#207](https://github.com/noir-lang/acvm/issues/207)) ([f156e18](https://github.com/noir-lang/acvm/commit/f156e18cf7a0f1a99bbe1683b8e75fec8325e6dd)) +* replace `MerkleMembership` opcode with `ComputeMerkleRoot` ([#233](https://github.com/noir-lang/acvm/issues/233)) ([74bfee8](https://github.com/noir-lang/acvm/commit/74bfee80e0ff0d205aee1eea548c97ade8bd0e41)) +* return `PartialWitnessGeneratorStatus` from `PartialWitnessGenerator.solve` ([#213](https://github.com/noir-lang/acvm/issues/213)) ([e877bed](https://github.com/noir-lang/acvm/commit/e877bed2cca76bd486e9bed66b4230e65a01f0a2)) + + +### Miscellaneous Chores + +* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) ([a619df6](https://github.com/noir-lang/acvm/commit/a619df614bbb9b2518b788b42a7553b069823a0f)) + +## [0.9.0](https://github.com/noir-lang/acvm/compare/acir-v0.8.1...acir-v0.9.0) (2023-04-07) + + +### Bug Fixes + +* Add test for Out of Memory ([#188](https://github.com/noir-lang/acvm/issues/188)) ([c3db985](https://github.com/noir-lang/acvm/commit/c3db985893e7e59ea04005bb3a57eda5c6ce28c7)) + +## [0.8.1](https://github.com/noir-lang/acvm/compare/acir-v0.8.0...acir-v0.8.1) (2023-03-30) + + +### Bug Fixes + +* unwraps if inputs is zero ([#171](https://github.com/noir-lang/acvm/issues/171)) ([10a3bb2](https://github.com/noir-lang/acvm/commit/10a3bb2a9930ccf422b3f08227aae07775686860)) + +## [0.8.0](https://github.com/noir-lang/acvm/compare/acir-v0.7.1...acir-v0.8.0) (2023-03-28) + + +### ⚠ BREAKING CHANGES + +* **acir:** Read Log Directive ([#156](https://github.com/noir-lang/acvm/issues/156)) + +### Bug Fixes + +* **acir:** Read Log Directive ([#156](https://github.com/noir-lang/acvm/issues/156)) ([1cc2b7f](https://github.com/noir-lang/acvm/commit/1cc2b7f2179cecc338fe0def72bb2dd17eaed0cd)) + +## [0.7.1](https://github.com/noir-lang/acvm/compare/acir-v0.7.0...acir-v0.7.1) (2023-03-27) + + +### Miscellaneous Chores + +* **acir:** Synchronize acvm versions + +## [0.7.0](https://github.com/noir-lang/acvm/compare/acir-v0.6.0...acir-v0.7.0) (2023-03-23) + + +### ⚠ BREAKING CHANGES + +* Add initial oracle opcode ([#149](https://github.com/noir-lang/acvm/issues/149)) +* **acir:** Add RAM and ROM opcodes +* **acir:** Add a public outputs field ([#56](https://github.com/noir-lang/acvm/issues/56)) +* **acir:** remove `Linear` struct ([#145](https://github.com/noir-lang/acvm/issues/145)) +* **acvm:** Remove truncate and oddrange directives ([#142](https://github.com/noir-lang/acvm/issues/142)) + +### Features + +* **acir:** Add a public outputs field ([#56](https://github.com/noir-lang/acvm/issues/56)) ([5f358a9](https://github.com/noir-lang/acvm/commit/5f358a97aaa81d87956e182cd8a6d60de75f9752)) +* **acir:** Add RAM and ROM opcodes ([73e9f25](https://github.com/noir-lang/acvm/commit/73e9f25dd87b2ca91245e93d2445eadc0f522fac)) +* Add initial oracle opcode ([#149](https://github.com/noir-lang/acvm/issues/149)) ([88ee2f8](https://github.com/noir-lang/acvm/commit/88ee2f89f37abf5dd1d9f91b4d2eed44dc651348)) + + +### Miscellaneous Chores + +* **acir:** remove `Linear` struct ([#145](https://github.com/noir-lang/acvm/issues/145)) ([bbb6d92](https://github.com/noir-lang/acvm/commit/bbb6d92e25c43dd33b12f5fcd639fc9ad2a9c9d8)) +* **acvm:** Remove truncate and oddrange directives ([#142](https://github.com/noir-lang/acvm/issues/142)) ([85dd6e8](https://github.com/noir-lang/acvm/commit/85dd6e85bfba85bfb97651f7e30e1f75deb986d5)) + +## [0.6.0](https://github.com/noir-lang/acvm/compare/acir-v0.5.0...acir-v0.6.0) (2023-03-03) + + +### ⚠ BREAKING CHANGES + +* **acir:** rename `term_addition` to `push_addition_term` +* **acir:** rename `term_multiplication` to `push_multiplication_term` ([#122](https://github.com/noir-lang/acvm/issues/122)) +* **acir:** remove `UnknownWitness` ([#123](https://github.com/noir-lang/acvm/issues/123)) +* add block opcode ([#114](https://github.com/noir-lang/acvm/issues/114)) + +### Features + +* **acir:** add useful methods from `noirc_evaluator` onto `Expression` ([#125](https://github.com/noir-lang/acvm/issues/125)) ([d3d5f89](https://github.com/noir-lang/acvm/commit/d3d5f8917482ce5649602695829862a5df4ea712)) +* add block opcode ([#114](https://github.com/noir-lang/acvm/issues/114)) ([097cfb0](https://github.com/noir-lang/acvm/commit/097cfb069291705ddb4bf1fca77ddcef21dbbd08)) + + +### Bug Fixes + +* **acir:** correctly display expressions with non-unit coefficients ([d3d5f89](https://github.com/noir-lang/acvm/commit/d3d5f8917482ce5649602695829862a5df4ea712)) + + +### Miscellaneous Chores + +* **acir:** remove `UnknownWitness` ([#123](https://github.com/noir-lang/acvm/issues/123)) ([9f002c7](https://github.com/noir-lang/acvm/commit/9f002c7b49a5cf222d4a01732cc4917a47690863)) +* **acir:** rename `term_addition` to `push_addition_term` ([d389385](https://github.com/noir-lang/acvm/commit/d38938542851a97dc01727438391e6a65e44c689)) +* **acir:** rename `term_multiplication` to `push_multiplication_term` ([#122](https://github.com/noir-lang/acvm/issues/122)) ([d389385](https://github.com/noir-lang/acvm/commit/d38938542851a97dc01727438391e6a65e44c689)) + +## [0.5.0](https://github.com/noir-lang/acvm/compare/acir-v0.4.1...acir-v0.5.0) (2023-02-22) + + +### ⚠ BREAKING CHANGES + +* **acir:** make PublicInputs use a BTreeSet rather than Vec ([#99](https://github.com/noir-lang/acvm/issues/99)) +* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) +* **acir:** Add keccak256 Opcode ([#91](https://github.com/noir-lang/acvm/issues/91)) +* reorganise compiler in terms of optimisers and transformers ([#88](https://github.com/noir-lang/acvm/issues/88)) + +### Features + +* **acir:** Add keccak256 Opcode ([#91](https://github.com/noir-lang/acvm/issues/91)) ([b909146](https://github.com/noir-lang/acvm/commit/b9091461e199bacdd073cc9b31f03dade0b4fb2d)) +* **acir:** make PublicInputs use a BTreeSet rather than Vec ([#99](https://github.com/noir-lang/acvm/issues/99)) ([53666b7](https://github.com/noir-lang/acvm/commit/53666b782d89c65cd755f9e4ded2c9cf5a141e46)) + + +### Miscellaneous Chores + +* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) ([2427a27](https://github.com/noir-lang/acvm/commit/2427a275048e598c6d651cce8348a4c55148f235)) +* reorganise compiler in terms of optimisers and transformers ([#88](https://github.com/noir-lang/acvm/issues/88)) ([9329307](https://github.com/noir-lang/acvm/commit/9329307e054de202cfc55207162ad952b70d515e)) diff --git a/acvm-repo/acir/Cargo.toml b/acvm-repo/acir/Cargo.toml new file mode 100644 index 00000000000..f4bdd72e25a --- /dev/null +++ b/acvm-repo/acir/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "acir" +description = "ACIR is the IR that the VM processes, it is analogous to LLVM IR" +# x-release-please-start-version +version = "0.27.3" +# x-release-please-end +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +acir_field.workspace = true +brillig.workspace = true +serde.workspace = true +thiserror.workspace = true +rmp-serde = { version = "1.1.0", optional = true } +flate2 = "1.0.24" +bincode.workspace = true + +[dev-dependencies] +serde_json = "1.0" +strum = "0.24" +strum_macros = "0.24" + +[features] +default = ["bn254"] +bn254 = ["acir_field/bn254", "brillig/bn254"] +bls12_381 = ["acir_field/bls12_381", "brillig/bls12_381"] +serialize-messagepack = ["rmp-serde"] diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs new file mode 100644 index 00000000000..17c990c7670 --- /dev/null +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -0,0 +1,118 @@ +//! Black box functions are ACIR opcodes which rely on backends implementing support for specialized constraints. +//! This makes certain zk-snark unfriendly computations cheaper than if they were implemented in more basic constraints. +//! +//! It is possible to fallback to less efficient implementations written in ACIR in some cases. +//! These are implemented inside the ACVM stdlib. + +use serde::{Deserialize, Serialize}; +#[cfg(test)] +use strum_macros::EnumIter; + +#[allow(clippy::upper_case_acronyms)] +#[derive(Clone, Debug, Hash, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(test, derive(EnumIter))] +pub enum BlackBoxFunc { + /// Bitwise AND. + AND, + /// Bitwise XOR. + XOR, + /// Range constraint to ensure that a [`FieldElement`][acir_field::FieldElement] can be represented in a specified number of bits. + RANGE, + /// Calculates the SHA256 hash of the inputs. + SHA256, + /// Calculates the Blake2s hash of the inputs. + Blake2s, + /// Verifies a Schnorr signature over a curve which is "pairing friendly" with the curve on which the ACIR circuit is defined. + /// + /// The exact curve which this signature uses will vary based on the curve being used by ACIR. + /// For example, the BN254 curve supports Schnorr signatures over the [Grumpkin][grumpkin] curve. + /// + /// [grumpkin]: https://hackmd.io/@aztec-network/ByzgNxBfd#2-Grumpkin---A-curve-on-top-of-BN-254-for-SNARK-efficient-group-operations + SchnorrVerify, + /// Calculates a Pedersen commitment to the inputs. + Pedersen, + /// Hashes a set of inputs and applies the field modulus to the result + /// to return a value which can be represented as a [`FieldElement`][acir_field::FieldElement] + /// + /// This is implemented using the `Blake2s` hash function. + /// The "128" in the name specifies that this function should have 128 bits of security. + HashToField128Security, + /// Verifies a ECDSA signature over the secp256k1 curve. + EcdsaSecp256k1, + /// Verifies a ECDSA signature over the secp256r1 curve. + EcdsaSecp256r1, + /// Performs scalar multiplication over the embedded curve on which [`FieldElement`][acir_field::FieldElement] is defined. + FixedBaseScalarMul, + /// Calculates the Keccak256 hash of the inputs. + Keccak256, + /// Compute a recursive aggregation object when verifying a proof inside another circuit. + /// This outputted aggregation object will then be either checked in a top-level verifier or aggregated upon again. + RecursiveAggregation, +} + +impl std::fmt::Display for BlackBoxFunc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl BlackBoxFunc { + pub fn name(&self) -> &'static str { + match self { + BlackBoxFunc::SHA256 => "sha256", + BlackBoxFunc::SchnorrVerify => "schnorr_verify", + BlackBoxFunc::Blake2s => "blake2s", + BlackBoxFunc::Pedersen => "pedersen", + BlackBoxFunc::HashToField128Security => "hash_to_field_128_security", + BlackBoxFunc::EcdsaSecp256k1 => "ecdsa_secp256k1", + BlackBoxFunc::FixedBaseScalarMul => "fixed_base_scalar_mul", + BlackBoxFunc::AND => "and", + BlackBoxFunc::XOR => "xor", + BlackBoxFunc::RANGE => "range", + BlackBoxFunc::Keccak256 => "keccak256", + BlackBoxFunc::RecursiveAggregation => "recursive_aggregation", + BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1", + } + } + pub fn lookup(op_name: &str) -> Option { + match op_name { + "sha256" => Some(BlackBoxFunc::SHA256), + "schnorr_verify" => Some(BlackBoxFunc::SchnorrVerify), + "blake2s" => Some(BlackBoxFunc::Blake2s), + "pedersen" => Some(BlackBoxFunc::Pedersen), + "hash_to_field_128_security" => Some(BlackBoxFunc::HashToField128Security), + "ecdsa_secp256k1" => Some(BlackBoxFunc::EcdsaSecp256k1), + "ecdsa_secp256r1" => Some(BlackBoxFunc::EcdsaSecp256r1), + "fixed_base_scalar_mul" => Some(BlackBoxFunc::FixedBaseScalarMul), + "and" => Some(BlackBoxFunc::AND), + "xor" => Some(BlackBoxFunc::XOR), + "range" => Some(BlackBoxFunc::RANGE), + "keccak256" => Some(BlackBoxFunc::Keccak256), + "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation), + _ => None, + } + } + pub fn is_valid_black_box_func_name(op_name: &str) -> bool { + BlackBoxFunc::lookup(op_name).is_some() + } +} + +#[cfg(test)] +mod tests { + use strum::IntoEnumIterator; + + use crate::BlackBoxFunc; + + #[test] + fn consistent_function_names() { + for bb_func in BlackBoxFunc::iter() { + let resolved_func = BlackBoxFunc::lookup(bb_func.name()).unwrap_or_else(|| { + panic!("BlackBoxFunc::lookup couldn't find black box function {}", bb_func) + }); + assert_eq!( + resolved_func, bb_func, + "BlackBoxFunc::lookup returns unexpected BlackBoxFunc" + ) + } + } +} diff --git a/acvm-repo/acir/src/circuit/brillig.rs b/acvm-repo/acir/src/circuit/brillig.rs new file mode 100644 index 00000000000..5b1ec9d032a --- /dev/null +++ b/acvm-repo/acir/src/circuit/brillig.rs @@ -0,0 +1,33 @@ +use crate::native_types::{Expression, Witness}; +use brillig::ForeignCallResult; +use brillig::Opcode as BrilligOpcode; +use serde::{Deserialize, Serialize}; + +/// Inputs for the Brillig VM. These are the initial inputs +/// that the Brillig VM will use to start. +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +pub enum BrilligInputs { + Single(Expression), + Array(Vec), +} + +/// Outputs for the Brillig VM. Once the VM has completed +/// execution, this will be the object that is returned. +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +pub enum BrilligOutputs { + Simple(Witness), + Array(Vec), +} + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +pub struct Brillig { + pub inputs: Vec, + pub outputs: Vec, + /// Results of oracles/functions external to brillig like a database read. + // Each element of this vector corresponds to a single foreign call but may contain several values. + pub foreign_call_results: Vec, + /// The Brillig VM bytecode to be executed by this ACIR opcode. + pub bytecode: Vec, + /// Predicate of the Brillig execution - indicates if it should be skipped + pub predicate: Option, +} diff --git a/acvm-repo/acir/src/circuit/directives.rs b/acvm-repo/acir/src/circuit/directives.rs new file mode 100644 index 00000000000..32c0bd6337a --- /dev/null +++ b/acvm-repo/acir/src/circuit/directives.rs @@ -0,0 +1,46 @@ +use crate::native_types::{Expression, Witness}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct QuotientDirective { + pub a: Expression, + pub b: Expression, + pub q: Witness, + pub r: Witness, + pub predicate: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +/// Directives do not apply any constraints. +/// You can think of them as opcodes that allow one to use non-determinism +/// In the future, this can be replaced with asm non-determinism blocks +pub enum Directive { + //Performs euclidian division of a / b (as integers) and stores the quotient in q and the rest in r + Quotient(QuotientDirective), + + //decomposition of a: a=\sum b[i]*radix^i where b is an array of witnesses < radix in little endian form + ToLeRadix { + a: Expression, + b: Vec, + radix: u32, + }, + + // Sort directive, using a sorting network + // This directive is used to generate the values of the control bits for the sorting network such that its outputs are properly sorted according to sort_by + PermutationSort { + inputs: Vec>, // Array of tuples to sort + tuple: u32, // tuple size; if 1 then inputs is a single array [a0,a1,..], if 2 then inputs=[(a0,b0),..] is [a0,b0,a1,b1,..], etc.. + bits: Vec, // control bits of the network which permutes the inputs into its sorted version + sort_by: Vec, // specify primary index to sort by, then the secondary,... For instance, if tuple is 2 and sort_by is [1,0], then a=[(a0,b0),..] is sorted by bi and then ai. + }, +} + +impl Directive { + pub fn name(&self) -> &str { + match self { + Directive::Quotient(_) => "quotient", + Directive::ToLeRadix { .. } => "to_le_radix", + Directive::PermutationSort { .. } => "permutation_sort", + } + } +} diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs new file mode 100644 index 00000000000..d03240af2c3 --- /dev/null +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -0,0 +1,285 @@ +pub mod black_box_functions; +pub mod brillig; +pub mod directives; +pub mod opcodes; + +use crate::native_types::Witness; +pub use opcodes::Opcode; +use thiserror::Error; + +use std::{io::prelude::*, num::ParseIntError, str::FromStr}; + +use flate2::Compression; + +use serde::{Deserialize, Serialize}; +use std::collections::BTreeSet; + +#[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, + + /// The set of private inputs to the circuit. + pub private_parameters: BTreeSet, + // ACIR distinguishes between the public inputs which are provided externally or calculated within the circuit and returned. + // The elements of these sets may not be mutually exclusive, i.e. a parameter may be returned from the circuit. + // All public inputs (parameters and return values) must be provided to the verifier at verification time. + /// The set of public inputs provided by the prover. + pub public_parameters: PublicInputs, + /// The set of public inputs calculated within the circuit. + pub return_values: PublicInputs, + /// Maps opcode locations to failed assertion messages. + /// These messages are embedded in the circuit to provide useful feedback to users + /// when a constraint in the circuit is not satisfied. + /// + // Note: This should be a BTreeMap, but serde-reflect is creating invalid + // c++ code at the moment when it is, due to OpcodeLocation needing a comparison + // implementation which is never generated. + pub assert_messages: Vec<(OpcodeLocation, String)>, +} + +impl Circuit { + /// Returns the assert message associated with the provided [`OpcodeLocation`]. + /// Returns `None` if no such assert message exists. + pub fn get_assert_message(&self, opcode_location: OpcodeLocation) -> Option<&str> { + self.assert_messages + .iter() + .find(|(loc, _)| *loc == opcode_location) + .map(|(_, message)| message.as_str()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +/// Opcodes are locatable so that callers can +/// map opcodes to debug information related to their context. +pub enum OpcodeLocation { + Acir(usize), + Brillig { acir_index: usize, brillig_index: usize }, +} + +impl std::fmt::Display for OpcodeLocation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OpcodeLocation::Acir(index) => write!(f, "{index}"), + OpcodeLocation::Brillig { acir_index, brillig_index } => { + write!(f, "{acir_index}.{brillig_index}") + } + } + } +} + +#[derive(Error, Debug)] +pub enum OpcodeLocationFromStrError { + #[error("Invalid opcode location string: {0}")] + InvalidOpcodeLocationString(String), +} + +/// The implementation of display and FromStr allows serializing and deserializing a OpcodeLocation to a string. +/// This is useful when used as key in a map that has to be serialized to JSON/TOML, for example when mapping an opcode to its metadata. +impl FromStr for OpcodeLocation { + type Err = OpcodeLocationFromStrError; + fn from_str(s: &str) -> Result { + let parts: Vec<_> = s.split('.').collect(); + + if parts.is_empty() || parts.len() > 2 { + return Err(OpcodeLocationFromStrError::InvalidOpcodeLocationString(s.to_string())); + } + + fn parse_components(parts: Vec<&str>) -> Result { + match parts.len() { + 1 => { + let index = parts[0].parse()?; + Ok(OpcodeLocation::Acir(index)) + } + 2 => { + let acir_index = parts[0].parse()?; + let brillig_index = parts[1].parse()?; + Ok(OpcodeLocation::Brillig { acir_index, brillig_index }) + } + _ => unreachable!(), + } + } + + parse_components(parts) + .map_err(|_| OpcodeLocationFromStrError::InvalidOpcodeLocationString(s.to_string())) + } +} + +impl Circuit { + pub fn num_vars(&self) -> u32 { + self.current_witness_index + 1 + } + + /// Returns all witnesses which are required to execute the circuit successfully. + pub fn circuit_arguments(&self) -> BTreeSet { + self.private_parameters.union(&self.public_parameters.0).cloned().collect() + } + + /// Returns all public inputs. This includes those provided as parameters to the circuit and those + /// computed as return values. + pub fn public_inputs(&self) -> PublicInputs { + let public_inputs = + self.public_parameters.0.union(&self.return_values.0).cloned().collect(); + PublicInputs(public_inputs) + } + + #[cfg(feature = "serialize-messagepack")] + pub fn write(&self, writer: W) -> std::io::Result<()> { + let buf = rmp_serde::to_vec(&self).unwrap(); + let mut deflater = flate2::write::DeflateEncoder::new(writer, Compression::best()); + deflater.write_all(&buf).unwrap(); + + Ok(()) + } + #[cfg(feature = "serialize-messagepack")] + pub fn read(reader: R) -> std::io::Result { + let mut deflater = flate2::read::DeflateDecoder::new(reader); + let mut buf_d = Vec::new(); + deflater.read_to_end(&mut buf_d).unwrap(); + let circuit = rmp_serde::from_slice(buf_d.as_slice()).unwrap(); + Ok(circuit) + } + + #[cfg(not(feature = "serialize-messagepack"))] + pub fn write(&self, writer: W) -> std::io::Result<()> { + let buf = bincode::serialize(&self).unwrap(); + let mut encoder = flate2::write::GzEncoder::new(writer, Compression::default()); + encoder.write_all(&buf).unwrap(); + encoder.finish().unwrap(); + Ok(()) + } + + #[cfg(not(feature = "serialize-messagepack"))] + pub fn read(reader: R) -> std::io::Result { + let mut gz_decoder = flate2::read::GzDecoder::new(reader); + let mut buf_d = Vec::new(); + gz_decoder.read_to_end(&mut buf_d).unwrap(); + let circuit = bincode::deserialize(&buf_d).unwrap(); + Ok(circuit) + } +} + +impl std::fmt::Display for Circuit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "current witness index : {}", self.current_witness_index)?; + + let write_public_inputs = |f: &mut std::fmt::Formatter<'_>, + public_inputs: &PublicInputs| + -> Result<(), std::fmt::Error> { + write!(f, "[")?; + let public_input_indices = public_inputs.indices(); + for (index, public_input) in public_input_indices.iter().enumerate() { + write!(f, "{public_input}")?; + if index != public_input_indices.len() - 1 { + write!(f, ", ")?; + } + } + writeln!(f, "]") + }; + + write!(f, "public parameters indices : ")?; + write_public_inputs(f, &self.public_parameters)?; + + write!(f, "return value indices : ")?; + write_public_inputs(f, &self.return_values)?; + + for opcode in &self.opcodes { + writeln!(f, "{opcode}")? + } + Ok(()) + } +} + +impl std::fmt::Debug for Circuit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct PublicInputs(pub BTreeSet); + +impl PublicInputs { + /// Returns the witness index of each public input + pub fn indices(&self) -> Vec { + self.0.iter().map(|witness| witness.witness_index()).collect() + } + + pub fn contains(&self, index: usize) -> bool { + self.0.contains(&Witness(index as u32)) + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeSet; + + use super::{ + opcodes::{BlackBoxFuncCall, FunctionInput}, + Circuit, Opcode, PublicInputs, + }; + use crate::native_types::Witness; + use acir_field::FieldElement; + + fn and_opcode() -> Opcode { + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::AND { + lhs: FunctionInput { witness: Witness(1), num_bits: 4 }, + rhs: FunctionInput { witness: Witness(2), num_bits: 4 }, + output: Witness(3), + }) + } + fn range_opcode() -> Opcode { + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { + input: FunctionInput { witness: Witness(1), num_bits: 8 }, + }) + } + + #[test] + fn serialization_roundtrip() { + let circuit = Circuit { + current_witness_index: 5, + opcodes: vec![and_opcode(), range_opcode()], + private_parameters: BTreeSet::new(), + public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), + return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])), + assert_messages: Default::default(), + }; + + fn read_write(circuit: Circuit) -> (Circuit, Circuit) { + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + let got_circuit = Circuit::read(&*bytes).unwrap(); + (circuit, got_circuit) + } + + let (circ, got_circ) = read_write(circuit); + assert_eq!(circ, got_circ) + } + + #[test] + fn test_serialize() { + let circuit = Circuit { + current_witness_index: 0, + opcodes: vec![ + Opcode::Arithmetic(crate::native_types::Expression { + mul_terms: vec![], + linear_combinations: vec![], + q_c: FieldElement::from(8u128), + }), + range_opcode(), + and_opcode(), + ], + private_parameters: BTreeSet::new(), + public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), + return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), + assert_messages: Default::default(), + }; + + let json = serde_json::to_string_pretty(&circuit).unwrap(); + + let deserialized = serde_json::from_str(&json).unwrap(); + assert_eq!(circuit, deserialized); + } +} diff --git a/acvm-repo/acir/src/circuit/opcodes.rs b/acvm-repo/acir/src/circuit/opcodes.rs new file mode 100644 index 00000000000..dc7f73b47e5 --- /dev/null +++ b/acvm-repo/acir/src/circuit/opcodes.rs @@ -0,0 +1,179 @@ +use super::{ + brillig::Brillig, + directives::{Directive, QuotientDirective}, +}; +use crate::native_types::{Expression, Witness}; +use serde::{Deserialize, Serialize}; + +mod black_box_function_call; +mod memory_operation; + +pub use black_box_function_call::{BlackBoxFuncCall, FunctionInput}; +pub use memory_operation::{BlockId, MemOp}; + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Opcode { + Arithmetic(Expression), + /// Calls to "gadgets" which rely on backends implementing support for specialized constraints. + /// + /// Often used for exposing more efficient implementations of SNARK-unfriendly computations. + BlackBoxFuncCall(BlackBoxFuncCall), + Directive(Directive), + Brillig(Brillig), + /// Atomic operation on a block of memory + MemoryOp { + block_id: BlockId, + op: MemOp, + /// Predicate of the memory operation - indicates if it should be skipped + predicate: Option, + }, + MemoryInit { + block_id: BlockId, + init: Vec, + }, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum UnsupportedMemoryOpcode { + MemoryOp, + MemoryInit, +} + +impl std::fmt::Display for UnsupportedMemoryOpcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UnsupportedMemoryOpcode::MemoryOp => write!(f, "MemoryOp"), + UnsupportedMemoryOpcode::MemoryInit => write!(f, "MemoryInit"), + } + } +} + +impl Opcode { + // TODO We can add a domain separator by doing something like: + // TODO concat!("directive:", directive.name) + pub fn name(&self) -> &str { + match self { + Opcode::Arithmetic(_) => "arithmetic", + Opcode::Directive(directive) => directive.name(), + Opcode::BlackBoxFuncCall(g) => g.name(), + Opcode::Brillig(_) => "brillig", + Opcode::MemoryOp { .. } => "mem", + Opcode::MemoryInit { .. } => "init memory block", + } + } + + pub fn unsupported_opcode(&self) -> UnsupportedMemoryOpcode { + match self { + Opcode::MemoryOp { .. } => UnsupportedMemoryOpcode::MemoryOp, + Opcode::MemoryInit { .. } => UnsupportedMemoryOpcode::MemoryInit, + Opcode::BlackBoxFuncCall(_) => { + unreachable!("Unsupported Blackbox function should not be reported here") + } + _ => unreachable!("Opcode is supported"), + } + } + + pub fn is_arithmetic(&self) -> bool { + matches!(self, Opcode::Arithmetic(_)) + } + + pub fn arithmetic(self) -> Option { + match self { + Opcode::Arithmetic(expr) => Some(expr), + _ => None, + } + } +} + +impl std::fmt::Display for Opcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Opcode::Arithmetic(expr) => { + write!(f, "EXPR [ ")?; + for i in &expr.mul_terms { + write!(f, "({}, _{}, _{}) ", i.0, i.1.witness_index(), i.2.witness_index())?; + } + for i in &expr.linear_combinations { + write!(f, "({}, _{}) ", i.0, i.1.witness_index())?; + } + write!(f, "{}", expr.q_c)?; + + write!(f, " ]") + } + Opcode::Directive(Directive::Quotient(QuotientDirective { a, b, q, r, predicate })) => { + write!(f, "DIR::QUOTIENT ")?; + if let Some(pred) = predicate { + writeln!(f, "PREDICATE = {pred}")?; + } + + write!( + f, + "(out : _{}, (_{}, {}), _{})", + a, + q.witness_index(), + b, + r.witness_index() + ) + } + Opcode::BlackBoxFuncCall(g) => write!(f, "{g}"), + Opcode::Directive(Directive::ToLeRadix { a, b, radix: _ }) => { + write!(f, "DIR::TORADIX ")?; + write!( + f, + // TODO (Note): this assumes that the decomposed bits have contiguous witness indices + // This should be the case, however, we can also have a function which checks this + "(_{}, [_{}..._{}] )", + a, + b.first().unwrap().witness_index(), + b.last().unwrap().witness_index(), + ) + } + Opcode::Directive(Directive::PermutationSort { inputs: a, tuple, bits, sort_by }) => { + write!(f, "DIR::PERMUTATIONSORT ")?; + write!( + f, + "(permutation size: {} {}-tuples, sort_by: {:#?}, bits: [_{}..._{}]))", + a.len(), + tuple, + sort_by, + // (Note): the bits do not have contiguous index but there are too many for display + bits.first().unwrap().witness_index(), + bits.last().unwrap().witness_index(), + ) + } + + Opcode::Brillig(brillig) => { + write!(f, "BRILLIG: ")?; + writeln!(f, "inputs: {:?}", brillig.inputs)?; + writeln!(f, "outputs: {:?}", brillig.outputs)?; + writeln!(f, "{:?}", brillig.bytecode) + } + Opcode::MemoryOp { block_id, op, predicate } => { + write!(f, "MEM ")?; + if let Some(pred) = predicate { + writeln!(f, "PREDICATE = {pred}")?; + } + + let is_read = op.operation.is_zero(); + let is_write = op.operation == Expression::one(); + if is_read { + write!(f, "(id: {}, read at: {}, value: {}) ", block_id.0, op.index, op.value) + } else if is_write { + write!(f, "(id: {}, write {} at: {}) ", block_id.0, op.value, op.index) + } else { + write!(f, "(id: {}, op {} at: {}) ", block_id.0, op.operation, op.index) + } + } + Opcode::MemoryInit { block_id, init } => { + write!(f, "INIT ")?; + write!(f, "(id: {}, len: {}) ", block_id.0, init.len()) + } + } + } +} + +impl std::fmt::Debug for Opcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs new file mode 100644 index 00000000000..b2ca0440b59 --- /dev/null +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -0,0 +1,410 @@ +use crate::native_types::Witness; +use crate::BlackBoxFunc; +use serde::{Deserialize, Serialize}; + +// Note: Some functions will not use all of the witness +// So we need to supply how many bits of the witness is needed +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct FunctionInput { + pub witness: Witness, + pub num_bits: u32, +} + +impl FunctionInput { + pub fn dummy() -> Self { + Self { witness: Witness(0), num_bits: 0 } + } +} + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum BlackBoxFuncCall { + AND { + lhs: FunctionInput, + rhs: FunctionInput, + output: Witness, + }, + XOR { + lhs: FunctionInput, + rhs: FunctionInput, + output: Witness, + }, + RANGE { + input: FunctionInput, + }, + SHA256 { + inputs: Vec, + outputs: Vec, + }, + Blake2s { + inputs: Vec, + outputs: Vec, + }, + SchnorrVerify { + public_key_x: FunctionInput, + public_key_y: FunctionInput, + signature: Vec, + message: Vec, + output: Witness, + }, + Pedersen { + inputs: Vec, + domain_separator: u32, + outputs: (Witness, Witness), + }, + // 128 here specifies that this function + // should have 128 bits of security + HashToField128Security { + inputs: Vec, + output: Witness, + }, + EcdsaSecp256k1 { + public_key_x: Vec, + public_key_y: Vec, + signature: Vec, + hashed_message: Vec, + output: Witness, + }, + EcdsaSecp256r1 { + public_key_x: Vec, + public_key_y: Vec, + signature: Vec, + hashed_message: Vec, + output: Witness, + }, + FixedBaseScalarMul { + low: FunctionInput, + high: FunctionInput, + outputs: (Witness, Witness), + }, + Keccak256 { + inputs: Vec, + outputs: Vec, + }, + Keccak256VariableLength { + inputs: Vec, + /// This is the number of bytes to take + /// from the input. Note: if `var_message_size` + /// is more than the number of bytes in the input, + /// then an error is returned. + var_message_size: FunctionInput, + outputs: Vec, + }, + RecursiveAggregation { + verification_key: Vec, + proof: Vec, + /// These represent the public inputs of the proof we are verifying + /// They should be checked against in the circuit after construction + /// of a new aggregation state + public_inputs: Vec, + /// A key hash is used to check the validity of the verification key. + /// The circuit implementing this opcode can use this hash to ensure that the + /// key provided to the circuit matches the key produced by the circuit creator + key_hash: FunctionInput, + /// An aggregation object is blob of data that the top-level verifier must run some proof system specific + /// algorithm on to complete verification. The size is proof system specific and will be set by the backend integrating this opcode. + /// The input aggregation object is only not `None` when we are verifying a previous recursive aggregation in + /// the current circuit. If this is the first recursive aggregation there is no input aggregation object. + /// It is left to the backend to determine how to handle when there is no input aggregation object. + input_aggregation_object: Option>, + /// This is the result of a recursive aggregation and is what will be fed into the next verifier. + /// The next verifier can either perform a final verification (returning true or false) + /// or perform another recursive aggregation where this output aggregation object + /// will be the input aggregation object of the next recursive aggregation. + output_aggregation_object: Vec, + }, +} + +impl BlackBoxFuncCall { + #[deprecated = "BlackBoxFuncCall::dummy() is unnecessary and will be removed in ACVM 0.24.0"] + pub fn dummy(bb_func: BlackBoxFunc) -> Self { + match bb_func { + BlackBoxFunc::AND => BlackBoxFuncCall::AND { + lhs: FunctionInput::dummy(), + rhs: FunctionInput::dummy(), + output: Witness(0), + }, + BlackBoxFunc::XOR => BlackBoxFuncCall::XOR { + lhs: FunctionInput::dummy(), + rhs: FunctionInput::dummy(), + output: Witness(0), + }, + BlackBoxFunc::RANGE => BlackBoxFuncCall::RANGE { input: FunctionInput::dummy() }, + BlackBoxFunc::SHA256 => BlackBoxFuncCall::SHA256 { inputs: vec![], outputs: vec![] }, + BlackBoxFunc::Blake2s => BlackBoxFuncCall::Blake2s { inputs: vec![], outputs: vec![] }, + BlackBoxFunc::SchnorrVerify => BlackBoxFuncCall::SchnorrVerify { + public_key_x: FunctionInput::dummy(), + public_key_y: FunctionInput::dummy(), + signature: vec![], + message: vec![], + output: Witness(0), + }, + BlackBoxFunc::Pedersen => BlackBoxFuncCall::Pedersen { + inputs: vec![], + domain_separator: 0, + outputs: (Witness(0), Witness(0)), + }, + BlackBoxFunc::HashToField128Security => { + BlackBoxFuncCall::HashToField128Security { inputs: vec![], output: Witness(0) } + } + BlackBoxFunc::EcdsaSecp256k1 => BlackBoxFuncCall::EcdsaSecp256k1 { + public_key_x: vec![], + public_key_y: vec![], + signature: vec![], + hashed_message: vec![], + output: Witness(0), + }, + BlackBoxFunc::EcdsaSecp256r1 => BlackBoxFuncCall::EcdsaSecp256r1 { + public_key_x: vec![], + public_key_y: vec![], + signature: vec![], + hashed_message: vec![], + output: Witness(0), + }, + BlackBoxFunc::FixedBaseScalarMul => BlackBoxFuncCall::FixedBaseScalarMul { + low: FunctionInput::dummy(), + high: FunctionInput::dummy(), + outputs: (Witness(0), Witness(0)), + }, + BlackBoxFunc::Keccak256 => { + BlackBoxFuncCall::Keccak256 { inputs: vec![], outputs: vec![] } + } + BlackBoxFunc::RecursiveAggregation => BlackBoxFuncCall::RecursiveAggregation { + verification_key: vec![], + proof: vec![], + public_inputs: vec![], + key_hash: FunctionInput::dummy(), + input_aggregation_object: None, + output_aggregation_object: vec![], + }, + } + } + + pub fn get_black_box_func(&self) -> BlackBoxFunc { + match self { + BlackBoxFuncCall::AND { .. } => BlackBoxFunc::AND, + BlackBoxFuncCall::XOR { .. } => BlackBoxFunc::XOR, + BlackBoxFuncCall::RANGE { .. } => BlackBoxFunc::RANGE, + BlackBoxFuncCall::SHA256 { .. } => BlackBoxFunc::SHA256, + BlackBoxFuncCall::Blake2s { .. } => BlackBoxFunc::Blake2s, + BlackBoxFuncCall::SchnorrVerify { .. } => BlackBoxFunc::SchnorrVerify, + BlackBoxFuncCall::Pedersen { .. } => BlackBoxFunc::Pedersen, + BlackBoxFuncCall::HashToField128Security { .. } => BlackBoxFunc::HashToField128Security, + BlackBoxFuncCall::EcdsaSecp256k1 { .. } => BlackBoxFunc::EcdsaSecp256k1, + BlackBoxFuncCall::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1, + BlackBoxFuncCall::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, + BlackBoxFuncCall::Keccak256 { .. } => BlackBoxFunc::Keccak256, + BlackBoxFuncCall::Keccak256VariableLength { .. } => BlackBoxFunc::Keccak256, + BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation, + } + } + + pub fn name(&self) -> &str { + self.get_black_box_func().name() + } + + pub fn get_inputs_vec(&self) -> Vec { + match self { + BlackBoxFuncCall::SHA256 { inputs, .. } + | BlackBoxFuncCall::Blake2s { inputs, .. } + | BlackBoxFuncCall::Keccak256 { inputs, .. } + | BlackBoxFuncCall::Pedersen { inputs, .. } + | BlackBoxFuncCall::HashToField128Security { inputs, .. } => inputs.to_vec(), + BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => { + vec![*lhs, *rhs] + } + BlackBoxFuncCall::FixedBaseScalarMul { low, high, .. } => vec![*low, *high], + BlackBoxFuncCall::RANGE { input } => vec![*input], + BlackBoxFuncCall::SchnorrVerify { + public_key_x, + public_key_y, + signature, + message, + .. + } => { + let mut inputs = Vec::with_capacity(2 + signature.len() + message.len()); + inputs.push(*public_key_x); + inputs.push(*public_key_y); + inputs.extend(signature.iter().copied()); + inputs.extend(message.iter().copied()); + inputs + } + BlackBoxFuncCall::EcdsaSecp256k1 { + public_key_x, + public_key_y, + signature, + hashed_message, + .. + } => { + let mut inputs = Vec::with_capacity( + public_key_x.len() + + public_key_y.len() + + signature.len() + + hashed_message.len(), + ); + inputs.extend(public_key_x.iter().copied()); + inputs.extend(public_key_y.iter().copied()); + inputs.extend(signature.iter().copied()); + inputs.extend(hashed_message.iter().copied()); + inputs + } + BlackBoxFuncCall::EcdsaSecp256r1 { + public_key_x, + public_key_y, + signature, + hashed_message, + .. + } => { + let mut inputs = Vec::with_capacity( + public_key_x.len() + + public_key_y.len() + + signature.len() + + hashed_message.len(), + ); + inputs.extend(public_key_x.iter().copied()); + inputs.extend(public_key_y.iter().copied()); + inputs.extend(signature.iter().copied()); + inputs.extend(hashed_message.iter().copied()); + inputs + } + BlackBoxFuncCall::Keccak256VariableLength { inputs, var_message_size, .. } => { + let mut inputs = inputs.clone(); + inputs.push(*var_message_size); + inputs + } + BlackBoxFuncCall::RecursiveAggregation { + verification_key: key, + proof, + public_inputs, + key_hash, + .. + } => { + let mut inputs = Vec::new(); + inputs.extend(key.iter().copied()); + inputs.extend(proof.iter().copied()); + inputs.extend(public_inputs.iter().copied()); + inputs.push(*key_hash); + // NOTE: we do not return an input aggregation object as it will either be non-existent for the first recursive aggregation + // or the output aggregation object of a previous recursive aggregation. We do not simulate recursive aggregation + // thus the input aggregation object will always be unassigned until proving + inputs + } + } + } + + pub fn get_outputs_vec(&self) -> Vec { + match self { + BlackBoxFuncCall::SHA256 { outputs, .. } + | BlackBoxFuncCall::Blake2s { outputs, .. } + | BlackBoxFuncCall::Keccak256 { outputs, .. } + | BlackBoxFuncCall::RecursiveAggregation { + output_aggregation_object: outputs, .. + } => outputs.to_vec(), + BlackBoxFuncCall::AND { output, .. } + | BlackBoxFuncCall::XOR { output, .. } + | BlackBoxFuncCall::HashToField128Security { output, .. } + | BlackBoxFuncCall::SchnorrVerify { output, .. } + | BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } + | BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } => vec![*output], + BlackBoxFuncCall::FixedBaseScalarMul { outputs, .. } + | BlackBoxFuncCall::Pedersen { outputs, .. } => vec![outputs.0, outputs.1], + BlackBoxFuncCall::RANGE { .. } => vec![], + BlackBoxFuncCall::Keccak256VariableLength { outputs, .. } => outputs.to_vec(), + } + } +} + +const ABBREVIATION_LIMIT: usize = 5; + +fn get_inputs_string(inputs: &[FunctionInput]) -> String { + // Once a vectors length gets above this limit, + // instead of listing all of their elements, we use ellipses + // to abbreviate them + let should_abbreviate_inputs = inputs.len() <= ABBREVIATION_LIMIT; + + if should_abbreviate_inputs { + let mut result = String::new(); + for (index, inp) in inputs.iter().enumerate() { + result += &format!("(_{}, num_bits: {})", inp.witness.witness_index(), inp.num_bits); + // Add a comma, unless it is the last entry + if index != inputs.len() - 1 { + result += ", " + } + } + result + } else { + let first = inputs.first().unwrap(); + let last = inputs.last().unwrap(); + + let mut result = String::new(); + + result += &format!( + "(_{}, num_bits: {})...(_{}, num_bits: {})", + first.witness.witness_index(), + first.num_bits, + last.witness.witness_index(), + last.num_bits, + ); + + result + } +} + +fn get_outputs_string(outputs: &[Witness]) -> String { + let should_abbreviate_outputs = outputs.len() <= ABBREVIATION_LIMIT; + + if should_abbreviate_outputs { + let mut result = String::new(); + for (index, output) in outputs.iter().enumerate() { + result += &format!("_{}", output.witness_index()); + // Add a comma, unless it is the last entry + if index != outputs.len() - 1 { + result += ", " + } + } + result + } else { + let first = outputs.first().unwrap(); + let last = outputs.last().unwrap(); + + let mut result = String::new(); + result += &format!("(_{},...,_{})", first.witness_index(), last.witness_index()); + result + } +} + +impl std::fmt::Display for BlackBoxFuncCall { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let uppercase_name = self.name().to_uppercase(); + write!(f, "BLACKBOX::{uppercase_name} ")?; + // INPUTS + write!(f, "[")?; + + let inputs_str = get_inputs_string(&self.get_inputs_vec()); + + write!(f, "{inputs_str}")?; + write!(f, "] ")?; + + // OUTPUTS + write!(f, "[ ")?; + + let outputs_str = get_outputs_string(&self.get_outputs_vec()); + + write!(f, "{outputs_str}")?; + + write!(f, "]")?; + + // SPECIFIC PARAMETERS + match self { + BlackBoxFuncCall::Pedersen { domain_separator, .. } => { + write!(f, " domain_separator: {domain_separator}") + } + _ => write!(f, ""), + } + } +} + +impl std::fmt::Debug for BlackBoxFuncCall { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} diff --git a/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs b/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs new file mode 100644 index 00000000000..9e45dc4ee8c --- /dev/null +++ b/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs @@ -0,0 +1,28 @@ +use crate::native_types::{Expression, Witness}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] +pub struct BlockId(pub u32); + +/// Operation on a block of memory +/// We can either write or read at an index in memory +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] +pub struct MemOp { + /// Can be 0 (read) or 1 (write) + pub operation: Expression, + pub index: Expression, + pub value: Expression, +} + +impl MemOp { + /// Creates a `MemOp` which reads from memory at `index` and inserts the read value + /// into the [`WitnessMap`][crate::native_types::WitnessMap] at `witness` + pub fn read_at_mem_index(index: Expression, witness: Witness) -> Self { + MemOp { operation: Expression::zero(), index, value: witness.into() } + } + + /// Creates a `MemOp` which writes the [`Expression`] `value` into memory at `index`. + pub fn write_to_mem_index(index: Expression, value: Expression) -> Self { + MemOp { operation: Expression::one(), index, value } + } +} diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs new file mode 100644 index 00000000000..96ac444b6d9 --- /dev/null +++ b/acvm-repo/acir/src/lib.rs @@ -0,0 +1,12 @@ +#![warn(unused_crate_dependencies)] +#![warn(unreachable_pub)] + +// Arbitrary Circuit Intermediate Representation + +pub mod circuit; +pub mod native_types; + +pub use acir_field; +pub use acir_field::FieldElement; +pub use brillig; +pub use circuit::black_box_functions::BlackBoxFunc; diff --git a/acvm-repo/acir/src/native_types/expression/mod.rs b/acvm-repo/acir/src/native_types/expression/mod.rs new file mode 100644 index 00000000000..368630c2e06 --- /dev/null +++ b/acvm-repo/acir/src/native_types/expression/mod.rs @@ -0,0 +1,398 @@ +use crate::native_types::Witness; +use acir_field::FieldElement; +use serde::{Deserialize, Serialize}; +use std::cmp::Ordering; + +mod operators; +mod ordering; + +// In the addition polynomial +// We can have arbitrary fan-in/out, so we need more than wL,wR and wO +// When looking at the arithmetic opcode for the quotient polynomial in standard plonk +// You can think of it as fan-in 2 and fan out-1 , or you can think of it as fan-in 1 and fan-out 2 +// +// In the multiplication polynomial +// XXX: If we allow the degree of the quotient polynomial to be arbitrary, then we will need a vector of wire values +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)] +pub struct Expression { + // To avoid having to create intermediate variables pre-optimization + // We collect all of the multiplication terms in the arithmetic opcode + // A multiplication term if of the form q_M * wL * wR + // Hence this vector represents the following sum: q_M1 * wL1 * wR1 + q_M2 * wL2 * wR2 + .. + + pub mul_terms: Vec<(FieldElement, Witness, Witness)>, + + pub linear_combinations: Vec<(FieldElement, Witness)>, + // TODO: rename q_c to `constant` moreover q_X is not clear to those who + // TODO are not familiar with PLONK + pub q_c: FieldElement, +} + +impl Default for Expression { + fn default() -> Expression { + Expression { + mul_terms: Vec::new(), + linear_combinations: Vec::new(), + q_c: FieldElement::zero(), + } + } +} + +impl std::fmt::Display for Expression { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(witness) = self.to_witness() { + write!(f, "x{}", witness.witness_index()) + } else { + write!(f, "%{:?}%", crate::circuit::opcodes::Opcode::Arithmetic(self.clone())) + } + } +} + +impl Expression { + // TODO: possibly remove, and move to noir repo. + pub const fn can_defer_constraint(&self) -> bool { + false + } + + /// Returns the number of multiplication terms + pub fn num_mul_terms(&self) -> usize { + self.mul_terms.len() + } + + pub fn from_field(q_c: FieldElement) -> Expression { + Self { q_c, ..Default::default() } + } + + pub fn one() -> Expression { + Self::from_field(FieldElement::one()) + } + + pub fn zero() -> Expression { + Self::default() + } + + /// Adds a new linear term to the `Expression`. + pub fn push_addition_term(&mut self, coefficient: FieldElement, variable: Witness) { + self.linear_combinations.push((coefficient, variable)) + } + + /// Adds a new quadratic term to the `Expression`. + pub fn push_multiplication_term( + &mut self, + coefficient: FieldElement, + lhs: Witness, + rhs: Witness, + ) { + self.mul_terms.push((coefficient, lhs, rhs)) + } + + /// Returns `true` if the expression represents a constant polynomial. + /// + /// Examples: + /// - f(x,y) = x + y would return false + /// - f(x,y) = xy would return false, the degree here is 2 + /// - f(x,y) = 5 would return true, the degree is 0 + pub fn is_const(&self) -> bool { + self.mul_terms.is_empty() && self.linear_combinations.is_empty() + } + + /// Returns `true` if highest degree term in the expression is one or less. + /// + /// - `mul_term` in an expression contains degree-2 terms + /// - `linear_combinations` contains degree-1 terms + /// Hence, it is sufficient to check that there are no `mul_terms` + /// + /// Examples: + /// - f(x,y) = x + y would return true + /// - f(x,y) = xy would return false, the degree here is 2 + /// - f(x,y) = 0 would return true, the degree is 0 + pub fn is_linear(&self) -> bool { + self.mul_terms.is_empty() + } + + /// Returns `true` if the expression can be seen as a degree-1 univariate polynomial + /// + /// - `mul_terms` in an expression can be univariate, however unless the coefficient + /// is zero, it is always degree-2. + /// - `linear_combinations` contains the sum of degree-1 terms, these terms do not + /// need to contain the same variable and so it can be multivariate. However, we + /// have thus far only checked if `linear_combinations` contains one term, so this + /// method will return false, if the `Expression` has not been simplified. + /// + /// Hence, we check in the simplest case if an expression is a degree-1 univariate, + /// by checking if it contains no `mul_terms` and it contains one `linear_combination` term. + /// + /// Examples: + /// - f(x,y) = x would return true + /// - f(x,y) = x + 6 would return true + /// - f(x,y) = 2*y + 6 would return true + /// - f(x,y) = x + y would return false + /// - f(x,y) = x + x should return true, but we return false *** (we do not simplify) + /// - f(x,y) = 5 would return false + pub fn is_degree_one_univariate(&self) -> bool { + self.is_linear() && self.linear_combinations.len() == 1 + } + + pub fn is_zero(&self) -> bool { + *self == Self::zero() + } + + /// Returns a `FieldElement` if the expression represents a constant polynomial. + /// Otherwise returns `None`. + /// + /// Examples: + /// - f(x,y) = x would return `None` + /// - f(x,y) = x + 6 would return `None` + /// - f(x,y) = 2*y + 6 would return `None` + /// - f(x,y) = x + y would return `None` + /// - f(x,y) = 5 would return `FieldElement(5)` + pub fn to_const(&self) -> Option { + self.is_const().then_some(self.q_c) + } + + /// Returns a `Witness` if the `Expression` can be represented as a degree-1 + /// univariate polynomial. Otherwise returns `None`. + /// + /// Note that `Witness` is only capable of expressing polynomials of the form + /// f(x) = x and not polynomials of the form f(x) = mx+c , so this method has + /// extra checks to ensure that m=1 and c=0 + pub fn to_witness(&self) -> Option { + if self.is_degree_one_univariate() { + // If we get here, we know that our expression is of the form `f(x) = mx+c` + // We want to now restrict ourselves to expressions of the form f(x) = x + // ie where the constant term is 0 and the coefficient in front of the variable is + // one. + let (coefficient, variable) = self.linear_combinations[0]; + let constant = self.q_c; + + if coefficient.is_one() && constant.is_zero() { + return Some(variable); + } + } + None + } + + /// Sorts opcode in a deterministic order + /// XXX: We can probably make this more efficient by sorting on each phase. We only care if it is deterministic + pub fn sort(&mut self) { + self.mul_terms.sort_by(|a, b| a.1.cmp(&b.1).then(a.2.cmp(&b.2))); + self.linear_combinations.sort_by(|a, b| a.1.cmp(&b.1)); + } + + /// Checks if this polynomial can fit into one arithmetic identity + pub fn fits_in_one_identity(&self, width: usize) -> bool { + // A Polynomial with more than one mul term cannot fit into one opcode + if self.mul_terms.len() > 1 { + return false; + }; + // A Polynomial with more terms than fan-in cannot fit within a single opcode + if self.linear_combinations.len() > width { + return false; + } + + // A polynomial with no mul term and a fan-in that fits inside of the width can fit into a single opcode + if self.mul_terms.is_empty() { + return true; + } + + // A polynomial with width-2 fan-in terms and a single non-zero mul term can fit into one opcode + // Example: Axy + Dz . Notice, that the mul term places a constraint on the first two terms, but not the last term + // XXX: This would change if our arithmetic polynomial equation was changed to Axyz for example, but for now it is not. + if self.linear_combinations.len() <= (width - 2) { + return true; + } + + // We now know that we have a single mul term. We also know that the mul term must match up with two other terms + // A polynomial whose mul terms are non zero which do not match up with two terms in the fan-in cannot fit into one opcode + // An example of this is: Axy + Bx + Cy + ... + // Notice how the bivariate monomial xy has two univariate monomials with their respective coefficients + // XXX: note that if x or y is zero, then we could apply a further optimization, but this would be done in another algorithm. + // It would be the same as when we have zero coefficients - Can only work if wire is constrained to be zero publicly + let mul_term = &self.mul_terms[0]; + + // The coefficient should be non-zero, as this method is ran after the compiler removes all zero coefficient terms + assert_ne!(mul_term.0, FieldElement::zero()); + + let mut found_x = false; + let mut found_y = false; + + for term in self.linear_combinations.iter() { + let witness = &term.1; + let x = &mul_term.1; + let y = &mul_term.2; + if witness == x { + found_x = true; + }; + if witness == y { + found_y = true; + }; + if found_x & found_y { + break; + } + } + + found_x & found_y + } + + /// Returns `self + k*b` + pub fn add_mul(&self, k: FieldElement, b: &Expression) -> Expression { + if k.is_zero() { + return self.clone(); + } else if self.is_const() { + return self.q_c + (k * b); + } else if b.is_const() { + return self.clone() + (k * b.q_c); + } + + let mut mul_terms: Vec<(FieldElement, Witness, Witness)> = + Vec::with_capacity(self.mul_terms.len() + b.mul_terms.len()); + let mut linear_combinations: Vec<(FieldElement, Witness)> = + Vec::with_capacity(self.linear_combinations.len() + b.linear_combinations.len()); + let q_c = self.q_c + k * b.q_c; + + //linear combinations + let mut i1 = 0; //a + let mut i2 = 0; //b + while i1 < self.linear_combinations.len() && i2 < b.linear_combinations.len() { + let (a_c, a_w) = self.linear_combinations[i1]; + let (b_c, b_w) = b.linear_combinations[i2]; + + let (coeff, witness) = match a_w.cmp(&b_w) { + Ordering::Greater => { + i2 += 1; + (k * b_c, b_w) + } + Ordering::Less => { + i1 += 1; + (a_c, a_w) + } + Ordering::Equal => { + // Here we're taking both witnesses as the witness indices are equal. + // We then advance both `i1` and `i2`. + i1 += 1; + i2 += 1; + (a_c + k * b_c, a_w) + } + }; + + if !coeff.is_zero() { + linear_combinations.push((coeff, witness)); + } + } + + // Finally process all the remaining terms which we didn't handle in the above loop. + while i1 < self.linear_combinations.len() { + linear_combinations.push(self.linear_combinations[i1]); + i1 += 1; + } + while i2 < b.linear_combinations.len() { + let (b_c, b_w) = b.linear_combinations[i2]; + let coeff = b_c * k; + if !coeff.is_zero() { + linear_combinations.push((coeff, b_w)); + } + i2 += 1; + } + + //mul terms + + i1 = 0; //a + i2 = 0; //b + while i1 < self.mul_terms.len() && i2 < b.mul_terms.len() { + let (a_c, a_wl, a_wr) = self.mul_terms[i1]; + let (b_c, b_wl, b_wr) = b.mul_terms[i2]; + + let (coeff, wl, wr) = match (a_wl, a_wr).cmp(&(b_wl, b_wr)) { + Ordering::Greater => { + i2 += 1; + (k * b_c, b_wl, b_wr) + } + Ordering::Less => { + i1 += 1; + (a_c, a_wl, a_wr) + } + Ordering::Equal => { + // Here we're taking both terms as the witness indices are equal. + // We then advance both `i1` and `i2`. + i2 += 1; + i1 += 1; + (a_c + k * b_c, a_wl, a_wr) + } + }; + + if !coeff.is_zero() { + mul_terms.push((coeff, wl, wr)); + } + } + + // Finally process all the remaining terms which we didn't handle in the above loop. + while i1 < self.mul_terms.len() { + mul_terms.push(self.mul_terms[i1]); + i1 += 1; + } + while i2 < b.mul_terms.len() { + let (b_c, b_wl, b_wr) = b.mul_terms[i2]; + let coeff = b_c * k; + if coeff != FieldElement::zero() { + mul_terms.push((coeff, b_wl, b_wr)); + } + i2 += 1; + } + + Expression { mul_terms, linear_combinations, q_c } + } +} + +impl From for Expression { + fn from(constant: FieldElement) -> Expression { + Expression { q_c: constant, linear_combinations: Vec::new(), mul_terms: Vec::new() } + } +} + +impl From for Expression { + /// Creates an Expression from a Witness. + /// + /// This is infallible since an `Expression` is + /// a multi-variate polynomial and a `Witness` + /// can be seen as a univariate polynomial + fn from(wit: Witness) -> Expression { + Expression { + q_c: FieldElement::zero(), + linear_combinations: vec![(FieldElement::one(), wit)], + mul_terms: Vec::new(), + } + } +} + +#[test] +fn add_mul_smoketest() { + let a = Expression { + mul_terms: vec![(FieldElement::from(2u128), Witness(1), Witness(2))], + ..Default::default() + }; + + let k = FieldElement::from(10u128); + + let b = Expression { + mul_terms: vec![ + (FieldElement::from(3u128), Witness(0), Witness(2)), + (FieldElement::from(3u128), Witness(1), Witness(2)), + (FieldElement::from(4u128), Witness(4), Witness(5)), + ], + linear_combinations: vec![(FieldElement::from(4u128), Witness(4))], + q_c: FieldElement::one(), + }; + + let result = a.add_mul(k, &b); + assert_eq!( + result, + Expression { + mul_terms: vec![ + (FieldElement::from(30u128), Witness(0), Witness(2)), + (FieldElement::from(32u128), Witness(1), Witness(2)), + (FieldElement::from(40u128), Witness(4), Witness(5)), + ], + linear_combinations: vec![(FieldElement::from(40u128), Witness(4))], + q_c: FieldElement::from(10u128) + } + ) +} diff --git a/acvm-repo/acir/src/native_types/expression/operators.rs b/acvm-repo/acir/src/native_types/expression/operators.rs new file mode 100644 index 00000000000..35a548a2e3f --- /dev/null +++ b/acvm-repo/acir/src/native_types/expression/operators.rs @@ -0,0 +1,290 @@ +use crate::native_types::Witness; +use acir_field::FieldElement; +use std::{ + cmp::Ordering, + ops::{Add, Mul, Neg, Sub}, +}; + +use super::Expression; + +// Negation + +impl Neg for &Expression { + type Output = Expression; + fn neg(self) -> Self::Output { + // XXX(med) : Implement an efficient way to do this + + let mul_terms: Vec<_> = + self.mul_terms.iter().map(|(q_m, w_l, w_r)| (-*q_m, *w_l, *w_r)).collect(); + + let linear_combinations: Vec<_> = + self.linear_combinations.iter().map(|(q_k, w_k)| (-*q_k, *w_k)).collect(); + let q_c = -self.q_c; + + Expression { mul_terms, linear_combinations, q_c } + } +} + +// FieldElement + +impl Add for Expression { + type Output = Expression; + fn add(self, rhs: FieldElement) -> Self::Output { + // Increase the constant + let q_c = self.q_c + rhs; + + Expression { mul_terms: self.mul_terms, q_c, linear_combinations: self.linear_combinations } + } +} + +impl Add for FieldElement { + type Output = Expression; + #[inline] + fn add(self, rhs: Expression) -> Self::Output { + rhs + self + } +} + +impl Sub for Expression { + type Output = Expression; + fn sub(self, rhs: FieldElement) -> Self::Output { + // Increase the constant + let q_c = self.q_c - rhs; + + Expression { mul_terms: self.mul_terms, q_c, linear_combinations: self.linear_combinations } + } +} + +impl Sub for FieldElement { + type Output = Expression; + #[inline] + fn sub(self, rhs: Expression) -> Self::Output { + rhs - self + } +} + +impl Mul for &Expression { + type Output = Expression; + fn mul(self, rhs: FieldElement) -> Self::Output { + // Scale the mul terms + let mul_terms: Vec<_> = + self.mul_terms.iter().map(|(q_m, w_l, w_r)| (*q_m * rhs, *w_l, *w_r)).collect(); + + // Scale the linear combinations terms + let lin_combinations: Vec<_> = + self.linear_combinations.iter().map(|(q_l, w_l)| (*q_l * rhs, *w_l)).collect(); + + // Scale the constant + let q_c = self.q_c * rhs; + + Expression { mul_terms, q_c, linear_combinations: lin_combinations } + } +} + +impl Mul<&Expression> for FieldElement { + type Output = Expression; + #[inline] + fn mul(self, rhs: &Expression) -> Self::Output { + rhs * self + } +} + +// Witness + +impl Add for &Expression { + type Output = Expression; + fn add(self, rhs: Witness) -> Expression { + self + &Expression::from(rhs) + } +} + +impl Add<&Expression> for Witness { + type Output = Expression; + #[inline] + fn add(self, rhs: &Expression) -> Expression { + rhs + self + } +} + +impl Sub for &Expression { + type Output = Expression; + fn sub(self, rhs: Witness) -> Expression { + self - &Expression::from(rhs) + } +} + +impl Sub<&Expression> for Witness { + type Output = Expression; + #[inline] + fn sub(self, rhs: &Expression) -> Expression { + rhs - self + } +} + +// Mul is not implemented as this could result in degree 3 terms. + +// Expression + +impl Add<&Expression> for &Expression { + type Output = Expression; + fn add(self, rhs: &Expression) -> Expression { + self.add_mul(FieldElement::one(), rhs) + } +} + +impl Sub<&Expression> for &Expression { + type Output = Expression; + fn sub(self, rhs: &Expression) -> Expression { + self.add_mul(-FieldElement::one(), rhs) + } +} + +impl Mul<&Expression> for &Expression { + type Output = Option; + fn mul(self, rhs: &Expression) -> Option { + if self.is_const() { + return Some(self.q_c * rhs); + } else if rhs.is_const() { + return Some(self * rhs.q_c); + } else if !(self.is_linear() && rhs.is_linear()) { + // `Expression`s can only represent terms which are up to degree 2. + // We then disallow multiplication of `Expression`s which have degree 2 terms. + return None; + } + + let mut output = Expression::from_field(self.q_c * rhs.q_c); + + //TODO to optimize... + for lc in &self.linear_combinations { + let single = single_mul(lc.1, rhs); + output = output.add_mul(lc.0, &single); + } + + //linear terms + let mut i1 = 0; //a + let mut i2 = 0; //b + while i1 < self.linear_combinations.len() && i2 < rhs.linear_combinations.len() { + let (a_c, a_w) = self.linear_combinations[i1]; + let (b_c, b_w) = rhs.linear_combinations[i2]; + + // Apply scaling from multiplication + let a_c = rhs.q_c * a_c; + let b_c = self.q_c * b_c; + + let (coeff, witness) = match a_w.cmp(&b_w) { + Ordering::Greater => { + i2 += 1; + (b_c, b_w) + } + Ordering::Less => { + i1 += 1; + (a_c, a_w) + } + Ordering::Equal => { + // Here we're taking both terms as the witness indices are equal. + // We then advance both `i1` and `i2`. + i1 += 1; + i2 += 1; + (a_c + b_c, a_w) + } + }; + + if !coeff.is_zero() { + output.linear_combinations.push((coeff, witness)); + } + } + while i1 < self.linear_combinations.len() { + let (a_c, a_w) = self.linear_combinations[i1]; + let coeff = rhs.q_c * a_c; + if !coeff.is_zero() { + output.linear_combinations.push((coeff, a_w)); + } + i1 += 1; + } + while i2 < rhs.linear_combinations.len() { + let (b_c, b_w) = rhs.linear_combinations[i2]; + let coeff = self.q_c * b_c; + if !coeff.is_zero() { + output.linear_combinations.push((coeff, b_w)); + } + i2 += 1; + } + + Some(output) + } +} + +/// Returns `w*b.linear_combinations` +fn single_mul(w: Witness, b: &Expression) -> Expression { + Expression { + mul_terms: b + .linear_combinations + .iter() + .map(|(a, wit)| { + let (wl, wr) = if w < *wit { (w, *wit) } else { (*wit, w) }; + (*a, wl, wr) + }) + .collect(), + ..Default::default() + } +} + +#[test] +fn add_smoketest() { + let a = Expression { + mul_terms: vec![], + linear_combinations: vec![(FieldElement::from(2u128), Witness(2))], + q_c: FieldElement::from(2u128), + }; + + let b = Expression { + mul_terms: vec![], + linear_combinations: vec![(FieldElement::from(4u128), Witness(4))], + q_c: FieldElement::one(), + }; + + assert_eq!( + &a + &b, + Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::from(2u128), Witness(2)), + (FieldElement::from(4u128), Witness(4)) + ], + q_c: FieldElement::from(3u128) + } + ); + + // Enforce commutativity + assert_eq!(&a + &b, &b + &a); +} + +#[test] +fn mul_smoketest() { + let a = Expression { + mul_terms: vec![], + linear_combinations: vec![(FieldElement::from(2u128), Witness(2))], + q_c: FieldElement::from(2u128), + }; + + let b = Expression { + mul_terms: vec![], + linear_combinations: vec![(FieldElement::from(4u128), Witness(4))], + q_c: FieldElement::one(), + }; + + assert_eq!( + (&a * &b).unwrap(), + Expression { + mul_terms: vec![(FieldElement::from(8u128), Witness(2), Witness(4)),], + linear_combinations: vec![ + (FieldElement::from(2u128), Witness(2)), + (FieldElement::from(8u128), Witness(4)) + ], + q_c: FieldElement::from(2u128) + } + ); + + // Enforce commutativity + assert_eq!(&a * &b, &b * &a); +} diff --git a/acvm-repo/acir/src/native_types/expression/ordering.rs b/acvm-repo/acir/src/native_types/expression/ordering.rs new file mode 100644 index 00000000000..e24a25ec3af --- /dev/null +++ b/acvm-repo/acir/src/native_types/expression/ordering.rs @@ -0,0 +1,99 @@ +use crate::native_types::Witness; +use std::cmp::Ordering; + +use super::Expression; + +// TODO: It's undecided whether `Expression` should implement `Ord/PartialOrd`. +// This is currently used in ACVM in the compiler. + +impl Ord for Expression { + fn cmp(&self, other: &Self) -> Ordering { + let mut i1 = self.get_max_idx(); + let mut i2 = other.get_max_idx(); + let mut result = Ordering::Equal; + while result == Ordering::Equal { + let m1 = self.get_max_term(&mut i1); + let m2 = other.get_max_term(&mut i2); + if m1.is_none() && m2.is_none() { + return Ordering::Equal; + } + result = Expression::cmp_max(m1, m2); + } + result + } +} + +impl PartialOrd for Expression { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +struct WitnessIdx { + linear: usize, + mul: usize, + second_term: bool, +} + +impl Expression { + fn get_max_idx(&self) -> WitnessIdx { + WitnessIdx { + linear: self.linear_combinations.len(), + mul: self.mul_terms.len(), + second_term: true, + } + } + + /// Returns the maximum witness at the provided position, and decrement the position. + /// + /// This function assumes the gate is sorted + fn get_max_term(&self, idx: &mut WitnessIdx) -> Option { + if idx.linear > 0 { + if idx.mul > 0 { + let mul_term = if idx.second_term { + self.mul_terms[idx.mul - 1].2 + } else { + self.mul_terms[idx.mul - 1].1 + }; + if self.linear_combinations[idx.linear - 1].1 > mul_term { + idx.linear -= 1; + Some(self.linear_combinations[idx.linear].1) + } else { + if idx.second_term { + idx.second_term = false; + } else { + idx.mul -= 1; + } + Some(mul_term) + } + } else { + idx.linear -= 1; + Some(self.linear_combinations[idx.linear].1) + } + } else if idx.mul > 0 { + if idx.second_term { + idx.second_term = false; + Some(self.mul_terms[idx.mul - 1].2) + } else { + idx.mul -= 1; + Some(self.mul_terms[idx.mul].1) + } + } else { + None + } + } + + fn cmp_max(m1: Option, m2: Option) -> Ordering { + if let Some(m1) = m1 { + if let Some(m2) = m2 { + m1.cmp(&m2) + } else { + Ordering::Greater + } + } else if m2.is_some() { + Ordering::Less + } else { + Ordering::Equal + } + } +} diff --git a/acvm-repo/acir/src/native_types/mod.rs b/acvm-repo/acir/src/native_types/mod.rs new file mode 100644 index 00000000000..66c822bfff8 --- /dev/null +++ b/acvm-repo/acir/src/native_types/mod.rs @@ -0,0 +1,8 @@ +mod expression; +mod witness; +mod witness_map; + +pub use expression::Expression; +pub use witness::Witness; +pub use witness_map::WitnessMap; +pub use witness_map::WitnessMapError; diff --git a/acvm-repo/acir/src/native_types/witness.rs b/acvm-repo/acir/src/native_types/witness.rs new file mode 100644 index 00000000000..740d10d2951 --- /dev/null +++ b/acvm-repo/acir/src/native_types/witness.rs @@ -0,0 +1,43 @@ +use std::ops::Add; + +use acir_field::FieldElement; +use serde::{Deserialize, Serialize}; + +use super::Expression; + +// Witness might be a misnomer. This is an index that represents the position a witness will take +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize, +)] +pub struct Witness(pub u32); + +impl Witness { + pub fn new(witness_index: u32) -> Witness { + Witness(witness_index) + } + pub fn witness_index(&self) -> u32 { + self.0 + } + pub fn as_usize(&self) -> usize { + // This is safe as long as the architecture is 32bits minimum + self.0 as usize + } + + pub const fn can_defer_constraint(&self) -> bool { + true + } +} + +impl From for Witness { + fn from(value: u32) -> Self { + Self(value) + } +} + +impl Add for Witness { + type Output = Expression; + + fn add(self, rhs: Witness) -> Self::Output { + Expression::from(self).add_mul(FieldElement::one(), &Expression::from(rhs)) + } +} diff --git a/acvm-repo/acir/src/native_types/witness_map.rs b/acvm-repo/acir/src/native_types/witness_map.rs new file mode 100644 index 00000000000..400e0a8ca1a --- /dev/null +++ b/acvm-repo/acir/src/native_types/witness_map.rs @@ -0,0 +1,146 @@ +use std::{ + collections::{btree_map, BTreeMap}, + io::Read, + ops::Index, +}; + +use acir_field::FieldElement; +use flate2::bufread::GzDecoder; +use flate2::bufread::GzEncoder; +use flate2::Compression; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::native_types::Witness; + +#[cfg(feature = "serialize-messagepack")] +#[derive(Debug, Error)] +enum SerializationError { + #[error(transparent)] + MsgpackEncode(#[from] rmp_serde::encode::Error), + + #[error(transparent)] + MsgpackDecode(#[from] rmp_serde::decode::Error), + + #[error(transparent)] + Deflate(#[from] std::io::Error), +} + +#[cfg(not(feature = "serialize-messagepack"))] +#[derive(Debug, Error)] +enum SerializationError { + #[error(transparent)] + Deflate(#[from] std::io::Error), +} + +#[derive(Debug, Error)] +#[error(transparent)] +pub struct WitnessMapError(#[from] SerializationError); + +/// A map from the witnesses in a constraint system to the field element values +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize)] +pub struct WitnessMap(BTreeMap); + +impl WitnessMap { + pub fn new() -> Self { + Self(BTreeMap::new()) + } + pub fn get(&self, witness: &Witness) -> Option<&FieldElement> { + self.0.get(witness) + } + pub fn get_index(&self, index: u32) -> Option<&FieldElement> { + self.0.get(&index.into()) + } + pub fn contains_key(&self, key: &Witness) -> bool { + self.0.contains_key(key) + } + pub fn insert(&mut self, key: Witness, value: FieldElement) -> Option { + self.0.insert(key, value) + } +} + +impl Index<&Witness> for WitnessMap { + type Output = FieldElement; + + fn index(&self, index: &Witness) -> &Self::Output { + &self.0[index] + } +} + +pub struct IntoIter(btree_map::IntoIter); + +impl Iterator for IntoIter { + type Item = (Witness, FieldElement); + + fn next(&mut self) -> Option { + self.0.next() + } +} + +impl IntoIterator for WitnessMap { + type Item = (Witness, FieldElement); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter(self.0.into_iter()) + } +} + +impl From> for WitnessMap { + fn from(value: BTreeMap) -> Self { + Self(value) + } +} + +#[cfg(feature = "serialize-messagepack")] +impl TryFrom for Vec { + type Error = WitnessMapError; + + fn try_from(val: WitnessMap) -> Result { + let buf = rmp_serde::to_vec(&val).map_err(|err| WitnessMapError(err.into()))?; + let mut deflater = flate2::write::DeflateEncoder::new(buf.as_slice(), Compression::best()); + let mut buf_c = Vec::new(); + deflater.read_to_end(&mut buf_c).map_err(|err| WitnessMapError(err.into()))?; + Ok(buf_c) + } +} + +#[cfg(not(feature = "serialize-messagepack"))] +impl TryFrom for Vec { + type Error = WitnessMapError; + + fn try_from(val: WitnessMap) -> Result { + let buf = bincode::serialize(&val).unwrap(); + let mut deflater = GzEncoder::new(buf.as_slice(), Compression::best()); + let mut buf_c = Vec::new(); + deflater.read_to_end(&mut buf_c).map_err(|err| WitnessMapError(err.into()))?; + Ok(buf_c) + } +} + +#[cfg(feature = "serialize-messagepack")] +impl TryFrom<&[u8]> for WitnessMap { + type Error = WitnessMapError; + + fn try_from(bytes: &[u8]) -> Result { + let mut deflater = flate2::bufread::DeflateDecoder::new(bytes); + let mut buf_d = Vec::new(); + deflater.read_to_end(&mut buf_d).map_err(|err| WitnessMapError(err.into()))?; + let witness_map = + rmp_serde::from_slice(buf_d.as_slice()).map_err(|err| WitnessMapError(err.into()))?; + Ok(Self(witness_map)) + } +} + +#[cfg(not(feature = "serialize-messagepack"))] +impl TryFrom<&[u8]> for WitnessMap { + type Error = WitnessMapError; + + fn try_from(bytes: &[u8]) -> Result { + let mut deflater = GzDecoder::new(bytes); + let mut buf_d = Vec::new(); + deflater.read_to_end(&mut buf_d).map_err(|err| WitnessMapError(err.into()))?; + let witness_map = bincode::deserialize(buf_d.as_slice()).unwrap(); + Ok(Self(witness_map)) + } +} diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs new file mode 100644 index 00000000000..5aa51237dd9 --- /dev/null +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -0,0 +1,330 @@ +//! This integration test defines a set of circuits which are used in order to test the acvm_js package. +//! +//! The acvm_js test suite contains serialized [circuits][`Circuit`] which must be kept in sync with the format +//! outputted from the [ACIR crate][acir]. +//! Breaking changes to the serialization format then require refreshing acvm_js's test suite. +//! This file contains Rust definitions of these circuits and outputs the updated serialized format. +//! +//! These tests also check this circuit serialization against an expected value, erroring if the serialization changes. +//! Generally in this situation we just need to refresh the `expected_serialization` variables to match the +//! actual output, **HOWEVER** note that this results in a breaking change to the ACIR format. + +use std::collections::BTreeSet; + +use acir::{ + circuit::{ + brillig::{Brillig, BrilligInputs, BrilligOutputs}, + opcodes::{BlackBoxFuncCall, BlockId, FunctionInput, MemOp}, + Circuit, Opcode, PublicInputs, + }, + native_types::{Expression, Witness}, +}; +use acir_field::FieldElement; +use brillig::{HeapArray, RegisterIndex, RegisterOrMemory}; + +#[test] +fn addition_circuit() { + let addition = Opcode::Arithmetic(Expression { + mul_terms: Vec::new(), + linear_combinations: vec![ + (FieldElement::one(), Witness(1)), + (FieldElement::one(), Witness(2)), + (-FieldElement::one(), Witness(3)), + ], + q_c: FieldElement::zero(), + }); + + let circuit = Circuit { + current_witness_index: 4, + opcodes: vec![addition], + private_parameters: BTreeSet::from([Witness(1), Witness(2)]), + return_values: PublicInputs([Witness(3)].into()), + ..Circuit::default() + }; + + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + 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, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn fixed_base_scalar_mul_circuit() { + let fixed_base_scalar_mul = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::FixedBaseScalarMul { + low: FunctionInput { witness: Witness(1), num_bits: 128 }, + high: FunctionInput { witness: Witness(2), num_bits: 128 }, + outputs: (Witness(3), Witness(4)), + }); + + let circuit = Circuit { + current_witness_index: 5, + opcodes: vec![fixed_base_scalar_mul], + private_parameters: BTreeSet::from([Witness(1), Witness(2)]), + return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(3), Witness(4)])), + ..Circuit::default() + }; + + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + 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, 207, 78, 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, 68, 185, 243, 207, 92, 0, 0, 0, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn pedersen_circuit() { + let pedersen = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Pedersen { + inputs: vec![FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() }], + outputs: (Witness(2), Witness(3)), + domain_separator: 0, + }); + + let circuit = Circuit { + current_witness_index: 4, + opcodes: vec![pedersen], + private_parameters: BTreeSet::from([Witness(1)]), + return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])), + ..Circuit::default() + }; + + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + 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, 250, 255, 139, + 163, 162, 130, 72, 16, 149, 241, 3, 135, 84, 164, 172, 173, 213, 175, 251, 45, 198, 96, + 243, 211, 50, 152, 67, 220, 211, 92, 0, 0, 0, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn schnorr_verify_circuit() { + let public_key_x = + FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() }; + let public_key_y = + FunctionInput { witness: Witness(2), num_bits: FieldElement::max_num_bits() }; + let signature = + (3..(3 + 64)).map(|i| FunctionInput { witness: Witness(i), num_bits: 8 }).collect(); + let message = ((3 + 64)..(3 + 64 + 10)) + .map(|i| FunctionInput { witness: Witness(i), num_bits: 8 }) + .collect(); + let output = Witness(3 + 64 + 10); + let last_input = output.witness_index() - 1; + + let schnorr = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::SchnorrVerify { + public_key_x, + public_key_y, + signature, + message, + output, + }); + + let circuit = Circuit { + current_witness_index: 100, + opcodes: vec![schnorr], + private_parameters: BTreeSet::from_iter((1..=last_input).map(Witness)), + return_values: PublicInputs(BTreeSet::from([output])), + ..Circuit::default() + }; + + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + 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, 241, 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, + 19, 89, 159, 101, 220, 3, 0, 0, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn simple_brillig_foreign_call() { + let w_input = Witness(1); + let w_inverted = Witness(2); + + let brillig_data = Brillig { + inputs: vec![ + BrilligInputs::Single(w_input.into()), // Input Register 0, + ], + // This tells the BrilligSolver which witnesses its output registers correspond to + outputs: vec![ + BrilligOutputs::Simple(w_inverted), // Output Register 1 + ], + // stack of foreign call/oracle resolutions, starts empty + foreign_call_results: vec![], + bytecode: vec![brillig::Opcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + }], + predicate: None, + }; + + let opcodes = vec![Opcode::Brillig(brillig_data)]; + let circuit = Circuit { + current_witness_index: 8, + opcodes, + private_parameters: BTreeSet::from([Witness(1), Witness(2)]), + ..Circuit::default() + }; + + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + let expected_serialization: Vec = vec![ + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 81, 10, 0, 16, 16, 68, 199, 42, 57, 14, 55, + 112, 25, 31, 126, 124, 72, 206, 79, 161, 86, 225, 135, 87, 219, 78, 187, 53, 205, 104, 0, + 2, 29, 201, 52, 103, 222, 220, 216, 230, 13, 43, 254, 121, 25, 158, 151, 54, 153, 117, 27, + 53, 116, 136, 197, 167, 124, 107, 184, 64, 236, 73, 56, 83, 1, 18, 139, 122, 157, 67, 1, 0, + 0, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn complex_brillig_foreign_call() { + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let a = Witness(1); + let b = Witness(2); + let c = Witness(3); + + let a_times_2 = Witness(4); + let b_times_3 = Witness(5); + let c_times_4 = Witness(6); + let a_plus_b_plus_c = Witness(7); + let a_plus_b_plus_c_times_2 = Witness(8); + + let brillig_data = Brillig { + inputs: vec![ + // Input Register 0 + BrilligInputs::Array(vec![ + Expression::from(a), + Expression::from(b), + Expression::from(c), + ]), + // Input Register 1 + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, a), (fe_1, b), (fe_1, c)], + q_c: fe_0, + }), + ], + // This tells the BrilligSolver which witnesses its output registers correspond to + outputs: vec![ + BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output Register 0 + BrilligOutputs::Simple(a_plus_b_plus_c), // Output Register 1 + BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output Register 2 + ], + // stack of foreign call/oracle resolutions, starts empty + foreign_call_results: vec![], + bytecode: vec![ + // Oracles are named 'foreign calls' in brillig + brillig::Opcode::ForeignCall { + function: "complex".into(), + inputs: vec![ + RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), + RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), + ], + destinations: vec![ + RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), + RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), + RegisterOrMemory::RegisterIndex(RegisterIndex::from(2)), + ], + }, + ], + predicate: None, + }; + + let opcodes = vec![Opcode::Brillig(brillig_data)]; + let circuit = Circuit { + current_witness_index: 8, + opcodes, + private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]), + ..Circuit::default() + }; + + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + let expected_serialization: Vec = vec![ + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 245, 210, 101, 159, 179, + 254, 160, 127, 137, 222, 138, 122, 236, 243, 27, 228, 64, 44, 232, 33, 7, 237, 128, 56, + 157, 147, 131, 103, 6, 0, 64, 184, 192, 201, 72, 206, 40, 177, 70, 174, 27, 197, 199, 111, + 24, 208, 175, 87, 44, 197, 145, 42, 224, 200, 5, 56, 230, 255, 240, 83, 189, 61, 117, 113, + 157, 31, 63, 236, 79, 147, 172, 77, 214, 73, 220, 139, 15, 106, 214, 168, 114, 249, 126, + 218, 214, 125, 153, 15, 54, 37, 90, 26, 155, 39, 227, 95, 223, 232, 230, 4, 247, 157, 215, + 56, 1, 153, 86, 63, 138, 44, 4, 0, 0, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn memory_op_circuit() { + let init = vec![Witness(1), Witness(2)]; + + let memory_init = Opcode::MemoryInit { block_id: BlockId(0), init }; + let write = Opcode::MemoryOp { + block_id: BlockId(0), + op: MemOp::write_to_mem_index(FieldElement::from(1u128).into(), Witness(3).into()), + predicate: None, + }; + let read = Opcode::MemoryOp { + block_id: BlockId(0), + op: MemOp::read_at_mem_index(FieldElement::one().into(), Witness(4)), + predicate: None, + }; + + let circuit = Circuit { + current_witness_index: 5, + opcodes: vec![memory_init, write, read], + private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]), + return_values: PublicInputs([Witness(4)].into()), + ..Circuit::default() + }; + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + 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, + ]; + + assert_eq!(bytes, expected_serialization) +} diff --git a/acvm-repo/acir_field/.gitignore b/acvm-repo/acir_field/.gitignore new file mode 100644 index 00000000000..c41cc9e35e3 --- /dev/null +++ b/acvm-repo/acir_field/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/acvm-repo/acir_field/CHANGELOG.md b/acvm-repo/acir_field/CHANGELOG.md new file mode 100644 index 00000000000..1d80bfd6a20 --- /dev/null +++ b/acvm-repo/acir_field/CHANGELOG.md @@ -0,0 +1,296 @@ +# Changelog + +## [0.27.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.26.1...acir_field-v0.27.0) (2023-09-19) + + +### ⚠ BREAKING CHANGES + +* Separate barretenberg solver from generic blackbox solver code ([#554](https://github.com/noir-lang/acvm/issues/554)) + +### Miscellaneous Chores + +* Separate barretenberg solver from generic blackbox solver code ([#554](https://github.com/noir-lang/acvm/issues/554)) ([a4b9772](https://github.com/noir-lang/acvm/commit/a4b97722a0892fe379ff075e6080675adafdce0e)) + +## [0.26.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.26.0...acir_field-v0.26.1) (2023-09-12) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.26.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.25.0...acir_field-v0.26.0) (2023-09-07) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.25.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.24.1...acir_field-v0.25.0) (2023-09-04) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.24.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.24.0...acir_field-v0.24.1) (2023-09-03) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.24.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.23.0...acir_field-v0.24.0) (2023-08-31) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.23.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.22.0...acir_field-v0.23.0) (2023-08-30) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.22.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.21.0...acir_field-v0.22.0) (2023-08-18) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.21.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.20.1...acir_field-v0.21.0) (2023-07-26) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.20.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.20.0...acir_field-v0.20.1) (2023-07-26) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.20.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.19.1...acir_field-v0.20.0) (2023-07-20) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.19.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.19.0...acir_field-v0.19.1) (2023-07-17) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.19.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.18.2...acir_field-v0.19.0) (2023-07-15) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.18.2](https://github.com/noir-lang/acvm/compare/acir_field-v0.18.1...acir_field-v0.18.2) (2023-07-12) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.18.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.18.0...acir_field-v0.18.1) (2023-07-12) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.18.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.17.0...acir_field-v0.18.0) (2023-07-12) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.17.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.16.0...acir_field-v0.17.0) (2023-07-07) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.16.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.15.1...acir_field-v0.16.0) (2023-07-06) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.15.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.15.0...acir_field-v0.15.1) (2023-06-20) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.15.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.14.2...acir_field-v0.15.0) (2023-06-15) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.14.2](https://github.com/noir-lang/acvm/compare/acir_field-v0.14.1...acir_field-v0.14.2) (2023-06-08) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.14.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.14.0...acir_field-v0.14.1) (2023-06-07) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.14.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.13.3...acir_field-v0.14.0) (2023-06-06) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.13.3](https://github.com/noir-lang/acvm/compare/acir_field-v0.13.2...acir_field-v0.13.3) (2023-06-05) + + +### Bug Fixes + +* Empty commit to trigger release-please ([e8f0748](https://github.com/noir-lang/acvm/commit/e8f0748042ef505d59ab63266d3c36c5358ee30d)) + +## [0.13.2](https://github.com/noir-lang/acvm/compare/acir_field-v0.13.1...acir_field-v0.13.2) (2023-06-02) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.13.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.13.0...acir_field-v0.13.1) (2023-06-01) + + +### Bug Fixes + +* **ci:** Correct typo to avoid `undefined` in changelogs ([#333](https://github.com/noir-lang/acvm/issues/333)) ([d3424c0](https://github.com/noir-lang/acvm/commit/d3424c04fd303c9cbe25d03118d8b358cbb84b83)) + +## [0.13.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.12.0...acir_field-v0.13.0) (2023-06-01) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.12.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.11.0...acir_field-v0.12.0) (2023-05-17) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.11.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.10.3...acir_field-v0.11.0) (2023-05-04) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.10.3](https://github.com/noir-lang/acvm/compare/acir_field-v0.10.2...acir_field-v0.10.3) (2023-04-28) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.10.2](https://github.com/noir-lang/acvm/compare/acir_field-v0.10.1...acir_field-v0.10.2) (2023-04-28) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.10.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.10.0...acir_field-v0.10.1) (2023-04-28) + + +### Features + +* implement `FieldElement::from<bool>()` ([#203](https://github.com/noir-lang/acvm/issues/203)) ([476cfa2](https://github.com/noir-lang/acvm/commit/476cfa247fddb515c64c2801c6868357c9375294)) +* Update Arkworks' dependencies on `acir_field` ([#69](https://github.com/noir-lang/acvm/issues/69)) ([65d6130](https://github.com/noir-lang/acvm/commit/65d61307a12f25e04afad2d50e4c4db5ce97dd8c)) + + +### Bug Fixes + +* prevent `bn254` feature flag always being enabled ([#225](https://github.com/noir-lang/acvm/issues/225)) ([82eee6a](https://github.com/noir-lang/acvm/commit/82eee6ab08ae480f04904ca8571fd88f4466c000)) + +## [0.10.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.9.0...acir_field-v0.10.0) (2023-04-26) + + +### Features + +* implement `FieldElement::from<bool>()` ([#203](https://github.com/noir-lang/acvm/issues/203)) ([476cfa2](https://github.com/noir-lang/acvm/commit/476cfa247fddb515c64c2801c6868357c9375294)) + + +### Bug Fixes + +* prevent `bn254` feature flag always being enabled ([#225](https://github.com/noir-lang/acvm/issues/225)) ([82eee6a](https://github.com/noir-lang/acvm/commit/82eee6ab08ae480f04904ca8571fd88f4466c000)) + +## [0.9.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.8.1...acir_field-v0.9.0) (2023-04-07) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.8.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.8.0...acir_field-v0.8.1) (2023-03-30) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.8.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.7.1...acir_field-v0.8.0) (2023-03-28) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.7.1](https://github.com/noir-lang/acvm/compare/acir_field-v0.7.0...acir_field-v0.7.1) (2023-03-27) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.7.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.6.0...acir_field-v0.7.0) (2023-03-23) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.6.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.5.0...acir_field-v0.6.0) (2023-03-03) + + +### Miscellaneous Chores + +* **acir_field:** Synchronize acvm versions + +## [0.5.0](https://github.com/noir-lang/acvm/compare/acir_field-v0.4.1...acir_field-v0.5.0) (2023-02-22) + + +### Features + +* Update Arkworks' dependencies on `acir_field` ([#69](https://github.com/noir-lang/acvm/issues/69)) ([65d6130](https://github.com/noir-lang/acvm/commit/65d61307a12f25e04afad2d50e4c4db5ce97dd8c)) diff --git a/acvm-repo/acir_field/Cargo.toml b/acvm-repo/acir_field/Cargo.toml new file mode 100644 index 00000000000..40f4abc8a07 --- /dev/null +++ b/acvm-repo/acir_field/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "acir_field" +description = "The field implementation being used by ACIR." +# x-release-please-start-version +version = "0.27.3" +# x-release-please-end +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hex.workspace = true +num-bigint.workspace = true +serde.workspace = true + +ark-bn254 = { version = "^0.4.0", optional = true, default-features = false, features = [ + "curve", +] } +ark-bls12-381 = { version = "^0.4.0", optional = true, default-features = false, features = [ + "curve", +] } +ark-ff = { version = "^0.4.0", optional = true, default-features = false } + +cfg-if = "1.0.0" + +[features] +default = ["bn254"] +bn254 = ["dep:ark-bn254", "dep:ark-ff"] +bls12_381 = ["dep:ark-bls12-381", "dep:ark-ff"] diff --git a/acvm-repo/acir_field/src/generic_ark.rs b/acvm-repo/acir_field/src/generic_ark.rs new file mode 100644 index 00000000000..59600549f32 --- /dev/null +++ b/acvm-repo/acir_field/src/generic_ark.rs @@ -0,0 +1,502 @@ +use ark_ff::PrimeField; +use ark_ff::Zero; +use num_bigint::BigUint; +use serde::{Deserialize, Serialize}; + +// XXX: Switch out for a trait and proper implementations +// This implementation is in-efficient, can definitely remove hex usage and Iterator instances for trivial functionality +#[derive(Clone, Copy, Eq, PartialOrd, Ord)] +pub struct FieldElement(F); + +impl std::fmt::Display for FieldElement { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + // First check if the number is zero + // + let number = BigUint::from_bytes_be(&self.to_be_bytes()); + if number == BigUint::zero() { + return write!(f, "0"); + } + // Check if the negative version is smaller to represent + // + let minus_number = BigUint::from_bytes_be(&(self.neg()).to_be_bytes()); + let (smaller_repr, is_negative) = + if minus_number.to_string().len() < number.to_string().len() { + (minus_number, true) + } else { + (number, false) + }; + if is_negative { + write!(f, "-")?; + } + + // Number of bits needed to represent the smaller representation + let num_bits = smaller_repr.bits(); + + // Check if the number represents a power of 2 + if smaller_repr.count_ones() == 1 { + let mut bit_index = 0; + for i in 0..num_bits { + if smaller_repr.bit(i) { + bit_index = i; + break; + } + } + return match bit_index { + 0 => write!(f, "1"), + 1 => write!(f, "2"), + 2 => write!(f, "4"), + 3 => write!(f, "8"), + _ => write!(f, "2{}", superscript(bit_index)), + }; + } + + // Check if number is a multiple of a power of 2. + // This is used because when computing the quotient + // we usually have numbers in the form 2^t * q + r + // We focus on 2^64, 2^32, 2^16, 2^8, 2^4 because + // they are common. We could extend this to a more + // general factorization strategy, but we pay in terms of CPU time + let mul_sign = "×"; + for power in [64, 32, 16, 8, 4] { + let power_of_two = BigUint::from(2_u128).pow(power); + if &smaller_repr % &power_of_two == BigUint::zero() { + return write!( + f, + "2{}{}{}", + superscript(power as u64), + mul_sign, + smaller_repr / &power_of_two, + ); + } + } + write!(f, "{smaller_repr}") + } +} + +impl std::fmt::Debug for FieldElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +impl std::hash::Hash for FieldElement { + fn hash(&self, state: &mut H) { + state.write(&self.to_be_bytes()) + } +} + +impl PartialEq for FieldElement { + fn eq(&self, other: &Self) -> bool { + self.to_be_bytes() == other.to_be_bytes() + } +} + +impl From for FieldElement { + fn from(mut a: i128) -> FieldElement { + let mut negative = false; + if a < 0 { + a = -a; + negative = true; + } + + let mut result = match F::from_str(&a.to_string()) { + Ok(result) => result, + Err(_) => panic!("Cannot convert i128 as a string to a field element"), + }; + + if negative { + result = -result; + } + FieldElement(result) + } +} + +impl Serialize for FieldElement { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_hex().serialize(serializer) + } +} + +impl<'de, T: ark_ff::PrimeField> Deserialize<'de> for FieldElement { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = <&str>::deserialize(deserializer)?; + match Self::from_hex(s) { + Some(value) => Ok(value), + None => Err(serde::de::Error::custom(format!("Invalid hex for FieldElement: {s}",))), + } + } +} + +impl From for FieldElement { + fn from(a: u128) -> FieldElement { + let result = match F::from_str(&a.to_string()) { + Ok(result) => result, + Err(_) => panic!("Cannot convert u128 as a string to a field element"), + }; + FieldElement(result) + } +} + +impl From for FieldElement { + fn from(boolean: bool) -> FieldElement { + if boolean { + FieldElement::one() + } else { + FieldElement::zero() + } + } +} + +impl FieldElement { + pub fn one() -> FieldElement { + FieldElement(F::one()) + } + pub fn zero() -> FieldElement { + FieldElement(F::zero()) + } + + pub fn is_zero(&self) -> bool { + self == &Self::zero() + } + pub fn is_one(&self) -> bool { + self == &Self::one() + } + + pub fn pow(&self, exponent: &Self) -> Self { + FieldElement(self.0.pow(exponent.0.into_bigint())) + } + + /// Maximum number of bits needed to represent a field element + /// This is not the amount of bits being used to represent a field element + /// Example, you only need 254 bits to represent a field element in BN256 + /// But the representation uses 256 bits, so the top two bits are always zero + /// This method would return 254 + pub const fn max_num_bits() -> u32 { + F::MODULUS_BIT_SIZE + } + + /// Maximum numbers of bytes needed to represent a field element + /// We are not guaranteed that the number of bits being used to represent a field element + /// will always be divisible by 8. If the case that it is not, we add one to the max number of bytes + /// For example, a max bit size of 254 would give a max byte size of 32. + pub const fn max_num_bytes() -> u32 { + let num_bytes = Self::max_num_bits() / 8; + if Self::max_num_bits() % 8 == 0 { + num_bytes + } else { + num_bytes + 1 + } + } + + pub fn modulus() -> BigUint { + F::MODULUS.into() + } + /// Returns None, if the string is not a canonical + /// representation of a field element; less than the order + /// or if the hex string is invalid. + /// This method can be used for both hex and decimal representations. + pub fn try_from_str(input: &str) -> Option> { + if input.contains('x') { + return FieldElement::from_hex(input); + } + + let fr = F::from_str(input).ok()?; + Some(FieldElement(fr)) + } + + /// This is the number of bits required to represent this specific field element + pub fn num_bits(&self) -> u32 { + let bits = self.bits(); + // Iterate the number of bits and pop off all leading zeroes + let iter = bits.iter().skip_while(|x| !(**x)); + // Note: count will panic if it goes over usize::MAX. + // This may not be suitable for devices whose usize < u16 + iter.count() as u32 + } + + pub fn fits_in_u128(&self) -> bool { + self.num_bits() <= 128 + } + + pub fn to_u128(self) -> u128 { + let bytes = self.to_be_bytes(); + u128::from_be_bytes(bytes[16..32].try_into().unwrap()) + } + + pub fn try_into_u128(self) -> Option { + self.fits_in_u128().then(|| self.to_u128()) + } + + pub fn try_to_u64(&self) -> Option { + (self.num_bits() <= 64).then(|| self.to_u128() as u64) + } + + /// Computes the inverse or returns zero if the inverse does not exist + /// Before using this FieldElement, please ensure that this behavior is necessary + pub fn inverse(&self) -> FieldElement { + let inv = self.0.inverse().unwrap_or_else(F::zero); + FieldElement(inv) + } + + pub fn try_inverse(mut self) -> Option { + self.0.inverse_in_place().map(|f| FieldElement(*f)) + } + + // XXX: This method is used while this field element + // implementation is not generic. + pub fn into_repr(self) -> F { + self.0 + } + + pub fn to_hex(self) -> String { + let mut bytes = Vec::new(); + self.0.serialize_uncompressed(&mut bytes).unwrap(); + bytes.reverse(); + hex::encode(bytes) + } + pub fn from_hex(hex_str: &str) -> Option> { + let value = hex_str.strip_prefix("0x").unwrap_or(hex_str); + let hex_as_bytes = hex::decode(value).ok()?; + Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes)) + } + + pub fn to_be_bytes(self) -> Vec { + // to_be_bytes! uses little endian which is why we reverse the output + // TODO: Add a little endian equivalent, so the caller can use whichever one + // TODO they desire + let mut bytes = Vec::new(); + self.0.serialize_uncompressed(&mut bytes).unwrap(); + bytes.reverse(); + bytes + } + + /// Converts bytes into a FieldElement and applies a + /// reduction if needed. + pub fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement { + FieldElement(F::from_be_bytes_mod_order(bytes)) + } + + pub fn bits(&self) -> Vec { + let bytes = self.to_be_bytes(); + let mut bits = Vec::with_capacity(bytes.len() * 8); + for byte in bytes { + let _bits = FieldElement::::byte_to_bit(byte); + bits.extend(_bits); + } + bits + } + + fn byte_to_bit(byte: u8) -> Vec { + let mut bits = Vec::with_capacity(8); + for index in (0..=7).rev() { + bits.push((byte & (1 << index)) >> index == 1) + } + bits + } + + /// Returns the closest number of bytes to the bits specified + /// This method truncates + pub fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec { + fn nearest_bytes(num_bits: usize) -> usize { + ((num_bits + 7) / 8) * 8 + } + + let num_bytes = nearest_bytes(num_bits); + let num_elements = num_bytes / 8; + + let mut bytes = self.to_be_bytes(); + bytes.reverse(); // put it in big endian format. XXX(next refactor): we should be explicit about endianness. + + bytes[0..num_elements].to_vec() + } + + // mask_to methods will not remove any bytes from the field + // they are simply zeroed out + // Whereas truncate_to will remove those bits and make the byte array smaller + fn mask_to_be_bytes(&self, num_bits: u32) -> Vec { + let mut bytes = self.to_be_bytes(); + mask_vector_le(&mut bytes, num_bits as usize); + bytes + } + + fn and_xor(&self, rhs: &FieldElement, num_bits: u32, is_xor: bool) -> FieldElement { + // XXX: Gadgets like SHA256 need to have their input be a multiple of 8 + // This is not a restriction caused by SHA256, as it works on bits + // but most backends assume bytes. + // We could implicitly pad, however this may not be intuitive for users. + // assert!( + // num_bits % 8 == 0, + // "num_bits is not a multiple of 8, it is {}", + // num_bits + // ); + + let lhs_bytes = self.mask_to_be_bytes(num_bits); + let rhs_bytes = rhs.mask_to_be_bytes(num_bits); + + let and_byte_arr: Vec<_> = lhs_bytes + .into_iter() + .zip(rhs_bytes.into_iter()) + .map(|(lhs, rhs)| if is_xor { lhs ^ rhs } else { lhs & rhs }) + .collect(); + + FieldElement::from_be_bytes_reduce(&and_byte_arr) + } + pub fn and(&self, rhs: &FieldElement, num_bits: u32) -> FieldElement { + self.and_xor(rhs, num_bits, false) + } + pub fn xor(&self, rhs: &FieldElement, num_bits: u32) -> FieldElement { + self.and_xor(rhs, num_bits, true) + } +} + +use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; + +impl Neg for FieldElement { + type Output = FieldElement; + + fn neg(self) -> Self::Output { + FieldElement(-self.0) + } +} + +impl Mul for FieldElement { + type Output = FieldElement; + fn mul(mut self, rhs: FieldElement) -> Self::Output { + self.0.mul_assign(&rhs.0); + FieldElement(self.0) + } +} +impl Div for FieldElement { + type Output = FieldElement; + #[allow(clippy::suspicious_arithmetic_impl)] + fn div(self, rhs: FieldElement) -> Self::Output { + self * rhs.inverse() + } +} +impl Add for FieldElement { + type Output = FieldElement; + fn add(mut self, rhs: FieldElement) -> Self::Output { + self.0.add_assign(&rhs.0); + FieldElement(self.0) + } +} +impl AddAssign for FieldElement { + fn add_assign(&mut self, rhs: FieldElement) { + self.0.add_assign(&rhs.0); + } +} + +impl Sub for FieldElement { + type Output = FieldElement; + fn sub(mut self, rhs: FieldElement) -> Self::Output { + self.0.sub_assign(&rhs.0); + FieldElement(self.0) + } +} +impl SubAssign for FieldElement { + fn sub_assign(&mut self, rhs: FieldElement) { + self.0.sub_assign(&rhs.0); + } +} + +#[cfg(test)] +mod tests { + #[test] + fn and() { + let max = 10_000u32; + + let num_bits = (std::mem::size_of::() * 8) as u32 - max.leading_zeros(); + + for x in 0..max { + let x = crate::generic_ark::FieldElement::::from(x as i128); + let res = x.and(&x, num_bits); + assert_eq!(res.to_be_bytes(), x.to_be_bytes()); + } + } + + #[test] + fn serialize_fixed_test_vectors() { + // Serialized field elements from of 0, -1, -2, -3 + let hex_strings = vec![ + "0000000000000000000000000000000000000000000000000000000000000000", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe", + ]; + + for (i, string) in hex_strings.into_iter().enumerate() { + let minus_i_field_element = + -crate::generic_ark::FieldElement::::from(i as i128); + assert_eq!(minus_i_field_element.to_hex(), string) + } + } + #[test] + fn max_num_bits_smoke() { + let max_num_bits_bn254 = crate::generic_ark::FieldElement::::max_num_bits(); + assert_eq!(max_num_bits_bn254, 254) + } +} + +fn mask_vector_le(bytes: &mut [u8], num_bits: usize) { + // reverse to big endian format + bytes.reverse(); + + let mask_power = num_bits % 8; + let array_mask_index = num_bits / 8; + + for (index, byte) in bytes.iter_mut().enumerate() { + match index.cmp(&array_mask_index) { + std::cmp::Ordering::Less => { + // do nothing if the current index is less than + // the array index. + } + std::cmp::Ordering::Equal => { + let mask = 2u8.pow(mask_power as u32) - 1; + // mask the byte + *byte &= mask; + } + std::cmp::Ordering::Greater => { + // Anything greater than the array index + // will be set to zero + *byte = 0; + } + } + } + // reverse back to little endian + bytes.reverse(); +} + +// For pretty printing powers +fn superscript(n: u64) -> String { + if n == 0 { + "⁰".to_owned() + } else if n == 1 { + "¹".to_owned() + } else if n == 2 { + "²".to_owned() + } else if n == 3 { + "³".to_owned() + } else if n == 4 { + "⁴".to_owned() + } else if n == 5 { + "⁵".to_owned() + } else if n == 6 { + "⁶".to_owned() + } else if n == 7 { + "⁷".to_owned() + } else if n == 8 { + "⁸".to_owned() + } else if n == 9 { + "⁹".to_owned() + } else if n >= 10 { + superscript(n / 10) + &superscript(n % 10) + } else { + panic!("{}", n.to_string() + " can't be converted to superscript."); + } +} diff --git a/acvm-repo/acir_field/src/lib.rs b/acvm-repo/acir_field/src/lib.rs new file mode 100644 index 00000000000..97cd8c66c71 --- /dev/null +++ b/acvm-repo/acir_field/src/lib.rs @@ -0,0 +1,40 @@ +#![warn(unused_crate_dependencies)] +#![warn(unreachable_pub)] + +cfg_if::cfg_if! { + if #[cfg(feature = "bn254")] { + mod generic_ark; + pub type FieldElement = generic_ark::FieldElement; + pub const CHOSEN_FIELD : FieldOptions = FieldOptions::BN254; + + } else if #[cfg(feature = "bls12_381")] { + mod generic_ark; + pub type FieldElement = generic_ark::FieldElement; + pub const CHOSEN_FIELD : FieldOptions = FieldOptions::BLS12_381; + } else { + compile_error!("please specify a field to compile with"); + } +} + +#[derive(Debug)] +pub enum FieldOptions { + BN254, + BLS12_381, +} + +// This is needed because features are additive through the dependency graph; if a dependency turns on the bn254, then it +// will be turned on in all crates that depend on it +#[macro_export] +macro_rules! assert_unique_feature { + () => {}; + ($first:tt $(,$rest:tt)*) => { + $( + #[cfg(all(feature = $first, feature = $rest))] + compile_error!(concat!("features \"", $first, "\" and \"", $rest, "\" cannot be used together")); + )* + assert_unique_feature!($($rest),*); + } +} +// https://internals.rust-lang.org/t/mutually-exclusive-feature-flags/8601/7 +// If another field/feature is added, we add it here too +assert_unique_feature!("bn254", "bls12_381"); diff --git a/acvm-repo/acvm/CHANGELOG.md b/acvm-repo/acvm/CHANGELOG.md new file mode 100644 index 00000000000..29a4aa93adc --- /dev/null +++ b/acvm-repo/acvm/CHANGELOG.md @@ -0,0 +1,662 @@ +# Changelog + +## [0.27.0](https://github.com/noir-lang/acvm/compare/acvm-v0.26.1...acvm-v0.27.0) (2023-09-19) + + +### ⚠ BREAKING CHANGES + +* Separate barretenberg solver from generic blackbox solver code ([#554](https://github.com/noir-lang/acvm/issues/554)) + +### Miscellaneous Chores + +* Separate barretenberg solver from generic blackbox solver code ([#554](https://github.com/noir-lang/acvm/issues/554)) ([a4b9772](https://github.com/noir-lang/acvm/commit/a4b97722a0892fe379ff075e6080675adafdce0e)) + +## [0.26.1](https://github.com/noir-lang/acvm/compare/acvm-v0.26.0...acvm-v0.26.1) (2023-09-12) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.26.0 to 0.26.1 + +## [0.26.0](https://github.com/noir-lang/acvm/compare/acvm-v0.25.0...acvm-v0.26.0) (2023-09-07) + + +### ⚠ BREAKING CHANGES + +* Add a low and high limb to scalar mul opcode ([#532](https://github.com/noir-lang/acvm/issues/532)) + +### Miscellaneous Chores + +* Add a low and high limb to scalar mul opcode ([#532](https://github.com/noir-lang/acvm/issues/532)) ([b054f66](https://github.com/noir-lang/acvm/commit/b054f66be9c73d4e02dbecdab80874a907f19242)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.25.0 to 0.26.0 + +## [0.25.0](https://github.com/noir-lang/acvm/compare/acvm-v0.24.1...acvm-v0.25.0) (2023-09-04) + + +### ⚠ BREAKING CHANGES + +* Provide runtime callstacks for brillig failures and return errors in acvm_js ([#523](https://github.com/noir-lang/acvm/issues/523)) + +### Features + +* Provide runtime callstacks for brillig failures and return errors in acvm_js ([#523](https://github.com/noir-lang/acvm/issues/523)) ([7ab7cff](https://github.com/noir-lang/acvm/commit/7ab7cff48a9aba61a97fad2a759fc8e55740b098)) + + +### Bug Fixes + +* initialize recursive proof output to zero ([#524](https://github.com/noir-lang/acvm/issues/524)) ([5453074](https://github.com/noir-lang/acvm/commit/545307457dd7634b20ea3977e2d2cc751eba06d2)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.24.1 to 0.25.0 + +## [0.24.1](https://github.com/noir-lang/acvm/compare/acvm-v0.24.0...acvm-v0.24.1) (2023-09-03) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.24.0 to 0.24.1 + +## [0.24.0](https://github.com/noir-lang/acvm/compare/acvm-v0.23.0...acvm-v0.24.0) (2023-08-31) + + +### ⚠ BREAKING CHANGES + +* **acvm:** Remove the `Backend` trait ([#514](https://github.com/noir-lang/acvm/issues/514)) +* **acir:** Remove unused `Directive` opcodes ([#510](https://github.com/noir-lang/acvm/issues/510)) +* **acir:** Add predicate to MemoryOp ([#503](https://github.com/noir-lang/acvm/issues/503)) +* **acvm:** Remove unused arguments from `Backend` trait ([#511](https://github.com/noir-lang/acvm/issues/511)) +* Assertion messages embedded in the circuit ([#484](https://github.com/noir-lang/acvm/issues/484)) + +### Features + +* **acir:** Add predicate to MemoryOp ([#503](https://github.com/noir-lang/acvm/issues/503)) ([ca9eebe](https://github.com/noir-lang/acvm/commit/ca9eebe34e61adabf97318c8ccaf60c8a424aafd)) +* Assertion messages embedded in the circuit ([#484](https://github.com/noir-lang/acvm/issues/484)) ([06b97c5](https://github.com/noir-lang/acvm/commit/06b97c51041e16651cf8b2be8bc18214e276c6c9)) + + +### Miscellaneous Chores + +* **acir:** Remove unused `Directive` opcodes ([#510](https://github.com/noir-lang/acvm/issues/510)) ([cfd8cbf](https://github.com/noir-lang/acvm/commit/cfd8cbf58307511ac0cc9106c299695c2ca779de)) +* **acvm:** Remove the `Backend` trait ([#514](https://github.com/noir-lang/acvm/issues/514)) ([681535d](https://github.com/noir-lang/acvm/commit/681535da52815a4a164ee4f48f7b48329664af98)) +* **acvm:** Remove unused arguments from `Backend` trait ([#511](https://github.com/noir-lang/acvm/issues/511)) ([ae65355](https://github.com/noir-lang/acvm/commit/ae65355afb7df98c71f81d5a54e89f39f9333920)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.23.0 to 0.24.0 + +## [0.23.0](https://github.com/noir-lang/acvm/compare/acvm-v0.22.0...acvm-v0.23.0) (2023-08-30) + + +### ⚠ BREAKING CHANGES + +* Return an iterator from `new_locations()` instead of collecting ([#507](https://github.com/noir-lang/acvm/issues/507)) +* **acvm:** remove `CommonReferenceString` trait and preprocess method ([#508](https://github.com/noir-lang/acvm/issues/508)) +* **acvm:** Pass `BlackBoxFunctionSolver` to `ACVM` by reference + +### Features + +* **acvm_js:** Add `execute_circuit_with_black_box_solver` to prevent reinitialization of `BlackBoxFunctionSolver` ([3877e0e](https://github.com/noir-lang/acvm/commit/3877e0e438a8d0e5545a4da7210767dec05c342f)) + + +### Miscellaneous Chores + +* **acvm:** Pass `BlackBoxFunctionSolver` to `ACVM` by reference ([3877e0e](https://github.com/noir-lang/acvm/commit/3877e0e438a8d0e5545a4da7210767dec05c342f)) +* **acvm:** remove `CommonReferenceString` trait and preprocess method ([#508](https://github.com/noir-lang/acvm/issues/508)) ([3827dd3](https://github.com/noir-lang/acvm/commit/3827dd3ce487650843ba4df8337b423e39f97edf)) +* Return an iterator from `new_locations()` instead of collecting ([#507](https://github.com/noir-lang/acvm/issues/507)) ([8d49a5c](https://github.com/noir-lang/acvm/commit/8d49a5c15b1e962cd59252467a20a922edadc2f2)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.22.0 to 0.23.0 + +## [0.22.0](https://github.com/noir-lang/acvm/compare/acvm-v0.21.0...acvm-v0.22.0) (2023-08-18) + + +### ⚠ BREAKING CHANGES + +* Switched from OpcodeLabel to OpcodeLocation and ErrorLocation ([#493](https://github.com/noir-lang/acvm/issues/493)) +* **acvm:** check for index out-of-bounds on memory operations ([#468](https://github.com/noir-lang/acvm/issues/468)) + +### Features + +* **acvm:** check for index out-of-bounds on memory operations ([#468](https://github.com/noir-lang/acvm/issues/468)) ([740468c](https://github.com/noir-lang/acvm/commit/740468c0a144f7179c38f615cfda31b2fcc77359)) +* print error location with fmt ([#497](https://github.com/noir-lang/acvm/issues/497)) ([575a9e5](https://github.com/noir-lang/acvm/commit/575a9e50e97afb04a7b91799e06752cec3093f0b)) +* Switched from OpcodeLabel to OpcodeLocation and ErrorLocation ([#493](https://github.com/noir-lang/acvm/issues/493)) ([27a5a93](https://github.com/noir-lang/acvm/commit/27a5a935849f8904e10056b08089f532a06962b8)) + + +### Bug Fixes + +* add opcode label to unsatisfied constrain string ([#482](https://github.com/noir-lang/acvm/issues/482)) ([cbbbe67](https://github.com/noir-lang/acvm/commit/cbbbe67b9a19a4a560b2dfa8f27ea1c6ebd61f28)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.21.0 to 0.22.0 + +## [0.21.0](https://github.com/noir-lang/acvm/compare/acvm-v0.20.1...acvm-v0.21.0) (2023-07-26) + + +### ⚠ BREAKING CHANGES + +* **acir:** Remove `Block`, `RAM` and `ROM` opcodes ([#457](https://github.com/noir-lang/acvm/issues/457)) +* **acvm:** Remove `OpcodeResolution` enum ([#400](https://github.com/noir-lang/acvm/issues/400)) +* **acvm:** Support stepwise execution of ACIR ([#399](https://github.com/noir-lang/acvm/issues/399)) + +### Features + +* **acvm:** Remove `OpcodeResolution` enum ([#400](https://github.com/noir-lang/acvm/issues/400)) ([d0ce48c](https://github.com/noir-lang/acvm/commit/d0ce48c506619a5560412ef6693bfa11036b501e)) +* **acvm:** Support stepwise execution of ACIR ([#399](https://github.com/noir-lang/acvm/issues/399)) ([6a03950](https://github.com/noir-lang/acvm/commit/6a0395021779a2711353c2fe2948e09b5b538fc0)) + + +### Miscellaneous Chores + +* **acir:** Remove `Block`, `RAM` and `ROM` opcodes ([#457](https://github.com/noir-lang/acvm/issues/457)) ([8dd220a](https://github.com/noir-lang/acvm/commit/8dd220ae127baf6cc5a31d8ab7ffdeeb161f6109)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.20.1 to 0.21.0 + +## [0.20.1](https://github.com/noir-lang/acvm/compare/acvm-v0.20.0...acvm-v0.20.1) (2023-07-26) + + +### Features + +* **stdlib:** Add fallback implementation of `Keccak256` black box function ([#445](https://github.com/noir-lang/acvm/issues/445)) ([f7ebb03](https://github.com/noir-lang/acvm/commit/f7ebb03653c971f119700ff8126d9eb5ff01be0f)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.20.0 to 0.20.1 + +## [0.20.0](https://github.com/noir-lang/acvm/compare/acvm-v0.19.1...acvm-v0.20.0) (2023-07-20) + + +### ⚠ BREAKING CHANGES + +* atomic memory opcodes ([#447](https://github.com/noir-lang/acvm/issues/447)) + +### Features + +* atomic memory opcodes ([#447](https://github.com/noir-lang/acvm/issues/447)) ([3261c7a](https://github.com/noir-lang/acvm/commit/3261c7a2fd4f3a300bc5f39ef4febccd8a853560)) +* **stdlib:** Add fallback implementation of `HashToField128Security` black box function ([#435](https://github.com/noir-lang/acvm/issues/435)) ([ed40f22](https://github.com/noir-lang/acvm/commit/ed40f228529e888d1960bfa70cb92b277e24b37f)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.19.1 to 0.20.0 + +## [0.19.1](https://github.com/noir-lang/acvm/compare/acvm-v0.19.0...acvm-v0.19.1) (2023-07-17) + + +### Bug Fixes + +* Remove panic when we divide 0/0 in quotient directive ([#437](https://github.com/noir-lang/acvm/issues/437)) ([9c8ff64](https://github.com/noir-lang/acvm/commit/9c8ff64ebf27a86787ae184e10ed9581041ec0ff)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.19.0 to 0.19.1 + +## [0.19.0](https://github.com/noir-lang/acvm/compare/acvm-v0.18.2...acvm-v0.19.0) (2023-07-15) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.18.2 to 0.19.0 + +## [0.18.2](https://github.com/noir-lang/acvm/compare/acvm-v0.18.1...acvm-v0.18.2) (2023-07-12) + + +### Features + +* **acvm:** reexport `blackbox_solver` crate from `acvm` ([#431](https://github.com/noir-lang/acvm/issues/431)) ([517e942](https://github.com/noir-lang/acvm/commit/517e942b732d7107f6e064c6791917d1508229b3)) +* **stdlib:** Add fallback implementation of `Blake2s` black box function ([#424](https://github.com/noir-lang/acvm/issues/424)) ([982d940](https://github.com/noir-lang/acvm/commit/982d94087d46092ce7a5e94dbd7e732195f58e42)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.18.1 to 0.18.2 + +## [0.18.1](https://github.com/noir-lang/acvm/compare/acvm-v0.18.0...acvm-v0.18.1) (2023-07-12) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.18.0 to 0.18.1 + +## [0.18.0](https://github.com/noir-lang/acvm/compare/acvm-v0.17.0...acvm-v0.18.0) (2023-07-12) + + +### ⚠ BREAKING CHANGES + +* add backend-solvable blackboxes to brillig & unify implementations ([#422](https://github.com/noir-lang/acvm/issues/422)) +* **acvm:** Remove `CircuitSimplifer` ([#421](https://github.com/noir-lang/acvm/issues/421)) +* **acvm:** Add `circuit: &Circuit` to `eth_contract_from_vk` function signature ([#420](https://github.com/noir-lang/acvm/issues/420)) +* Returns index of failing opcode and transformation mapping ([#412](https://github.com/noir-lang/acvm/issues/412)) + +### Features + +* **acvm:** Add `circuit: &Circuit` to `eth_contract_from_vk` function signature ([#420](https://github.com/noir-lang/acvm/issues/420)) ([744e9da](https://github.com/noir-lang/acvm/commit/744e9da71f7ca477a5390a63f47211dd4dffb8b3)) +* add backend-solvable blackboxes to brillig & unify implementations ([#422](https://github.com/noir-lang/acvm/issues/422)) ([093342e](https://github.com/noir-lang/acvm/commit/093342ea9481a311fa71343b8b7a22774788838a)) +* Returns index of failing opcode and transformation mapping ([#412](https://github.com/noir-lang/acvm/issues/412)) ([79950e9](https://github.com/noir-lang/acvm/commit/79950e943f60e4082e1cf5ec4442aa67ea91aade)) +* **stdlib:** Add fallback implementation of `SHA256` black box function ([#407](https://github.com/noir-lang/acvm/issues/407)) ([040369a](https://github.com/noir-lang/acvm/commit/040369adc8749fa5ec2edd255ff54c105c3140f5)) + + +### Miscellaneous Chores + +* **acvm:** Remove `CircuitSimplifer` ([#421](https://github.com/noir-lang/acvm/issues/421)) ([e07a56d](https://github.com/noir-lang/acvm/commit/e07a56d9c542a7f03ce156761054cd403de0bd23)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * brillig_vm bumped from 0.17.0 to 0.18.0 + +## [0.17.0](https://github.com/noir-lang/acvm/compare/acvm-v0.16.0...acvm-v0.17.0) (2023-07-07) + + +### ⚠ BREAKING CHANGES + +* **acir:** add `EcdsaSecp256r1` blackbox function ([#408](https://github.com/noir-lang/acvm/issues/408)) + +### Features + +* **acir:** add `EcdsaSecp256r1` blackbox function ([#408](https://github.com/noir-lang/acvm/issues/408)) ([9895817](https://github.com/noir-lang/acvm/commit/98958170c9fa9b4731e33b31cb494a72bb90549e)) + +## [0.16.0](https://github.com/noir-lang/acvm/compare/acvm-v0.15.1...acvm-v0.16.0) (2023-07-06) + + +### ⚠ BREAKING CHANGES + +* **acvm:** replace `PartialWitnessGeneratorStatus` with `ACVMStatus` ([#410](https://github.com/noir-lang/acvm/issues/410)) +* **acir:** revert changes to `SchnorrVerify` opcode ([#409](https://github.com/noir-lang/acvm/issues/409)) +* **acvm:** Replace `PartialWitnessGenerator` trait with `BlackBoxFunctionSolver` ([#378](https://github.com/noir-lang/acvm/issues/378)) +* **acvm:** Encapsulate internal state of ACVM within a struct ([#384](https://github.com/noir-lang/acvm/issues/384)) +* remove unused `OpcodeResolutionError::IncorrectNumFunctionArguments` variant ([#397](https://github.com/noir-lang/acvm/issues/397)) +* **acir:** Remove `Oracle` opcode ([#368](https://github.com/noir-lang/acvm/issues/368)) +* **acir:** Use fixed length data structures in black box function inputs/outputs where possible. ([#386](https://github.com/noir-lang/acvm/issues/386)) + +### Features + +* **acir:** Remove `Oracle` opcode ([#368](https://github.com/noir-lang/acvm/issues/368)) ([63354df](https://github.com/noir-lang/acvm/commit/63354df1fe47a4f1128b91641d1b66dfc1281794)) +* **acir:** Use fixed length data structures in black box function inputs/outputs where possible. ([#386](https://github.com/noir-lang/acvm/issues/386)) ([b139d4d](https://github.com/noir-lang/acvm/commit/b139d4d566c715009465a430aab0fb819aacab4f)) +* **acvm:** Derive `Copy` for `Language` ([#406](https://github.com/noir-lang/acvm/issues/406)) ([69a6c22](https://github.com/noir-lang/acvm/commit/69a6c224d80be556ac5388ffeb7a02424df22031)) +* **acvm:** Encapsulate internal state of ACVM within a struct ([#384](https://github.com/noir-lang/acvm/issues/384)) ([84d4867](https://github.com/noir-lang/acvm/commit/84d4867b2d97097d451d59174781555dafd2591f)) +* **acvm:** Replace `PartialWitnessGenerator` trait with `BlackBoxFunctionSolver` ([#378](https://github.com/noir-lang/acvm/issues/378)) ([73fbc95](https://github.com/noir-lang/acvm/commit/73fbc95942b0039565c93719809975f66dc9ec53)) +* **acvm:** replace `PartialWitnessGeneratorStatus` with `ACVMStatus` ([#410](https://github.com/noir-lang/acvm/issues/410)) ([fc3240d](https://github.com/noir-lang/acvm/commit/fc3240d456d0128f6eb42096beb8b7a586ea48da)) +* **brillig:** implemented first blackbox functions ([#401](https://github.com/noir-lang/acvm/issues/401)) ([62d40f7](https://github.com/noir-lang/acvm/commit/62d40f7c03cd1102f615b8d565f82496962db637)) + + +### Bug Fixes + +* **acir:** revert changes to `SchnorrVerify` opcode ([#409](https://github.com/noir-lang/acvm/issues/409)) ([f1c7940](https://github.com/noir-lang/acvm/commit/f1c7940f4ac618c7b440b6ed30199f85cbe72cca)) + + +### Miscellaneous Chores + +* remove unused `OpcodeResolutionError::IncorrectNumFunctionArguments` variant ([#397](https://github.com/noir-lang/acvm/issues/397)) ([d1368d0](https://github.com/noir-lang/acvm/commit/d1368d041eb42d265a4ef385e066b82bc36d0743)) + +## [0.15.1](https://github.com/noir-lang/acvm/compare/acvm-v0.15.0...acvm-v0.15.1) (2023-06-20) + + +### Features + +* **brillig:** Allow dynamic-size foreign calls ([#370](https://github.com/noir-lang/acvm/issues/370)) ([5ba0349](https://github.com/noir-lang/acvm/commit/5ba0349420cc1b20113cb5e96490a0808a769757)) + +## [0.15.0](https://github.com/noir-lang/acvm/compare/acvm-v0.14.2...acvm-v0.15.0) (2023-06-15) + + +### ⚠ BREAKING CHANGES + +* **brillig:** Accept multiple inputs/outputs for foreign calls ([#367](https://github.com/noir-lang/acvm/issues/367)) +* **acvm:** Make internals of ACVM private ([#353](https://github.com/noir-lang/acvm/issues/353)) + +### Features + +* Add method to generate updated `Brillig` opcode from `UnresolvedBrilligCall` ([#363](https://github.com/noir-lang/acvm/issues/363)) ([fda5dbe](https://github.com/noir-lang/acvm/commit/fda5dbe57c28dc4bc28dfd8fe0a4a8ba29635393)) +* **brillig:** Accept multiple inputs/outputs for foreign calls ([#367](https://github.com/noir-lang/acvm/issues/367)) ([78d62b2](https://github.com/noir-lang/acvm/commit/78d62b2d7c1c8b884e1f3fe7983e6e5029700e70)) + + +### Miscellaneous Chores + +* **acvm:** Make internals of ACVM private ([#353](https://github.com/noir-lang/acvm/issues/353)) ([c902a01](https://github.com/noir-lang/acvm/commit/c902a01639033665d106e2d9f4e5c7070af8c0bb)) + +## [0.14.2](https://github.com/noir-lang/acvm/compare/acvm-v0.14.1...acvm-v0.14.2) (2023-06-08) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + +## [0.14.1](https://github.com/noir-lang/acvm/compare/acvm-v0.14.0...acvm-v0.14.1) (2023-06-07) + + +### Features + +* Re-use intermediate variables created during width reduction, with proper scale. ([#343](https://github.com/noir-lang/acvm/issues/343)) ([6bd0baa](https://github.com/noir-lang/acvm/commit/6bd0baa4bc9ac204e7710ec6d17d1752d2e924c0)) + +## [0.14.0](https://github.com/noir-lang/acvm/compare/acvm-v0.13.3...acvm-v0.14.0) (2023-06-06) + + +### ⚠ BREAKING CHANGES + +* **acir:** Verify Proof ([#291](https://github.com/noir-lang/acvm/issues/291)) + +### Features + +* **acir:** Verify Proof ([#291](https://github.com/noir-lang/acvm/issues/291)) ([9f34428](https://github.com/noir-lang/acvm/commit/9f34428b7084c7c38de401a16ca76e748d8b1d77)) + +## [0.13.3](https://github.com/noir-lang/acvm/compare/acvm-v0.13.2...acvm-v0.13.3) (2023-06-05) + + +### Bug Fixes + +* Empty commit to trigger release-please ([e8f0748](https://github.com/noir-lang/acvm/commit/e8f0748042ef505d59ab63266d3c36c5358ee30d)) + +## [0.13.2](https://github.com/noir-lang/acvm/compare/acvm-v0.13.1...acvm-v0.13.2) (2023-06-02) + + +### Bug Fixes + +* re-use intermediate vars during width reduction ([#278](https://github.com/noir-lang/acvm/issues/278)) ([5b32920](https://github.com/noir-lang/acvm/commit/5b32920263c4481c60faf0b84f0031aa8149b6b2)) + +## [0.13.1](https://github.com/noir-lang/acvm/compare/acvm-v0.13.0...acvm-v0.13.1) (2023-06-01) + + +### Bug Fixes + +* **brillig:** Proper error handling for Brillig failures ([#329](https://github.com/noir-lang/acvm/issues/329)) ([cffa110](https://github.com/noir-lang/acvm/commit/cffa110c8df30ee3dd8b635d38b17b1fcd54b03e)) +* **ci:** Correct typo to avoid `undefined` in changelogs ([#333](https://github.com/noir-lang/acvm/issues/333)) ([d3424c0](https://github.com/noir-lang/acvm/commit/d3424c04fd303c9cbe25d03118d8b358cbb84b83)) + +## [0.13.0](https://github.com/noir-lang/acvm/compare/acvm-v0.12.0...acvm-v0.13.0) (2023-06-01) + + +### ⚠ BREAKING CHANGES + +* added hash index to pedersen ([#281](https://github.com/noir-lang/acvm/issues/281)) +* Add variable length keccak opcode ([#314](https://github.com/noir-lang/acvm/issues/314)) +* Remove AES opcode ([#302](https://github.com/noir-lang/acvm/issues/302)) +* **acir, acvm:** Remove ComputeMerkleRoot opcode #296 +* Remove backend solvable methods from the interface and solve them in ACVM ([#264](https://github.com/noir-lang/acvm/issues/264)) +* Reorganize code related to `PartialWitnessGenerator` ([#287](https://github.com/noir-lang/acvm/issues/287)) + +### Features + +* **acir, acvm:** Remove ComputeMerkleRoot opcode [#296](https://github.com/noir-lang/acvm/issues/296) ([8b3923e](https://github.com/noir-lang/acvm/commit/8b3923e191e4ac399400025496e8bb4453734040)) +* Add `Brillig` opcode to introduce custom non-determinism to ACVM ([#152](https://github.com/noir-lang/acvm/issues/152)) ([3c6740a](https://github.com/noir-lang/acvm/commit/3c6740af75125afc8ebb4379f781f8274015e2e2)) +* Add variable length keccak opcode ([#314](https://github.com/noir-lang/acvm/issues/314)) ([7bfd169](https://github.com/noir-lang/acvm/commit/7bfd1695b6f119cd70fce4866314c9bb4991eaab)) +* added hash index to pedersen ([#281](https://github.com/noir-lang/acvm/issues/281)) ([61820b6](https://github.com/noir-lang/acvm/commit/61820b651900aac8d9557b4b9477ed0e1763c124)) +* Remove backend solvable methods from the interface and solve them in ACVM ([#264](https://github.com/noir-lang/acvm/issues/264)) ([69916cb](https://github.com/noir-lang/acvm/commit/69916cbdd928875b2e8fe4775f2251f71c3f3c92)) + + +### Bug Fixes + +* Allow async functions without send on async trait ([#292](https://github.com/noir-lang/acvm/issues/292)) ([9f9fc21](https://github.com/noir-lang/acvm/commit/9f9fc216a6d09ca97352ffd365bfd347e94ad8eb)) + + +### Miscellaneous Chores + +* Remove AES opcode ([#302](https://github.com/noir-lang/acvm/issues/302)) ([a429a54](https://github.com/noir-lang/acvm/commit/a429a5422d6f001b6db0d0a0f30c79ec0f96de89)) +* Reorganize code related to `PartialWitnessGenerator` ([#287](https://github.com/noir-lang/acvm/issues/287)) ([b9d61a1](https://github.com/noir-lang/acvm/commit/b9d61a16210d70e350a7e953951362c94f497f89)) + +## [0.12.0](https://github.com/noir-lang/acvm/compare/acvm-v0.11.0...acvm-v0.12.0) (2023-05-17) + + +### ⚠ BREAKING CHANGES + +* remove deprecated circuit hash functions ([#288](https://github.com/noir-lang/acvm/issues/288)) +* allow backends to specify support for all opcode variants ([#273](https://github.com/noir-lang/acvm/issues/273)) +* **acvm:** Add CommonReferenceString backend trait ([#231](https://github.com/noir-lang/acvm/issues/231)) +* Introduce WitnessMap data structure to avoid leaking internal structure ([#252](https://github.com/noir-lang/acvm/issues/252)) +* use struct variants for blackbox function calls ([#269](https://github.com/noir-lang/acvm/issues/269)) +* **acvm:** Backend trait must implement Debug ([#275](https://github.com/noir-lang/acvm/issues/275)) +* remove `OpcodeResolutionError::UnexpectedOpcode` ([#274](https://github.com/noir-lang/acvm/issues/274)) +* **acvm:** rename `hash_to_field128_security` to `hash_to_field_128_security` ([#271](https://github.com/noir-lang/acvm/issues/271)) +* **acvm:** update black box solver interfaces to match `pwg:black_box::solve` ([#268](https://github.com/noir-lang/acvm/issues/268)) +* **acvm:** expose separate solvers for AND and XOR opcodes ([#266](https://github.com/noir-lang/acvm/issues/266)) +* **acvm:** Simplification pass for ACIR ([#151](https://github.com/noir-lang/acvm/issues/151)) +* Remove `solve` from PWG trait & introduce separate solvers for each blackbox ([#257](https://github.com/noir-lang/acvm/issues/257)) + +### Features + +* **acvm:** Add CommonReferenceString backend trait ([#231](https://github.com/noir-lang/acvm/issues/231)) ([eeddcf1](https://github.com/noir-lang/acvm/commit/eeddcf179880f246383f7f67a11e589269c4e3ff)) +* **acvm:** Simplification pass for ACIR ([#151](https://github.com/noir-lang/acvm/issues/151)) ([7bc42c6](https://github.com/noir-lang/acvm/commit/7bc42c62b6e095f838b781c87cbb1ecd2af5f179)) +* **acvm:** update black box solver interfaces to match `pwg:black_box::solve` ([#268](https://github.com/noir-lang/acvm/issues/268)) ([0098b7d](https://github.com/noir-lang/acvm/commit/0098b7d9640076d970e6c15d5fd6f368eb1513ff)) +* Introduce WitnessMap data structure to avoid leaking internal structure ([#252](https://github.com/noir-lang/acvm/issues/252)) ([b248e60](https://github.com/noir-lang/acvm/commit/b248e606dd69c25d33ae77c5c5c0541adbf80cd6)) +* Remove `solve` from PWG trait & introduce separate solvers for each blackbox ([#257](https://github.com/noir-lang/acvm/issues/257)) ([3f3dd74](https://github.com/noir-lang/acvm/commit/3f3dd7460b27ab06b55dfc3fe5dd733f08e30a9f)) +* use struct variants for blackbox function calls ([#269](https://github.com/noir-lang/acvm/issues/269)) ([a83333b](https://github.com/noir-lang/acvm/commit/a83333b9e270dfcfd40a36271896840ec0201bc4)) + + +### Miscellaneous Chores + +* **acvm:** Backend trait must implement Debug ([#275](https://github.com/noir-lang/acvm/issues/275)) ([3288b4c](https://github.com/noir-lang/acvm/commit/3288b4c7eb01f5621e577d5ff9e7c92c7757e021)) +* **acvm:** expose separate solvers for AND and XOR opcodes ([#266](https://github.com/noir-lang/acvm/issues/266)) ([84b5d18](https://github.com/noir-lang/acvm/commit/84b5d18d29a111a42bfc1c3d122129c8f062c3db)) +* **acvm:** rename `hash_to_field128_security` to `hash_to_field_128_security` ([#271](https://github.com/noir-lang/acvm/issues/271)) ([fad9af2](https://github.com/noir-lang/acvm/commit/fad9af27fb102fa34bf7511f8ed7b16b3ec2d115)) +* allow backends to specify support for all opcode variants ([#273](https://github.com/noir-lang/acvm/issues/273)) ([efd37fe](https://github.com/noir-lang/acvm/commit/efd37fedcbbabb3fac810e662731439e07fef49a)) +* remove `OpcodeResolutionError::UnexpectedOpcode` ([#274](https://github.com/noir-lang/acvm/issues/274)) ([0e71aac](https://github.com/noir-lang/acvm/commit/0e71aac7aa85b3e9142972a26ba122c2c7c51d9b)) +* remove deprecated circuit hash functions ([#288](https://github.com/noir-lang/acvm/issues/288)) ([1a22c75](https://github.com/noir-lang/acvm/commit/1a22c752de3354a2a6d34892331ab6623b24c0b0)) + +## [0.11.0](https://github.com/noir-lang/acvm/compare/acvm-v0.10.3...acvm-v0.11.0) (2023-05-04) + + +### ⚠ BREAKING CHANGES + +* **acvm:** Introduce Error type for fallible Backend traits ([#248](https://github.com/noir-lang/acvm/issues/248)) + +### Features + +* **acvm:** Add generic error for failing to solve an opcode ([#251](https://github.com/noir-lang/acvm/issues/251)) ([bc89528](https://github.com/noir-lang/acvm/commit/bc8952820de610e585d505decfac6e590bbb1a35)) +* **acvm:** Introduce Error type for fallible Backend traits ([#248](https://github.com/noir-lang/acvm/issues/248)) ([45c45f7](https://github.com/noir-lang/acvm/commit/45c45f7cdb79c3ccb0373ca0e698b282d4dabc39)) +* Add Keccak Hash function ([#259](https://github.com/noir-lang/acvm/issues/259)) ([443c734](https://github.com/noir-lang/acvm/commit/443c73482eeef6cc42a1a254bf0d7706698ee353)) + +## [0.10.3](https://github.com/noir-lang/acvm/compare/acvm-v0.10.2...acvm-v0.10.3) (2023-04-28) + + +### Bug Fixes + +* add default feature flag to ACVM crate ([#245](https://github.com/noir-lang/acvm/issues/245)) ([455fddb](https://github.com/noir-lang/acvm/commit/455fddbc19af81cb01d54e29cad199691e1a1d98)) + +## [0.10.2](https://github.com/noir-lang/acvm/compare/acvm-v0.10.1...acvm-v0.10.2) (2023-04-28) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + +## [0.10.1](https://github.com/noir-lang/acvm/compare/acvm-v0.10.0...acvm-v0.10.1) (2023-04-28) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + +## [0.10.0](https://github.com/noir-lang/acvm/compare/acvm-v0.9.0...acvm-v0.10.0) (2023-04-26) + + +### ⚠ BREAKING CHANGES + +* return `Result` from `solve_range_opcode` ([#238](https://github.com/noir-lang/acvm/issues/238)) +* **acvm:** have all black box functions return `Result` ([#237](https://github.com/noir-lang/acvm/issues/237)) +* **acvm:** implement `hash_to_field_128_security` ([#230](https://github.com/noir-lang/acvm/issues/230)) +* require `Backend` to implement `Default` trait ([#223](https://github.com/noir-lang/acvm/issues/223)) +* Make GeneralOptimizer crate visible ([#220](https://github.com/noir-lang/acvm/issues/220)) +* return `PartialWitnessGeneratorStatus` from `PartialWitnessGenerator.solve` ([#213](https://github.com/noir-lang/acvm/issues/213)) +* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) + +### Features + +* **acvm:** have all black box functions return `Result<OpcodeResolution, OpcodeResolutionError>` ([#237](https://github.com/noir-lang/acvm/issues/237)) ([e8e93fd](https://github.com/noir-lang/acvm/commit/e8e93fda0db18f0d266dd1aacbb53ec787992dc9)) +* **acvm:** implement `hash_to_field_128_security` ([#230](https://github.com/noir-lang/acvm/issues/230)) ([198fb69](https://github.com/noir-lang/acvm/commit/198fb69e90a5ed3c0a8716d888b4dc6c2f9b18aa)) +* Add range opcode optimization ([#219](https://github.com/noir-lang/acvm/issues/219)) ([7abe6e5](https://github.com/noir-lang/acvm/commit/7abe6e5f6d6fea379c3748a910afd00db066eb45)) +* require `Backend` to implement `Default` trait ([#223](https://github.com/noir-lang/acvm/issues/223)) ([00282dc](https://github.com/noir-lang/acvm/commit/00282dc5e2b03947bf709a088d829f3e0ba80eed)) +* return `PartialWitnessGeneratorStatus` from `PartialWitnessGenerator.solve` ([#213](https://github.com/noir-lang/acvm/issues/213)) ([e877bed](https://github.com/noir-lang/acvm/commit/e877bed2cca76bd486e9bed66b4230e65a01f0a2)) +* return `Result<OpcodeResolution, OpcodeResolutionError>` from `solve_range_opcode` ([#238](https://github.com/noir-lang/acvm/issues/238)) ([15d3c5a](https://github.com/noir-lang/acvm/commit/15d3c5a9be2dd92f266fcb7e672da17cada9fec5)) + + +### Bug Fixes + +* prevent `bn254` feature flag always being enabled ([#225](https://github.com/noir-lang/acvm/issues/225)) ([82eee6a](https://github.com/noir-lang/acvm/commit/82eee6ab08ae480f04904ca8571fd88f4466c000)) + + +### Miscellaneous Chores + +* Make GeneralOptimizer crate visible ([#220](https://github.com/noir-lang/acvm/issues/220)) ([64bb346](https://github.com/noir-lang/acvm/commit/64bb346524428a0ce196826ea1e5ccde08ad6201)) +* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) ([a619df6](https://github.com/noir-lang/acvm/commit/a619df614bbb9b2518b788b42a7553b069823a0f)) + +## [0.9.0](https://github.com/noir-lang/acvm/compare/acvm-v0.8.1...acvm-v0.9.0) (2023-04-07) + + +### ⚠ BREAKING CHANGES + +* **acvm:** Remove deprecated eth_contract_from_cs from SmartContract trait ([#185](https://github.com/noir-lang/acvm/issues/185)) +* **acvm:** make `Backend` trait object safe ([#180](https://github.com/noir-lang/acvm/issues/180)) + +### Features + +* **acvm:** make `Backend` trait object safe ([#180](https://github.com/noir-lang/acvm/issues/180)) ([fd28657](https://github.com/noir-lang/acvm/commit/fd28657426260ce3c53517b75a27eb5c4a74e234)) + + +### Miscellaneous Chores + +* **acvm:** Remove deprecated eth_contract_from_cs from SmartContract trait ([#185](https://github.com/noir-lang/acvm/issues/185)) ([ee59c9e](https://github.com/noir-lang/acvm/commit/ee59c9efe9a54ff6b97e4daaebf64f3e327e97d9)) + +## [0.8.1](https://github.com/noir-lang/acvm/compare/acvm-v0.8.0...acvm-v0.8.1) (2023-03-30) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + +## [0.8.0](https://github.com/noir-lang/acvm/compare/acvm-v0.7.1...acvm-v0.8.0) (2023-03-28) + + +### Miscellaneous Chores + +* **acvm:** Synchronize acvm versions + +## [0.7.1](https://github.com/noir-lang/acvm/compare/acvm-v0.7.0...acvm-v0.7.1) (2023-03-27) + + +### Bug Fixes + +* **pwg:** stall instead of fail for unassigned black box ([#154](https://github.com/noir-lang/acvm/issues/154)) ([412a1a6](https://github.com/noir-lang/acvm/commit/412a1a60b434bef53e12d37c3b2bb3d51a317994)) + +## [0.7.0](https://github.com/noir-lang/acvm/compare/acvm-v0.6.0...acvm-v0.7.0) (2023-03-23) + + +### ⚠ BREAKING CHANGES + +* Add initial oracle opcode ([#149](https://github.com/noir-lang/acvm/issues/149)) +* **acir:** Add RAM and ROM opcodes +* **acir:** Add a public outputs field ([#56](https://github.com/noir-lang/acvm/issues/56)) +* **acvm:** remove `prove_with_meta` and `verify_from_cs` from `ProofSystemCompiler` ([#140](https://github.com/noir-lang/acvm/issues/140)) +* **acvm:** Remove truncate and oddrange directives ([#142](https://github.com/noir-lang/acvm/issues/142)) + +### Features + +* **acir:** Add a public outputs field ([#56](https://github.com/noir-lang/acvm/issues/56)) ([5f358a9](https://github.com/noir-lang/acvm/commit/5f358a97aaa81d87956e182cd8a6d60de75f9752)) +* **acir:** Add RAM and ROM opcodes ([73e9f25](https://github.com/noir-lang/acvm/commit/73e9f25dd87b2ca91245e93d2445eadc0f522fac)) +* Add initial oracle opcode ([#149](https://github.com/noir-lang/acvm/issues/149)) ([88ee2f8](https://github.com/noir-lang/acvm/commit/88ee2f89f37abf5dd1d9f91b4d2eed44dc651348)) + + +### Miscellaneous Chores + +* **acvm:** remove `prove_with_meta` and `verify_from_cs` from `ProofSystemCompiler` ([#140](https://github.com/noir-lang/acvm/issues/140)) ([35dd181](https://github.com/noir-lang/acvm/commit/35dd181102203df17eef510666b327ef41f4b036)) +* **acvm:** Remove truncate and oddrange directives ([#142](https://github.com/noir-lang/acvm/issues/142)) ([85dd6e8](https://github.com/noir-lang/acvm/commit/85dd6e85bfba85bfb97651f7e30e1f75deb986d5)) + +## [0.6.0](https://github.com/noir-lang/acvm/compare/acvm-v0.5.0...acvm-v0.6.0) (2023-03-03) + + +### ⚠ BREAKING CHANGES + +* add block opcode ([#114](https://github.com/noir-lang/acvm/issues/114)) + +### Features + +* add block opcode ([#114](https://github.com/noir-lang/acvm/issues/114)) ([097cfb0](https://github.com/noir-lang/acvm/commit/097cfb069291705ddb4bf1fca77ddcef21dbbd08)) + +## [0.5.0](https://github.com/noir-lang/acvm/compare/acvm-v0.4.1...acvm-v0.5.0) (2023-02-22) + + +### ⚠ BREAKING CHANGES + +* **acvm:** switch to accepting public inputs as a map ([#96](https://github.com/noir-lang/acvm/issues/96)) +* **acvm:** add `eth_contract_from_vk` to `SmartContract +* update `ProofSystemCompiler` to not take ownership of keys ([#111](https://github.com/noir-lang/acvm/issues/111)) +* update `ProofSystemCompiler` methods to take `&Circuit` ([#108](https://github.com/noir-lang/acvm/issues/108)) +* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) +* reorganise compiler in terms of optimisers and transformers ([#88](https://github.com/noir-lang/acvm/issues/88)) + +### Features + +* **acvm:** add `eth_contract_from_vk` to `SmartContract ([#113](https://github.com/noir-lang/acvm/issues/113)) ([373c18f](https://github.com/noir-lang/acvm/commit/373c18fc05edf673cfec9e8bbb78bd7d7514999e)) +* **acvm:** switch to accepting public inputs as a map ([#96](https://github.com/noir-lang/acvm/issues/96)) ([f57ba57](https://github.com/noir-lang/acvm/commit/f57ba57c2bb2597edf2b02fb1321c69cf11993ee)) +* update `ProofSystemCompiler` methods to take `&Circuit` ([#108](https://github.com/noir-lang/acvm/issues/108)) ([af56ca9](https://github.com/noir-lang/acvm/commit/af56ca9da06068c650c66e76bfd09e65eb0ec213)) +* update `ProofSystemCompiler` to not take ownership of keys ([#111](https://github.com/noir-lang/acvm/issues/111)) ([39b8a41](https://github.com/noir-lang/acvm/commit/39b8a41293e567971f700f61103852cb987a8d16)) + + +### Bug Fixes + +* Clean up Log Directive hex output ([#97](https://github.com/noir-lang/acvm/issues/97)) ([d23c735](https://github.com/noir-lang/acvm/commit/d23c7352523ffb42f3e8f4229b61f9803ab78a7e)) + + +### Miscellaneous Chores + +* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) ([2427a27](https://github.com/noir-lang/acvm/commit/2427a275048e598c6d651cce8348a4c55148f235)) +* reorganise compiler in terms of optimisers and transformers ([#88](https://github.com/noir-lang/acvm/issues/88)) ([9329307](https://github.com/noir-lang/acvm/commit/9329307e054de202cfc55207162ad952b70d515e)) diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml new file mode 100644 index 00000000000..19535607390 --- /dev/null +++ b/acvm-repo/acvm/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "acvm" +description = "The virtual machine that processes ACIR given a backend/proof system." +# x-release-please-start-version +version = "0.27.3" +# x-release-please-end +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num-bigint.workspace = true +num-traits.workspace = true +thiserror.workspace = true + +acir.workspace = true +stdlib.workspace = true +brillig_vm.workspace = true +acvm_blackbox_solver.workspace = true + +indexmap = "1.7.0" + +[features] +default = ["bn254", "testing"] +bn254 = [ + "acir/bn254", + "stdlib/bn254", + "brillig_vm/bn254", + "acvm_blackbox_solver/bn254", +] +bls12_381 = [ + "acir/bls12_381", + "stdlib/bls12_381", + "brillig_vm/bls12_381", + "acvm_blackbox_solver/bls12_381", +] +testing = ["stdlib/testing", "unstable-fallbacks"] +unstable-fallbacks = [] + +[dev-dependencies] +rand = "0.8.5" +proptest = "1.2.0" +paste = "1.0.14" diff --git a/acvm-repo/acvm/src/compiler/mod.rs b/acvm-repo/acvm/src/compiler/mod.rs new file mode 100644 index 00000000000..e824117180f --- /dev/null +++ b/acvm-repo/acvm/src/compiler/mod.rs @@ -0,0 +1,280 @@ +use acir::{ + circuit::{ + brillig::BrilligOutputs, directives::Directive, opcodes::UnsupportedMemoryOpcode, Circuit, + Opcode, OpcodeLocation, + }, + native_types::{Expression, Witness}, + BlackBoxFunc, FieldElement, +}; +use indexmap::IndexMap; +use thiserror::Error; + +use crate::Language; + +// The various passes that we can use over ACIR +mod optimizers; +mod transformers; + +use optimizers::{GeneralOptimizer, RangeOptimizer}; +use transformers::{CSatTransformer, FallbackTransformer, R1CSTransformer}; + +#[derive(PartialEq, Eq, Debug, Error)] +pub enum CompileError { + #[error("The blackbox function {0} is not supported by the backend and acvm does not have a fallback implementation")] + UnsupportedBlackBox(BlackBoxFunc), + #[error("The opcode {0} is not supported by the backend and acvm does not have a fallback implementation")] + UnsupportedMemoryOpcode(UnsupportedMemoryOpcode), +} + +/// This module moves and decomposes acir opcodes. The transformation map allows consumers of this module to map +/// metadata they had about the opcodes to the new opcode structure generated after the transformation. +#[derive(Debug)] +pub struct AcirTransformationMap { + /// This is a vector of pointers to the old acir opcodes. The index of the vector is the new opcode index. + /// The value of the vector is the old opcode index pointed. + acir_opcode_positions: Vec, +} + +impl AcirTransformationMap { + pub fn new_locations( + &self, + old_location: OpcodeLocation, + ) -> impl Iterator + '_ { + let old_acir_index = match old_location { + OpcodeLocation::Acir(index) => index, + OpcodeLocation::Brillig { acir_index, .. } => acir_index, + }; + + self.acir_opcode_positions + .iter() + .enumerate() + .filter(move |(_, &old_index)| old_index == old_acir_index) + .map(move |(new_index, _)| match old_location { + OpcodeLocation::Acir(_) => OpcodeLocation::Acir(new_index), + OpcodeLocation::Brillig { brillig_index, .. } => { + OpcodeLocation::Brillig { acir_index: new_index, brillig_index } + } + }) + } +} + +fn transform_assert_messages( + assert_messages: Vec<(OpcodeLocation, String)>, + map: &AcirTransformationMap, +) -> Vec<(OpcodeLocation, String)> { + assert_messages + .into_iter() + .flat_map(|(location, message)| { + let new_locations = map.new_locations(location); + new_locations.into_iter().map(move |new_location| (new_location, message.clone())) + }) + .collect() +} + +/// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. +pub fn compile( + acir: Circuit, + np_language: Language, + is_opcode_supported: impl Fn(&Opcode) -> bool, +) -> Result<(Circuit, AcirTransformationMap), CompileError> { + // Instantiate the optimizer. + // Currently the optimizer and reducer are one in the same + // for CSAT + + // Track original acir opcode positions throughout the transformation passes of the compilation + // by applying the modifications done to the circuit opcodes and also to the opcode_positions (delete and insert) + let acir_opcode_positions = acir.opcodes.iter().enumerate().map(|(i, _)| i).collect(); + + // Fallback transformer pass + let (acir, acir_opcode_positions) = + FallbackTransformer::transform(acir, is_opcode_supported, acir_opcode_positions)?; + + // General optimizer pass + let mut opcodes: Vec = Vec::new(); + for opcode in acir.opcodes { + match opcode { + Opcode::Arithmetic(arith_expr) => { + opcodes.push(Opcode::Arithmetic(GeneralOptimizer::optimize(arith_expr))) + } + other_opcode => opcodes.push(other_opcode), + }; + } + let acir = Circuit { opcodes, ..acir }; + + // Range optimization pass + let range_optimizer = RangeOptimizer::new(acir); + let (mut acir, acir_opcode_positions) = + range_optimizer.replace_redundant_ranges(acir_opcode_positions); + + let mut transformer = match &np_language { + crate::Language::R1CS => { + let transformation_map = AcirTransformationMap { acir_opcode_positions }; + acir.assert_messages = + transform_assert_messages(acir.assert_messages, &transformation_map); + let transformer = R1CSTransformer::new(acir); + return Ok((transformer.transform(), transformation_map)); + } + crate::Language::PLONKCSat { width } => { + let mut csat = CSatTransformer::new(*width); + for value in acir.circuit_arguments() { + csat.mark_solvable(value); + } + csat + } + }; + + // TODO: the code below is only for CSAT transformer + // TODO it may be possible to refactor it in a way that we do not need to return early from the r1cs + // TODO or at the very least, we could put all of it inside of CSatOptimizer pass + + let mut new_acir_opcode_positions: Vec = Vec::with_capacity(acir_opcode_positions.len()); + // Optimize the arithmetic gates by reducing them into the correct width and + // creating intermediate variables when necessary + let mut transformed_opcodes = Vec::new(); + + let mut next_witness_index = acir.current_witness_index + 1; + // maps a normalized expression to the intermediate variable which represents the expression, along with its 'norm' + // the 'norm' is simply the value of the first non zero coefficient in the expression, taken from the linear terms, or quadratic terms if there is none. + let mut intermediate_variables: IndexMap = IndexMap::new(); + for (index, opcode) in acir.opcodes.iter().enumerate() { + match opcode { + Opcode::Arithmetic(arith_expr) => { + let len = intermediate_variables.len(); + + let arith_expr = transformer.transform( + arith_expr.clone(), + &mut intermediate_variables, + &mut next_witness_index, + ); + + // Update next_witness counter + next_witness_index += (intermediate_variables.len() - len) as u32; + let mut new_opcodes = Vec::new(); + for (g, (norm, w)) in intermediate_variables.iter().skip(len) { + // de-normalize + let mut intermediate_opcode = g * *norm; + // constrain the intermediate opcode to the intermediate variable + intermediate_opcode.linear_combinations.push((-FieldElement::one(), *w)); + intermediate_opcode.sort(); + new_opcodes.push(intermediate_opcode); + } + new_opcodes.push(arith_expr); + for opcode in new_opcodes { + new_acir_opcode_positions.push(acir_opcode_positions[index]); + transformed_opcodes.push(Opcode::Arithmetic(opcode)); + } + } + Opcode::BlackBoxFuncCall(func) => { + match func { + acir::circuit::opcodes::BlackBoxFuncCall::AND { output, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::XOR { output, .. } => { + transformer.mark_solvable(*output) + } + acir::circuit::opcodes::BlackBoxFuncCall::RANGE { .. } => (), + acir::circuit::opcodes::BlackBoxFuncCall::SHA256 { outputs, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::Keccak256 { outputs, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::Keccak256VariableLength { + outputs, + .. + } + | acir::circuit::opcodes::BlackBoxFuncCall::RecursiveAggregation { + output_aggregation_object: outputs, + .. + } + | acir::circuit::opcodes::BlackBoxFuncCall::Blake2s { outputs, .. } => { + for witness in outputs { + transformer.mark_solvable(*witness); + } + } + acir::circuit::opcodes::BlackBoxFuncCall::FixedBaseScalarMul { + outputs, + .. + } + | acir::circuit::opcodes::BlackBoxFuncCall::Pedersen { outputs, .. } => { + transformer.mark_solvable(outputs.0); + transformer.mark_solvable(outputs.1) + } + acir::circuit::opcodes::BlackBoxFuncCall::HashToField128Security { + output, + .. + } + | acir::circuit::opcodes::BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::SchnorrVerify { output, .. } => { + transformer.mark_solvable(*output) + } + } + + new_acir_opcode_positions.push(acir_opcode_positions[index]); + transformed_opcodes.push(opcode.clone()); + } + Opcode::Directive(directive) => { + match directive { + Directive::Quotient(quotient_directive) => { + transformer.mark_solvable(quotient_directive.q); + transformer.mark_solvable(quotient_directive.r); + } + Directive::ToLeRadix { b, .. } => { + for witness in b { + transformer.mark_solvable(*witness); + } + } + Directive::PermutationSort { bits, .. } => { + for witness in bits { + transformer.mark_solvable(*witness); + } + } + } + new_acir_opcode_positions.push(acir_opcode_positions[index]); + transformed_opcodes.push(opcode.clone()); + } + Opcode::MemoryInit { .. } => { + // `MemoryInit` does not write values to the `WitnessMap` + new_acir_opcode_positions.push(acir_opcode_positions[index]); + transformed_opcodes.push(opcode.clone()); + } + Opcode::MemoryOp { op, .. } => { + for (_, witness1, witness2) in &op.value.mul_terms { + transformer.mark_solvable(*witness1); + transformer.mark_solvable(*witness2); + } + for (_, witness) in &op.value.linear_combinations { + transformer.mark_solvable(*witness); + } + new_acir_opcode_positions.push(acir_opcode_positions[index]); + transformed_opcodes.push(opcode.clone()); + } + Opcode::Brillig(brillig) => { + for output in &brillig.outputs { + match output { + BrilligOutputs::Simple(w) => transformer.mark_solvable(*w), + BrilligOutputs::Array(v) => { + for witness in v { + transformer.mark_solvable(*witness); + } + } + } + } + new_acir_opcode_positions.push(acir_opcode_positions[index]); + transformed_opcodes.push(opcode.clone()); + } + } + } + + let current_witness_index = next_witness_index - 1; + + let transformation_map = + AcirTransformationMap { acir_opcode_positions: new_acir_opcode_positions }; + + let acir = Circuit { + current_witness_index, + opcodes: transformed_opcodes, + // The optimizer does not add new public inputs + private_parameters: acir.private_parameters, + public_parameters: acir.public_parameters, + return_values: acir.return_values, + assert_messages: transform_assert_messages(acir.assert_messages, &transformation_map), + }; + + Ok((acir, transformation_map)) +} diff --git a/acvm-repo/acvm/src/compiler/optimizers/general.rs b/acvm-repo/acvm/src/compiler/optimizers/general.rs new file mode 100644 index 00000000000..be5359a4114 --- /dev/null +++ b/acvm-repo/acvm/src/compiler/optimizers/general.rs @@ -0,0 +1,44 @@ +use acir::{ + native_types::{Expression, Witness}, + FieldElement, +}; +use indexmap::IndexMap; + +/// The `GeneralOptimizer` processes all [`Expression`]s to: +/// - remove any zero-coefficient terms. +/// - merge any quadratic terms containing the same two witnesses. +pub(crate) struct GeneralOptimizer; + +impl GeneralOptimizer { + pub(crate) fn optimize(opcode: Expression) -> Expression { + // XXX: Perhaps this optimization can be done on the fly + let opcode = remove_zero_coefficients(opcode); + simplify_mul_terms(opcode) + } +} + +// Remove all terms with zero as a coefficient +fn remove_zero_coefficients(mut opcode: Expression) -> Expression { + // Check the mul terms + opcode.mul_terms.retain(|(scale, _, _)| !scale.is_zero()); + // Check the linear combination terms + opcode.linear_combinations.retain(|(scale, _)| !scale.is_zero()); + opcode +} + +// Simplifies all mul terms with the same bi-variate variables +fn simplify_mul_terms(mut gate: Expression) -> Expression { + let mut hash_map: IndexMap<(Witness, Witness), FieldElement> = IndexMap::new(); + + // Canonicalize the ordering of the multiplication, lets just order by variable name + for (scale, w_l, w_r) in gate.mul_terms.clone().into_iter() { + let mut pair = vec![w_l, w_r]; + // Sort using rust sort algorithm + pair.sort(); + + *hash_map.entry((pair[0], pair[1])).or_insert_with(FieldElement::zero) += scale; + } + + gate.mul_terms = hash_map.into_iter().map(|((w_l, w_r), scale)| (scale, w_l, w_r)).collect(); + gate +} diff --git a/acvm-repo/acvm/src/compiler/optimizers/mod.rs b/acvm-repo/acvm/src/compiler/optimizers/mod.rs new file mode 100644 index 00000000000..cde7bdd2064 --- /dev/null +++ b/acvm-repo/acvm/src/compiler/optimizers/mod.rs @@ -0,0 +1,5 @@ +mod general; +mod redundant_range; + +pub(crate) use general::GeneralOptimizer; +pub(crate) use redundant_range::RangeOptimizer; diff --git a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs new file mode 100644 index 00000000000..ac6ffef305d --- /dev/null +++ b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -0,0 +1,238 @@ +use acir::{ + circuit::{opcodes::BlackBoxFuncCall, Circuit, Opcode}, + native_types::Witness, +}; +use std::collections::{BTreeMap, HashSet}; + +/// `RangeOptimizer` will remove redundant range constraints. +/// +/// # Example +/// +/// Suppose we had the following pseudo-code: +/// +/// ```noir +/// let z1 = x as u16; +/// let z2 = x as u32; +/// ``` +/// It is clear that if `x` fits inside of a 16-bit integer, +/// it must also fit inside of a 32-bit integer. +/// +/// The generated ACIR may produce two range opcodes however; +/// - One for the 16 bit range constraint of `x` +/// - One for the 32-bit range constraint of `x` +/// +/// This optimization pass will keep the 16-bit range constraint +/// and remove the 32-bit range constraint opcode. +pub(crate) struct RangeOptimizer { + /// Maps witnesses to their lowest known bit sizes. + lists: BTreeMap, + circuit: Circuit, +} + +impl RangeOptimizer { + /// Creates a new `RangeOptimizer` by collecting all known range + /// constraints from `Circuit`. + pub(crate) fn new(circuit: Circuit) -> Self { + let range_list = Self::collect_ranges(&circuit); + Self { circuit, lists: range_list } + } + + /// Stores the lowest bit range, that a witness + /// has been constrained to be. + /// For example, if we constrain a witness `x` to be + /// both 32 bits and 16 bits. This function will + /// only store the fact that we have constrained it to + /// be 16 bits. + fn collect_ranges(circuit: &Circuit) -> BTreeMap { + let mut witness_to_bit_sizes = BTreeMap::new(); + + for opcode in &circuit.opcodes { + // Extract the witness index and number of bits, + // if it is a range constraint + let (witness, num_bits) = match extract_range_opcode(opcode) { + Some(func_inputs) => func_inputs, + None => continue, + }; + + // Check if the witness has already been recorded and if the witness + // size is more than the current one, we replace it + let should_replace = match witness_to_bit_sizes.get(&witness).copied() { + Some(old_range_bits) => old_range_bits > num_bits, + None => true, + }; + if should_replace { + witness_to_bit_sizes.insert(witness, num_bits); + } + } + witness_to_bit_sizes + } + + /// Returns a `Circuit` where each Witness is only range constrained + /// once to the lowest number `bit size` possible. + pub(crate) fn replace_redundant_ranges(self, order_list: Vec) -> (Circuit, Vec) { + let mut already_seen_witness = HashSet::new(); + + let mut new_order_list = Vec::with_capacity(order_list.len()); + let mut optimized_opcodes = Vec::with_capacity(self.circuit.opcodes.len()); + for (idx, opcode) in self.circuit.opcodes.iter().enumerate() { + let (witness, num_bits) = match extract_range_opcode(opcode) { + Some(range_opcode) => range_opcode, + None => { + // If its not the range opcode, add it to the opcode + // list and continue; + optimized_opcodes.push(opcode.clone()); + new_order_list.push(order_list[idx]); + continue; + } + }; + // If we've already applied the range constraint for this witness then skip this opcode. + let already_added = already_seen_witness.contains(&witness); + if already_added { + continue; + } + + // Check if this is the lowest number of bits in the circuit + let stored_num_bits = self.lists.get(&witness).expect("Could not find witness. This should never be the case if `collect_ranges` is called"); + let is_lowest_bit_size = num_bits <= *stored_num_bits; + + // If the opcode is associated with the lowest bit size + // and we have not added a duplicate of this opcode yet, + // then we should add retain this range opcode. + if is_lowest_bit_size { + already_seen_witness.insert(witness); + new_order_list.push(order_list[idx]); + optimized_opcodes.push(opcode.clone()); + } + } + + ( + Circuit { + current_witness_index: self.circuit.current_witness_index, + opcodes: optimized_opcodes, + ..self.circuit + }, + new_order_list, + ) + } +} + +/// Extract the range opcode from the `Opcode` enum +/// Returns None, if `Opcode` is not the range opcode. +fn extract_range_opcode(opcode: &Opcode) -> Option<(Witness, u32)> { + // Range constraints are blackbox function calls + // so we first extract the function call + let func_call = match opcode { + acir::circuit::Opcode::BlackBoxFuncCall(func_call) => func_call, + _ => return None, + }; + + // Skip if it is not a range constraint + match func_call { + BlackBoxFuncCall::RANGE { input } => Some((input.witness, input.num_bits)), + _ => None, + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeSet; + + use crate::compiler::optimizers::redundant_range::{extract_range_opcode, RangeOptimizer}; + use acir::{ + circuit::{ + opcodes::{BlackBoxFuncCall, FunctionInput}, + Circuit, Opcode, PublicInputs, + }, + native_types::{Expression, Witness}, + }; + + fn test_circuit(ranges: Vec<(Witness, u32)>) -> Circuit { + fn test_range_constraint(witness: Witness, num_bits: u32) -> Opcode { + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { + input: FunctionInput { witness, num_bits }, + }) + } + + let opcodes: Vec<_> = ranges + .into_iter() + .map(|(witness, num_bits)| test_range_constraint(witness, num_bits)) + .collect(); + + Circuit { + current_witness_index: 1, + opcodes, + private_parameters: BTreeSet::new(), + public_parameters: PublicInputs::default(), + return_values: PublicInputs::default(), + assert_messages: Default::default(), + } + } + + #[test] + fn retain_lowest_range_size() { + // The optimizer should keep the lowest bit size range constraint + let circuit = test_circuit(vec![(Witness(1), 32), (Witness(1), 16)]); + let acir_opcode_positions = circuit.opcodes.iter().enumerate().map(|(i, _)| i).collect(); + let optimizer = RangeOptimizer::new(circuit); + + let range_size = *optimizer + .lists + .get(&Witness(1)) + .expect("Witness(1) was inserted, but it is missing from the map"); + assert_eq!( + range_size, 16, + "expected a range size of 16 since that was the lowest bit size provided" + ); + + let (optimized_circuit, _) = optimizer.replace_redundant_ranges(acir_opcode_positions); + assert_eq!(optimized_circuit.opcodes.len(), 1); + + let (witness, num_bits) = + extract_range_opcode(&optimized_circuit.opcodes[0]).expect("expected one range opcode"); + + assert_eq!(witness, Witness(1)); + assert_eq!(num_bits, 16); + } + + #[test] + fn remove_duplicates() { + // The optimizer should remove all duplicate range opcodes. + + let circuit = test_circuit(vec![ + (Witness(1), 16), + (Witness(1), 16), + (Witness(2), 23), + (Witness(2), 23), + ]); + let acir_opcode_positions = circuit.opcodes.iter().enumerate().map(|(i, _)| i).collect(); + let optimizer = RangeOptimizer::new(circuit); + let (optimized_circuit, _) = optimizer.replace_redundant_ranges(acir_opcode_positions); + assert_eq!(optimized_circuit.opcodes.len(), 2); + + let (witness_a, num_bits_a) = + extract_range_opcode(&optimized_circuit.opcodes[0]).expect("expected two range opcode"); + let (witness_b, num_bits_b) = + extract_range_opcode(&optimized_circuit.opcodes[1]).expect("expected two range opcode"); + + assert_eq!(witness_a, Witness(1)); + assert_eq!(witness_b, Witness(2)); + assert_eq!(num_bits_a, 16); + assert_eq!(num_bits_b, 23); + } + + #[test] + fn non_range_opcodes() { + // The optimizer should not remove or change non-range opcodes + // The four Arithmetic opcodes should remain unchanged. + let mut circuit = test_circuit(vec![(Witness(1), 16), (Witness(1), 16)]); + + circuit.opcodes.push(Opcode::Arithmetic(Expression::default())); + circuit.opcodes.push(Opcode::Arithmetic(Expression::default())); + circuit.opcodes.push(Opcode::Arithmetic(Expression::default())); + circuit.opcodes.push(Opcode::Arithmetic(Expression::default())); + let acir_opcode_positions = circuit.opcodes.iter().enumerate().map(|(i, _)| i).collect(); + let optimizer = RangeOptimizer::new(circuit); + let (optimized_circuit, _) = optimizer.replace_redundant_ranges(acir_opcode_positions); + assert_eq!(optimized_circuit.opcodes.len(), 5) + } +} diff --git a/acvm-repo/acvm/src/compiler/transformers/csat.rs b/acvm-repo/acvm/src/compiler/transformers/csat.rs new file mode 100644 index 00000000000..9f89ac4671a --- /dev/null +++ b/acvm-repo/acvm/src/compiler/transformers/csat.rs @@ -0,0 +1,509 @@ +use std::{cmp::Ordering, collections::HashSet}; + +use acir::{ + native_types::{Expression, Witness}, + FieldElement, +}; +use indexmap::IndexMap; + +/// A transformer which processes any [`Expression`]s to break them up such that they +/// fit within the [`ProofSystemCompiler`][crate::ProofSystemCompiler]'s width. +/// +/// This transformer is only used when targetting the [`PLONKCSat`][crate::Language::PLONKCSat] language. +/// +/// This is done by creating intermediate variables to hold partial calculations and then combining them +/// to calculate the original expression. +// Should we give it all of the opcodes? +// Have a single transformer that you instantiate with a width, then pass many opcodes through +pub(crate) struct CSatTransformer { + width: usize, + /// Track the witness that can be solved + solvable_witness: HashSet, +} + +impl CSatTransformer { + // Configure the width for the optimizer + pub(crate) fn new(width: usize) -> CSatTransformer { + assert!(width > 2); + + CSatTransformer { width, solvable_witness: HashSet::new() } + } + + /// Check if the equation 'expression=0' can be solved, and if yes, add the solved witness to set of solvable witness + fn try_solve(&mut self, opcode: &Expression) { + let mut unresolved = Vec::new(); + for (_, w1, w2) in &opcode.mul_terms { + if !self.solvable_witness.contains(w1) { + unresolved.push(w1); + if !self.solvable_witness.contains(w2) { + return; + } + } + if !self.solvable_witness.contains(w2) { + unresolved.push(w2); + if !self.solvable_witness.contains(w1) { + return; + } + } + } + for (_, w) in &opcode.linear_combinations { + if !self.solvable_witness.contains(w) { + unresolved.push(w); + } + } + if unresolved.len() == 1 { + self.mark_solvable(*unresolved[0]); + } + } + + /// Adds the witness to set of solvable witness + pub(crate) fn mark_solvable(&mut self, witness: Witness) { + self.solvable_witness.insert(witness); + } + + // Still missing dead witness optimization. + // To do this, we will need the whole set of arithmetic opcodes + // I think it can also be done before the local optimization seen here, as dead variables will come from the user + pub(crate) fn transform( + &mut self, + opcode: Expression, + intermediate_variables: &mut IndexMap, + num_witness: &mut u32, + ) -> Expression { + // Here we create intermediate variables and constrain them to be equal to any subset of the polynomial that can be represented as a full opcode + let opcode = + self.full_opcode_scan_optimization(opcode, intermediate_variables, num_witness); + // The last optimization to do is to create intermediate variables in order to flatten the fan-in and the amount of mul terms + // If a opcode has more than one mul term. We may need an intermediate variable for each one. Since not every variable will need to link to + // the mul term, we could possibly do it that way. + // We wil call this a partial opcode scan optimization which will result in the opcodes being able to fit into the correct width + let mut opcode = + self.partial_opcode_scan_optimization(opcode, intermediate_variables, num_witness); + opcode.sort(); + self.try_solve(&opcode); + opcode + } + + // This optimization will search for combinations of terms which can be represented in a single arithmetic opcode + // Case 1 : qM * wL * wR + qL * wL + qR * wR + qO * wO + qC + // This polynomial does not require any further optimizations, it can be safely represented in one opcode + // ie a polynomial with 1 mul(bi-variate) term and 3 (univariate) terms where 2 of those terms match the bivariate term + // wL and wR, we can represent it in one opcode + // GENERALIZED for WIDTH: instead of the number 3, we use `WIDTH` + // + // + // Case 2: qM * wL * wR + qL * wL + qR * wR + qO * wO + qC + qM2 * wL2 * wR2 + qL * wL2 + qR * wR2 + qO * wO2 + qC2 + // This polynomial cannot be represented using one arithmetic opcode. + // + // This algorithm will first extract the first full opcode(if possible): + // t = qM * wL * wR + qL * wL + qR * wR + qO * wO + qC + // + // The polynomial now looks like so t + qM2 * wL2 * wR2 + qL * wL2 + qR * wR2 + qO * wO2 + qC2 + // This polynomial cannot be represented using one arithmetic opcode. + // + // This algorithm will then extract the second full opcode(if possible): + // t2 = qM2 * wL2 * wR2 + qL * wL2 + qR * wR2 + qO * wO2 + qC2 + // + // The polynomial now looks like so t + t2 + // We can no longer extract another full opcode, hence the algorithm terminates. Creating two intermediate variables t and t2. + // This stage of preprocessing does not guarantee that all polynomials can fit into a opcode. It only guarantees that all full opcodes have been extracted from each polynomial + fn full_opcode_scan_optimization( + &mut self, + mut opcode: Expression, + intermediate_variables: &mut IndexMap, + num_witness: &mut u32, + ) -> Expression { + // We pass around this intermediate variable IndexMap, so that we do not create intermediate variables that we have created before + // One instance where this might happen is t1 = wL * wR and t2 = wR * wL + + // First check that this is not a simple opcode which does not need optimization + // + // If the opcode only has one mul term, then this algorithm cannot optimize it any further + // Either it can be represented in a single arithmetic equation or it's fan-in is too large and we need intermediate variables for those + // large-fan-in optimization is not this algorithms purpose. + // If the opcode has 0 mul terms, then it is an add opcode and similarly it can either fit into a single arithmetic opcode or it has a large fan-in + if opcode.mul_terms.len() <= 1 { + return opcode; + } + + // We now know that this opcode has multiple mul terms and can possibly be simplified into multiple full opcodes + // We need to create a (wl, wr) IndexMap and then check the simplified fan-in to verify if we have terms both with wl and wr + // In general, we can then push more terms into the opcode until we are at width-1 then the last variable will be the intermediate variable + // + + // This will be our new opcode which will be equal to `self` except we will have intermediate variables that will be constrained to any + // subset of the terms that can be represented as full opcodes + let mut new_opcode = Expression::default(); + let mut remaining_mul_terms = Vec::with_capacity(opcode.mul_terms.len()); + for pair in opcode.mul_terms { + // We want to layout solvable intermediate variable, if we cannot solve one of the witness + // that means the intermediate opcode will not be immediately solvable + if !self.solvable_witness.contains(&pair.1) || !self.solvable_witness.contains(&pair.2) + { + remaining_mul_terms.push(pair); + continue; + } + + // Check if this pair is present in the simplified fan-in + // We are assuming that the fan-in/fan-out has been simplified. + // Note this function is not public, and can only be called within the optimize method, so this guarantee will always hold + let index_wl = + opcode.linear_combinations.iter().position(|(_scale, witness)| *witness == pair.1); + let index_wr = + opcode.linear_combinations.iter().position(|(_scale, witness)| *witness == pair.2); + + match (index_wl, index_wr) { + (None, _) => { + // This means that the polynomial does not contain both terms + // Just push the Qm term as it cannot form a full opcode + new_opcode.mul_terms.push(pair); + } + (_, None) => { + // This means that the polynomial does not contain both terms + // Just push the Qm term as it cannot form a full opcode + new_opcode.mul_terms.push(pair); + } + (Some(x), Some(y)) => { + // This means that we can form a full opcode with this Qm term + + // First fetch the left and right wires which match the mul term + let left_wire_term = opcode.linear_combinations[x]; + let right_wire_term = opcode.linear_combinations[y]; + + // Lets create an intermediate opcode to store this full opcode + // + let mut intermediate_opcode = Expression::default(); + intermediate_opcode.mul_terms.push(pair); + + // Add the left and right wires + intermediate_opcode.linear_combinations.push(left_wire_term); + intermediate_opcode.linear_combinations.push(right_wire_term); + // Remove the left and right wires so we do not re-add them + match x.cmp(&y) { + Ordering::Greater => { + opcode.linear_combinations.remove(x); + opcode.linear_combinations.remove(y); + } + Ordering::Less => { + opcode.linear_combinations.remove(y); + opcode.linear_combinations.remove(x); + } + Ordering::Equal => { + opcode.linear_combinations.remove(x); + intermediate_opcode.linear_combinations.pop(); + } + } + + // Now we have used up 2 spaces in our arithmetic opcode. The width now dictates, how many more we can add + let mut remaining_space = self.width - 2 - 1; // We minus 1 because we need an extra space to contain the intermediate variable + // Keep adding terms until we have no more left, or we reach the width + let mut remaining_linear_terms = + Vec::with_capacity(opcode.linear_combinations.len()); + while remaining_space > 0 { + if let Some(wire_term) = opcode.linear_combinations.pop() { + // Add this element into the new opcode + if self.solvable_witness.contains(&wire_term.1) { + intermediate_opcode.linear_combinations.push(wire_term); + remaining_space -= 1; + } else { + remaining_linear_terms.push(wire_term); + } + } else { + // No more usable elements left in the old opcode + opcode.linear_combinations = remaining_linear_terms; + break; + } + } + // Constraint this intermediate_opcode to be equal to the temp variable by adding it into the IndexMap + // We need a unique name for our intermediate variable + // XXX: Another optimization, which could be applied in another algorithm + // If two opcodes have a large fan-in/out and they share a few common terms, then we should create intermediate variables for them + // Do some sort of subset matching algorithm for this on the terms of the polynomial + + let inter_var = Self::get_or_create_intermediate_vars( + intermediate_variables, + intermediate_opcode, + num_witness, + ); + + // Add intermediate variable to the new opcode instead of the full opcode + self.mark_solvable(inter_var.1); + new_opcode.linear_combinations.push(inter_var); + } + }; + } + opcode.mul_terms = remaining_mul_terms; + + // Add the rest of the elements back into the new_opcode + new_opcode.mul_terms.extend(opcode.mul_terms); + new_opcode.linear_combinations.extend(opcode.linear_combinations); + new_opcode.q_c = opcode.q_c; + new_opcode.sort(); + new_opcode + } + + /// Normalize an expression by dividing it by its first coefficient + /// The first coefficient here means coefficient of the first linear term, or of the first quadratic term if no linear terms exist. + /// The function panic if the input expression is constant + fn normalize(mut expr: Expression) -> (FieldElement, Expression) { + expr.sort(); + let a = if !expr.linear_combinations.is_empty() { + expr.linear_combinations[0].0 + } else { + expr.mul_terms[0].0 + }; + (a, &expr * a.inverse()) + } + + /// Get or generate a scaled intermediate witness which is equal to the provided expression + /// The sets of previously generated witness and their (normalized) expression is cached in the intermediate_variables map + /// If there is no cache hit, we generate a new witness (and add the expression to the cache) + /// else, we return the cached witness along with the scaling factor so it is equal to the provided expression + fn get_or_create_intermediate_vars( + intermediate_variables: &mut IndexMap, + expr: Expression, + num_witness: &mut u32, + ) -> (FieldElement, Witness) { + let (k, normalized_expr) = Self::normalize(expr); + + if intermediate_variables.contains_key(&normalized_expr) { + let (l, iv) = intermediate_variables[&normalized_expr]; + (k / l, iv) + } else { + let inter_var = Witness(*num_witness); + *num_witness += 1; + // Add intermediate opcode and variable to map + intermediate_variables.insert(normalized_expr, (k, inter_var)); + (FieldElement::one(), inter_var) + } + } + + // A partial opcode scan optimization aim to create intermediate variables in order to compress the polynomial + // So that it fits within the given width + // Note that this opcode follows the full opcode scan optimization. + // We define the partial width as equal to the full width - 2. + // This is because two of our variables cannot be used as they are linked to the multiplication terms + // Example: qM1 * wL1 * wR2 + qL1 * wL3 + qR1 * wR4+ qR2 * wR5 + qO1 * wO5 + qC + // One thing to note is that the multiplication wires do not match any of the fan-in/out wires. This is guaranteed as we have + // just completed the full opcode optimization algorithm. + // + //Actually we can optimize in two ways here: We can create an intermediate variable which is equal to the fan-in terms + // t = qL1 * wL3 + qR1 * wR4 -> width = 3 + // This `t` value can only use width - 1 terms + // The opcode now looks like: qM1 * wL1 * wR2 + t + qR2 * wR5+ qO1 * wO5 + qC + // But this is still not acceptable since wR5 is not wR2, so we need another intermediate variable + // t2 = t + qR2 * wR5 + // + // The opcode now looks like: qM1 * wL1 * wR2 + t2 + qO1 * wO5 + qC + // This is still not good, so we do it one more time: + // t3 = t2 + qO1 * wO5 + // The opcode now looks like: qM1 * wL1 * wR2 + t3 + qC + // + // Another strategy is to create a temporary variable for the multiplier term and then we can see it as a term in the fan-in + // + // Same Example: qM1 * wL1 * wR2 + qL1 * wL3 + qR1 * wR4+ qR2 * wR5 + qO1 * wO5 + qC + // t = qM1 * wL1 * wR2 + // The opcode now looks like: t + qL1 * wL3 + qR1 * wR4+ qR2 * wR5 + qO1 * wO5 + qC + // Still assuming width3, we still need to use width-1 terms for the intermediate variables, however we can stop at an earlier stage because + // the opcode does not need the multiplier term to match with any of the fan-in terms + // t2 = t + qL1 * wL3 + // The opcode now looks like: t2 + qR1 * wR4+ qR2 * wR5 + qO1 * wO5 + qC + // t3 = t2 + qR1 * wR4 + // The opcode now looks like: t3 + qR2 * wR5 + qO1 * wO5 + qC + // This took the same amount of opcodes, but which one is better when the width increases? Compute this and maybe do both optimizations + // naming : partial_opcode_mul_first_opt and partial_opcode_fan_first_opt + // Also remember that since we did full opcode scan, there is no way we can have a non-zero mul term along with the wL and wR terms being non-zero + // + // Cases, a lot of mul terms, a lot of fan-in terms, 50/50 + fn partial_opcode_scan_optimization( + &mut self, + mut opcode: Expression, + intermediate_variables: &mut IndexMap, + num_witness: &mut u32, + ) -> Expression { + // We will go for the easiest route, which is to convert all multiplications into additions using intermediate variables + // Then use intermediate variables again to squash the fan-in, so that it can fit into the appropriate width + + // First check if this polynomial actually needs a partial opcode optimization + // There is the chance that it fits perfectly within the arithmetic opcode + if opcode.fits_in_one_identity(self.width) { + return opcode; + } + + // 2. Create Intermediate variables for the multiplication opcodes + let mut remaining_mul_terms = Vec::with_capacity(opcode.mul_terms.len()); + for mul_term in opcode.mul_terms { + if self.solvable_witness.contains(&mul_term.1) + && self.solvable_witness.contains(&mul_term.2) + { + let mut intermediate_opcode = Expression::default(); + + // Push mul term into the opcode + intermediate_opcode.mul_terms.push(mul_term); + // Get an intermediate variable which squashes the multiplication term + let inter_var = Self::get_or_create_intermediate_vars( + intermediate_variables, + intermediate_opcode, + num_witness, + ); + + // Add intermediate variable as a part of the fan-in for the original opcode + opcode.linear_combinations.push(inter_var); + self.mark_solvable(inter_var.1); + } else { + remaining_mul_terms.push(mul_term); + } + } + + // Remove all of the mul terms as we have intermediate variables to represent them now + opcode.mul_terms = remaining_mul_terms; + + // We now only have a polynomial with only fan-in/fan-out terms i.e. terms of the form Ax + By + Cd + ... + // Lets create intermediate variables if all of them cannot fit into the width + // + // If the polynomial fits perfectly within the given width, we are finished + if opcode.linear_combinations.len() <= self.width { + return opcode; + } + + // Stores the intermediate variables that are used to + // reduce the fan in. + let mut added = Vec::new(); + + while opcode.linear_combinations.len() > self.width { + // Collect as many terms up to the given width-1 and constrain them to an intermediate variable + let mut intermediate_opcode = Expression::default(); + + let mut remaining_linear_terms = Vec::with_capacity(opcode.linear_combinations.len()); + + for term in opcode.linear_combinations { + if self.solvable_witness.contains(&term.1) + && intermediate_opcode.linear_combinations.len() < self.width - 1 + { + intermediate_opcode.linear_combinations.push(term); + } else { + remaining_linear_terms.push(term); + } + } + opcode.linear_combinations = remaining_linear_terms; + let not_full = intermediate_opcode.linear_combinations.len() < self.width - 1; + if intermediate_opcode.linear_combinations.len() > 1 { + let inter_var = Self::get_or_create_intermediate_vars( + intermediate_variables, + intermediate_opcode, + num_witness, + ); + self.mark_solvable(inter_var.1); + added.push(inter_var); + } + // The intermediate opcode is not full, but the opcode still has too many terms + if not_full && opcode.linear_combinations.len() > self.width { + unreachable!("Could not reduce the expression"); + } + } + + // Add back the intermediate variables to + // keep consistency with the original equation. + opcode.linear_combinations.extend(added); + self.partial_opcode_scan_optimization(opcode, intermediate_variables, num_witness) + } +} + +#[test] +fn simple_reduction_smoke_test() { + let a = Witness(0); + let b = Witness(1); + let c = Witness(2); + let d = Witness(3); + + // a = b + c + d; + let opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::one(), a), + (-FieldElement::one(), b), + (-FieldElement::one(), c), + (-FieldElement::one(), d), + ], + q_c: FieldElement::zero(), + }; + + let mut intermediate_variables: IndexMap = IndexMap::new(); + + let mut num_witness = 4; + + let mut optimizer = CSatTransformer::new(3); + optimizer.mark_solvable(b); + optimizer.mark_solvable(c); + optimizer.mark_solvable(d); + let got_optimized_opcode_a = + optimizer.transform(opcode_a, &mut intermediate_variables, &mut num_witness); + + // a = b + c + d => a - b - c - d = 0 + // For width3, the result becomes: + // a - d + e = 0 + // - c - b - e = 0 + // + // a - b + e = 0 + let e = Witness(4); + let expected_optimized_opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::one(), a), + (-FieldElement::one(), d), + (FieldElement::one(), e), + ], + q_c: FieldElement::zero(), + }; + assert_eq!(expected_optimized_opcode_a, got_optimized_opcode_a); + + assert_eq!(intermediate_variables.len(), 1); + + // e = - c - b + let expected_intermediate_opcode = Expression { + mul_terms: vec![], + linear_combinations: vec![(-FieldElement::one(), c), (-FieldElement::one(), b)], + q_c: FieldElement::zero(), + }; + let (_, normalized_opcode) = CSatTransformer::normalize(expected_intermediate_opcode); + assert!(intermediate_variables.contains_key(&normalized_opcode)); + assert_eq!(intermediate_variables[&normalized_opcode].1, e); +} + +#[test] +fn stepwise_reduction_test() { + let a = Witness(0); + let b = Witness(1); + let c = Witness(2); + let d = Witness(3); + let e = Witness(4); + + // a = b + c + d + e; + let opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (-FieldElement::one(), a), + (FieldElement::one(), b), + (FieldElement::one(), c), + (FieldElement::one(), d), + (FieldElement::one(), e), + ], + q_c: FieldElement::zero(), + }; + + let mut intermediate_variables: IndexMap = IndexMap::new(); + + let mut num_witness = 4; + + let mut optimizer = CSatTransformer::new(3); + optimizer.mark_solvable(a); + optimizer.mark_solvable(c); + optimizer.mark_solvable(d); + optimizer.mark_solvable(e); + let got_optimized_opcode_a = + optimizer.transform(opcode_a, &mut intermediate_variables, &mut num_witness); + + // Since b is not known, it cannot be put inside intermediate opcodes, so it must belong to the transformed opcode. + let contains_b = got_optimized_opcode_a.linear_combinations.iter().any(|(_, w)| *w == b); + assert!(contains_b); +} diff --git a/acvm-repo/acvm/src/compiler/transformers/fallback.rs b/acvm-repo/acvm/src/compiler/transformers/fallback.rs new file mode 100644 index 00000000000..d3e4ea506f8 --- /dev/null +++ b/acvm-repo/acvm/src/compiler/transformers/fallback.rs @@ -0,0 +1,154 @@ +use super::super::CompileError; +use acir::{ + circuit::{opcodes::BlackBoxFuncCall, Circuit, Opcode}, + native_types::Expression, +}; + +/// The initial transformer to act on a [`Circuit`]. This replaces any unsupported opcodes with +/// fallback implementations consisting of well supported opcodes. +pub(crate) struct FallbackTransformer; + +impl FallbackTransformer { + //ACIR pass which replace unsupported opcodes using arithmetic fallback + pub(crate) fn transform( + acir: Circuit, + is_supported: impl Fn(&Opcode) -> bool, + opcode_positions: Vec, + ) -> Result<(Circuit, Vec), CompileError> { + let mut acir_supported_opcodes = Vec::with_capacity(acir.opcodes.len()); + let mut new_opcode_positions = Vec::with_capacity(opcode_positions.len()); + let mut witness_idx = acir.current_witness_index + 1; + + for (idx, opcode) in acir.opcodes.into_iter().enumerate() { + match &opcode { + Opcode::Arithmetic(_) | Opcode::Directive(_) | Opcode::Brillig(_) => { + // directive, arithmetic expression or blocks are handled by acvm + new_opcode_positions.push(opcode_positions[idx]); + acir_supported_opcodes.push(opcode); + continue; + } + Opcode::MemoryInit { .. } | Opcode::MemoryOp { .. } => { + if !is_supported(&opcode) { + return Err(CompileError::UnsupportedMemoryOpcode( + opcode.unsupported_opcode(), + )); + } + new_opcode_positions.push(opcode_positions[idx]); + acir_supported_opcodes.push(opcode); + } + Opcode::BlackBoxFuncCall(bb_func_call) => { + // We know it is an black box function. Now check if it is + // supported by the backend. If it is supported, then we can simply + // collect the opcode + if is_supported(&opcode) { + new_opcode_positions.push(opcode_positions[idx]); + acir_supported_opcodes.push(opcode); + continue; + } else { + // If we get here then we know that this black box function is not supported + // so we need to replace it with a version of the opcode which only uses arithmetic + // expressions + let (updated_witness_index, opcodes_fallback) = + Self::opcode_fallback(bb_func_call, witness_idx)?; + witness_idx = updated_witness_index; + new_opcode_positions + .extend(vec![opcode_positions[idx]; opcodes_fallback.len()]); + acir_supported_opcodes.extend(opcodes_fallback); + } + } + } + } + + Ok(( + Circuit { current_witness_index: witness_idx, opcodes: acir_supported_opcodes, ..acir }, + new_opcode_positions, + )) + } + + fn opcode_fallback( + gc: &BlackBoxFuncCall, + current_witness_idx: u32, + ) -> Result<(u32, Vec), CompileError> { + let (updated_witness_index, opcodes_fallback) = match gc { + BlackBoxFuncCall::AND { lhs, rhs, output } => { + assert_eq!( + lhs.num_bits, rhs.num_bits, + "number of bits specified for each input must be the same" + ); + stdlib::blackbox_fallbacks::and( + Expression::from(lhs.witness), + Expression::from(rhs.witness), + *output, + lhs.num_bits, + current_witness_idx, + ) + } + BlackBoxFuncCall::XOR { lhs, rhs, output } => { + assert_eq!( + lhs.num_bits, rhs.num_bits, + "number of bits specified for each input must be the same" + ); + stdlib::blackbox_fallbacks::xor( + Expression::from(lhs.witness), + Expression::from(rhs.witness), + *output, + lhs.num_bits, + current_witness_idx, + ) + } + BlackBoxFuncCall::RANGE { input } => { + // Note there are no outputs because range produces no outputs + stdlib::blackbox_fallbacks::range( + Expression::from(input.witness), + input.num_bits, + current_witness_idx, + ) + } + #[cfg(feature = "unstable-fallbacks")] + BlackBoxFuncCall::SHA256 { inputs, outputs } => { + let sha256_inputs = + inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); + stdlib::blackbox_fallbacks::sha256( + sha256_inputs, + outputs.to_vec(), + current_witness_idx, + ) + } + #[cfg(feature = "unstable-fallbacks")] + BlackBoxFuncCall::Blake2s { inputs, outputs } => { + let blake2s_inputs = + inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); + stdlib::blackbox_fallbacks::blake2s( + blake2s_inputs, + outputs.to_vec(), + current_witness_idx, + ) + } + #[cfg(feature = "unstable-fallbacks")] + BlackBoxFuncCall::HashToField128Security { inputs, output } => { + let hash_to_field_inputs = + inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); + stdlib::blackbox_fallbacks::hash_to_field( + hash_to_field_inputs, + *output, + current_witness_idx, + ) + } + #[cfg(feature = "unstable-fallbacks")] + BlackBoxFuncCall::Keccak256 { inputs, outputs } => { + let keccak_inputs = + inputs.iter().map(|input| (input.witness.into(), input.num_bits)).collect(); + stdlib::blackbox_fallbacks::keccak256( + keccak_inputs, + outputs.to_vec(), + current_witness_idx, + ) + } + _ => { + return Err(CompileError::UnsupportedBlackBox(gc.get_black_box_func())); + } + }; + + Ok((updated_witness_index, opcodes_fallback)) + } +} diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs new file mode 100644 index 00000000000..89e17ca68d0 --- /dev/null +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -0,0 +1,7 @@ +mod csat; +mod fallback; +mod r1cs; + +pub(crate) use csat::CSatTransformer; +pub(crate) use fallback::FallbackTransformer; +pub(crate) use r1cs::R1CSTransformer; diff --git a/acvm-repo/acvm/src/compiler/transformers/r1cs.rs b/acvm-repo/acvm/src/compiler/transformers/r1cs.rs new file mode 100644 index 00000000000..3bdd29c9c53 --- /dev/null +++ b/acvm-repo/acvm/src/compiler/transformers/r1cs.rs @@ -0,0 +1,16 @@ +use acir::circuit::Circuit; + +/// Currently a "noop" transformer. +pub(crate) struct R1CSTransformer { + acir: Circuit, +} + +impl R1CSTransformer { + pub(crate) fn new(acir: Circuit) -> Self { + Self { acir } + } + // TODO: We could possibly make sure that all polynomials are at most degree-2 + pub(crate) fn transform(self) -> Circuit { + self.acir + } +} diff --git a/acvm-repo/acvm/src/lib.rs b/acvm-repo/acvm/src/lib.rs new file mode 100644 index 00000000000..f32d30ee9aa --- /dev/null +++ b/acvm-repo/acvm/src/lib.rs @@ -0,0 +1,25 @@ +#![warn(unused_crate_dependencies)] +#![warn(unreachable_pub)] + +pub mod compiler; +pub mod pwg; + +pub use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; +use core::fmt::Debug; +use pwg::OpcodeResolutionError; + +// re-export acir +pub use acir; +pub use acir::FieldElement; +// re-export brillig vm +pub use brillig_vm; +// re-export blackbox solver +pub use acvm_blackbox_solver as blackbox_solver; + +/// Supported NP complete languages +/// This might need to be in ACIR instead +#[derive(Debug, Clone, Copy)] +pub enum Language { + R1CS, + PLONKCSat { width: usize }, +} diff --git a/acvm-repo/acvm/src/pwg/arithmetic.rs b/acvm-repo/acvm/src/pwg/arithmetic.rs new file mode 100644 index 00000000000..93a39fb249c --- /dev/null +++ b/acvm-repo/acvm/src/pwg/arithmetic.rs @@ -0,0 +1,281 @@ +use acir::{ + native_types::{Expression, Witness, WitnessMap}, + FieldElement, +}; + +use super::{insert_value, ErrorLocation, OpcodeNotSolvable, OpcodeResolutionError}; + +/// An Arithmetic solver will take a Circuit's arithmetic opcodes with witness assignments +/// and create the other witness variables +pub(super) struct ArithmeticSolver; + +#[allow(clippy::enum_variant_names)] +pub(super) enum OpcodeStatus { + OpcodeSatisfied(FieldElement), + OpcodeSolvable(FieldElement, (FieldElement, Witness)), + OpcodeUnsolvable, +} + +pub(crate) enum MulTerm { + OneUnknown(FieldElement, Witness), // (qM * known_witness, unknown_witness) + TooManyUnknowns, + Solved(FieldElement), +} + +impl ArithmeticSolver { + /// Derives the rest of the witness based on the initial low level variables + pub(super) fn solve( + initial_witness: &mut WitnessMap, + opcode: &Expression, + ) -> Result<(), OpcodeResolutionError> { + let opcode = &ArithmeticSolver::evaluate(opcode, initial_witness); + // Evaluate multiplication term + let mul_result = ArithmeticSolver::solve_mul_term(opcode, initial_witness); + // Evaluate the fan-in terms + let opcode_status = ArithmeticSolver::solve_fan_in_term(opcode, initial_witness); + + match (mul_result, opcode_status) { + (MulTerm::TooManyUnknowns, _) | (_, OpcodeStatus::OpcodeUnsolvable) => { + Err(OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::ExpressionHasTooManyUnknowns(opcode.clone()), + )) + } + (MulTerm::OneUnknown(q, w1), OpcodeStatus::OpcodeSolvable(a, (b, w2))) => { + if w1 == w2 { + // We have one unknown so we can solve the equation + let total_sum = a + opcode.q_c; + if (q + b).is_zero() { + if !total_sum.is_zero() { + Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }) + } else { + Ok(()) + } + } else { + let assignment = -total_sum / (q + b); + // Add this into the witness assignments + insert_value(&w1, assignment, initial_witness)?; + Ok(()) + } + } else { + // TODO: can we be more specific with this error? + Err(OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::ExpressionHasTooManyUnknowns(opcode.clone()), + )) + } + } + ( + MulTerm::OneUnknown(partial_prod, unknown_var), + OpcodeStatus::OpcodeSatisfied(sum), + ) => { + // We have one unknown in the mul term and the fan-in terms are solved. + // Hence the equation is solvable, since there is a single unknown + // The equation is: partial_prod * unknown_var + sum + qC = 0 + + let total_sum = sum + opcode.q_c; + if partial_prod.is_zero() { + if !total_sum.is_zero() { + Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }) + } else { + Ok(()) + } + } else { + let assignment = -(total_sum / partial_prod); + // Add this into the witness assignments + insert_value(&unknown_var, assignment, initial_witness)?; + Ok(()) + } + } + (MulTerm::Solved(a), OpcodeStatus::OpcodeSatisfied(b)) => { + // All the variables in the MulTerm are solved and the Fan-in is also solved + // There is nothing to solve + if !(a + b + opcode.q_c).is_zero() { + Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }) + } else { + Ok(()) + } + } + ( + MulTerm::Solved(total_prod), + OpcodeStatus::OpcodeSolvable(partial_sum, (coeff, unknown_var)), + ) => { + // The variables in the MulTerm are solved nad there is one unknown in the Fan-in + // Hence the equation is solvable, since we have one unknown + // The equation is total_prod + partial_sum + coeff * unknown_var + q_C = 0 + let total_sum = total_prod + partial_sum + opcode.q_c; + if coeff.is_zero() { + if !total_sum.is_zero() { + Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }) + } else { + Ok(()) + } + } else { + let assignment = -(total_sum / coeff); + // Add this into the witness assignments + insert_value(&unknown_var, assignment, initial_witness)?; + Ok(()) + } + } + } + } + + /// Returns the evaluation of the multiplication term in the arithmetic opcode + /// If the witness values are not known, then the function returns a None + /// XXX: Do we need to account for the case where 5xy + 6x = 0 ? We do not know y, but it can be solved given x . But I believe x can be solved with another opcode + /// XXX: What about making a mul opcode = a constant 5xy + 7 = 0 ? This is the same as the above. + fn solve_mul_term(arith_opcode: &Expression, witness_assignments: &WitnessMap) -> MulTerm { + // First note that the mul term can only contain one/zero term + // We are assuming it has been optimized. + match arith_opcode.mul_terms.len() { + 0 => MulTerm::Solved(FieldElement::zero()), + 1 => ArithmeticSolver::solve_mul_term_helper( + &arith_opcode.mul_terms[0], + witness_assignments, + ), + _ => panic!("Mul term in the arithmetic opcode must contain either zero or one term"), + } + } + + fn solve_mul_term_helper( + term: &(FieldElement, Witness, Witness), + witness_assignments: &WitnessMap, + ) -> MulTerm { + let (q_m, w_l, w_r) = term; + // Check if these values are in the witness assignments + let w_l_value = witness_assignments.get(w_l); + let w_r_value = witness_assignments.get(w_r); + + match (w_l_value, w_r_value) { + (None, None) => MulTerm::TooManyUnknowns, + (Some(w_l), Some(w_r)) => MulTerm::Solved(*q_m * *w_l * *w_r), + (None, Some(w_r)) => MulTerm::OneUnknown(*q_m * *w_r, *w_l), + (Some(w_l), None) => MulTerm::OneUnknown(*q_m * *w_l, *w_r), + } + } + + fn solve_fan_in_term_helper( + term: &(FieldElement, Witness), + witness_assignments: &WitnessMap, + ) -> Option { + let (q_l, w_l) = term; + // Check if we have w_l + let w_l_value = witness_assignments.get(w_l); + w_l_value.map(|a| *q_l * *a) + } + + /// Returns the summation of all of the variables, plus the unknown variable + /// Returns None, if there is more than one unknown variable + /// We cannot assign + pub(super) fn solve_fan_in_term( + arith_opcode: &Expression, + witness_assignments: &WitnessMap, + ) -> OpcodeStatus { + // This is assuming that the fan-in is more than 0 + + // This is the variable that we want to assign the value to + let mut unknown_variable = (FieldElement::zero(), Witness::default()); + let mut num_unknowns = 0; + // This is the sum of all of the known variables + let mut result = FieldElement::zero(); + + for term in arith_opcode.linear_combinations.iter() { + let value = ArithmeticSolver::solve_fan_in_term_helper(term, witness_assignments); + match value { + Some(a) => result += a, + None => { + unknown_variable = *term; + num_unknowns += 1; + } + } + + // If we have more than 1 unknown, then we cannot solve this equation + if num_unknowns > 1 { + return OpcodeStatus::OpcodeUnsolvable; + } + } + + if num_unknowns == 0 { + return OpcodeStatus::OpcodeSatisfied(result); + } + + OpcodeStatus::OpcodeSolvable(result, unknown_variable) + } + + // Partially evaluate the opcode using the known witnesses + pub(super) fn evaluate(expr: &Expression, initial_witness: &WitnessMap) -> Expression { + let mut result = Expression::default(); + for &(c, w1, w2) in &expr.mul_terms { + let mul_result = ArithmeticSolver::solve_mul_term_helper(&(c, w1, w2), initial_witness); + match mul_result { + MulTerm::OneUnknown(v, w) => { + if !v.is_zero() { + result.linear_combinations.push((v, w)); + } + } + MulTerm::TooManyUnknowns => { + if !c.is_zero() { + result.mul_terms.push((c, w1, w2)); + } + } + MulTerm::Solved(f) => result.q_c += f, + } + } + for &(c, w) in &expr.linear_combinations { + if let Some(f) = ArithmeticSolver::solve_fan_in_term_helper(&(c, w), initial_witness) { + result.q_c += f; + } else if !c.is_zero() { + result.linear_combinations.push((c, w)); + } + } + result.q_c += expr.q_c; + result + } +} + +#[test] +fn arithmetic_smoke_test() { + let a = Witness(0); + let b = Witness(1); + let c = Witness(2); + let d = Witness(3); + + // a = b + c + d; + let opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::one(), a), + (-FieldElement::one(), b), + (-FieldElement::one(), c), + (-FieldElement::one(), d), + ], + q_c: FieldElement::zero(), + }; + + let e = Witness(4); + let opcode_b = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::one(), e), + (-FieldElement::one(), a), + (-FieldElement::one(), b), + ], + q_c: FieldElement::zero(), + }; + + let mut values = WitnessMap::new(); + values.insert(b, FieldElement::from(2_i128)); + values.insert(c, FieldElement::from(1_i128)); + values.insert(d, FieldElement::from(1_i128)); + + assert_eq!(ArithmeticSolver::solve(&mut values, &opcode_a), Ok(())); + assert_eq!(ArithmeticSolver::solve(&mut values, &opcode_b), Ok(())); + + assert_eq!(values.get(&a).unwrap(), &FieldElement::from(4_i128)); +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs b/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs new file mode 100644 index 00000000000..975025971dc --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs @@ -0,0 +1,27 @@ +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, +}; + +use crate::{ + pwg::{insert_value, witness_to_value, OpcodeResolutionError}, + BlackBoxFunctionSolver, +}; + +pub(super) fn fixed_base_scalar_mul( + backend: &impl BlackBoxFunctionSolver, + initial_witness: &mut WitnessMap, + low: FunctionInput, + high: FunctionInput, + outputs: (Witness, Witness), +) -> Result<(), OpcodeResolutionError> { + let low = witness_to_value(initial_witness, low.witness)?; + let high = witness_to_value(initial_witness, high.witness)?; + + let (pub_x, pub_y) = backend.fixed_base_scalar_mul(low, high)?; + + insert_value(&outputs.0, pub_x, initial_witness)?; + insert_value(&outputs.1, pub_y, initial_witness)?; + + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/acvm-repo/acvm/src/pwg/blackbox/hash.rs new file mode 100644 index 00000000000..80665a743c4 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -0,0 +1,103 @@ +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + BlackBoxFunc, FieldElement, +}; +use acvm_blackbox_solver::{hash_to_field_128_security, BlackBoxResolutionError}; + +use crate::pwg::{insert_value, witness_to_value}; +use crate::OpcodeResolutionError; + +/// Attempts to solve a `HashToField128Security` opcode +/// If successful, `initial_witness` will be mutated to contain the new witness assignment. +pub(super) fn solve_hash_to_field( + initial_witness: &mut WitnessMap, + inputs: &[FunctionInput], + output: &Witness, +) -> Result<(), OpcodeResolutionError> { + let message_input = get_hash_input(initial_witness, inputs, None)?; + let field = hash_to_field_128_security(&message_input)?; + + insert_value(output, field, initial_witness)?; + + Ok(()) +} + +/// Attempts to solve a 256 bit hash function opcode. +/// If successful, `initial_witness` will be mutated to contain the new witness assignment. +pub(super) fn solve_generic_256_hash_opcode( + initial_witness: &mut WitnessMap, + inputs: &[FunctionInput], + var_message_size: Option<&FunctionInput>, + outputs: &[Witness], + hash_function: fn(data: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError>, + black_box_func: BlackBoxFunc, +) -> Result<(), OpcodeResolutionError> { + let message_input = get_hash_input(initial_witness, inputs, var_message_size)?; + let digest: [u8; 32] = hash_function(&message_input)?; + + let outputs: [Witness; 32] = outputs.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + black_box_func, + format!("Expected 32 outputs but encountered {}", outputs.len()), + ) + })?; + write_digest_to_outputs(initial_witness, outputs, digest)?; + + Ok(()) +} + +/// Reads the hash function input from a [`WitnessMap`]. +fn get_hash_input( + initial_witness: &WitnessMap, + inputs: &[FunctionInput], + message_size: Option<&FunctionInput>, +) -> Result, OpcodeResolutionError> { + // Read witness assignments. + let mut message_input = Vec::new(); + for input in inputs.iter() { + let witness = input.witness; + let num_bits = input.num_bits as usize; + + let witness_assignment = witness_to_value(initial_witness, witness)?; + let bytes = witness_assignment.fetch_nearest_bytes(num_bits); + message_input.extend(bytes); + } + + // Truncate the message if there is a `message_size` parameter given + match message_size { + Some(input) => { + let num_bytes_to_take = + witness_to_value(initial_witness, input.witness)?.to_u128() as usize; + + // If the number of bytes to take is more than the amount of bytes available + // in the message, then we error. + if num_bytes_to_take > message_input.len() { + return Err(OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::Keccak256, + format!("the number of bytes to take from the message is more than the number of bytes in the message. {} > {}", num_bytes_to_take, message_input.len()), + )); + } + let truncated_message = message_input[0..num_bytes_to_take].to_vec(); + Ok(truncated_message) + } + None => Ok(message_input), + } +} + +/// Writes a `digest` to the [`WitnessMap`] at witness indices `outputs`. +fn write_digest_to_outputs( + initial_witness: &mut WitnessMap, + outputs: [Witness; 32], + digest: [u8; 32], +) -> Result<(), OpcodeResolutionError> { + for (output_witness, value) in outputs.iter().zip(digest.into_iter()) { + insert_value( + output_witness, + FieldElement::from_be_bytes_reduce(&[value]), + initial_witness, + )?; + } + + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/logic.rs b/acvm-repo/acvm/src/pwg/blackbox/logic.rs new file mode 100644 index 00000000000..8e69730f71d --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/logic.rs @@ -0,0 +1,56 @@ +use crate::pwg::{insert_value, witness_to_value}; +use crate::OpcodeResolutionError; +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + FieldElement, +}; + +/// Solves a [`BlackBoxFunc::And`][acir::circuit::black_box_functions::BlackBoxFunc::AND] opcode and inserts +/// the result into the supplied witness map +pub(super) fn and( + initial_witness: &mut WitnessMap, + lhs: &FunctionInput, + rhs: &FunctionInput, + output: &Witness, +) -> Result<(), OpcodeResolutionError> { + assert_eq!( + lhs.num_bits, rhs.num_bits, + "number of bits specified for each input must be the same" + ); + solve_logic_opcode(initial_witness, &lhs.witness, &rhs.witness, *output, |left, right| { + left.and(right, lhs.num_bits) + }) +} + +/// Solves a [`BlackBoxFunc::XOR`][acir::circuit::black_box_functions::BlackBoxFunc::XOR] opcode and inserts +/// the result into the supplied witness map +pub(super) fn xor( + initial_witness: &mut WitnessMap, + lhs: &FunctionInput, + rhs: &FunctionInput, + output: &Witness, +) -> Result<(), OpcodeResolutionError> { + assert_eq!( + lhs.num_bits, rhs.num_bits, + "number of bits specified for each input must be the same" + ); + solve_logic_opcode(initial_witness, &lhs.witness, &rhs.witness, *output, |left, right| { + left.xor(right, lhs.num_bits) + }) +} + +/// Derives the rest of the witness based on the initial low level variables +fn solve_logic_opcode( + initial_witness: &mut WitnessMap, + a: &Witness, + b: &Witness, + result: Witness, + logic_op: impl Fn(&FieldElement, &FieldElement) -> FieldElement, +) -> Result<(), OpcodeResolutionError> { + let w_l_value = witness_to_value(initial_witness, *a)?; + let w_r_value = witness_to_value(initial_witness, *b)?; + let assignment = logic_op(w_l_value, w_r_value); + + insert_value(&result, assignment, initial_witness) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs new file mode 100644 index 00000000000..c4d9d561f46 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -0,0 +1,163 @@ +use acir::{ + circuit::opcodes::{BlackBoxFuncCall, FunctionInput}, + native_types::{Witness, WitnessMap}, + FieldElement, +}; +use acvm_blackbox_solver::{blake2s, keccak256, sha256}; + +use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; +use crate::BlackBoxFunctionSolver; + +mod fixed_base_scalar_mul; +mod hash; +mod logic; +mod pedersen; +mod range; +mod signature; + +use fixed_base_scalar_mul::fixed_base_scalar_mul; +// Hash functions should eventually be exposed for external consumers. +use hash::{solve_generic_256_hash_opcode, solve_hash_to_field}; +use logic::{and, xor}; +use pedersen::pedersen; +use range::solve_range_opcode; +use signature::{ + ecdsa::{secp256k1_prehashed, secp256r1_prehashed}, + schnorr::schnorr_verify, +}; + +/// Check if all of the inputs to the function have assignments +/// +/// Returns the first missing assignment if any are missing +fn first_missing_assignment( + witness_assignments: &WitnessMap, + inputs: &[FunctionInput], +) -> Option { + inputs.iter().find_map(|input| { + if witness_assignments.contains_key(&input.witness) { + None + } else { + Some(input.witness) + } + }) +} + +/// Check if all of the inputs to the function have assignments +fn contains_all_inputs(witness_assignments: &WitnessMap, inputs: &[FunctionInput]) -> bool { + inputs.iter().all(|input| witness_assignments.contains_key(&input.witness)) +} + +pub(crate) fn solve( + backend: &impl BlackBoxFunctionSolver, + initial_witness: &mut WitnessMap, + bb_func: &BlackBoxFuncCall, +) -> Result<(), OpcodeResolutionError> { + let inputs = bb_func.get_inputs_vec(); + if !contains_all_inputs(initial_witness, &inputs) { + let unassigned_witness = first_missing_assignment(initial_witness, &inputs) + .expect("Some assignments must be missing because it does not contains all inputs"); + return Err(OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::MissingAssignment(unassigned_witness.0), + )); + } + + match bb_func { + BlackBoxFuncCall::AND { lhs, rhs, output } => and(initial_witness, lhs, rhs, output), + BlackBoxFuncCall::XOR { lhs, rhs, output } => xor(initial_witness, lhs, rhs, output), + BlackBoxFuncCall::RANGE { input } => solve_range_opcode(initial_witness, input), + BlackBoxFuncCall::SHA256 { inputs, outputs } => solve_generic_256_hash_opcode( + initial_witness, + inputs, + None, + outputs, + sha256, + bb_func.get_black_box_func(), + ), + BlackBoxFuncCall::Blake2s { inputs, outputs } => solve_generic_256_hash_opcode( + initial_witness, + inputs, + None, + outputs, + blake2s, + bb_func.get_black_box_func(), + ), + BlackBoxFuncCall::Keccak256 { inputs, outputs } => solve_generic_256_hash_opcode( + initial_witness, + inputs, + None, + outputs, + keccak256, + bb_func.get_black_box_func(), + ), + BlackBoxFuncCall::Keccak256VariableLength { inputs, var_message_size, outputs } => { + solve_generic_256_hash_opcode( + initial_witness, + inputs, + Some(var_message_size), + outputs, + keccak256, + bb_func.get_black_box_func(), + ) + } + BlackBoxFuncCall::HashToField128Security { inputs, output } => { + solve_hash_to_field(initial_witness, inputs, output) + } + BlackBoxFuncCall::SchnorrVerify { + public_key_x, + public_key_y, + signature, + message, + output, + } => schnorr_verify( + backend, + initial_witness, + *public_key_x, + *public_key_y, + signature, + message, + *output, + ), + BlackBoxFuncCall::Pedersen { inputs, domain_separator, outputs } => { + pedersen(backend, initial_witness, inputs, *domain_separator, *outputs) + } + BlackBoxFuncCall::EcdsaSecp256k1 { + public_key_x, + public_key_y, + signature, + hashed_message: message, + output, + } => secp256k1_prehashed( + initial_witness, + public_key_x, + public_key_y, + signature, + message, + *output, + ), + BlackBoxFuncCall::EcdsaSecp256r1 { + public_key_x, + public_key_y, + signature, + hashed_message: message, + output, + } => secp256r1_prehashed( + initial_witness, + public_key_x, + public_key_y, + signature, + message, + *output, + ), + BlackBoxFuncCall::FixedBaseScalarMul { low, high, outputs } => { + fixed_base_scalar_mul(backend, initial_witness, *low, *high, *outputs) + } + BlackBoxFuncCall::RecursiveAggregation { output_aggregation_object, .. } => { + // Solve the output of the recursive aggregation to zero to prevent missing assignment errors + // The correct value will be computed by the backend + for witness in output_aggregation_object { + insert_value(witness, FieldElement::zero(), initial_witness)?; + } + Ok(()) + } + } +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs b/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs new file mode 100644 index 00000000000..44b4c91dc63 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs @@ -0,0 +1,28 @@ +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, +}; + +use crate::{ + pwg::{insert_value, witness_to_value, OpcodeResolutionError}, + BlackBoxFunctionSolver, +}; + +pub(super) fn pedersen( + backend: &impl BlackBoxFunctionSolver, + initial_witness: &mut WitnessMap, + inputs: &[FunctionInput], + domain_separator: u32, + outputs: (Witness, Witness), +) -> Result<(), OpcodeResolutionError> { + let scalars: Result, _> = + inputs.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); + let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); + + let (res_x, res_y) = backend.pedersen(&scalars, domain_separator)?; + + insert_value(&outputs.0, res_x, initial_witness)?; + insert_value(&outputs.1, res_y, initial_witness)?; + + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/range.rs b/acvm-repo/acvm/src/pwg/blackbox/range.rs new file mode 100644 index 00000000000..2c2b96cd753 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/range.rs @@ -0,0 +1,18 @@ +use crate::{ + pwg::{witness_to_value, ErrorLocation}, + OpcodeResolutionError, +}; +use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; + +pub(super) fn solve_range_opcode( + initial_witness: &mut WitnessMap, + input: &FunctionInput, +) -> Result<(), OpcodeResolutionError> { + let w_value = witness_to_value(initial_witness, input.witness)?; + if w_value.num_bits() > input.num_bits { + return Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }); + } + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs new file mode 100644 index 00000000000..8f0df8378ad --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs @@ -0,0 +1,91 @@ +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + FieldElement, +}; +use acvm_blackbox_solver::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; + +use crate::{pwg::insert_value, OpcodeResolutionError}; + +use super::to_u8_vec; + +pub(crate) fn secp256k1_prehashed( + initial_witness: &mut WitnessMap, + public_key_x_inputs: &[FunctionInput], + public_key_y_inputs: &[FunctionInput], + signature_inputs: &[FunctionInput], + hashed_message_inputs: &[FunctionInput], + output: Witness, +) -> Result<(), OpcodeResolutionError> { + let hashed_message = to_u8_vec(initial_witness, hashed_message_inputs)?; + + // These errors should never be emitted in practice as they would imply malformed ACIR generation. + let pub_key_x: [u8; 32] = + to_u8_vec(initial_witness, public_key_x_inputs)?.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::EcdsaSecp256k1, + format!("expected pubkey_x size 32 but received {}", public_key_x_inputs.len()), + ) + })?; + + let pub_key_y: [u8; 32] = + to_u8_vec(initial_witness, public_key_y_inputs)?.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::EcdsaSecp256k1, + format!("expected pubkey_y size 32 but received {}", public_key_y_inputs.len()), + ) + })?; + + let signature: [u8; 64] = + to_u8_vec(initial_witness, signature_inputs)?.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::EcdsaSecp256k1, + format!("expected signature size 64 but received {}", signature_inputs.len()), + ) + })?; + + let is_valid = ecdsa_secp256k1_verify(&hashed_message, &pub_key_x, &pub_key_y, &signature)?; + + insert_value(&output, FieldElement::from(is_valid), initial_witness)?; + Ok(()) +} + +pub(crate) fn secp256r1_prehashed( + initial_witness: &mut WitnessMap, + public_key_x_inputs: &[FunctionInput], + public_key_y_inputs: &[FunctionInput], + signature_inputs: &[FunctionInput], + hashed_message_inputs: &[FunctionInput], + output: Witness, +) -> Result<(), OpcodeResolutionError> { + let hashed_message = to_u8_vec(initial_witness, hashed_message_inputs)?; + + let pub_key_x: [u8; 32] = + to_u8_vec(initial_witness, public_key_x_inputs)?.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::EcdsaSecp256r1, + format!("expected pubkey_x size 32 but received {}", public_key_x_inputs.len()), + ) + })?; + + let pub_key_y: [u8; 32] = + to_u8_vec(initial_witness, public_key_y_inputs)?.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::EcdsaSecp256r1, + format!("expected pubkey_y size 32 but received {}", public_key_y_inputs.len()), + ) + })?; + + let signature: [u8; 64] = + to_u8_vec(initial_witness, signature_inputs)?.try_into().map_err(|_| { + OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::EcdsaSecp256r1, + format!("expected signature size 64 but received {}", signature_inputs.len()), + ) + })?; + + let is_valid = ecdsa_secp256r1_verify(&hashed_message, &pub_key_x, &pub_key_y, &signature)?; + + insert_value(&output, FieldElement::from(is_valid), initial_witness)?; + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs new file mode 100644 index 00000000000..0e28a63ff68 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs @@ -0,0 +1,21 @@ +use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; + +use crate::pwg::{witness_to_value, OpcodeResolutionError}; + +fn to_u8_vec( + initial_witness: &WitnessMap, + inputs: &[FunctionInput], +) -> Result, OpcodeResolutionError> { + let mut result = Vec::with_capacity(inputs.len()); + for input in inputs { + let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); + let byte = witness_value_bytes + .last() + .expect("Field element must be represented by non-zero amount of bytes"); + result.push(*byte); + } + Ok(result) +} + +pub(super) mod ecdsa; +pub(super) mod schnorr; diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs new file mode 100644 index 00000000000..7f5381cee91 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs @@ -0,0 +1,35 @@ +use super::to_u8_vec; +use crate::{ + pwg::{insert_value, witness_to_value, OpcodeResolutionError}, + BlackBoxFunctionSolver, +}; +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + FieldElement, +}; + +#[allow(clippy::too_many_arguments)] +pub(crate) fn schnorr_verify( + backend: &impl BlackBoxFunctionSolver, + initial_witness: &mut WitnessMap, + public_key_x: FunctionInput, + public_key_y: FunctionInput, + signature: &[FunctionInput], + message: &[FunctionInput], + output: Witness, +) -> Result<(), OpcodeResolutionError> { + let public_key_x: &FieldElement = witness_to_value(initial_witness, public_key_x.witness)?; + let public_key_y: &FieldElement = witness_to_value(initial_witness, public_key_y.witness)?; + + let signature = to_u8_vec(initial_witness, signature)?; + + let message = to_u8_vec(initial_witness, message)?; + + let valid_signature = + backend.schnorr_verify(public_key_x, public_key_y, &signature, &message)?; + + insert_value(&output, FieldElement::from(valid_signature), initial_witness)?; + + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs new file mode 100644 index 00000000000..8662dab71e1 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -0,0 +1,163 @@ +use acir::{ + brillig::{RegisterIndex, Value}, + circuit::{ + brillig::{Brillig, BrilligInputs, BrilligOutputs}, + OpcodeLocation, + }, + native_types::WitnessMap, + FieldElement, +}; +use acvm_blackbox_solver::BlackBoxFunctionSolver; +use brillig_vm::{Registers, VMStatus, VM}; + +use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; + +use super::{get_value, insert_value}; + +pub(super) struct BrilligSolver; + +impl BrilligSolver { + pub(super) fn solve( + initial_witness: &mut WitnessMap, + brillig: &Brillig, + bb_solver: &B, + acir_index: usize, + ) -> Result, OpcodeResolutionError> { + // If the predicate is `None`, then we simply return the value 1 + // If the predicate is `Some` but we cannot find a value, then we return stalled + let pred_value = match &brillig.predicate { + Some(pred) => get_value(pred, initial_witness), + None => Ok(FieldElement::one()), + }?; + + // A zero predicate indicates the oracle should be skipped, and its outputs zeroed. + if pred_value.is_zero() { + Self::zero_out_brillig_outputs(initial_witness, brillig)?; + return Ok(None); + } + + // Set input values + let mut input_register_values: Vec = Vec::new(); + let mut input_memory: Vec = Vec::new(); + // Each input represents an expression or array of expressions to evaluate. + // Iterate over each input and evaluate the expression(s) associated with it. + // Push the results into registers and/or memory. + // If a certain expression is not solvable, we stall the ACVM and do not proceed with Brillig VM execution. + for input in &brillig.inputs { + match input { + BrilligInputs::Single(expr) => match get_value(expr, initial_witness) { + Ok(value) => input_register_values.push(value.into()), + Err(_) => { + return Err(OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), + )) + } + }, + BrilligInputs::Array(expr_arr) => { + // Attempt to fetch all array input values + let memory_pointer = input_memory.len(); + for expr in expr_arr.iter() { + match get_value(expr, initial_witness) { + Ok(value) => input_memory.push(value.into()), + Err(_) => { + return Err(OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), + )) + } + } + } + + // Push value of the array pointer as a register + input_register_values.push(Value::from(memory_pointer)); + } + } + } + + // Instantiate a Brillig VM given the solved input registers and memory + // along with the Brillig bytecode, and any present foreign call results. + let input_registers = Registers::load(input_register_values); + let mut vm = VM::new( + input_registers, + input_memory, + brillig.bytecode.clone(), + brillig.foreign_call_results.clone(), + bb_solver, + ); + + // Run the Brillig VM on these inputs, bytecode, etc! + let vm_status = vm.process_opcodes(); + + // Check the status of the Brillig VM. + // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. + // Return the "resolution" to the caller who may choose to make subsequent calls + // (when it gets foreign call results for example). + match vm_status { + VMStatus::Finished => { + for (i, output) in brillig.outputs.iter().enumerate() { + let register_value = vm.get_registers().get(RegisterIndex::from(i)); + match output { + BrilligOutputs::Simple(witness) => { + insert_value(witness, register_value.to_field(), initial_witness)?; + } + BrilligOutputs::Array(witness_arr) => { + // Treat the register value as a pointer to memory + for (i, witness) in witness_arr.iter().enumerate() { + let value = &vm.get_memory()[register_value.to_usize() + i]; + insert_value(witness, value.to_field(), initial_witness)?; + } + } + } + } + Ok(None) + } + VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), + VMStatus::Failure { message, call_stack } => { + Err(OpcodeResolutionError::BrilligFunctionFailed { + message, + call_stack: call_stack + .iter() + .map(|brillig_index| OpcodeLocation::Brillig { + acir_index, + brillig_index: *brillig_index, + }) + .collect(), + }) + } + VMStatus::ForeignCallWait { function, inputs } => { + Ok(Some(ForeignCallWaitInfo { function, inputs })) + } + } + } + + /// Assigns the zero value to all outputs of the given [`Brillig`] bytecode. + fn zero_out_brillig_outputs( + initial_witness: &mut WitnessMap, + brillig: &Brillig, + ) -> Result<(), OpcodeResolutionError> { + for output in &brillig.outputs { + match output { + BrilligOutputs::Simple(witness) => { + insert_value(witness, FieldElement::zero(), initial_witness)? + } + BrilligOutputs::Array(witness_arr) => { + for witness in witness_arr { + insert_value(witness, FieldElement::zero(), initial_witness)? + } + } + } + } + Ok(()) + } +} + +/// Encapsulates a request from a Brillig VM process that encounters a [foreign call opcode][acir::brillig_vm::Opcode::ForeignCall] +/// where the result of the foreign call has not yet been provided. +/// +/// The caller must resolve this opcode externally based upon the information in the request. +#[derive(Debug, PartialEq, Clone)] +pub struct ForeignCallWaitInfo { + /// An identifier interpreted by the caller process + pub function: String, + /// Resolved inputs to a foreign call computed in the previous steps of a Brillig VM process + pub inputs: Vec>, +} diff --git a/acvm-repo/acvm/src/pwg/directives/mod.rs b/acvm-repo/acvm/src/pwg/directives/mod.rs new file mode 100644 index 00000000000..d7dbb3edaf2 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/directives/mod.rs @@ -0,0 +1,150 @@ +use std::cmp::Ordering; + +use acir::{ + circuit::directives::{Directive, QuotientDirective}, + native_types::WitnessMap, + FieldElement, +}; +use num_bigint::BigUint; +use num_traits::Zero; + +use crate::OpcodeResolutionError; + +use super::{get_value, insert_value, ErrorLocation}; + +mod sorting; + +/// Attempts to solve the [`Directive`] opcode `directive`. +/// If successful, `initial_witness` will be mutated to contain the new witness assignment. +/// +/// Returns `Ok(OpcodeResolution)` to signal whether the directive was successful solved. +/// +/// Returns `Err(OpcodeResolutionError)` if a circuit constraint is unsatisfied. +pub(super) fn solve_directives( + initial_witness: &mut WitnessMap, + directive: &Directive, +) -> Result<(), OpcodeResolutionError> { + match directive { + Directive::Quotient(QuotientDirective { a, b, q, r, predicate }) => { + let val_a = get_value(a, initial_witness)?; + let val_b = get_value(b, initial_witness)?; + let int_a = BigUint::from_bytes_be(&val_a.to_be_bytes()); + let int_b = BigUint::from_bytes_be(&val_b.to_be_bytes()); + + // If the predicate is `None`, then we simply return the value 1 + // If the predicate is `Some` but we cannot find a value, then we return unresolved + let pred_value = match predicate { + Some(pred) => get_value(pred, initial_witness)?, + None => FieldElement::one(), + }; + + let (int_r, int_q) = if pred_value.is_zero() || int_b.is_zero() { + (BigUint::zero(), BigUint::zero()) + } else { + (&int_a % &int_b, &int_a / &int_b) + }; + + insert_value( + q, + FieldElement::from_be_bytes_reduce(&int_q.to_bytes_be()), + initial_witness, + )?; + insert_value( + r, + FieldElement::from_be_bytes_reduce(&int_r.to_bytes_be()), + initial_witness, + )?; + + Ok(()) + } + Directive::ToLeRadix { a, b, radix } => { + let value_a = get_value(a, initial_witness)?; + let big_integer = BigUint::from_bytes_be(&value_a.to_be_bytes()); + + // Decompose the integer into its radix digits in little endian form. + let decomposed_integer = big_integer.to_radix_le(*radix); + + if b.len() < decomposed_integer.len() { + return Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }); + } + + for (i, witness) in b.iter().enumerate() { + // Fetch the `i'th` digit from the decomposed integer list + // and convert it to a field element. + // If it is not available, which can happen when the decomposed integer + // list is shorter than the witness list, we return 0. + let value = match decomposed_integer.get(i) { + Some(digit) => FieldElement::from_be_bytes_reduce(&[*digit]), + None => FieldElement::zero(), + }; + + insert_value(witness, value, initial_witness)? + } + + Ok(()) + } + Directive::PermutationSort { inputs: a, tuple, bits, sort_by } => { + let mut val_a = Vec::new(); + let mut base = Vec::new(); + for (i, element) in a.iter().enumerate() { + assert_eq!(element.len(), *tuple as usize); + let mut element_val = Vec::with_capacity(*tuple as usize + 1); + for e in element { + element_val.push(get_value(e, initial_witness)?); + } + let field_i = FieldElement::from(i as i128); + element_val.push(field_i); + base.push(field_i); + val_a.push(element_val); + } + val_a.sort_by(|a, b| { + for i in sort_by { + let int_a = BigUint::from_bytes_be(&a[*i as usize].to_be_bytes()); + let int_b = BigUint::from_bytes_be(&b[*i as usize].to_be_bytes()); + let cmp = int_a.cmp(&int_b); + if cmp != Ordering::Equal { + return cmp; + } + } + Ordering::Equal + }); + let b = val_a.iter().map(|a| *a.last().unwrap()).collect(); + let control = sorting::route(base, b); + for (w, value) in bits.iter().zip(control) { + let value = if value { FieldElement::one() } else { FieldElement::zero() }; + insert_value(w, value, initial_witness)?; + } + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use acir::{ + circuit::directives::{Directive, QuotientDirective}, + native_types::{Expression, Witness, WitnessMap}, + FieldElement, + }; + + use super::solve_directives; + + #[test] + fn divisor_is_zero() { + let quotient_directive = QuotientDirective { + a: Expression::zero(), + b: Expression::zero(), + q: Witness(0), + r: Witness(0), + predicate: Some(Expression::one()), + }; + + let mut witness_map = WitnessMap::new(); + witness_map.insert(Witness(0), FieldElement::zero()); + + solve_directives(&mut witness_map, &Directive::Quotient(quotient_directive)) + .expect("expected 0/0 to return 0"); + } +} diff --git a/acvm-repo/acvm/src/pwg/directives/sorting.rs b/acvm-repo/acvm/src/pwg/directives/sorting.rs new file mode 100644 index 00000000000..5ff43320226 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/directives/sorting.rs @@ -0,0 +1,396 @@ +use std::collections::{BTreeMap, BTreeSet}; + +use acir::FieldElement; + +// A sorting network is a graph of connected switches +// It is defined recursively so here we only keep track of the outer layer of switches +struct SortingNetwork { + n: usize, // size of the network + x_inputs: Vec, // inputs of the network + y_inputs: Vec, // outputs of the network + x_values: BTreeMap, // map for matching a y value with a x value + y_values: BTreeMap, // map for matching a x value with a y value + inner_x: Vec, // positions after the switch_x + inner_y: Vec, // positions after the sub-networks, and before the switch_y + switch_x: Vec, // outer switches for the inputs + switch_y: Vec, // outer switches for the outputs + free: BTreeSet, // outer switches available for looping +} + +impl SortingNetwork { + fn new(n: usize) -> SortingNetwork { + let free_len = (n - 1) / 2; + let mut free = BTreeSet::new(); + for i in 0..free_len { + free.insert(i); + } + SortingNetwork { + n, + x_inputs: Vec::with_capacity(n), + y_inputs: Vec::with_capacity(n), + x_values: BTreeMap::new(), + y_values: BTreeMap::new(), + inner_x: Vec::with_capacity(n), + inner_y: Vec::with_capacity(n), + switch_x: Vec::with_capacity(n / 2), + switch_y: Vec::with_capacity(free_len), + free, + } + } + + fn init(&mut self, inputs: Vec, outputs: Vec) { + let n = self.n; + assert_eq!(inputs.len(), outputs.len()); + assert_eq!(inputs.len(), n); + + self.x_inputs = inputs; + self.y_inputs = outputs; + for i in 0..self.n { + self.x_values.insert(self.x_inputs[i], i); + self.y_values.insert(self.y_inputs[i], i); + } + self.switch_x = vec![false; n / 2]; + self.switch_y = vec![false; (n - 1) / 2]; + self.inner_x = vec![FieldElement::zero(); n]; + self.inner_y = vec![FieldElement::zero(); n]; + + //Route the single wires so we do not need to handle this case later on + self.inner_y[n - 1] = self.y_inputs[n - 1]; + if n % 2 == 0 { + self.inner_y[n / 2 - 1] = self.y_inputs[n - 2]; + } else { + self.inner_x[n - 1] = self.x_inputs[n - 1]; + } + } + + //route a wire from outputs to its value in the inputs + fn route_out_wire(&mut self, y: usize, sub: bool) -> usize { + // sub <- y + if self.is_single_y(y) { + assert!(sub); + } else { + let port = y % 2 != 0; + let s1 = sub ^ port; + let inner = self.compute_inner(y, s1); + self.configure_y(y, s1, inner); + } + // x <- sub + let x = self.x_values.remove(&self.y_inputs[y]).unwrap(); + if !self.is_single_x(x) { + let port2 = x % 2 != 0; + let s2 = sub ^ port2; + let inner = self.compute_inner(x, s2); + self.configure_x(x, s2, inner); + } + x + } + + //route a wire from inputs to its value in the outputs + fn route_in_wire(&mut self, x: usize, sub: bool) -> usize { + // x -> sub + assert!(!self.is_single_x(x)); + let port = x % 2 != 0; + let s1 = sub ^ port; + let inner = self.compute_inner(x, s1); + self.configure_x(x, s1, inner); + + // sub -> y + let y = self.y_values.remove(&self.x_inputs[x]).unwrap(); + if !self.is_single_y(y) { + let port = y % 2 != 0; + let s2 = sub ^ port; + let inner = self.compute_inner(y, s2); + self.configure_y(y, s2, inner); + } + y + } + + //update the computed switch and inner values for an input wire + fn configure_x(&mut self, x: usize, switch: bool, inner: usize) { + self.inner_x[inner] = self.x_inputs[x]; + self.switch_x[x / 2] = switch; + } + + //update the computed switch and inner values for an output wire + fn configure_y(&mut self, y: usize, switch: bool, inner: usize) { + self.inner_y[inner] = self.y_inputs[y]; + self.switch_y[y / 2] = switch; + } + + // returns the other wire belonging to the same switch + fn sibling(index: usize) -> usize { + index + 1 - 2 * (index % 2) + } + + // returns a free switch + fn take(&mut self) -> Option { + self.free.first().copied() + } + + fn is_single_x(&self, a: usize) -> bool { + let n = self.x_inputs.len(); + n % 2 == 1 && a == n - 1 + } + + fn is_single_y(&mut self, a: usize) -> bool { + let n = self.x_inputs.len(); + a >= n - 2 + n % 2 + } + + // compute the inner position of idx through its switch + fn compute_inner(&self, idx: usize, switch: bool) -> usize { + if switch ^ (idx % 2 == 1) { + idx / 2 + self.n / 2 + } else { + idx / 2 + } + } + + fn new_start(&mut self) -> (Option, usize) { + let next = self.take(); + if let Some(switch) = next { + (next, 2 * switch) + } else { + (None, 0) + } + } +} + +// Computes the control bits of the sorting network which transform inputs into outputs +// implementation is based on https://www.mdpi.com/2227-7080/10/1/16 +pub(super) fn route(inputs: Vec, outputs: Vec) -> Vec { + assert_eq!(inputs.len(), outputs.len()); + match inputs.len() { + 0 => Vec::new(), + 1 => { + assert_eq!(inputs[0], outputs[0]); + Vec::new() + } + 2 => { + if inputs[0] == outputs[0] { + assert_eq!(inputs[1], outputs[1]); + vec![false] + } else { + assert_eq!(inputs[1], outputs[0]); + assert_eq!(inputs[0], outputs[1]); + vec![true] + } + } + _ => { + let n = inputs.len(); + + let mut result; + let n1 = n / 2; + let in_sub1; + let out_sub1; + let in_sub2; + let out_sub2; + + // process the outer layer in a code block so that the intermediate data is cleared before recursion + { + let mut network = SortingNetwork::new(n); + network.init(inputs, outputs); + + //We start with the last single wire + let mut out_idx = n - 1; + let mut start_sub = true; //it is connected to the lower inner network + let mut switch = None; + let mut start = None; + + while !network.free.is_empty() { + // the processed switch is no more available + if let Some(free_switch) = switch { + network.free.remove(&free_switch); + } + + // connect the output wire to its matching input + let in_idx = network.route_out_wire(out_idx, start_sub); + if network.is_single_x(in_idx) { + start_sub = !start_sub; //We need to restart, but did not complete the loop so we switch the sub network + (start, out_idx) = network.new_start(); + switch = start; + continue; + } + + // loop from the sibling + let next = SortingNetwork::sibling(in_idx); + // connect the input wire to its matching output, using the other sub-network + out_idx = network.route_in_wire(next, !start_sub); + switch = Some(out_idx / 2); + if start == switch || network.is_single_y(out_idx) { + //loop is complete, need a fresh start + (start, out_idx) = network.new_start(); + switch = start; + } else { + // we loop back from the sibling + out_idx = SortingNetwork::sibling(out_idx); + } + } + //All the wires are connected, we can now route the sub-networks + result = network.switch_x; + result.extend(network.switch_y); + in_sub1 = network.inner_x[0..n1].to_vec(); + in_sub2 = network.inner_x[n1..].to_vec(); + out_sub1 = network.inner_y[0..n1].to_vec(); + out_sub2 = network.inner_y[n1..].to_vec(); + } + let s1 = route(in_sub1, out_sub1); + result.extend(s1); + let s2 = route(in_sub2, out_sub2); + result.extend(s2); + result + } + } +} + +#[cfg(test)] +mod tests { + // Silence `unused_crate_dependencies` warning + use paste as _; + use proptest as _; + + use super::route; + use acir::FieldElement; + use rand::prelude::*; + + fn execute_network(config: Vec, inputs: Vec) -> Vec { + let n = inputs.len(); + if n == 1 { + return inputs; + } + let mut in1 = Vec::new(); + let mut in2 = Vec::new(); + //layer 1: + for i in 0..n / 2 { + if config[i] { + in1.push(inputs[2 * i + 1]); + in2.push(inputs[2 * i]); + } else { + in1.push(inputs[2 * i]); + in2.push(inputs[2 * i + 1]); + } + } + if n % 2 == 1 { + in2.push(*inputs.last().unwrap()); + } + let n2 = n / 2 + (n - 1) / 2; + let n3 = n2 + switch_nb(n / 2); + let mut result = Vec::new(); + let out1 = execute_network(config[n2..n3].to_vec(), in1); + let out2 = execute_network(config[n3..].to_vec(), in2); + //last layer: + for i in 0..(n - 1) / 2 { + if config[n / 2 + i] { + result.push(out2[i]); + result.push(out1[i]); + } else { + result.push(out1[i]); + result.push(out2[i]); + } + } + if n % 2 == 0 { + result.push(*out1.last().unwrap()); + result.push(*out2.last().unwrap()); + } else { + result.push(*out2.last().unwrap()) + } + result + } + + // returns the number of switches in the network + fn switch_nb(n: usize) -> usize { + let mut s = 0; + for i in 0..n { + s += f64::from((i + 1) as u32).log2().ceil() as usize; + } + s + } + + #[test] + fn test_route() { + //basic tests + let a = vec![ + FieldElement::from(1_i128), + FieldElement::from(2_i128), + FieldElement::from(3_i128), + ]; + let b = vec![ + FieldElement::from(1_i128), + FieldElement::from(2_i128), + FieldElement::from(3_i128), + ]; + let c = route(a, b); + assert_eq!(c, vec![false, false, false]); + + let a = vec![ + FieldElement::from(1_i128), + FieldElement::from(2_i128), + FieldElement::from(3_i128), + ]; + let b = vec![ + FieldElement::from(1_i128), + FieldElement::from(3_i128), + FieldElement::from(2_i128), + ]; + let c = route(a, b); + assert_eq!(c, vec![false, false, true]); + + let a = vec![ + FieldElement::from(1_i128), + FieldElement::from(2_i128), + FieldElement::from(3_i128), + ]; + let b = vec![ + FieldElement::from(3_i128), + FieldElement::from(2_i128), + FieldElement::from(1_i128), + ]; + let c = route(a, b); + assert_eq!(c, vec![true, true, true]); + + let a = vec![ + FieldElement::from(0_i128), + FieldElement::from(1_i128), + FieldElement::from(2_i128), + FieldElement::from(3_i128), + ]; + let b = vec![ + FieldElement::from(2_i128), + FieldElement::from(3_i128), + FieldElement::from(0_i128), + FieldElement::from(1_i128), + ]; + let c = route(a, b); + assert_eq!(c, vec![false, true, true, true, true]); + + let a = vec![ + FieldElement::from(0_i128), + FieldElement::from(1_i128), + FieldElement::from(2_i128), + FieldElement::from(3_i128), + FieldElement::from(4_i128), + ]; + let b = vec![ + FieldElement::from(0_i128), + FieldElement::from(3_i128), + FieldElement::from(4_i128), + FieldElement::from(2_i128), + FieldElement::from(1_i128), + ]; + let c = route(a, b); + assert_eq!(c, vec![false, false, false, true, false, true, false, true]); + + // random tests + for i in 2..50 { + let mut a = vec![FieldElement::zero()]; + for j in 0..i - 1 { + a.push(a[j] + FieldElement::one()); + } + let mut rng = rand::thread_rng(); + let mut b = a.clone(); + b.shuffle(&mut rng); + let c = route(a.clone(), b.clone()); + assert_eq!(b, execute_network(c, a)); + } + } +} diff --git a/acvm-repo/acvm/src/pwg/memory_op.rs b/acvm-repo/acvm/src/pwg/memory_op.rs new file mode 100644 index 00000000000..42951dfa3c1 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/memory_op.rs @@ -0,0 +1,259 @@ +use std::collections::HashMap; + +use acir::{ + circuit::opcodes::MemOp, + native_types::{Expression, Witness, WitnessMap}, + FieldElement, +}; + +use super::{arithmetic::ArithmeticSolver, get_value, insert_value, witness_to_value}; +use super::{ErrorLocation, OpcodeResolutionError}; + +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, +} + +impl MemoryOpSolver { + fn write_memory_index( + &mut self, + index: MemoryIndex, + value: FieldElement, + ) -> Result<(), OpcodeResolutionError> { + if index >= self.block_len { + return Err(OpcodeResolutionError::IndexOutOfBounds { + opcode_location: ErrorLocation::Unresolved, + index, + array_size: self.block_len, + }); + } + self.block_value.insert(index, value); + Ok(()) + } + + fn read_memory_index(&self, index: MemoryIndex) -> Result { + self.block_value.get(&index).copied().ok_or(OpcodeResolutionError::IndexOutOfBounds { + opcode_location: ErrorLocation::Unresolved, + index, + array_size: self.block_len, + }) + } + + /// Set the block_value from a MemoryInit opcode + pub(crate) fn init( + &mut self, + init: &[Witness], + initial_witness: &WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + self.block_len = init.len() as u32; + for (memory_index, witness) in init.iter().enumerate() { + self.write_memory_index( + memory_index as MemoryIndex, + *witness_to_value(initial_witness, *witness)?, + )?; + } + Ok(()) + } + + pub(crate) fn solve_memory_op( + &mut self, + op: &MemOp, + initial_witness: &mut WitnessMap, + predicate: &Option, + ) -> Result<(), OpcodeResolutionError> { + let operation = get_value(&op.operation, initial_witness)?; + + // Find the memory index associated with this memory operation. + let index = get_value(&op.index, initial_witness)?; + let memory_index = index.try_to_u64().unwrap() as MemoryIndex; + + // Calculate the value associated with this memory operation. + // + // In read operations, this corresponds to the witness index at which the value from memory will be written. + // In write operations, this corresponds to the expression which will be written to memory. + let value = ArithmeticSolver::evaluate(&op.value, initial_witness); + + // `operation == 0` implies a read operation. (`operation == 1` implies write operation). + let is_read_operation = operation.is_zero(); + + // If the predicate is `None`, then we simply return the value 1 + let pred_value = match predicate { + Some(pred) => get_value(pred, initial_witness), + None => Ok(FieldElement::one()), + }?; + + if is_read_operation { + // `value_read = arr[memory_index]` + // + // This is the value that we want to read into; i.e. copy from the memory block + // into this value. + let value_read_witness = value.to_witness().expect( + "Memory must be read into a specified witness index, encountered an Expression", + ); + + // A zero predicate indicates that we should skip the read operation + // and zero out the operation's output. + let value_in_array = if pred_value.is_zero() { + FieldElement::zero() + } else { + self.read_memory_index(memory_index)? + }; + insert_value(&value_read_witness, value_in_array, initial_witness) + } else { + // `arr[memory_index] = value_write` + // + // This is the value that we want to write into; i.e. copy from `value_write` + // into the memory block. + let value_write = value; + + // A zero predicate indicates that we should skip the write operation. + if pred_value.is_zero() { + // We only want to write to already initialized memory. + // Do nothing if the predicate is zero. + Ok(()) + } else { + let value_to_write = get_value(&value_write, initial_witness)?; + self.write_memory_index(memory_index, value_to_write) + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use acir::{ + circuit::opcodes::MemOp, + native_types::{Expression, Witness, WitnessMap}, + FieldElement, + }; + + use super::MemoryOpSolver; + + #[test] + fn test_solver() { + let mut initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(1u128)), + (Witness(3), FieldElement::from(2u128)), + ])); + + let init = vec![Witness(1), Witness(2)]; + + let trace = vec![ + MemOp::write_to_mem_index(FieldElement::from(1u128).into(), Witness(3).into()), + MemOp::read_at_mem_index(FieldElement::one().into(), Witness(4)), + ]; + + let mut block_solver = MemoryOpSolver::default(); + block_solver.init(&init, &initial_witness).unwrap(); + + for op in trace { + block_solver.solve_memory_op(&op, &mut initial_witness, &None).unwrap(); + } + + assert_eq!(initial_witness[&Witness(4)], FieldElement::from(2u128)); + } + + #[test] + fn test_index_out_of_bounds() { + let mut initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(1u128)), + (Witness(3), FieldElement::from(2u128)), + ])); + + let init = vec![Witness(1), Witness(2)]; + + let invalid_trace = vec![ + MemOp::write_to_mem_index(FieldElement::from(1u128).into(), Witness(3).into()), + MemOp::read_at_mem_index(FieldElement::from(2u128).into(), Witness(4)), + ]; + let mut block_solver = MemoryOpSolver::default(); + block_solver.init(&init, &initial_witness).unwrap(); + let mut err = None; + for op in invalid_trace { + if err.is_none() { + err = block_solver.solve_memory_op(&op, &mut initial_witness, &None).err(); + } + } + + assert!(matches!( + err, + Some(crate::pwg::OpcodeResolutionError::IndexOutOfBounds { + opcode_location: _, + index: 2, + array_size: 2 + }) + )); + } + + #[test] + fn test_predicate_on_read() { + let mut initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(1u128)), + (Witness(3), FieldElement::from(2u128)), + ])); + + let init = vec![Witness(1), Witness(2)]; + + let invalid_trace = vec![ + MemOp::write_to_mem_index(FieldElement::from(1u128).into(), Witness(3).into()), + MemOp::read_at_mem_index(FieldElement::from(2u128).into(), Witness(4)), + ]; + let mut block_solver = MemoryOpSolver::default(); + block_solver.init(&init, &initial_witness).unwrap(); + let mut err = None; + for op in invalid_trace { + if err.is_none() { + err = block_solver + .solve_memory_op(&op, &mut initial_witness, &Some(Expression::zero())) + .err(); + } + } + + // Should have no index out of bounds error where predicate is zero + assert_eq!(err, None); + // The result of a read under a zero predicate should be zero + assert_eq!(initial_witness[&Witness(4)], FieldElement::from(0u128)); + } + + #[test] + fn test_predicate_on_write() { + let mut initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(1u128)), + (Witness(3), FieldElement::from(2u128)), + ])); + + let init = vec![Witness(1), Witness(2)]; + + let invalid_trace = vec![ + MemOp::write_to_mem_index(FieldElement::from(2u128).into(), Witness(3).into()), + MemOp::read_at_mem_index(FieldElement::from(0u128).into(), Witness(4)), + MemOp::read_at_mem_index(FieldElement::from(1u128).into(), Witness(5)), + ]; + let mut block_solver = MemoryOpSolver::default(); + block_solver.init(&init, &initial_witness).unwrap(); + let mut err = None; + for op in invalid_trace { + if err.is_none() { + err = block_solver + .solve_memory_op(&op, &mut initial_witness, &Some(Expression::zero())) + .err(); + } + } + + // Should have no index out of bounds error where predicate is zero + assert_eq!(err, None); + // The memory under a zero predicate should be zeroed out + assert_eq!(initial_witness[&Witness(4)], FieldElement::from(0u128)); + assert_eq!(initial_witness[&Witness(5)], FieldElement::from(0u128)); + } +} diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs new file mode 100644 index 00000000000..3fcf1088225 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -0,0 +1,399 @@ +// Re-usable methods that backends can use to implement their PWG + +use std::collections::HashMap; + +use acir::{ + brillig::ForeignCallResult, + circuit::{opcodes::BlockId, Opcode, OpcodeLocation}, + native_types::{Expression, Witness, WitnessMap}, + BlackBoxFunc, FieldElement, +}; +use acvm_blackbox_solver::BlackBoxResolutionError; + +use self::{ + arithmetic::ArithmeticSolver, brillig::BrilligSolver, directives::solve_directives, + memory_op::MemoryOpSolver, +}; +use crate::{BlackBoxFunctionSolver, Language}; + +use thiserror::Error; + +// arithmetic +pub(crate) mod arithmetic; +// Brillig bytecode +mod brillig; +// Directives +mod directives; +// black box functions +mod blackbox; +mod memory_op; + +pub use brillig::ForeignCallWaitInfo; + +#[derive(Debug, Clone, PartialEq)] +pub enum ACVMStatus { + /// All opcodes have been solved. + Solved, + + /// The ACVM is in the process of executing the circuit. + InProgress, + + /// The ACVM has encountered an irrecoverable error while executing the circuit and can not progress. + /// Most commonly this will be due to an unsatisfied constraint due to invalid inputs to the circuit. + Failure(OpcodeResolutionError), + + /// The ACVM has encountered a request for a Brillig [foreign call][acir::brillig_vm::Opcode::ForeignCall] + /// to retrieve information from outside of the ACVM. The result of the foreign call must be passed back + /// to the ACVM using [`ACVM::resolve_pending_foreign_call`]. + /// + /// Once this is done, the ACVM can be restarted to solve the remaining opcodes. + RequiresForeignCall(ForeignCallWaitInfo), +} + +impl std::fmt::Display for ACVMStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ACVMStatus::Solved => write!(f, "Solved"), + ACVMStatus::InProgress => write!(f, "In progress"), + ACVMStatus::Failure(_) => write!(f, "Execution failure"), + ACVMStatus::RequiresForeignCall(_) => write!(f, "Waiting on foreign call"), + } + } +} + +// This enum represents the different cases in which an +// opcode can be unsolvable. +// The most common being that one of its input has not been +// assigned a value. +// +// TODO: ExpressionHasTooManyUnknowns is specific for arithmetic expressions +// TODO: we could have a error enum for arithmetic failure cases in that module +// TODO that can be converted into an OpcodeNotSolvable or OpcodeResolutionError enum +#[derive(Clone, PartialEq, Eq, Debug, Error)] +pub enum OpcodeNotSolvable { + #[error("missing assignment for witness index {0}")] + MissingAssignment(u32), + #[error("expression has too many unknowns {0}")] + ExpressionHasTooManyUnknowns(Expression), +} + +/// Allows to point to a specific opcode as cause in errors. +/// Some errors don't have a specific opcode associated with them, or are created without one and added later. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +pub enum ErrorLocation { + #[default] + Unresolved, + Resolved(OpcodeLocation), +} + +impl std::fmt::Display for ErrorLocation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ErrorLocation::Unresolved => write!(f, "unresolved"), + ErrorLocation::Resolved(location) => { + write!(f, "{location}") + } + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Error)] +pub enum OpcodeResolutionError { + #[error("Cannot solve opcode: {0}")] + OpcodeNotSolvable(#[from] OpcodeNotSolvable), + #[error("Backend does not currently support the {0} opcode. ACVM does not currently have a fallback for this opcode.")] + UnsupportedBlackBoxFunc(BlackBoxFunc), + #[error("Cannot satisfy constraint")] + UnsatisfiedConstrain { opcode_location: ErrorLocation }, + #[error("Index out of bounds, array has size {array_size:?}, but index was {index:?}")] + IndexOutOfBounds { opcode_location: ErrorLocation, index: u32, array_size: u32 }, + #[error("Failed to solve blackbox function: {0}, reason: {1}")] + BlackBoxFunctionFailed(BlackBoxFunc, String), + #[error("Failed to solve brillig function, reason: {message}")] + BrilligFunctionFailed { message: String, call_stack: Vec }, +} + +impl From for OpcodeResolutionError { + fn from(value: BlackBoxResolutionError) -> Self { + match value { + BlackBoxResolutionError::Failed(func, reason) => { + OpcodeResolutionError::BlackBoxFunctionFailed(func, reason) + } + BlackBoxResolutionError::Unsupported(func) => { + OpcodeResolutionError::UnsupportedBlackBoxFunc(func) + } + } + } +} + +pub struct ACVM<'backend, B: BlackBoxFunctionSolver> { + status: ACVMStatus, + + backend: &'backend B, + + /// Stores the solver for memory operations acting on blocks of memory disambiguated by [block][`BlockId`]. + block_solvers: HashMap, + + /// A list of opcodes which are to be executed by the ACVM. + opcodes: Vec, + /// Index of the next opcode to be executed. + instruction_pointer: usize, + + witness_map: WitnessMap, +} + +impl<'backend, B: BlackBoxFunctionSolver> ACVM<'backend, B> { + pub fn new(backend: &'backend B, opcodes: Vec, initial_witness: WitnessMap) -> Self { + let status = if opcodes.is_empty() { ACVMStatus::Solved } else { ACVMStatus::InProgress }; + ACVM { + status, + backend, + block_solvers: HashMap::default(), + opcodes, + instruction_pointer: 0, + witness_map: initial_witness, + } + } + + /// Returns a reference to the current state of the ACVM's [`WitnessMap`]. + /// + /// Once execution has completed, the witness map can be extracted using [`ACVM::finalize`] + pub fn witness_map(&self) -> &WitnessMap { + &self.witness_map + } + + /// Returns a slice containing the opcodes of the circuit being executed. + pub fn opcodes(&self) -> &[Opcode] { + &self.opcodes + } + + /// Returns the index of the current opcode to be executed. + pub fn instruction_pointer(&self) -> usize { + self.instruction_pointer + } + + /// Finalize the ACVM execution, returning the resulting [`WitnessMap`]. + pub fn finalize(self) -> WitnessMap { + if self.status != ACVMStatus::Solved { + panic!("ACVM execution is not complete: ({})", self.status); + } + self.witness_map + } + + /// Updates the current status of the VM. + /// Returns the given status. + fn status(&mut self, status: ACVMStatus) -> ACVMStatus { + self.status = status.clone(); + status + } + + /// Sets the VM status to [ACVMStatus::Failure] using the provided `error`. + /// Returns the new status. + fn fail(&mut self, error: OpcodeResolutionError) -> ACVMStatus { + self.status(ACVMStatus::Failure(error)) + } + + /// Sets the status of the VM to `RequiresForeignCall`. + /// Indicating that the VM is now waiting for a foreign call to be resolved. + fn wait_for_foreign_call(&mut self, foreign_call: ForeignCallWaitInfo) -> ACVMStatus { + self.status(ACVMStatus::RequiresForeignCall(foreign_call)) + } + + /// Return a reference to the arguments for the next pending foreign call, if one exists. + pub fn get_pending_foreign_call(&self) -> Option<&ForeignCallWaitInfo> { + if let ACVMStatus::RequiresForeignCall(foreign_call) = &self.status { + Some(foreign_call) + } else { + None + } + } + + /// Resolves a foreign call's [result][acir::brillig_vm::ForeignCallResult] using a result calculated outside of the ACVM. + /// + /// The ACVM can then be restarted to solve the remaining Brillig VM process as well as the remaining ACIR opcodes. + pub fn resolve_pending_foreign_call(&mut self, foreign_call_result: ForeignCallResult) { + if !matches!(self.status, ACVMStatus::RequiresForeignCall(_)) { + panic!("ACVM is not expecting a foreign call response as no call was made"); + } + + // We want to inject the foreign call result into the brillig opcode which initiated the call. + let opcode = &mut self.opcodes[self.instruction_pointer]; + let Opcode::Brillig(brillig) = opcode else { + unreachable!("ACVM can only enter `RequiresForeignCall` state on a Brillig opcode"); + }; + brillig.foreign_call_results.push(foreign_call_result); + + // Now that the foreign call has been resolved then we can resume execution. + self.status(ACVMStatus::InProgress); + } + + /// Executes the ACVM's circuit until execution halts. + /// + /// Execution can halt due to three reasons: + /// 1. All opcodes have been executed successfully. + /// 2. The circuit has been found to be unsatisfiable. + /// 2. A Brillig [foreign call][`ForeignCallWaitInfo`] has been encountered and must be resolved. + pub fn solve(&mut self) -> ACVMStatus { + while self.status == ACVMStatus::InProgress { + self.solve_opcode(); + } + self.status.clone() + } + + pub fn solve_opcode(&mut self) -> ACVMStatus { + let opcode = &self.opcodes[self.instruction_pointer]; + + let resolution = match opcode { + Opcode::Arithmetic(expr) => ArithmeticSolver::solve(&mut self.witness_map, expr), + Opcode::BlackBoxFuncCall(bb_func) => { + blackbox::solve(self.backend, &mut self.witness_map, bb_func) + } + 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(); + solver.init(init, &self.witness_map) + } + Opcode::MemoryOp { block_id, op, predicate } => { + let solver = self.block_solvers.entry(*block_id).or_default(); + solver.solve_memory_op(op, &mut self.witness_map, predicate) + } + Opcode::Brillig(brillig) => { + match BrilligSolver::solve( + &mut self.witness_map, + brillig, + self.backend, + self.instruction_pointer, + ) { + Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call), + res => res.map(|_| ()), + } + } + }; + match resolution { + Ok(()) => { + self.instruction_pointer += 1; + if self.instruction_pointer == self.opcodes.len() { + self.status(ACVMStatus::Solved) + } else { + self.status(ACVMStatus::InProgress) + } + } + Err(mut error) => { + match &mut error { + // If we have an index out of bounds or an unsatisfied constraint, the opcode label will be unresolved + // because the solvers do not have knowledge of this information. + // We resolve, by setting this to the corresponding opcode that we just attempted to solve. + OpcodeResolutionError::IndexOutOfBounds { + opcode_location: opcode_index, + .. + } + | OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: opcode_index, + } => { + *opcode_index = ErrorLocation::Resolved(OpcodeLocation::Acir( + self.instruction_pointer(), + )); + } + // All other errors are thrown normally. + _ => (), + }; + self.fail(error) + } + } + } +} + +// Returns the concrete value for a particular witness +// If the witness has no assignment, then +// an error is returned +pub fn witness_to_value( + initial_witness: &WitnessMap, + witness: Witness, +) -> Result<&FieldElement, OpcodeResolutionError> { + match initial_witness.get(&witness) { + Some(value) => Ok(value), + None => Err(OpcodeNotSolvable::MissingAssignment(witness.0).into()), + } +} + +// TODO: There is an issue open to decide on whether we need to get values from Expressions +// TODO versus just getting values from Witness +pub fn get_value( + expr: &Expression, + initial_witness: &WitnessMap, +) -> Result { + let expr = ArithmeticSolver::evaluate(expr, initial_witness); + match expr.to_const() { + Some(value) => Ok(value), + None => Err(OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::MissingAssignment(any_witness_from_expression(&expr).unwrap().0), + )), + } +} + +/// Inserts `value` into the initial witness map under the index `witness`. +/// +/// Returns an error if there was already a value in the map +/// which does not match the value that one is about to insert +pub fn insert_value( + witness: &Witness, + value_to_insert: FieldElement, + initial_witness: &mut WitnessMap, +) -> Result<(), OpcodeResolutionError> { + let optional_old_value = initial_witness.insert(*witness, value_to_insert); + + let old_value = match optional_old_value { + Some(old_value) => old_value, + None => return Ok(()), + }; + + if old_value != value_to_insert { + return Err(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Unresolved, + }); + } + + Ok(()) +} + +// Returns one witness belonging to an expression, in no relevant order +// Returns None if the expression is const +// The function is used during partial witness generation to report unsolved witness +fn any_witness_from_expression(expr: &Expression) -> Option { + if expr.linear_combinations.is_empty() { + if expr.mul_terms.is_empty() { + None + } else { + Some(expr.mul_terms[0].1) + } + } else { + Some(expr.linear_combinations[0].1) + } +} + +#[deprecated( + note = "For backwards compatibility, this method allows you to derive _sensible_ defaults for opcode support based on the np language. \n Backends should simply specify what they support." +)] +// This is set to match the previous functionality that we had +// Where we could deduce what opcodes were supported +// by knowing the np complete language +pub fn default_is_opcode_supported(language: Language) -> fn(&Opcode) -> bool { + // R1CS does not support any of the opcode except Arithmetic by default. + // The compiler will replace those that it can -- ie range, xor, and + fn r1cs_is_supported(opcode: &Opcode) -> bool { + matches!(opcode, Opcode::Arithmetic(_)) + } + + // PLONK supports most of the opcodes by default + // The ones which are not supported, the acvm compiler will + // attempt to transform into supported opcodes. If these are also not available + // then a compiler error will be emitted. + fn plonk_is_supported(_opcode: &Opcode) -> bool { + true + } + + match language { + Language::R1CS => r1cs_is_supported, + Language::PLONKCSat { .. } => plonk_is_supported, + } +} diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs new file mode 100644 index 00000000000..ca0ca99ba07 --- /dev/null +++ b/acvm-repo/acvm/tests/solver.rs @@ -0,0 +1,648 @@ +use std::collections::BTreeMap; + +use acir::{ + brillig::{BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, Value}, + circuit::{ + brillig::{Brillig, BrilligInputs, BrilligOutputs}, + opcodes::{BlockId, MemOp}, + Opcode, OpcodeLocation, + }, + native_types::{Expression, Witness, WitnessMap}, + FieldElement, +}; + +use acvm::{ + pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}, + BlackBoxFunctionSolver, +}; +use acvm_blackbox_solver::BlackBoxResolutionError; + +pub(crate) struct StubbedBackend; + +impl BlackBoxFunctionSolver for StubbedBackend { + fn schnorr_verify( + &self, + _public_key_x: &FieldElement, + _public_key_y: &FieldElement, + _signature: &[u8], + _message: &[u8], + ) -> Result { + panic!("Path not trodden by this test") + } + fn pedersen( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + panic!("Path not trodden by this test") + } + fn fixed_base_scalar_mul( + &self, + _low: &FieldElement, + _high: &FieldElement, + ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + panic!("Path not trodden by this test") + } +} + +// Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. + +#[test] +#[ignore] +fn inversion_brillig_oracle_equivalence() { + // Opcodes below describe the following: + // fn main(x : Field, y : pub Field) { + // let z = x + y; + // assert( 1/z == Oracle("inverse", x + y) ); + // } + // Also performs an unrelated equality check + // just for the sake of testing multiple brillig opcodes. + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let w_x = Witness(1); + let w_y = Witness(2); + let w_oracle = Witness(3); + let w_z = Witness(4); + let w_z_inverse = Witness(5); + let w_x_plus_y = Witness(6); + let w_equal_res = Witness(7); + + let equal_opcode = BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(2), + }; + + let brillig_data = Brillig { + inputs: vec![ + BrilligInputs::Single(Expression { + // Input Register 0 + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression::default()), // Input Register 1 + ], + // This tells the BrilligSolver which witnesses its output registers correspond to + outputs: vec![ + BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input + BrilligOutputs::Simple(w_oracle), // Output Register 1 + BrilligOutputs::Simple(w_equal_res), // Output Register 2 + ], + // stack of foreign call/oracle resolutions, starts empty + foreign_call_results: vec![], + bytecode: vec![ + equal_opcode, + // Oracles are named 'foreign calls' in brillig + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + }, + ], + predicate: None, + }; + + let opcodes = vec![ + Opcode::Brillig(brillig_data), + Opcode::Arithmetic(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y), (-fe_1, w_z)], + q_c: fe_0, + }), + // Opcode::Directive(Directive::Invert { x: w_z, result: w_z_inverse }), + Opcode::Arithmetic(Expression { + mul_terms: vec![(fe_1, w_z, w_z_inverse)], + linear_combinations: vec![], + q_c: -fe_1, + }), + Opcode::Arithmetic(Expression { + mul_terms: vec![], + linear_combinations: vec![(-fe_1, w_oracle), (fe_1, w_z_inverse)], + q_c: fe_0, + }), + ]; + + let witness_assignments = BTreeMap::from([ + (Witness(1), FieldElement::from(2u128)), + (Witness(2), FieldElement::from(3u128)), + ]) + .into(); + + let mut acvm = ACVM::new(&StubbedBackend, opcodes, witness_assignments); + // use the partial witness generation solver with our acir program + let solver_status = acvm.solve(); + + assert!( + matches!(solver_status, ACVMStatus::RequiresForeignCall(_)), + "should require foreign call response" + ); + assert_eq!(acvm.instruction_pointer(), 0, "brillig should have been removed"); + + let foreign_call_wait_info: &ForeignCallWaitInfo = + acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); + assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); + + // As caller of VM, need to resolve foreign calls + let foreign_call_result = Value::from(foreign_call_wait_info.inputs[0][0].to_field().inverse()); + // Alter Brillig oracle opcode with foreign call resolution + acvm.resolve_pending_foreign_call(foreign_call_result.into()); + + // After filling data request, continue solving + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + + // ACVM should be able to be finalized in `Solved` state. + acvm.finalize(); +} + +#[test] +#[ignore] +fn double_inversion_brillig_oracle() { + // Opcodes below describe the following: + // fn main(x : Field, y : pub Field) { + // let z = x + y; + // let ij = i + j; + // assert( 1/z == Oracle("inverse", x + y) ); + // assert( 1/ij == Oracle("inverse", i + j) ); + // } + // Also performs an unrelated equality check + // just for the sake of testing multiple brillig opcodes. + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let w_x = Witness(1); + let w_y = Witness(2); + let w_oracle = Witness(3); + let w_z = Witness(4); + let w_z_inverse = Witness(5); + let w_x_plus_y = Witness(6); + let w_equal_res = Witness(7); + let w_i = Witness(8); + let w_j = Witness(9); + let w_ij_oracle = Witness(10); + let w_i_plus_j = Witness(11); + + let equal_opcode = BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(4), + }; + + let brillig_data = Brillig { + inputs: vec![ + BrilligInputs::Single(Expression { + // Input Register 0 + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression::default()), // Input Register 1 + BrilligInputs::Single(Expression { + // Input Register 2 + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_i), (fe_1, w_j)], + q_c: fe_0, + }), + ], + outputs: vec![ + BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input + BrilligOutputs::Simple(w_oracle), // Output Register 1 + BrilligOutputs::Simple(w_i_plus_j), // Output Register 2 - from input + BrilligOutputs::Simple(w_ij_oracle), // Output Register 3 + BrilligOutputs::Simple(w_equal_res), // Output Register 4 + ], + // stack of foreign call/oracle resolutions, starts empty + foreign_call_results: vec![], + bytecode: vec![ + equal_opcode, + // Oracles are named 'foreign calls' in brillig + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + }, + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + }, + ], + predicate: None, + }; + + let opcodes = vec![ + Opcode::Brillig(brillig_data), + Opcode::Arithmetic(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y), (-fe_1, w_z)], + q_c: fe_0, + }), + // Opcode::Directive(Directive::Invert { x: w_z, result: w_z_inverse }), + Opcode::Arithmetic(Expression { + mul_terms: vec![(fe_1, w_z, w_z_inverse)], + linear_combinations: vec![], + q_c: -fe_1, + }), + Opcode::Arithmetic(Expression { + mul_terms: vec![], + linear_combinations: vec![(-fe_1, w_oracle), (fe_1, w_z_inverse)], + q_c: fe_0, + }), + ]; + + let witness_assignments = BTreeMap::from([ + (Witness(1), FieldElement::from(2u128)), + (Witness(2), FieldElement::from(3u128)), + (Witness(8), FieldElement::from(5u128)), + (Witness(9), FieldElement::from(10u128)), + ]) + .into(); + + let mut acvm = ACVM::new(&StubbedBackend, opcodes, witness_assignments); + + // use the partial witness generation solver with our acir program + let solver_status = acvm.solve(); + assert!( + matches!(solver_status, ACVMStatus::RequiresForeignCall(_)), + "should require foreign call response" + ); + assert_eq!(acvm.instruction_pointer(), 0, "should stall on brillig"); + + let foreign_call_wait_info: &ForeignCallWaitInfo = + acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); + assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); + + let x_plus_y_inverse = Value::from(foreign_call_wait_info.inputs[0][0].to_field().inverse()); + + // Resolve Brillig foreign call + acvm.resolve_pending_foreign_call(x_plus_y_inverse.into()); + + // After filling data request, continue solving + let solver_status = acvm.solve(); + assert!( + matches!(solver_status, ACVMStatus::RequiresForeignCall(_)), + "should require foreign call response" + ); + assert_eq!(acvm.instruction_pointer(), 0, "should stall on brillig"); + + let foreign_call_wait_info = + acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); + assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); + + let i_plus_j_inverse = Value::from(foreign_call_wait_info.inputs[0][0].to_field().inverse()); + assert_ne!(x_plus_y_inverse, i_plus_j_inverse); + + // Alter Brillig oracle opcode + acvm.resolve_pending_foreign_call(i_plus_j_inverse.into()); + + // After filling data request, continue solving + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + + // ACVM should be able to be finalized in `Solved` state. + acvm.finalize(); +} + +#[test] +fn oracle_dependent_execution() { + // This test ensures that we properly track the list of opcodes which still need to be resolved + // across any brillig foreign calls we may have to perform. + // + // Opcodes below describe the following: + // fn main(x : Field, y : pub Field) { + // assert(x == y); + // let x_inv = Oracle("inverse", x); + // let y_inv = Oracle("inverse", y); + // + // assert(x_inv == y_inv); + // } + // Also performs an unrelated equality check + // just for the sake of testing multiple brillig opcodes. + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let w_x = Witness(1); + let w_y = Witness(2); + let w_x_inv = Witness(3); + let w_y_inv = Witness(4); + + let brillig_data = Brillig { + inputs: vec![ + BrilligInputs::Single(w_x.into()), // Input Register 0 + BrilligInputs::Single(Expression::default()), // Input Register 1 + BrilligInputs::Single(w_y.into()), // Input Register 2, + ], + outputs: vec![ + BrilligOutputs::Simple(w_x), // Output Register 0 - from input + BrilligOutputs::Simple(w_y_inv), // Output Register 1 + BrilligOutputs::Simple(w_y), // Output Register 2 - from input + BrilligOutputs::Simple(w_y_inv), // Output Register 3 + ], + // stack of foreign call/oracle resolutions, starts empty + foreign_call_results: vec![], + bytecode: vec![ + // Oracles are named 'foreign calls' in brillig + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + }, + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + }, + ], + predicate: None, + }; + + // This equality check can be executed immediately before resolving any foreign calls. + let equality_check = Expression { + mul_terms: vec![], + linear_combinations: vec![(-fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }; + + // This equality check relies on the outputs of the Brillig call. + // It then cannot be solved until the foreign calls are resolved. + let inverse_equality_check = Expression { + mul_terms: vec![], + linear_combinations: vec![(-fe_1, w_x_inv), (fe_1, w_y_inv)], + q_c: fe_0, + }; + + let opcodes = vec![ + Opcode::Arithmetic(equality_check), + Opcode::Brillig(brillig_data), + Opcode::Arithmetic(inverse_equality_check), + ]; + + let witness_assignments = + BTreeMap::from([(w_x, FieldElement::from(2u128)), (w_y, FieldElement::from(2u128))]).into(); + + let mut acvm = ACVM::new(&StubbedBackend, opcodes, witness_assignments); + + // use the partial witness generation solver with our acir program + let solver_status = acvm.solve(); + assert!( + matches!(solver_status, ACVMStatus::RequiresForeignCall(_)), + "should require foreign call response" + ); + assert_eq!(acvm.instruction_pointer(), 1, "should stall on brillig"); + + let foreign_call_wait_info: &ForeignCallWaitInfo = + acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); + assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); + + // Resolve Brillig foreign call + let x_inverse = Value::from(foreign_call_wait_info.inputs[0][0].to_field().inverse()); + acvm.resolve_pending_foreign_call(x_inverse.into()); + + // After filling data request, continue solving + let solver_status = acvm.solve(); + assert!( + matches!(solver_status, ACVMStatus::RequiresForeignCall(_)), + "should require foreign call response" + ); + assert_eq!(acvm.instruction_pointer(), 1, "should stall on brillig"); + + let foreign_call_wait_info: &ForeignCallWaitInfo = + acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); + assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); + + // Resolve Brillig foreign call + let y_inverse = Value::from(foreign_call_wait_info.inputs[0][0].to_field().inverse()); + acvm.resolve_pending_foreign_call(y_inverse.into()); + + // We've resolved all the brillig foreign calls so we should be able to complete execution now. + + // After filling data request, continue solving + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + + // ACVM should be able to be finalized in `Solved` state. + acvm.finalize(); +} + +#[test] +fn brillig_oracle_predicate() { + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let w_x = Witness(1); + let w_y = Witness(2); + let w_oracle = Witness(3); + let w_x_plus_y = Witness(4); + let w_equal_res = Witness(5); + let w_lt_res = Witness(6); + + let equal_opcode = BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(2), + }; + + let brillig_opcode = Opcode::Brillig(Brillig { + inputs: vec![ + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression::default()), + ], + outputs: vec![ + BrilligOutputs::Simple(w_x_plus_y), + BrilligOutputs::Simple(w_oracle), + BrilligOutputs::Simple(w_equal_res), + BrilligOutputs::Simple(w_lt_res), + ], + bytecode: vec![ + equal_opcode, + // Oracles are named 'foreign calls' in brillig + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + }, + ], + predicate: Some(Expression::default()), + // oracle results + foreign_call_results: vec![], + }); + + let opcodes = vec![brillig_opcode]; + + let witness_assignments = BTreeMap::from([ + (Witness(1), FieldElement::from(2u128)), + (Witness(2), FieldElement::from(3u128)), + ]) + .into(); + + let mut acvm = ACVM::new(&StubbedBackend, opcodes, witness_assignments); + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + + // ACVM should be able to be finalized in `Solved` state. + acvm.finalize(); +} +#[test] +fn unsatisfied_opcode_resolved() { + let a = Witness(0); + let b = Witness(1); + let c = Witness(2); + let d = Witness(3); + + // a = b + c + d; + let opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::one(), a), + (-FieldElement::one(), b), + (-FieldElement::one(), c), + (-FieldElement::one(), d), + ], + q_c: FieldElement::zero(), + }; + + let mut values = WitnessMap::new(); + values.insert(a, FieldElement::from(4_i128)); + values.insert(b, FieldElement::from(2_i128)); + values.insert(c, FieldElement::from(1_i128)); + values.insert(d, FieldElement::from(2_i128)); + + let opcodes = vec![Opcode::Arithmetic(opcode_a)]; + let mut acvm = ACVM::new(&StubbedBackend, opcodes, values); + let solver_status = acvm.solve(); + assert_eq!( + solver_status, + ACVMStatus::Failure(OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Resolved(OpcodeLocation::Acir(0)), + }), + "The first opcode is not satisfiable, expected an error indicating this" + ); +} + +#[test] +fn unsatisfied_opcode_resolved_brillig() { + let a = Witness(0); + let b = Witness(1); + let c = Witness(2); + let d = Witness(3); + + let fe_1 = FieldElement::one(); + let fe_0 = FieldElement::zero(); + let w_x = Witness(4); + let w_y = Witness(5); + let w_result = Witness(6); + + let equal_opcode = BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(2), + }; + // Jump pass the trap if the values are equal, else + // jump to the trap + let location_of_stop = 3; + + let jmp_if_opcode = + BrilligOpcode::JumpIf { condition: RegisterIndex::from(2), location: location_of_stop }; + + let trap_opcode = BrilligOpcode::Trap; + let stop_opcode = BrilligOpcode::Stop; + + let brillig_opcode = Opcode::Brillig(Brillig { + inputs: vec![ + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_y)], + q_c: fe_0, + }), + ], + outputs: vec![BrilligOutputs::Simple(w_result)], + bytecode: vec![equal_opcode, jmp_if_opcode, trap_opcode, stop_opcode], + predicate: Some(Expression::one()), + // oracle results + foreign_call_results: vec![], + }); + + let opcode_a = Expression { + mul_terms: vec![], + linear_combinations: vec![ + (FieldElement::one(), a), + (-FieldElement::one(), b), + (-FieldElement::one(), c), + (-FieldElement::one(), d), + ], + q_c: FieldElement::zero(), + }; + + let mut values = WitnessMap::new(); + values.insert(a, FieldElement::from(4_i128)); + values.insert(b, FieldElement::from(2_i128)); + values.insert(c, FieldElement::from(1_i128)); + values.insert(d, FieldElement::from(2_i128)); + values.insert(w_x, FieldElement::from(0_i128)); + values.insert(w_y, FieldElement::from(1_i128)); + values.insert(w_result, FieldElement::from(0_i128)); + + let opcodes = vec![brillig_opcode, Opcode::Arithmetic(opcode_a)]; + + let mut acvm = ACVM::new(&StubbedBackend, opcodes, values); + let solver_status = acvm.solve(); + assert_eq!( + solver_status, + ACVMStatus::Failure(OpcodeResolutionError::BrilligFunctionFailed { + message: "explicit trap hit in brillig".to_string(), + call_stack: vec![OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 }] + }), + "The first opcode is not satisfiable, expected an error indicating this" + ); +} + +#[test] +fn memory_operations() { + let initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(2u128)), + (Witness(3), FieldElement::from(3u128)), + (Witness(4), FieldElement::from(4u128)), + (Witness(5), FieldElement::from(5u128)), + (Witness(6), FieldElement::from(4u128)), + ])); + + let block_id = BlockId(0); + + let init = Opcode::MemoryInit { block_id, init: (1..6).map(Witness).collect() }; + + let read_op = Opcode::MemoryOp { + block_id, + op: MemOp::read_at_mem_index(Witness(6).into(), Witness(7)), + predicate: None, + }; + + let expression = Opcode::Arithmetic(Expression { + mul_terms: Vec::new(), + linear_combinations: vec![ + (FieldElement::one(), Witness(7)), + (-FieldElement::one(), Witness(8)), + ], + q_c: FieldElement::one(), + }); + + let opcodes = vec![init, read_op, expression]; + + let mut acvm = ACVM::new(&StubbedBackend, opcodes, initial_witness); + let solver_status = acvm.solve(); + assert_eq!(solver_status, ACVMStatus::Solved); + let witness_map = acvm.finalize(); + + assert_eq!(witness_map[&Witness(8)], FieldElement::from(6u128)); +} diff --git a/acvm-repo/acvm/tests/stdlib.rs b/acvm-repo/acvm/tests/stdlib.rs new file mode 100644 index 00000000000..309130d3992 --- /dev/null +++ b/acvm-repo/acvm/tests/stdlib.rs @@ -0,0 +1,354 @@ +#![cfg(feature = "testing")] +mod solver; +use crate::solver::StubbedBackend; +use acir::{ + circuit::{ + opcodes::{BlackBoxFuncCall, FunctionInput}, + Circuit, Opcode, + }, + native_types::{Expression, Witness}, + FieldElement, +}; +use acvm::{ + compiler::compile, + pwg::{ACVMStatus, ACVM}, + Language, +}; +use acvm_blackbox_solver::{blake2s, hash_to_field_128_security, keccak256, sha256}; +use paste::paste; +use proptest::prelude::*; +use std::collections::{BTreeMap, BTreeSet}; +use stdlib::blackbox_fallbacks::{UInt32, UInt64, UInt8}; + +test_uint!(test_uint8, UInt8, u8, 8); +test_uint!(test_uint32, UInt32, u32, 32); +test_uint!(test_uint64, UInt64, u64, 64); + +#[macro_export] +macro_rules! test_uint { + ( + $name:tt, + $uint:ident, + $u:ident, + $size:expr + ) => { + paste! { + test_uint_inner!( + [<$name _rol>], + [<$name _ror>], + [<$name _euclidean_division>], + [<$name _add>], + [<$name _sub>], + [<$name _left_shift>], + [<$name _right_shift>], + [<$name _less_than>], + $uint, + $u, + $size + ); + } + }; +} + +#[macro_export] +macro_rules! test_uint_inner { + ( + $rol:tt, + $ror:tt, + $euclidean_division:tt, + $add:tt, + $sub:tt, + $left_shift:tt, + $right_shift:tt, + $less_than:tt, + $uint: ident, + $u: ident, + $size: expr + ) => { + proptest! { + #[test] + fn $rol(x in 0..$u::MAX, y in 0..32_u32) { + let fe = FieldElement::from(x as u128); + let w = Witness(1); + let result = x.rotate_left(y); + let uint = $uint::new(w); + let (w, extra_opcodes, _) = uint.rol(y, 2); + let witness_assignments = BTreeMap::from([(Witness(1), fe)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, extra_opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $ror(x in 0..$u::MAX, y in 0..32_u32) { + let fe = FieldElement::from(x as u128); + let w = Witness(1); + let result = x.rotate_right(y); + let uint = $uint::new(w); + let (w, extra_opcodes, _) = uint.ror(y, 2); + let witness_assignments = BTreeMap::from([(Witness(1), fe)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, extra_opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $euclidean_division(x in 0..$u::MAX, y in 1 + ..$u::MAX) { + let lhs = FieldElement::from(x as u128); + let rhs = FieldElement::from(y as u128); + let w1 = Witness(1); + let w2 = Witness(2); + let q = x.div_euclid(y); + let r = x.rem_euclid(y); + let u32_1 = $uint::new(w1); + let u32_2 = $uint::new(w2); + let (q_w, r_w, extra_opcodes, _) = $uint::euclidean_division(&u32_1, &u32_2, 3); + let witness_assignments = BTreeMap::from([(Witness(1), lhs),(Witness(2), rhs)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, extra_opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&q_w.get_inner()).unwrap(), &FieldElement::from(q as u128)); + prop_assert_eq!(acvm.witness_map().get(&r_w.get_inner()).unwrap(), &FieldElement::from(r as u128)); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $add(x in 0..$u::MAX, y in 0..$u::MAX, z in 0..$u::MAX) { + let lhs = FieldElement::from(x as u128); + let rhs = FieldElement::from(y as u128); + let rhs_z = FieldElement::from(z as u128); + let result = FieldElement::from(((x as u128).wrapping_add(y as u128) % (1_u128 << $size)).wrapping_add(z as u128) % (1_u128 << $size)); + let w1 = Witness(1); + let w2 = Witness(2); + let w3 = Witness(3); + let u32_1 = $uint::new(w1); + let u32_2 = $uint::new(w2); + let u32_3 = $uint::new(w3); + let mut opcodes = Vec::new(); + let (w, extra_opcodes, num_witness) = u32_1.add(&u32_2, 4); + opcodes.extend(extra_opcodes); + let (w2, extra_opcodes, _) = w.add(&u32_3, num_witness); + opcodes.extend(extra_opcodes); + let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs), (Witness(3), rhs_z)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w2.get_inner()).unwrap(), &result); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $sub(x in 0..$u::MAX, y in 0..$u::MAX, z in 0..$u::MAX) { + let lhs = FieldElement::from(x as u128); + let rhs = FieldElement::from(y as u128); + let rhs_z = FieldElement::from(z as u128); + let result = FieldElement::from(((x as u128).wrapping_sub(y as u128) % (1_u128 << $size)).wrapping_sub(z as u128) % (1_u128 << $size)); + let w1 = Witness(1); + let w2 = Witness(2); + let w3 = Witness(3); + let u32_1 = $uint::new(w1); + let u32_2 = $uint::new(w2); + let u32_3 = $uint::new(w3); + let mut opcodes = Vec::new(); + let (w, extra_opcodes, num_witness) = u32_1.sub(&u32_2, 4); + opcodes.extend(extra_opcodes); + let (w2, extra_opcodes, _) = w.sub(&u32_3, num_witness); + opcodes.extend(extra_opcodes); + let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs), (Witness(3), rhs_z)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w2.get_inner()).unwrap(), &result); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $left_shift(x in 0..$u::MAX, y in 0..32_u32) { + let lhs = FieldElement::from(x as u128); + let w1 = Witness(1); + let result = x.overflowing_shl(y).0; + let u32_1 = $uint::new(w1); + let (w, extra_opcodes, _) = u32_1.leftshift(y, 2); + let witness_assignments = BTreeMap::from([(Witness(1), lhs)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, extra_opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $right_shift(x in 0..$u::MAX, y in 0..32_u32) { + let lhs = FieldElement::from(x as u128); + let w1 = Witness(1); + let result = x.overflowing_shr(y).0; + let u32_1 = $uint::new(w1); + let (w, extra_opcodes, _) = u32_1.rightshift(y, 2); + let witness_assignments = BTreeMap::from([(Witness(1), lhs)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, extra_opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + + #[test] + fn $less_than(x in 0..$u::MAX, y in 0..$u::MAX) { + let lhs = FieldElement::from(x as u128); + let rhs = FieldElement::from(y as u128); + let w1 = Witness(1); + let w2 = Witness(2); + let result = x < y; + let u32_1 = $uint::new(w1); + let u32_2 = $uint::new(w2); + let (w, extra_opcodes, _) = u32_1.less_than_comparison(&u32_2, 3); + let witness_assignments = BTreeMap::from([(Witness(1), lhs), (Witness(2), rhs)]).into(); + let mut acvm = ACVM::new(&StubbedBackend, extra_opcodes, witness_assignments); + let solver_status = acvm.solve(); + + prop_assert_eq!(acvm.witness_map().get(&w.get_inner()).unwrap(), &FieldElement::from(result as u128)); + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + } + }; +} + +test_hashes!(test_sha256, sha256, SHA256, does_not_support_sha256); +test_hashes!(test_blake2s, blake2s, Blake2s, does_not_support_blake2s); +test_hashes!(test_keccak, keccak256, Keccak256, does_not_support_keccak); + +fn does_not_support_sha256(opcode: &Opcode) -> bool { + !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::SHA256 { .. })) +} +fn does_not_support_blake2s(opcode: &Opcode) -> bool { + !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Blake2s { .. })) +} +fn does_not_support_keccak(opcode: &Opcode) -> bool { + !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccak256 { .. })) +} + +#[macro_export] +macro_rules! test_hashes { + ( + $name:ident, + $hasher:ident, + $opcode:ident, + $opcode_support: ident + ) => { + proptest! { + #![proptest_config(ProptestConfig::with_cases(3))] + #[test] + fn $name(input_values in proptest::collection::vec(0..u8::MAX, 1..50)) { + let mut opcodes = Vec::new(); + let mut witness_assignments = BTreeMap::new(); + let mut input_witnesses: Vec = Vec::new(); + let mut correct_result_witnesses: Vec = Vec::new(); + let mut output_witnesses: Vec = Vec::new(); + + // prepare test data + let mut counter = 0; + let output = $hasher(&input_values).unwrap(); + for inp_v in input_values { + counter += 1; + let function_input = FunctionInput { witness: Witness(counter), num_bits: 8 }; + input_witnesses.push(function_input); + witness_assignments.insert(Witness(counter), FieldElement::from(inp_v as u128)); + } + + for o_v in output { + counter += 1; + correct_result_witnesses.push(Witness(counter)); + witness_assignments.insert(Witness(counter), FieldElement::from(o_v as u128)); + } + + for _ in 0..32 { + counter += 1; + output_witnesses.push(Witness(counter)); + } + let blackbox = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::$opcode { inputs: input_witnesses, outputs: output_witnesses.clone() }); + opcodes.push(blackbox); + + // constrain the output to be the same as the hasher + for i in 0..correct_result_witnesses.len() { + let mut output_constraint = Expression::from(correct_result_witnesses[i]); + output_constraint.push_addition_term(-FieldElement::one(), output_witnesses[i]); + opcodes.push(Opcode::Arithmetic(output_constraint)); + } + + // compile circuit + let circuit = Circuit { + current_witness_index: witness_assignments.len() as u32 + 32, + opcodes, + private_parameters: BTreeSet::new(), // This is not correct but is unused in this test. + ..Circuit::default() + }; + let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, $opcode_support).unwrap().0; + + // solve witnesses + let mut acvm = ACVM::new(&StubbedBackend, circuit.opcodes, witness_assignments.into()); + let solver_status = acvm.solve(); + + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } + } + }; +} + +fn does_not_support_hash_to_field(opcode: &Opcode) -> bool { + !matches!(opcode, Opcode::BlackBoxFuncCall(BlackBoxFuncCall::HashToField128Security { .. })) +} + +proptest! { + #![proptest_config(ProptestConfig::with_cases(3))] + #[test] + fn test_hash_to_field(input_values in proptest::collection::vec(0..u8::MAX, 1..50)) { + let mut opcodes = Vec::new(); + let mut witness_assignments = BTreeMap::new(); + let mut input_witnesses: Vec = Vec::new(); + + // prepare test data + let mut counter = 0; + let output = hash_to_field_128_security(&input_values).unwrap(); + for inp_v in input_values { + counter += 1; + let function_input = FunctionInput { witness: Witness(counter), num_bits: 8 }; + input_witnesses.push(function_input); + witness_assignments.insert(Witness(counter), FieldElement::from(inp_v as u128)); + } + + counter += 1; + let correct_result_witnesses: Witness = Witness(counter); + witness_assignments.insert(Witness(counter), output); + + counter += 1; + let output_witness: Witness = Witness(counter); + + let blackbox = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::HashToField128Security { inputs: input_witnesses, output: output_witness }); + opcodes.push(blackbox); + + // constrain the output to be the same as the hasher + let mut output_constraint = Expression::from(correct_result_witnesses); + output_constraint.push_addition_term(-FieldElement::one(), output_witness); + opcodes.push(Opcode::Arithmetic(output_constraint)); + + // compile circuit + let circuit = Circuit { + current_witness_index: witness_assignments.len() as u32 + 1, + opcodes, + private_parameters: BTreeSet::new(), // This is not correct but is unused in this test. + ..Circuit::default() + }; + let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, does_not_support_hash_to_field).unwrap().0; + + // solve witnesses + let mut acvm = ACVM::new(&StubbedBackend, circuit.opcodes, witness_assignments.into()); + let solver_status = acvm.solve(); + + prop_assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); + } +} diff --git a/acvm-repo/acvm_js/.cargo/config.toml b/acvm-repo/acvm_js/.cargo/config.toml new file mode 100644 index 00000000000..85c748284e9 --- /dev/null +++ b/acvm-repo/acvm_js/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = "wasm32-unknown-unknown" + +[target.wasm32-unknown-unknown] +runner = 'wasm-bindgen-test-runner' diff --git a/acvm-repo/acvm_js/.eslintignore b/acvm-repo/acvm_js/.eslintignore new file mode 100644 index 00000000000..200ae222150 --- /dev/null +++ b/acvm-repo/acvm_js/.eslintignore @@ -0,0 +1,2 @@ +node_modules +pkg \ No newline at end of file diff --git a/acvm-repo/acvm_js/.eslintrc.js b/acvm-repo/acvm_js/.eslintrc.js new file mode 100644 index 00000000000..33335c2a877 --- /dev/null +++ b/acvm-repo/acvm_js/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ["../../.eslintrc.js"], +}; diff --git a/acvm-repo/acvm_js/.gitignore b/acvm-repo/acvm_js/.gitignore new file mode 100644 index 00000000000..95efa89513e --- /dev/null +++ b/acvm-repo/acvm_js/.gitignore @@ -0,0 +1,16 @@ +/target +node_modules + +# Build outputs +result +nodejs +web + +# Yarn +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions diff --git a/acvm-repo/acvm_js/.mocharc.json b/acvm-repo/acvm_js/.mocharc.json new file mode 100644 index 00000000000..27273835070 --- /dev/null +++ b/acvm-repo/acvm_js/.mocharc.json @@ -0,0 +1,5 @@ +{ + "extension": ["ts"], + "spec": "test/node/**/*.test.ts", + "require": "ts-node/register" +} \ No newline at end of file diff --git a/acvm-repo/acvm_js/.yarn/releases/yarn-3.5.1.cjs b/acvm-repo/acvm_js/.yarn/releases/yarn-3.5.1.cjs new file mode 100755 index 00000000000..97eed758032 --- /dev/null +++ b/acvm-repo/acvm_js/.yarn/releases/yarn-3.5.1.cjs @@ -0,0 +1,873 @@ +#!/usr/bin/env node +/* eslint-disable */ +//prettier-ignore +(()=>{var Sge=Object.create;var lS=Object.defineProperty;var vge=Object.getOwnPropertyDescriptor;var xge=Object.getOwnPropertyNames;var Pge=Object.getPrototypeOf,Dge=Object.prototype.hasOwnProperty;var J=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+r+'" is not supported')});var kge=(r,e)=>()=>(r&&(e=r(r=0)),e);var w=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),ut=(r,e)=>{for(var t in e)lS(r,t,{get:e[t],enumerable:!0})},Rge=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of xge(e))!Dge.call(r,n)&&n!==t&&lS(r,n,{get:()=>e[n],enumerable:!(i=vge(e,n))||i.enumerable});return r};var Pe=(r,e,t)=>(t=r!=null?Sge(Pge(r)):{},Rge(e||!r||!r.__esModule?lS(t,"default",{value:r,enumerable:!0}):t,r));var vU=w((j7e,SU)=>{SU.exports=bU;bU.sync=$ge;var BU=J("fs");function _ge(r,e){var t=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!t||(t=t.split(";"),t.indexOf("")!==-1))return!0;for(var i=0;i{kU.exports=PU;PU.sync=efe;var xU=J("fs");function PU(r,e,t){xU.stat(r,function(i,n){t(i,i?!1:DU(n,e))})}function efe(r,e){return DU(xU.statSync(r),e)}function DU(r,e){return r.isFile()&&tfe(r,e)}function tfe(r,e){var t=r.mode,i=r.uid,n=r.gid,s=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),o=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),a=parseInt("100",8),l=parseInt("010",8),c=parseInt("001",8),u=a|l,g=t&c||t&l&&n===o||t&a&&i===s||t&u&&s===0;return g}});var NU=w((W7e,FU)=>{var J7e=J("fs"),lI;process.platform==="win32"||global.TESTING_WINDOWS?lI=vU():lI=RU();FU.exports=SS;SS.sync=rfe;function SS(r,e,t){if(typeof e=="function"&&(t=e,e={}),!t){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(i,n){SS(r,e||{},function(s,o){s?n(s):i(o)})})}lI(r,e||{},function(i,n){i&&(i.code==="EACCES"||e&&e.ignoreErrors)&&(i=null,n=!1),t(i,n)})}function rfe(r,e){try{return lI.sync(r,e||{})}catch(t){if(e&&e.ignoreErrors||t.code==="EACCES")return!1;throw t}}});var HU=w((z7e,KU)=>{var Dg=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",LU=J("path"),ife=Dg?";":":",TU=NU(),OU=r=>Object.assign(new Error(`not found: ${r}`),{code:"ENOENT"}),MU=(r,e)=>{let t=e.colon||ife,i=r.match(/\//)||Dg&&r.match(/\\/)?[""]:[...Dg?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(t)],n=Dg?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",s=Dg?n.split(t):[""];return Dg&&r.indexOf(".")!==-1&&s[0]!==""&&s.unshift(""),{pathEnv:i,pathExt:s,pathExtExe:n}},UU=(r,e,t)=>{typeof e=="function"&&(t=e,e={}),e||(e={});let{pathEnv:i,pathExt:n,pathExtExe:s}=MU(r,e),o=[],a=c=>new Promise((u,g)=>{if(c===i.length)return e.all&&o.length?u(o):g(OU(r));let f=i[c],h=/^".*"$/.test(f)?f.slice(1,-1):f,p=LU.join(h,r),C=!h&&/^\.[\\\/]/.test(r)?r.slice(0,2)+p:p;u(l(C,c,0))}),l=(c,u,g)=>new Promise((f,h)=>{if(g===n.length)return f(a(u+1));let p=n[g];TU(c+p,{pathExt:s},(C,y)=>{if(!C&&y)if(e.all)o.push(c+p);else return f(c+p);return f(l(c,u,g+1))})});return t?a(0).then(c=>t(null,c),t):a(0)},nfe=(r,e)=>{e=e||{};let{pathEnv:t,pathExt:i,pathExtExe:n}=MU(r,e),s=[];for(let o=0;o{"use strict";var GU=(r={})=>{let e=r.env||process.env;return(r.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(i=>i.toUpperCase()==="PATH")||"Path"};vS.exports=GU;vS.exports.default=GU});var WU=w((X7e,JU)=>{"use strict";var jU=J("path"),sfe=HU(),ofe=YU();function qU(r,e){let t=r.options.env||process.env,i=process.cwd(),n=r.options.cwd!=null,s=n&&process.chdir!==void 0&&!process.chdir.disabled;if(s)try{process.chdir(r.options.cwd)}catch{}let o;try{o=sfe.sync(r.command,{path:t[ofe({env:t})],pathExt:e?jU.delimiter:void 0})}catch{}finally{s&&process.chdir(i)}return o&&(o=jU.resolve(n?r.options.cwd:"",o)),o}function afe(r){return qU(r)||qU(r,!0)}JU.exports=afe});var zU=w((Z7e,PS)=>{"use strict";var xS=/([()\][%!^"`<>&|;, *?])/g;function Afe(r){return r=r.replace(xS,"^$1"),r}function lfe(r,e){return r=`${r}`,r=r.replace(/(\\*)"/g,'$1$1\\"'),r=r.replace(/(\\*)$/,"$1$1"),r=`"${r}"`,r=r.replace(xS,"^$1"),e&&(r=r.replace(xS,"^$1")),r}PS.exports.command=Afe;PS.exports.argument=lfe});var XU=w((_7e,VU)=>{"use strict";VU.exports=/^#!(.*)/});var _U=w(($7e,ZU)=>{"use strict";var cfe=XU();ZU.exports=(r="")=>{let e=r.match(cfe);if(!e)return null;let[t,i]=e[0].replace(/#! ?/,"").split(" "),n=t.split("/").pop();return n==="env"?i:i?`${n} ${i}`:n}});var eK=w((eZe,$U)=>{"use strict";var DS=J("fs"),ufe=_U();function gfe(r){let t=Buffer.alloc(150),i;try{i=DS.openSync(r,"r"),DS.readSync(i,t,0,150,0),DS.closeSync(i)}catch{}return ufe(t.toString())}$U.exports=gfe});var nK=w((tZe,iK)=>{"use strict";var ffe=J("path"),tK=WU(),rK=zU(),hfe=eK(),pfe=process.platform==="win32",dfe=/\.(?:com|exe)$/i,Cfe=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function mfe(r){r.file=tK(r);let e=r.file&&hfe(r.file);return e?(r.args.unshift(r.file),r.command=e,tK(r)):r.file}function Efe(r){if(!pfe)return r;let e=mfe(r),t=!dfe.test(e);if(r.options.forceShell||t){let i=Cfe.test(e);r.command=ffe.normalize(r.command),r.command=rK.command(r.command),r.args=r.args.map(s=>rK.argument(s,i));let n=[r.command].concat(r.args).join(" ");r.args=["/d","/s","/c",`"${n}"`],r.command=process.env.comspec||"cmd.exe",r.options.windowsVerbatimArguments=!0}return r}function Ife(r,e,t){e&&!Array.isArray(e)&&(t=e,e=null),e=e?e.slice(0):[],t=Object.assign({},t);let i={command:r,args:e,options:t,file:void 0,original:{command:r,args:e}};return t.shell?i:Efe(i)}iK.exports=Ife});var aK=w((rZe,oK)=>{"use strict";var kS=process.platform==="win32";function RS(r,e){return Object.assign(new Error(`${e} ${r.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${r.command}`,path:r.command,spawnargs:r.args})}function yfe(r,e){if(!kS)return;let t=r.emit;r.emit=function(i,n){if(i==="exit"){let s=sK(n,e,"spawn");if(s)return t.call(r,"error",s)}return t.apply(r,arguments)}}function sK(r,e){return kS&&r===1&&!e.file?RS(e.original,"spawn"):null}function wfe(r,e){return kS&&r===1&&!e.file?RS(e.original,"spawnSync"):null}oK.exports={hookChildProcess:yfe,verifyENOENT:sK,verifyENOENTSync:wfe,notFoundError:RS}});var LS=w((iZe,kg)=>{"use strict";var AK=J("child_process"),FS=nK(),NS=aK();function lK(r,e,t){let i=FS(r,e,t),n=AK.spawn(i.command,i.args,i.options);return NS.hookChildProcess(n,i),n}function Bfe(r,e,t){let i=FS(r,e,t),n=AK.spawnSync(i.command,i.args,i.options);return n.error=n.error||NS.verifyENOENTSync(n.status,i),n}kg.exports=lK;kg.exports.spawn=lK;kg.exports.sync=Bfe;kg.exports._parse=FS;kg.exports._enoent=NS});var uK=w((nZe,cK)=>{"use strict";function Qfe(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function Zl(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Zl)}Qfe(Zl,Error);Zl.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;g>",ie=me(">>",!1),de=">&",_e=me(">&",!1),Pt=">",It=me(">",!1),Or="<<<",ii=me("<<<",!1),gi="<&",hr=me("<&",!1),fi="<",ni=me("<",!1),Us=function(m){return{type:"argument",segments:[].concat(...m)}},pr=function(m){return m},Ii="$'",rs=me("$'",!1),ga="'",dA=me("'",!1),cg=function(m){return[{type:"text",text:m}]},is='""',CA=me('""',!1),fa=function(){return{type:"text",text:""}},wp='"',mA=me('"',!1),EA=function(m){return m},wr=function(m){return{type:"arithmetic",arithmetic:m,quoted:!0}},Ll=function(m){return{type:"shell",shell:m,quoted:!0}},ug=function(m){return{type:"variable",...m,quoted:!0}},Io=function(m){return{type:"text",text:m}},gg=function(m){return{type:"arithmetic",arithmetic:m,quoted:!1}},Bp=function(m){return{type:"shell",shell:m,quoted:!1}},Qp=function(m){return{type:"variable",...m,quoted:!1}},vr=function(m){return{type:"glob",pattern:m}},se=/^[^']/,yo=Je(["'"],!0,!1),Rn=function(m){return m.join("")},fg=/^[^$"]/,Qt=Je(["$",'"'],!0,!1),Tl=`\\ +`,Fn=me(`\\ +`,!1),ns=function(){return""},ss="\\",gt=me("\\",!1),wo=/^[\\$"`]/,At=Je(["\\","$",'"',"`"],!1,!1),An=function(m){return m},S="\\a",Tt=me("\\a",!1),hg=function(){return"a"},Ol="\\b",bp=me("\\b",!1),Sp=function(){return"\b"},vp=/^[Ee]/,xp=Je(["E","e"],!1,!1),Pp=function(){return"\x1B"},G="\\f",yt=me("\\f",!1),IA=function(){return"\f"},Wi="\\n",Ml=me("\\n",!1),Xe=function(){return` +`},ha="\\r",pg=me("\\r",!1),OE=function(){return"\r"},Dp="\\t",ME=me("\\t",!1),ar=function(){return" "},Nn="\\v",Ul=me("\\v",!1),kp=function(){return"\v"},Ks=/^[\\'"?]/,pa=Je(["\\","'",'"',"?"],!1,!1),ln=function(m){return String.fromCharCode(parseInt(m,16))},Te="\\x",dg=me("\\x",!1),Kl="\\u",Hs=me("\\u",!1),Hl="\\U",yA=me("\\U",!1),Cg=function(m){return String.fromCodePoint(parseInt(m,16))},mg=/^[0-7]/,da=Je([["0","7"]],!1,!1),Ca=/^[0-9a-fA-f]/,rt=Je([["0","9"],["a","f"],["A","f"]],!1,!1),Bo=nt(),wA="-",Gl=me("-",!1),Gs="+",Yl=me("+",!1),UE=".",Rp=me(".",!1),Eg=function(m,b,N){return{type:"number",value:(m==="-"?-1:1)*parseFloat(b.join("")+"."+N.join(""))}},Fp=function(m,b){return{type:"number",value:(m==="-"?-1:1)*parseInt(b.join(""))}},KE=function(m){return{type:"variable",...m}},jl=function(m){return{type:"variable",name:m}},HE=function(m){return m},Ig="*",BA=me("*",!1),Rr="/",GE=me("/",!1),Ys=function(m,b,N){return{type:b==="*"?"multiplication":"division",right:N}},js=function(m,b){return b.reduce((N,K)=>({left:N,...K}),m)},yg=function(m,b,N){return{type:b==="+"?"addition":"subtraction",right:N}},QA="$((",R=me("$((",!1),q="))",Ce=me("))",!1),Ue=function(m){return m},Re="$(",ze=me("$(",!1),dt=function(m){return m},Ft="${",Ln=me("${",!1),Jb=":-",P1=me(":-",!1),D1=function(m,b){return{name:m,defaultValue:b}},Wb=":-}",k1=me(":-}",!1),R1=function(m){return{name:m,defaultValue:[]}},zb=":+",F1=me(":+",!1),N1=function(m,b){return{name:m,alternativeValue:b}},Vb=":+}",L1=me(":+}",!1),T1=function(m){return{name:m,alternativeValue:[]}},Xb=function(m){return{name:m}},O1="$",M1=me("$",!1),U1=function(m){return e.isGlobPattern(m)},K1=function(m){return m},Zb=/^[a-zA-Z0-9_]/,_b=Je([["a","z"],["A","Z"],["0","9"],"_"],!1,!1),$b=function(){return T()},eS=/^[$@*?#a-zA-Z0-9_\-]/,tS=Je(["$","@","*","?","#",["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),H1=/^[(){}<>$|&; \t"']/,wg=Je(["(",")","{","}","<",">","$","|","&",";"," "," ",'"',"'"],!1,!1),rS=/^[<>&; \t"']/,iS=Je(["<",">","&",";"," "," ",'"',"'"],!1,!1),YE=/^[ \t]/,jE=Je([" "," "],!1,!1),Q=0,Me=0,bA=[{line:1,column:1}],d=0,E=[],I=0,k;if("startRule"in e){if(!(e.startRule in i))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');n=i[e.startRule]}function T(){return r.substring(Me,Q)}function Z(){return Et(Me,Q)}function te(m,b){throw b=b!==void 0?b:Et(Me,Q),Ri([lt(m)],r.substring(Me,Q),b)}function we(m,b){throw b=b!==void 0?b:Et(Me,Q),Tn(m,b)}function me(m,b){return{type:"literal",text:m,ignoreCase:b}}function Je(m,b,N){return{type:"class",parts:m,inverted:b,ignoreCase:N}}function nt(){return{type:"any"}}function wt(){return{type:"end"}}function lt(m){return{type:"other",description:m}}function it(m){var b=bA[m],N;if(b)return b;for(N=m-1;!bA[N];)N--;for(b=bA[N],b={line:b.line,column:b.column};Nd&&(d=Q,E=[]),E.push(m))}function Tn(m,b){return new Zl(m,null,null,b)}function Ri(m,b,N){return new Zl(Zl.buildMessage(m,b),m,b,N)}function SA(){var m,b;return m=Q,b=Mr(),b===t&&(b=null),b!==t&&(Me=m,b=s(b)),m=b,m}function Mr(){var m,b,N,K,ce;if(m=Q,b=Ur(),b!==t){for(N=[],K=He();K!==t;)N.push(K),K=He();N!==t?(K=ma(),K!==t?(ce=os(),ce===t&&(ce=null),ce!==t?(Me=m,b=o(b,K,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;if(m===t)if(m=Q,b=Ur(),b!==t){for(N=[],K=He();K!==t;)N.push(K),K=He();N!==t?(K=ma(),K===t&&(K=null),K!==t?(Me=m,b=a(b,K),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;return m}function os(){var m,b,N,K,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=Mr(),N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();K!==t?(Me=m,b=l(N),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;return m}function ma(){var m;return r.charCodeAt(Q)===59?(m=c,Q++):(m=t,I===0&&Qe(u)),m===t&&(r.charCodeAt(Q)===38?(m=g,Q++):(m=t,I===0&&Qe(f))),m}function Ur(){var m,b,N;return m=Q,b=G1(),b!==t?(N=lge(),N===t&&(N=null),N!==t?(Me=m,b=h(b,N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function lge(){var m,b,N,K,ce,Se,ht;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=cge(),N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();if(K!==t)if(ce=Ur(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=p(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;return m}function cge(){var m;return r.substr(Q,2)===C?(m=C,Q+=2):(m=t,I===0&&Qe(y)),m===t&&(r.substr(Q,2)===B?(m=B,Q+=2):(m=t,I===0&&Qe(v))),m}function G1(){var m,b,N;return m=Q,b=fge(),b!==t?(N=uge(),N===t&&(N=null),N!==t?(Me=m,b=D(b,N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function uge(){var m,b,N,K,ce,Se,ht;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=gge(),N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();if(K!==t)if(ce=G1(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=L(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;return m}function gge(){var m;return r.substr(Q,2)===H?(m=H,Q+=2):(m=t,I===0&&Qe(j)),m===t&&(r.charCodeAt(Q)===124?(m=$,Q++):(m=t,I===0&&Qe(V))),m}function qE(){var m,b,N,K,ce,Se;if(m=Q,b=eU(),b!==t)if(r.charCodeAt(Q)===61?(N=W,Q++):(N=t,I===0&&Qe(_)),N!==t)if(K=q1(),K!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(Me=m,b=A(b,K),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;else Q=m,m=t;if(m===t)if(m=Q,b=eU(),b!==t)if(r.charCodeAt(Q)===61?(N=W,Q++):(N=t,I===0&&Qe(_)),N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();K!==t?(Me=m,b=Ae(b),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;return m}function fge(){var m,b,N,K,ce,Se,ht,Bt,Jr,hi,as;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(r.charCodeAt(Q)===40?(N=ge,Q++):(N=t,I===0&&Qe(re)),N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();if(K!==t)if(ce=Mr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();if(Se!==t)if(r.charCodeAt(Q)===41?(ht=O,Q++):(ht=t,I===0&&Qe(F)),ht!==t){for(Bt=[],Jr=He();Jr!==t;)Bt.push(Jr),Jr=He();if(Bt!==t){for(Jr=[],hi=Np();hi!==t;)Jr.push(hi),hi=Np();if(Jr!==t){for(hi=[],as=He();as!==t;)hi.push(as),as=He();hi!==t?(Me=m,b=ue(ce,Jr),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(r.charCodeAt(Q)===123?(N=pe,Q++):(N=t,I===0&&Qe(ke)),N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();if(K!==t)if(ce=Mr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();if(Se!==t)if(r.charCodeAt(Q)===125?(ht=Fe,Q++):(ht=t,I===0&&Qe(Ne)),ht!==t){for(Bt=[],Jr=He();Jr!==t;)Bt.push(Jr),Jr=He();if(Bt!==t){for(Jr=[],hi=Np();hi!==t;)Jr.push(hi),hi=Np();if(Jr!==t){for(hi=[],as=He();as!==t;)hi.push(as),as=He();hi!==t?(Me=m,b=oe(ce,Jr),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){for(N=[],K=qE();K!==t;)N.push(K),K=qE();if(N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();if(K!==t){if(ce=[],Se=j1(),Se!==t)for(;Se!==t;)ce.push(Se),Se=j1();else ce=t;if(ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=le(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){if(N=[],K=qE(),K!==t)for(;K!==t;)N.push(K),K=qE();else N=t;if(N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();K!==t?(Me=m,b=Be(N),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}}}return m}function Y1(){var m,b,N,K,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){if(N=[],K=JE(),K!==t)for(;K!==t;)N.push(K),K=JE();else N=t;if(N!==t){for(K=[],ce=He();ce!==t;)K.push(ce),ce=He();K!==t?(Me=m,b=fe(N),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t;return m}function j1(){var m,b,N;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t?(N=Np(),N!==t?(Me=m,b=ae(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();b!==t?(N=JE(),N!==t?(Me=m,b=ae(N),m=b):(Q=m,m=t)):(Q=m,m=t)}return m}function Np(){var m,b,N,K,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();return b!==t?(qe.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(ne)),N===t&&(N=null),N!==t?(K=hge(),K!==t?(ce=JE(),ce!==t?(Me=m,b=Y(N,K,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function hge(){var m;return r.substr(Q,2)===he?(m=he,Q+=2):(m=t,I===0&&Qe(ie)),m===t&&(r.substr(Q,2)===de?(m=de,Q+=2):(m=t,I===0&&Qe(_e)),m===t&&(r.charCodeAt(Q)===62?(m=Pt,Q++):(m=t,I===0&&Qe(It)),m===t&&(r.substr(Q,3)===Or?(m=Or,Q+=3):(m=t,I===0&&Qe(ii)),m===t&&(r.substr(Q,2)===gi?(m=gi,Q+=2):(m=t,I===0&&Qe(hr)),m===t&&(r.charCodeAt(Q)===60?(m=fi,Q++):(m=t,I===0&&Qe(ni))))))),m}function JE(){var m,b,N;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();return b!==t?(N=q1(),N!==t?(Me=m,b=ae(N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function q1(){var m,b,N;if(m=Q,b=[],N=J1(),N!==t)for(;N!==t;)b.push(N),N=J1();else b=t;return b!==t&&(Me=m,b=Us(b)),m=b,m}function J1(){var m,b;return m=Q,b=pge(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=dge(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=Cge(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=mge(),b!==t&&(Me=m,b=pr(b)),m=b))),m}function pge(){var m,b,N,K;return m=Q,r.substr(Q,2)===Ii?(b=Ii,Q+=2):(b=t,I===0&&Qe(rs)),b!==t?(N=yge(),N!==t?(r.charCodeAt(Q)===39?(K=ga,Q++):(K=t,I===0&&Qe(dA)),K!==t?(Me=m,b=cg(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function dge(){var m,b,N,K;return m=Q,r.charCodeAt(Q)===39?(b=ga,Q++):(b=t,I===0&&Qe(dA)),b!==t?(N=Ege(),N!==t?(r.charCodeAt(Q)===39?(K=ga,Q++):(K=t,I===0&&Qe(dA)),K!==t?(Me=m,b=cg(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function Cge(){var m,b,N,K;if(m=Q,r.substr(Q,2)===is?(b=is,Q+=2):(b=t,I===0&&Qe(CA)),b!==t&&(Me=m,b=fa()),m=b,m===t)if(m=Q,r.charCodeAt(Q)===34?(b=wp,Q++):(b=t,I===0&&Qe(mA)),b!==t){for(N=[],K=W1();K!==t;)N.push(K),K=W1();N!==t?(r.charCodeAt(Q)===34?(K=wp,Q++):(K=t,I===0&&Qe(mA)),K!==t?(Me=m,b=EA(N),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;return m}function mge(){var m,b,N;if(m=Q,b=[],N=z1(),N!==t)for(;N!==t;)b.push(N),N=z1();else b=t;return b!==t&&(Me=m,b=EA(b)),m=b,m}function W1(){var m,b;return m=Q,b=_1(),b!==t&&(Me=m,b=wr(b)),m=b,m===t&&(m=Q,b=$1(),b!==t&&(Me=m,b=Ll(b)),m=b,m===t&&(m=Q,b=aS(),b!==t&&(Me=m,b=ug(b)),m=b,m===t&&(m=Q,b=Ige(),b!==t&&(Me=m,b=Io(b)),m=b))),m}function z1(){var m,b;return m=Q,b=_1(),b!==t&&(Me=m,b=gg(b)),m=b,m===t&&(m=Q,b=$1(),b!==t&&(Me=m,b=Bp(b)),m=b,m===t&&(m=Q,b=aS(),b!==t&&(Me=m,b=Qp(b)),m=b,m===t&&(m=Q,b=Qge(),b!==t&&(Me=m,b=vr(b)),m=b,m===t&&(m=Q,b=Bge(),b!==t&&(Me=m,b=Io(b)),m=b)))),m}function Ege(){var m,b,N;for(m=Q,b=[],se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(yo));N!==t;)b.push(N),se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(yo));return b!==t&&(Me=m,b=Rn(b)),m=b,m}function Ige(){var m,b,N;if(m=Q,b=[],N=V1(),N===t&&(fg.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Qt))),N!==t)for(;N!==t;)b.push(N),N=V1(),N===t&&(fg.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Qt)));else b=t;return b!==t&&(Me=m,b=Rn(b)),m=b,m}function V1(){var m,b,N;return m=Q,r.substr(Q,2)===Tl?(b=Tl,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t&&(Me=m,b=ns()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=ss,Q++):(b=t,I===0&&Qe(gt)),b!==t?(wo.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(At)),N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t)),m}function yge(){var m,b,N;for(m=Q,b=[],N=X1(),N===t&&(se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(yo)));N!==t;)b.push(N),N=X1(),N===t&&(se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(yo)));return b!==t&&(Me=m,b=Rn(b)),m=b,m}function X1(){var m,b,N;return m=Q,r.substr(Q,2)===S?(b=S,Q+=2):(b=t,I===0&&Qe(Tt)),b!==t&&(Me=m,b=hg()),m=b,m===t&&(m=Q,r.substr(Q,2)===Ol?(b=Ol,Q+=2):(b=t,I===0&&Qe(bp)),b!==t&&(Me=m,b=Sp()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=ss,Q++):(b=t,I===0&&Qe(gt)),b!==t?(vp.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(xp)),N!==t?(Me=m,b=Pp(),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===G?(b=G,Q+=2):(b=t,I===0&&Qe(yt)),b!==t&&(Me=m,b=IA()),m=b,m===t&&(m=Q,r.substr(Q,2)===Wi?(b=Wi,Q+=2):(b=t,I===0&&Qe(Ml)),b!==t&&(Me=m,b=Xe()),m=b,m===t&&(m=Q,r.substr(Q,2)===ha?(b=ha,Q+=2):(b=t,I===0&&Qe(pg)),b!==t&&(Me=m,b=OE()),m=b,m===t&&(m=Q,r.substr(Q,2)===Dp?(b=Dp,Q+=2):(b=t,I===0&&Qe(ME)),b!==t&&(Me=m,b=ar()),m=b,m===t&&(m=Q,r.substr(Q,2)===Nn?(b=Nn,Q+=2):(b=t,I===0&&Qe(Ul)),b!==t&&(Me=m,b=kp()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=ss,Q++):(b=t,I===0&&Qe(gt)),b!==t?(Ks.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(pa)),N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=wge()))))))))),m}function wge(){var m,b,N,K,ce,Se,ht,Bt,Jr,hi,as,AS;return m=Q,r.charCodeAt(Q)===92?(b=ss,Q++):(b=t,I===0&&Qe(gt)),b!==t?(N=nS(),N!==t?(Me=m,b=ln(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Te?(b=Te,Q+=2):(b=t,I===0&&Qe(dg)),b!==t?(N=Q,K=Q,ce=nS(),ce!==t?(Se=On(),Se!==t?(ce=[ce,Se],K=ce):(Q=K,K=t)):(Q=K,K=t),K===t&&(K=nS()),K!==t?N=r.substring(N,Q):N=K,N!==t?(Me=m,b=ln(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Kl?(b=Kl,Q+=2):(b=t,I===0&&Qe(Hs)),b!==t?(N=Q,K=Q,ce=On(),ce!==t?(Se=On(),Se!==t?(ht=On(),ht!==t?(Bt=On(),Bt!==t?(ce=[ce,Se,ht,Bt],K=ce):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t),K!==t?N=r.substring(N,Q):N=K,N!==t?(Me=m,b=ln(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Hl?(b=Hl,Q+=2):(b=t,I===0&&Qe(yA)),b!==t?(N=Q,K=Q,ce=On(),ce!==t?(Se=On(),Se!==t?(ht=On(),ht!==t?(Bt=On(),Bt!==t?(Jr=On(),Jr!==t?(hi=On(),hi!==t?(as=On(),as!==t?(AS=On(),AS!==t?(ce=[ce,Se,ht,Bt,Jr,hi,as,AS],K=ce):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t)):(Q=K,K=t),K!==t?N=r.substring(N,Q):N=K,N!==t?(Me=m,b=Cg(N),m=b):(Q=m,m=t)):(Q=m,m=t)))),m}function nS(){var m;return mg.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(da)),m}function On(){var m;return Ca.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(rt)),m}function Bge(){var m,b,N,K,ce;if(m=Q,b=[],N=Q,r.charCodeAt(Q)===92?(K=ss,Q++):(K=t,I===0&&Qe(gt)),K!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Bo)),ce!==t?(Me=N,K=An(ce),N=K):(Q=N,N=t)):(Q=N,N=t),N===t&&(N=Q,K=Q,I++,ce=tU(),I--,ce===t?K=void 0:(Q=K,K=t),K!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Bo)),ce!==t?(Me=N,K=An(ce),N=K):(Q=N,N=t)):(Q=N,N=t)),N!==t)for(;N!==t;)b.push(N),N=Q,r.charCodeAt(Q)===92?(K=ss,Q++):(K=t,I===0&&Qe(gt)),K!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Bo)),ce!==t?(Me=N,K=An(ce),N=K):(Q=N,N=t)):(Q=N,N=t),N===t&&(N=Q,K=Q,I++,ce=tU(),I--,ce===t?K=void 0:(Q=K,K=t),K!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Bo)),ce!==t?(Me=N,K=An(ce),N=K):(Q=N,N=t)):(Q=N,N=t));else b=t;return b!==t&&(Me=m,b=Rn(b)),m=b,m}function sS(){var m,b,N,K,ce,Se;if(m=Q,r.charCodeAt(Q)===45?(b=wA,Q++):(b=t,I===0&&Qe(Gl)),b===t&&(r.charCodeAt(Q)===43?(b=Gs,Q++):(b=t,I===0&&Qe(Yl))),b===t&&(b=null),b!==t){if(N=[],qe.test(r.charAt(Q))?(K=r.charAt(Q),Q++):(K=t,I===0&&Qe(ne)),K!==t)for(;K!==t;)N.push(K),qe.test(r.charAt(Q))?(K=r.charAt(Q),Q++):(K=t,I===0&&Qe(ne));else N=t;if(N!==t)if(r.charCodeAt(Q)===46?(K=UE,Q++):(K=t,I===0&&Qe(Rp)),K!==t){if(ce=[],qe.test(r.charAt(Q))?(Se=r.charAt(Q),Q++):(Se=t,I===0&&Qe(ne)),Se!==t)for(;Se!==t;)ce.push(Se),qe.test(r.charAt(Q))?(Se=r.charAt(Q),Q++):(Se=t,I===0&&Qe(ne));else ce=t;ce!==t?(Me=m,b=Eg(b,N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;if(m===t){if(m=Q,r.charCodeAt(Q)===45?(b=wA,Q++):(b=t,I===0&&Qe(Gl)),b===t&&(r.charCodeAt(Q)===43?(b=Gs,Q++):(b=t,I===0&&Qe(Yl))),b===t&&(b=null),b!==t){if(N=[],qe.test(r.charAt(Q))?(K=r.charAt(Q),Q++):(K=t,I===0&&Qe(ne)),K!==t)for(;K!==t;)N.push(K),qe.test(r.charAt(Q))?(K=r.charAt(Q),Q++):(K=t,I===0&&Qe(ne));else N=t;N!==t?(Me=m,b=Fp(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;if(m===t&&(m=Q,b=aS(),b!==t&&(Me=m,b=KE(b)),m=b,m===t&&(m=Q,b=ql(),b!==t&&(Me=m,b=jl(b)),m=b,m===t)))if(m=Q,r.charCodeAt(Q)===40?(b=ge,Q++):(b=t,I===0&&Qe(re)),b!==t){for(N=[],K=He();K!==t;)N.push(K),K=He();if(N!==t)if(K=Z1(),K!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(r.charCodeAt(Q)===41?(Se=O,Q++):(Se=t,I===0&&Qe(F)),Se!==t?(Me=m,b=HE(K),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t}return m}function oS(){var m,b,N,K,ce,Se,ht,Bt;if(m=Q,b=sS(),b!==t){for(N=[],K=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===42?(Se=Ig,Q++):(Se=t,I===0&&Qe(BA)),Se===t&&(r.charCodeAt(Q)===47?(Se=Rr,Q++):(Se=t,I===0&&Qe(GE))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=sS(),Bt!==t?(Me=K,ce=Ys(b,Se,Bt),K=ce):(Q=K,K=t)):(Q=K,K=t)}else Q=K,K=t;else Q=K,K=t;for(;K!==t;){for(N.push(K),K=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===42?(Se=Ig,Q++):(Se=t,I===0&&Qe(BA)),Se===t&&(r.charCodeAt(Q)===47?(Se=Rr,Q++):(Se=t,I===0&&Qe(GE))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=sS(),Bt!==t?(Me=K,ce=Ys(b,Se,Bt),K=ce):(Q=K,K=t)):(Q=K,K=t)}else Q=K,K=t;else Q=K,K=t}N!==t?(Me=m,b=js(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;return m}function Z1(){var m,b,N,K,ce,Se,ht,Bt;if(m=Q,b=oS(),b!==t){for(N=[],K=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===43?(Se=Gs,Q++):(Se=t,I===0&&Qe(Yl)),Se===t&&(r.charCodeAt(Q)===45?(Se=wA,Q++):(Se=t,I===0&&Qe(Gl))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=oS(),Bt!==t?(Me=K,ce=yg(b,Se,Bt),K=ce):(Q=K,K=t)):(Q=K,K=t)}else Q=K,K=t;else Q=K,K=t;for(;K!==t;){for(N.push(K),K=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===43?(Se=Gs,Q++):(Se=t,I===0&&Qe(Yl)),Se===t&&(r.charCodeAt(Q)===45?(Se=wA,Q++):(Se=t,I===0&&Qe(Gl))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=oS(),Bt!==t?(Me=K,ce=yg(b,Se,Bt),K=ce):(Q=K,K=t)):(Q=K,K=t)}else Q=K,K=t;else Q=K,K=t}N!==t?(Me=m,b=js(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;return m}function _1(){var m,b,N,K,ce,Se;if(m=Q,r.substr(Q,3)===QA?(b=QA,Q+=3):(b=t,I===0&&Qe(R)),b!==t){for(N=[],K=He();K!==t;)N.push(K),K=He();if(N!==t)if(K=Z1(),K!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(r.substr(Q,2)===q?(Se=q,Q+=2):(Se=t,I===0&&Qe(Ce)),Se!==t?(Me=m,b=Ue(K),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;return m}function $1(){var m,b,N,K;return m=Q,r.substr(Q,2)===Re?(b=Re,Q+=2):(b=t,I===0&&Qe(ze)),b!==t?(N=Mr(),N!==t?(r.charCodeAt(Q)===41?(K=O,Q++):(K=t,I===0&&Qe(F)),K!==t?(Me=m,b=dt(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function aS(){var m,b,N,K,ce,Se;return m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Ln)),b!==t?(N=ql(),N!==t?(r.substr(Q,2)===Jb?(K=Jb,Q+=2):(K=t,I===0&&Qe(P1)),K!==t?(ce=Y1(),ce!==t?(r.charCodeAt(Q)===125?(Se=Fe,Q++):(Se=t,I===0&&Qe(Ne)),Se!==t?(Me=m,b=D1(N,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Ln)),b!==t?(N=ql(),N!==t?(r.substr(Q,3)===Wb?(K=Wb,Q+=3):(K=t,I===0&&Qe(k1)),K!==t?(Me=m,b=R1(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Ln)),b!==t?(N=ql(),N!==t?(r.substr(Q,2)===zb?(K=zb,Q+=2):(K=t,I===0&&Qe(F1)),K!==t?(ce=Y1(),ce!==t?(r.charCodeAt(Q)===125?(Se=Fe,Q++):(Se=t,I===0&&Qe(Ne)),Se!==t?(Me=m,b=N1(N,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Ln)),b!==t?(N=ql(),N!==t?(r.substr(Q,3)===Vb?(K=Vb,Q+=3):(K=t,I===0&&Qe(L1)),K!==t?(Me=m,b=T1(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Ln)),b!==t?(N=ql(),N!==t?(r.charCodeAt(Q)===125?(K=Fe,Q++):(K=t,I===0&&Qe(Ne)),K!==t?(Me=m,b=Xb(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.charCodeAt(Q)===36?(b=O1,Q++):(b=t,I===0&&Qe(M1)),b!==t?(N=ql(),N!==t?(Me=m,b=Xb(N),m=b):(Q=m,m=t)):(Q=m,m=t)))))),m}function Qge(){var m,b,N;return m=Q,b=bge(),b!==t?(Me=Q,N=U1(b),N?N=void 0:N=t,N!==t?(Me=m,b=K1(b),m=b):(Q=m,m=t)):(Q=m,m=t),m}function bge(){var m,b,N,K,ce;if(m=Q,b=[],N=Q,K=Q,I++,ce=rU(),I--,ce===t?K=void 0:(Q=K,K=t),K!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Bo)),ce!==t?(Me=N,K=An(ce),N=K):(Q=N,N=t)):(Q=N,N=t),N!==t)for(;N!==t;)b.push(N),N=Q,K=Q,I++,ce=rU(),I--,ce===t?K=void 0:(Q=K,K=t),K!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Bo)),ce!==t?(Me=N,K=An(ce),N=K):(Q=N,N=t)):(Q=N,N=t);else b=t;return b!==t&&(Me=m,b=Rn(b)),m=b,m}function eU(){var m,b,N;if(m=Q,b=[],Zb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(_b)),N!==t)for(;N!==t;)b.push(N),Zb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(_b));else b=t;return b!==t&&(Me=m,b=$b()),m=b,m}function ql(){var m,b,N;if(m=Q,b=[],eS.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(tS)),N!==t)for(;N!==t;)b.push(N),eS.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(tS));else b=t;return b!==t&&(Me=m,b=$b()),m=b,m}function tU(){var m;return H1.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(wg)),m}function rU(){var m;return rS.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(iS)),m}function He(){var m,b;if(m=[],YE.test(r.charAt(Q))?(b=r.charAt(Q),Q++):(b=t,I===0&&Qe(jE)),b!==t)for(;b!==t;)m.push(b),YE.test(r.charAt(Q))?(b=r.charAt(Q),Q++):(b=t,I===0&&Qe(jE));else m=t;return m}if(k=n(),k!==t&&Q===r.length)return k;throw k!==t&&Q{"use strict";function Sfe(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function $l(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,$l)}Sfe($l,Error);$l.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;gH&&(H=v,j=[]),j.push(ne))}function Ne(ne,Y){return new $l(ne,null,null,Y)}function oe(ne,Y,he){return new $l($l.buildMessage(ne,Y),ne,Y,he)}function le(){var ne,Y,he,ie;return ne=v,Y=Be(),Y!==t?(r.charCodeAt(v)===47?(he=s,v++):(he=t,$===0&&Fe(o)),he!==t?(ie=Be(),ie!==t?(D=ne,Y=a(Y,ie),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=Be(),Y!==t&&(D=ne,Y=l(Y)),ne=Y),ne}function Be(){var ne,Y,he,ie;return ne=v,Y=fe(),Y!==t?(r.charCodeAt(v)===64?(he=c,v++):(he=t,$===0&&Fe(u)),he!==t?(ie=qe(),ie!==t?(D=ne,Y=g(Y,ie),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=fe(),Y!==t&&(D=ne,Y=f(Y)),ne=Y),ne}function fe(){var ne,Y,he,ie,de;return ne=v,r.charCodeAt(v)===64?(Y=c,v++):(Y=t,$===0&&Fe(u)),Y!==t?(he=ae(),he!==t?(r.charCodeAt(v)===47?(ie=s,v++):(ie=t,$===0&&Fe(o)),ie!==t?(de=ae(),de!==t?(D=ne,Y=h(),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=ae(),Y!==t&&(D=ne,Y=h()),ne=Y),ne}function ae(){var ne,Y,he;if(ne=v,Y=[],p.test(r.charAt(v))?(he=r.charAt(v),v++):(he=t,$===0&&Fe(C)),he!==t)for(;he!==t;)Y.push(he),p.test(r.charAt(v))?(he=r.charAt(v),v++):(he=t,$===0&&Fe(C));else Y=t;return Y!==t&&(D=ne,Y=h()),ne=Y,ne}function qe(){var ne,Y,he;if(ne=v,Y=[],y.test(r.charAt(v))?(he=r.charAt(v),v++):(he=t,$===0&&Fe(B)),he!==t)for(;he!==t;)Y.push(he),y.test(r.charAt(v))?(he=r.charAt(v),v++):(he=t,$===0&&Fe(B));else Y=t;return Y!==t&&(D=ne,Y=h()),ne=Y,ne}if(V=n(),V!==t&&v===r.length)return V;throw V!==t&&v{"use strict";function dK(r){return typeof r>"u"||r===null}function xfe(r){return typeof r=="object"&&r!==null}function Pfe(r){return Array.isArray(r)?r:dK(r)?[]:[r]}function Dfe(r,e){var t,i,n,s;if(e)for(s=Object.keys(e),t=0,i=s.length;t{"use strict";function Vp(r,e){Error.call(this),this.name="YAMLException",this.reason=r,this.mark=e,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||""}Vp.prototype=Object.create(Error.prototype);Vp.prototype.constructor=Vp;Vp.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t};CK.exports=Vp});var IK=w((wZe,EK)=>{"use strict";var mK=tc();function HS(r,e,t,i,n){this.name=r,this.buffer=e,this.position=t,this.line=i,this.column=n}HS.prototype.getSnippet=function(e,t){var i,n,s,o,a;if(!this.buffer)return null;for(e=e||4,t=t||75,i="",n=this.position;n>0&&`\0\r +\x85\u2028\u2029`.indexOf(this.buffer.charAt(n-1))===-1;)if(n-=1,this.position-n>t/2-1){i=" ... ",n+=5;break}for(s="",o=this.position;ot/2-1){s=" ... ",o-=5;break}return a=this.buffer.slice(n,o),mK.repeat(" ",e)+i+a+s+` +`+mK.repeat(" ",e+this.position-n+i.length)+"^"};HS.prototype.toString=function(e){var t,i="";return this.name&&(i+='in "'+this.name+'" '),i+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet(),t&&(i+=`: +`+t)),i};EK.exports=HS});var si=w((BZe,wK)=>{"use strict";var yK=Ng(),Ffe=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],Nfe=["scalar","sequence","mapping"];function Lfe(r){var e={};return r!==null&&Object.keys(r).forEach(function(t){r[t].forEach(function(i){e[String(i)]=t})}),e}function Tfe(r,e){if(e=e||{},Object.keys(e).forEach(function(t){if(Ffe.indexOf(t)===-1)throw new yK('Unknown option "'+t+'" is met in definition of "'+r+'" YAML type.')}),this.tag=r,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(t){return t},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=Lfe(e.styleAliases||null),Nfe.indexOf(this.kind)===-1)throw new yK('Unknown kind "'+this.kind+'" is specified for "'+r+'" YAML type.')}wK.exports=Tfe});var rc=w((QZe,QK)=>{"use strict";var BK=tc(),dI=Ng(),Ofe=si();function GS(r,e,t){var i=[];return r.include.forEach(function(n){t=GS(n,e,t)}),r[e].forEach(function(n){t.forEach(function(s,o){s.tag===n.tag&&s.kind===n.kind&&i.push(o)}),t.push(n)}),t.filter(function(n,s){return i.indexOf(s)===-1})}function Mfe(){var r={scalar:{},sequence:{},mapping:{},fallback:{}},e,t;function i(n){r[n.kind][n.tag]=r.fallback[n.tag]=n}for(e=0,t=arguments.length;e{"use strict";var Ufe=si();bK.exports=new Ufe("tag:yaml.org,2002:str",{kind:"scalar",construct:function(r){return r!==null?r:""}})});var xK=w((SZe,vK)=>{"use strict";var Kfe=si();vK.exports=new Kfe("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(r){return r!==null?r:[]}})});var DK=w((vZe,PK)=>{"use strict";var Hfe=si();PK.exports=new Hfe("tag:yaml.org,2002:map",{kind:"mapping",construct:function(r){return r!==null?r:{}}})});var CI=w((xZe,kK)=>{"use strict";var Gfe=rc();kK.exports=new Gfe({explicit:[SK(),xK(),DK()]})});var FK=w((PZe,RK)=>{"use strict";var Yfe=si();function jfe(r){if(r===null)return!0;var e=r.length;return e===1&&r==="~"||e===4&&(r==="null"||r==="Null"||r==="NULL")}function qfe(){return null}function Jfe(r){return r===null}RK.exports=new Yfe("tag:yaml.org,2002:null",{kind:"scalar",resolve:jfe,construct:qfe,predicate:Jfe,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})});var LK=w((DZe,NK)=>{"use strict";var Wfe=si();function zfe(r){if(r===null)return!1;var e=r.length;return e===4&&(r==="true"||r==="True"||r==="TRUE")||e===5&&(r==="false"||r==="False"||r==="FALSE")}function Vfe(r){return r==="true"||r==="True"||r==="TRUE"}function Xfe(r){return Object.prototype.toString.call(r)==="[object Boolean]"}NK.exports=new Wfe("tag:yaml.org,2002:bool",{kind:"scalar",resolve:zfe,construct:Vfe,predicate:Xfe,represent:{lowercase:function(r){return r?"true":"false"},uppercase:function(r){return r?"TRUE":"FALSE"},camelcase:function(r){return r?"True":"False"}},defaultStyle:"lowercase"})});var OK=w((kZe,TK)=>{"use strict";var Zfe=tc(),_fe=si();function $fe(r){return 48<=r&&r<=57||65<=r&&r<=70||97<=r&&r<=102}function ehe(r){return 48<=r&&r<=55}function the(r){return 48<=r&&r<=57}function rhe(r){if(r===null)return!1;var e=r.length,t=0,i=!1,n;if(!e)return!1;if(n=r[t],(n==="-"||n==="+")&&(n=r[++t]),n==="0"){if(t+1===e)return!0;if(n=r[++t],n==="b"){for(t++;t=0?"0b"+r.toString(2):"-0b"+r.toString(2).slice(1)},octal:function(r){return r>=0?"0"+r.toString(8):"-0"+r.toString(8).slice(1)},decimal:function(r){return r.toString(10)},hexadecimal:function(r){return r>=0?"0x"+r.toString(16).toUpperCase():"-0x"+r.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})});var KK=w((RZe,UK)=>{"use strict";var MK=tc(),she=si(),ohe=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function ahe(r){return!(r===null||!ohe.test(r)||r[r.length-1]==="_")}function Ahe(r){var e,t,i,n;return e=r.replace(/_/g,"").toLowerCase(),t=e[0]==="-"?-1:1,n=[],"+-".indexOf(e[0])>=0&&(e=e.slice(1)),e===".inf"?t===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===".nan"?NaN:e.indexOf(":")>=0?(e.split(":").forEach(function(s){n.unshift(parseFloat(s,10))}),e=0,i=1,n.forEach(function(s){e+=s*i,i*=60}),t*e):t*parseFloat(e,10)}var lhe=/^[-+]?[0-9]+e/;function che(r,e){var t;if(isNaN(r))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===r)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===r)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(MK.isNegativeZero(r))return"-0.0";return t=r.toString(10),lhe.test(t)?t.replace("e",".e"):t}function uhe(r){return Object.prototype.toString.call(r)==="[object Number]"&&(r%1!==0||MK.isNegativeZero(r))}UK.exports=new she("tag:yaml.org,2002:float",{kind:"scalar",resolve:ahe,construct:Ahe,predicate:uhe,represent:che,defaultStyle:"lowercase"})});var YS=w((FZe,HK)=>{"use strict";var ghe=rc();HK.exports=new ghe({include:[CI()],implicit:[FK(),LK(),OK(),KK()]})});var jS=w((NZe,GK)=>{"use strict";var fhe=rc();GK.exports=new fhe({include:[YS()]})});var JK=w((LZe,qK)=>{"use strict";var hhe=si(),YK=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),jK=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function phe(r){return r===null?!1:YK.exec(r)!==null||jK.exec(r)!==null}function dhe(r){var e,t,i,n,s,o,a,l=0,c=null,u,g,f;if(e=YK.exec(r),e===null&&(e=jK.exec(r)),e===null)throw new Error("Date resolve error");if(t=+e[1],i=+e[2]-1,n=+e[3],!e[4])return new Date(Date.UTC(t,i,n));if(s=+e[4],o=+e[5],a=+e[6],e[7]){for(l=e[7].slice(0,3);l.length<3;)l+="0";l=+l}return e[9]&&(u=+e[10],g=+(e[11]||0),c=(u*60+g)*6e4,e[9]==="-"&&(c=-c)),f=new Date(Date.UTC(t,i,n,s,o,a,l)),c&&f.setTime(f.getTime()-c),f}function Che(r){return r.toISOString()}qK.exports=new hhe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:phe,construct:dhe,instanceOf:Date,represent:Che})});var zK=w((TZe,WK)=>{"use strict";var mhe=si();function Ehe(r){return r==="<<"||r===null}WK.exports=new mhe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:Ehe})});var ZK=w((OZe,XK)=>{"use strict";var ic;try{VK=J,ic=VK("buffer").Buffer}catch{}var VK,Ihe=si(),qS=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= +\r`;function yhe(r){if(r===null)return!1;var e,t,i=0,n=r.length,s=qS;for(t=0;t64)){if(e<0)return!1;i+=6}return i%8===0}function whe(r){var e,t,i=r.replace(/[\r\n=]/g,""),n=i.length,s=qS,o=0,a=[];for(e=0;e>16&255),a.push(o>>8&255),a.push(o&255)),o=o<<6|s.indexOf(i.charAt(e));return t=n%4*6,t===0?(a.push(o>>16&255),a.push(o>>8&255),a.push(o&255)):t===18?(a.push(o>>10&255),a.push(o>>2&255)):t===12&&a.push(o>>4&255),ic?ic.from?ic.from(a):new ic(a):a}function Bhe(r){var e="",t=0,i,n,s=r.length,o=qS;for(i=0;i>18&63],e+=o[t>>12&63],e+=o[t>>6&63],e+=o[t&63]),t=(t<<8)+r[i];return n=s%3,n===0?(e+=o[t>>18&63],e+=o[t>>12&63],e+=o[t>>6&63],e+=o[t&63]):n===2?(e+=o[t>>10&63],e+=o[t>>4&63],e+=o[t<<2&63],e+=o[64]):n===1&&(e+=o[t>>2&63],e+=o[t<<4&63],e+=o[64],e+=o[64]),e}function Qhe(r){return ic&&ic.isBuffer(r)}XK.exports=new Ihe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:yhe,construct:whe,predicate:Qhe,represent:Bhe})});var $K=w((UZe,_K)=>{"use strict";var bhe=si(),She=Object.prototype.hasOwnProperty,vhe=Object.prototype.toString;function xhe(r){if(r===null)return!0;var e=[],t,i,n,s,o,a=r;for(t=0,i=a.length;t{"use strict";var Dhe=si(),khe=Object.prototype.toString;function Rhe(r){if(r===null)return!0;var e,t,i,n,s,o=r;for(s=new Array(o.length),e=0,t=o.length;e{"use strict";var Nhe=si(),Lhe=Object.prototype.hasOwnProperty;function The(r){if(r===null)return!0;var e,t=r;for(e in t)if(Lhe.call(t,e)&&t[e]!==null)return!1;return!0}function Ohe(r){return r!==null?r:{}}r2.exports=new Nhe("tag:yaml.org,2002:set",{kind:"mapping",resolve:The,construct:Ohe})});var Tg=w((GZe,n2)=>{"use strict";var Mhe=rc();n2.exports=new Mhe({include:[jS()],implicit:[JK(),zK()],explicit:[ZK(),$K(),t2(),i2()]})});var o2=w((YZe,s2)=>{"use strict";var Uhe=si();function Khe(){return!0}function Hhe(){}function Ghe(){return""}function Yhe(r){return typeof r>"u"}s2.exports=new Uhe("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:Khe,construct:Hhe,predicate:Yhe,represent:Ghe})});var A2=w((jZe,a2)=>{"use strict";var jhe=si();function qhe(r){if(r===null||r.length===0)return!1;var e=r,t=/\/([gim]*)$/.exec(r),i="";return!(e[0]==="/"&&(t&&(i=t[1]),i.length>3||e[e.length-i.length-1]!=="/"))}function Jhe(r){var e=r,t=/\/([gim]*)$/.exec(r),i="";return e[0]==="/"&&(t&&(i=t[1]),e=e.slice(1,e.length-i.length-1)),new RegExp(e,i)}function Whe(r){var e="/"+r.source+"/";return r.global&&(e+="g"),r.multiline&&(e+="m"),r.ignoreCase&&(e+="i"),e}function zhe(r){return Object.prototype.toString.call(r)==="[object RegExp]"}a2.exports=new jhe("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:qhe,construct:Jhe,predicate:zhe,represent:Whe})});var u2=w((qZe,c2)=>{"use strict";var mI;try{l2=J,mI=l2("esprima")}catch{typeof window<"u"&&(mI=window.esprima)}var l2,Vhe=si();function Xhe(r){if(r===null)return!1;try{var e="("+r+")",t=mI.parse(e,{range:!0});return!(t.type!=="Program"||t.body.length!==1||t.body[0].type!=="ExpressionStatement"||t.body[0].expression.type!=="ArrowFunctionExpression"&&t.body[0].expression.type!=="FunctionExpression")}catch{return!1}}function Zhe(r){var e="("+r+")",t=mI.parse(e,{range:!0}),i=[],n;if(t.type!=="Program"||t.body.length!==1||t.body[0].type!=="ExpressionStatement"||t.body[0].expression.type!=="ArrowFunctionExpression"&&t.body[0].expression.type!=="FunctionExpression")throw new Error("Failed to resolve function");return t.body[0].expression.params.forEach(function(s){i.push(s.name)}),n=t.body[0].expression.body.range,t.body[0].expression.body.type==="BlockStatement"?new Function(i,e.slice(n[0]+1,n[1]-1)):new Function(i,"return "+e.slice(n[0],n[1]))}function _he(r){return r.toString()}function $he(r){return Object.prototype.toString.call(r)==="[object Function]"}c2.exports=new Vhe("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:Xhe,construct:Zhe,predicate:$he,represent:_he})});var Xp=w((WZe,f2)=>{"use strict";var g2=rc();f2.exports=g2.DEFAULT=new g2({include:[Tg()],explicit:[o2(),A2(),u2()]})});var R2=w((zZe,Zp)=>{"use strict";var wa=tc(),I2=Ng(),epe=IK(),y2=Tg(),tpe=Xp(),kA=Object.prototype.hasOwnProperty,EI=1,w2=2,B2=3,II=4,JS=1,rpe=2,h2=3,ipe=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,npe=/[\x85\u2028\u2029]/,spe=/[,\[\]\{\}]/,Q2=/^(?:!|!!|![a-z\-]+!)$/i,b2=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function p2(r){return Object.prototype.toString.call(r)}function vo(r){return r===10||r===13}function sc(r){return r===9||r===32}function gn(r){return r===9||r===32||r===10||r===13}function Og(r){return r===44||r===91||r===93||r===123||r===125}function ope(r){var e;return 48<=r&&r<=57?r-48:(e=r|32,97<=e&&e<=102?e-97+10:-1)}function ape(r){return r===120?2:r===117?4:r===85?8:0}function Ape(r){return 48<=r&&r<=57?r-48:-1}function d2(r){return r===48?"\0":r===97?"\x07":r===98?"\b":r===116||r===9?" ":r===110?` +`:r===118?"\v":r===102?"\f":r===114?"\r":r===101?"\x1B":r===32?" ":r===34?'"':r===47?"/":r===92?"\\":r===78?"\x85":r===95?"\xA0":r===76?"\u2028":r===80?"\u2029":""}function lpe(r){return r<=65535?String.fromCharCode(r):String.fromCharCode((r-65536>>10)+55296,(r-65536&1023)+56320)}var S2=new Array(256),v2=new Array(256);for(nc=0;nc<256;nc++)S2[nc]=d2(nc)?1:0,v2[nc]=d2(nc);var nc;function cpe(r,e){this.input=r,this.filename=e.filename||null,this.schema=e.schema||tpe,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=r.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function x2(r,e){return new I2(e,new epe(r.filename,r.input,r.position,r.line,r.position-r.lineStart))}function ft(r,e){throw x2(r,e)}function yI(r,e){r.onWarning&&r.onWarning.call(null,x2(r,e))}var C2={YAML:function(e,t,i){var n,s,o;e.version!==null&&ft(e,"duplication of %YAML directive"),i.length!==1&&ft(e,"YAML directive accepts exactly one argument"),n=/^([0-9]+)\.([0-9]+)$/.exec(i[0]),n===null&&ft(e,"ill-formed argument of the YAML directive"),s=parseInt(n[1],10),o=parseInt(n[2],10),s!==1&&ft(e,"unacceptable YAML version of the document"),e.version=i[0],e.checkLineBreaks=o<2,o!==1&&o!==2&&yI(e,"unsupported YAML version of the document")},TAG:function(e,t,i){var n,s;i.length!==2&&ft(e,"TAG directive accepts exactly two arguments"),n=i[0],s=i[1],Q2.test(n)||ft(e,"ill-formed tag handle (first argument) of the TAG directive"),kA.call(e.tagMap,n)&&ft(e,'there is a previously declared suffix for "'+n+'" tag handle'),b2.test(s)||ft(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[n]=s}};function DA(r,e,t,i){var n,s,o,a;if(e1&&(r.result+=wa.repeat(` +`,e-1))}function upe(r,e,t){var i,n,s,o,a,l,c,u,g=r.kind,f=r.result,h;if(h=r.input.charCodeAt(r.position),gn(h)||Og(h)||h===35||h===38||h===42||h===33||h===124||h===62||h===39||h===34||h===37||h===64||h===96||(h===63||h===45)&&(n=r.input.charCodeAt(r.position+1),gn(n)||t&&Og(n)))return!1;for(r.kind="scalar",r.result="",s=o=r.position,a=!1;h!==0;){if(h===58){if(n=r.input.charCodeAt(r.position+1),gn(n)||t&&Og(n))break}else if(h===35){if(i=r.input.charCodeAt(r.position-1),gn(i))break}else{if(r.position===r.lineStart&&wI(r)||t&&Og(h))break;if(vo(h))if(l=r.line,c=r.lineStart,u=r.lineIndent,zr(r,!1,-1),r.lineIndent>=e){a=!0,h=r.input.charCodeAt(r.position);continue}else{r.position=o,r.line=l,r.lineStart=c,r.lineIndent=u;break}}a&&(DA(r,s,o,!1),zS(r,r.line-l),s=o=r.position,a=!1),sc(h)||(o=r.position+1),h=r.input.charCodeAt(++r.position)}return DA(r,s,o,!1),r.result?!0:(r.kind=g,r.result=f,!1)}function gpe(r,e){var t,i,n;if(t=r.input.charCodeAt(r.position),t!==39)return!1;for(r.kind="scalar",r.result="",r.position++,i=n=r.position;(t=r.input.charCodeAt(r.position))!==0;)if(t===39)if(DA(r,i,r.position,!0),t=r.input.charCodeAt(++r.position),t===39)i=r.position,r.position++,n=r.position;else return!0;else vo(t)?(DA(r,i,n,!0),zS(r,zr(r,!1,e)),i=n=r.position):r.position===r.lineStart&&wI(r)?ft(r,"unexpected end of the document within a single quoted scalar"):(r.position++,n=r.position);ft(r,"unexpected end of the stream within a single quoted scalar")}function fpe(r,e){var t,i,n,s,o,a;if(a=r.input.charCodeAt(r.position),a!==34)return!1;for(r.kind="scalar",r.result="",r.position++,t=i=r.position;(a=r.input.charCodeAt(r.position))!==0;){if(a===34)return DA(r,t,r.position,!0),r.position++,!0;if(a===92){if(DA(r,t,r.position,!0),a=r.input.charCodeAt(++r.position),vo(a))zr(r,!1,e);else if(a<256&&S2[a])r.result+=v2[a],r.position++;else if((o=ape(a))>0){for(n=o,s=0;n>0;n--)a=r.input.charCodeAt(++r.position),(o=ope(a))>=0?s=(s<<4)+o:ft(r,"expected hexadecimal character");r.result+=lpe(s),r.position++}else ft(r,"unknown escape sequence");t=i=r.position}else vo(a)?(DA(r,t,i,!0),zS(r,zr(r,!1,e)),t=i=r.position):r.position===r.lineStart&&wI(r)?ft(r,"unexpected end of the document within a double quoted scalar"):(r.position++,i=r.position)}ft(r,"unexpected end of the stream within a double quoted scalar")}function hpe(r,e){var t=!0,i,n=r.tag,s,o=r.anchor,a,l,c,u,g,f={},h,p,C,y;if(y=r.input.charCodeAt(r.position),y===91)l=93,g=!1,s=[];else if(y===123)l=125,g=!0,s={};else return!1;for(r.anchor!==null&&(r.anchorMap[r.anchor]=s),y=r.input.charCodeAt(++r.position);y!==0;){if(zr(r,!0,e),y=r.input.charCodeAt(r.position),y===l)return r.position++,r.tag=n,r.anchor=o,r.kind=g?"mapping":"sequence",r.result=s,!0;t||ft(r,"missed comma between flow collection entries"),p=h=C=null,c=u=!1,y===63&&(a=r.input.charCodeAt(r.position+1),gn(a)&&(c=u=!0,r.position++,zr(r,!0,e))),i=r.line,Ug(r,e,EI,!1,!0),p=r.tag,h=r.result,zr(r,!0,e),y=r.input.charCodeAt(r.position),(u||r.line===i)&&y===58&&(c=!0,y=r.input.charCodeAt(++r.position),zr(r,!0,e),Ug(r,e,EI,!1,!0),C=r.result),g?Mg(r,s,f,p,h,C):c?s.push(Mg(r,null,f,p,h,C)):s.push(h),zr(r,!0,e),y=r.input.charCodeAt(r.position),y===44?(t=!0,y=r.input.charCodeAt(++r.position)):t=!1}ft(r,"unexpected end of the stream within a flow collection")}function ppe(r,e){var t,i,n=JS,s=!1,o=!1,a=e,l=0,c=!1,u,g;if(g=r.input.charCodeAt(r.position),g===124)i=!1;else if(g===62)i=!0;else return!1;for(r.kind="scalar",r.result="";g!==0;)if(g=r.input.charCodeAt(++r.position),g===43||g===45)JS===n?n=g===43?h2:rpe:ft(r,"repeat of a chomping mode identifier");else if((u=Ape(g))>=0)u===0?ft(r,"bad explicit indentation width of a block scalar; it cannot be less than one"):o?ft(r,"repeat of an indentation width identifier"):(a=e+u-1,o=!0);else break;if(sc(g)){do g=r.input.charCodeAt(++r.position);while(sc(g));if(g===35)do g=r.input.charCodeAt(++r.position);while(!vo(g)&&g!==0)}for(;g!==0;){for(WS(r),r.lineIndent=0,g=r.input.charCodeAt(r.position);(!o||r.lineIndenta&&(a=r.lineIndent),vo(g)){l++;continue}if(r.lineIndente)&&l!==0)ft(r,"bad indentation of a sequence entry");else if(r.lineIndente)&&(Ug(r,e,II,!0,n)&&(p?f=r.result:h=r.result),p||(Mg(r,c,u,g,f,h,s,o),g=f=h=null),zr(r,!0,-1),y=r.input.charCodeAt(r.position)),r.lineIndent>e&&y!==0)ft(r,"bad indentation of a mapping entry");else if(r.lineIndente?l=1:r.lineIndent===e?l=0:r.lineIndente?l=1:r.lineIndent===e?l=0:r.lineIndent tag; it should be "scalar", not "'+r.kind+'"'),g=0,f=r.implicitTypes.length;g tag; it should be "'+h.kind+'", not "'+r.kind+'"'),h.resolve(r.result)?(r.result=h.construct(r.result),r.anchor!==null&&(r.anchorMap[r.anchor]=r.result)):ft(r,"cannot resolve a node with !<"+r.tag+"> explicit tag")):ft(r,"unknown tag !<"+r.tag+">");return r.listener!==null&&r.listener("close",r),r.tag!==null||r.anchor!==null||u}function Ipe(r){var e=r.position,t,i,n,s=!1,o;for(r.version=null,r.checkLineBreaks=r.legacy,r.tagMap={},r.anchorMap={};(o=r.input.charCodeAt(r.position))!==0&&(zr(r,!0,-1),o=r.input.charCodeAt(r.position),!(r.lineIndent>0||o!==37));){for(s=!0,o=r.input.charCodeAt(++r.position),t=r.position;o!==0&&!gn(o);)o=r.input.charCodeAt(++r.position);for(i=r.input.slice(t,r.position),n=[],i.length<1&&ft(r,"directive name must not be less than one character in length");o!==0;){for(;sc(o);)o=r.input.charCodeAt(++r.position);if(o===35){do o=r.input.charCodeAt(++r.position);while(o!==0&&!vo(o));break}if(vo(o))break;for(t=r.position;o!==0&&!gn(o);)o=r.input.charCodeAt(++r.position);n.push(r.input.slice(t,r.position))}o!==0&&WS(r),kA.call(C2,i)?C2[i](r,i,n):yI(r,'unknown document directive "'+i+'"')}if(zr(r,!0,-1),r.lineIndent===0&&r.input.charCodeAt(r.position)===45&&r.input.charCodeAt(r.position+1)===45&&r.input.charCodeAt(r.position+2)===45?(r.position+=3,zr(r,!0,-1)):s&&ft(r,"directives end mark is expected"),Ug(r,r.lineIndent-1,II,!1,!0),zr(r,!0,-1),r.checkLineBreaks&&npe.test(r.input.slice(e,r.position))&&yI(r,"non-ASCII line breaks are interpreted as content"),r.documents.push(r.result),r.position===r.lineStart&&wI(r)){r.input.charCodeAt(r.position)===46&&(r.position+=3,zr(r,!0,-1));return}if(r.position"u"&&(t=e,e=null);var i=P2(r,t);if(typeof e!="function")return i;for(var n=0,s=i.length;n"u"&&(t=e,e=null),D2(r,e,wa.extend({schema:y2},t))}function wpe(r,e){return k2(r,wa.extend({schema:y2},e))}Zp.exports.loadAll=D2;Zp.exports.load=k2;Zp.exports.safeLoadAll=ype;Zp.exports.safeLoad=wpe});var tH=w((VZe,_S)=>{"use strict";var $p=tc(),ed=Ng(),Bpe=Xp(),Qpe=Tg(),K2=Object.prototype.toString,H2=Object.prototype.hasOwnProperty,bpe=9,_p=10,Spe=13,vpe=32,xpe=33,Ppe=34,G2=35,Dpe=37,kpe=38,Rpe=39,Fpe=42,Y2=44,Npe=45,j2=58,Lpe=61,Tpe=62,Ope=63,Mpe=64,q2=91,J2=93,Upe=96,W2=123,Kpe=124,z2=125,Ni={};Ni[0]="\\0";Ni[7]="\\a";Ni[8]="\\b";Ni[9]="\\t";Ni[10]="\\n";Ni[11]="\\v";Ni[12]="\\f";Ni[13]="\\r";Ni[27]="\\e";Ni[34]='\\"';Ni[92]="\\\\";Ni[133]="\\N";Ni[160]="\\_";Ni[8232]="\\L";Ni[8233]="\\P";var Hpe=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function Gpe(r,e){var t,i,n,s,o,a,l;if(e===null)return{};for(t={},i=Object.keys(e),n=0,s=i.length;n0?r.charCodeAt(s-1):null,f=f&&L2(o,a)}else{for(s=0;si&&r[g+1]!==" ",g=s);else if(!Kg(o))return BI;a=s>0?r.charCodeAt(s-1):null,f=f&&L2(o,a)}c=c||u&&s-g-1>i&&r[g+1]!==" "}return!l&&!c?f&&!n(r)?X2:Z2:t>9&&V2(r)?BI:c?$2:_2}function zpe(r,e,t,i){r.dump=function(){if(e.length===0)return"''";if(!r.noCompatMode&&Hpe.indexOf(e)!==-1)return"'"+e+"'";var n=r.indent*Math.max(1,t),s=r.lineWidth===-1?-1:Math.max(Math.min(r.lineWidth,40),r.lineWidth-n),o=i||r.flowLevel>-1&&t>=r.flowLevel;function a(l){return jpe(r,l)}switch(Wpe(e,o,r.indent,s,a)){case X2:return e;case Z2:return"'"+e.replace(/'/g,"''")+"'";case _2:return"|"+T2(e,r.indent)+O2(N2(e,n));case $2:return">"+T2(e,r.indent)+O2(N2(Vpe(e,s),n));case BI:return'"'+Xpe(e,s)+'"';default:throw new ed("impossible error: invalid scalar style")}}()}function T2(r,e){var t=V2(r)?String(e):"",i=r[r.length-1]===` +`,n=i&&(r[r.length-2]===` +`||r===` +`),s=n?"+":i?"":"-";return t+s+` +`}function O2(r){return r[r.length-1]===` +`?r.slice(0,-1):r}function Vpe(r,e){for(var t=/(\n+)([^\n]*)/g,i=function(){var c=r.indexOf(` +`);return c=c!==-1?c:r.length,t.lastIndex=c,M2(r.slice(0,c),e)}(),n=r[0]===` +`||r[0]===" ",s,o;o=t.exec(r);){var a=o[1],l=o[2];s=l[0]===" ",i+=a+(!n&&!s&&l!==""?` +`:"")+M2(l,e),n=s}return i}function M2(r,e){if(r===""||r[0]===" ")return r;for(var t=/ [^ ]/g,i,n=0,s,o=0,a=0,l="";i=t.exec(r);)a=i.index,a-n>e&&(s=o>n?o:a,l+=` +`+r.slice(n,s),n=s+1),o=a;return l+=` +`,r.length-n>e&&o>n?l+=r.slice(n,o)+` +`+r.slice(o+1):l+=r.slice(n),l.slice(1)}function Xpe(r){for(var e="",t,i,n,s=0;s=55296&&t<=56319&&(i=r.charCodeAt(s+1),i>=56320&&i<=57343)){e+=F2((t-55296)*1024+i-56320+65536),s++;continue}n=Ni[t],e+=!n&&Kg(t)?r[s]:n||F2(t)}return e}function Zpe(r,e,t){var i="",n=r.tag,s,o;for(s=0,o=t.length;s1024&&(u+="? "),u+=r.dump+(r.condenseFlow?'"':"")+":"+(r.condenseFlow?"":" "),oc(r,e,c,!1,!1)&&(u+=r.dump,i+=u));r.tag=n,r.dump="{"+i+"}"}function ede(r,e,t,i){var n="",s=r.tag,o=Object.keys(t),a,l,c,u,g,f;if(r.sortKeys===!0)o.sort();else if(typeof r.sortKeys=="function")o.sort(r.sortKeys);else if(r.sortKeys)throw new ed("sortKeys must be a boolean or a function");for(a=0,l=o.length;a1024,g&&(r.dump&&_p===r.dump.charCodeAt(0)?f+="?":f+="? "),f+=r.dump,g&&(f+=VS(r,e)),oc(r,e+1,u,!0,g)&&(r.dump&&_p===r.dump.charCodeAt(0)?f+=":":f+=": ",f+=r.dump,n+=f));r.tag=s,r.dump=n||"{}"}function U2(r,e,t){var i,n,s,o,a,l;for(n=t?r.explicitTypes:r.implicitTypes,s=0,o=n.length;s tag resolver accepts not "'+l+'" style');r.dump=i}return!0}return!1}function oc(r,e,t,i,n,s){r.tag=null,r.dump=t,U2(r,t,!1)||U2(r,t,!0);var o=K2.call(r.dump);i&&(i=r.flowLevel<0||r.flowLevel>e);var a=o==="[object Object]"||o==="[object Array]",l,c;if(a&&(l=r.duplicates.indexOf(t),c=l!==-1),(r.tag!==null&&r.tag!=="?"||c||r.indent!==2&&e>0)&&(n=!1),c&&r.usedDuplicates[l])r.dump="*ref_"+l;else{if(a&&c&&!r.usedDuplicates[l]&&(r.usedDuplicates[l]=!0),o==="[object Object]")i&&Object.keys(r.dump).length!==0?(ede(r,e,r.dump,n),c&&(r.dump="&ref_"+l+r.dump)):($pe(r,e,r.dump),c&&(r.dump="&ref_"+l+" "+r.dump));else if(o==="[object Array]"){var u=r.noArrayIndent&&e>0?e-1:e;i&&r.dump.length!==0?(_pe(r,u,r.dump,n),c&&(r.dump="&ref_"+l+r.dump)):(Zpe(r,u,r.dump),c&&(r.dump="&ref_"+l+" "+r.dump))}else if(o==="[object String]")r.tag!=="?"&&zpe(r,r.dump,e,s);else{if(r.skipInvalid)return!1;throw new ed("unacceptable kind of an object to dump "+o)}r.tag!==null&&r.tag!=="?"&&(r.dump="!<"+r.tag+"> "+r.dump)}return!0}function tde(r,e){var t=[],i=[],n,s;for(XS(r,t,i),n=0,s=i.length;n{"use strict";var QI=R2(),rH=tH();function bI(r){return function(){throw new Error("Function "+r+" is deprecated and cannot be used.")}}Fr.exports.Type=si();Fr.exports.Schema=rc();Fr.exports.FAILSAFE_SCHEMA=CI();Fr.exports.JSON_SCHEMA=YS();Fr.exports.CORE_SCHEMA=jS();Fr.exports.DEFAULT_SAFE_SCHEMA=Tg();Fr.exports.DEFAULT_FULL_SCHEMA=Xp();Fr.exports.load=QI.load;Fr.exports.loadAll=QI.loadAll;Fr.exports.safeLoad=QI.safeLoad;Fr.exports.safeLoadAll=QI.safeLoadAll;Fr.exports.dump=rH.dump;Fr.exports.safeDump=rH.safeDump;Fr.exports.YAMLException=Ng();Fr.exports.MINIMAL_SCHEMA=CI();Fr.exports.SAFE_SCHEMA=Tg();Fr.exports.DEFAULT_SCHEMA=Xp();Fr.exports.scan=bI("scan");Fr.exports.parse=bI("parse");Fr.exports.compose=bI("compose");Fr.exports.addConstructor=bI("addConstructor")});var sH=w((ZZe,nH)=>{"use strict";var ide=iH();nH.exports=ide});var aH=w((_Ze,oH)=>{"use strict";function nde(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function ac(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,ac)}nde(ac,Error);ac.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;g({[Ue]:Ce})))},H=function(R){return R},j=function(R){return R},$=Ks("correct indentation"),V=" ",W=ar(" ",!1),_=function(R){return R.length===QA*yg},A=function(R){return R.length===(QA+1)*yg},Ae=function(){return QA++,!0},ge=function(){return QA--,!0},re=function(){return pg()},O=Ks("pseudostring"),F=/^[^\r\n\t ?:,\][{}#&*!|>'"%@`\-]/,ue=Nn(["\r",` +`," "," ","?",":",",","]","[","{","}","#","&","*","!","|",">","'",'"',"%","@","`","-"],!0,!1),pe=/^[^\r\n\t ,\][{}:#"']/,ke=Nn(["\r",` +`," "," ",",","]","[","{","}",":","#",'"',"'"],!0,!1),Fe=function(){return pg().replace(/^ *| *$/g,"")},Ne="--",oe=ar("--",!1),le=/^[a-zA-Z\/0-9]/,Be=Nn([["a","z"],["A","Z"],"/",["0","9"]],!1,!1),fe=/^[^\r\n\t :,]/,ae=Nn(["\r",` +`," "," ",":",","],!0,!1),qe="null",ne=ar("null",!1),Y=function(){return null},he="true",ie=ar("true",!1),de=function(){return!0},_e="false",Pt=ar("false",!1),It=function(){return!1},Or=Ks("string"),ii='"',gi=ar('"',!1),hr=function(){return""},fi=function(R){return R},ni=function(R){return R.join("")},Us=/^[^"\\\0-\x1F\x7F]/,pr=Nn(['"',"\\",["\0",""],"\x7F"],!0,!1),Ii='\\"',rs=ar('\\"',!1),ga=function(){return'"'},dA="\\\\",cg=ar("\\\\",!1),is=function(){return"\\"},CA="\\/",fa=ar("\\/",!1),wp=function(){return"/"},mA="\\b",EA=ar("\\b",!1),wr=function(){return"\b"},Ll="\\f",ug=ar("\\f",!1),Io=function(){return"\f"},gg="\\n",Bp=ar("\\n",!1),Qp=function(){return` +`},vr="\\r",se=ar("\\r",!1),yo=function(){return"\r"},Rn="\\t",fg=ar("\\t",!1),Qt=function(){return" "},Tl="\\u",Fn=ar("\\u",!1),ns=function(R,q,Ce,Ue){return String.fromCharCode(parseInt(`0x${R}${q}${Ce}${Ue}`))},ss=/^[0-9a-fA-F]/,gt=Nn([["0","9"],["a","f"],["A","F"]],!1,!1),wo=Ks("blank space"),At=/^[ \t]/,An=Nn([" "," "],!1,!1),S=Ks("white space"),Tt=/^[ \t\n\r]/,hg=Nn([" "," ",` +`,"\r"],!1,!1),Ol=`\r +`,bp=ar(`\r +`,!1),Sp=` +`,vp=ar(` +`,!1),xp="\r",Pp=ar("\r",!1),G=0,yt=0,IA=[{line:1,column:1}],Wi=0,Ml=[],Xe=0,ha;if("startRule"in e){if(!(e.startRule in i))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');n=i[e.startRule]}function pg(){return r.substring(yt,G)}function OE(){return ln(yt,G)}function Dp(R,q){throw q=q!==void 0?q:ln(yt,G),Kl([Ks(R)],r.substring(yt,G),q)}function ME(R,q){throw q=q!==void 0?q:ln(yt,G),dg(R,q)}function ar(R,q){return{type:"literal",text:R,ignoreCase:q}}function Nn(R,q,Ce){return{type:"class",parts:R,inverted:q,ignoreCase:Ce}}function Ul(){return{type:"any"}}function kp(){return{type:"end"}}function Ks(R){return{type:"other",description:R}}function pa(R){var q=IA[R],Ce;if(q)return q;for(Ce=R-1;!IA[Ce];)Ce--;for(q=IA[Ce],q={line:q.line,column:q.column};CeWi&&(Wi=G,Ml=[]),Ml.push(R))}function dg(R,q){return new ac(R,null,null,q)}function Kl(R,q,Ce){return new ac(ac.buildMessage(R,q),R,q,Ce)}function Hs(){var R;return R=Cg(),R}function Hl(){var R,q,Ce;for(R=G,q=[],Ce=yA();Ce!==t;)q.push(Ce),Ce=yA();return q!==t&&(yt=R,q=s(q)),R=q,R}function yA(){var R,q,Ce,Ue,Re;return R=G,q=Ca(),q!==t?(r.charCodeAt(G)===45?(Ce=o,G++):(Ce=t,Xe===0&&Te(a)),Ce!==t?(Ue=Rr(),Ue!==t?(Re=da(),Re!==t?(yt=R,q=l(Re),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R}function Cg(){var R,q,Ce;for(R=G,q=[],Ce=mg();Ce!==t;)q.push(Ce),Ce=mg();return q!==t&&(yt=R,q=c(q)),R=q,R}function mg(){var R,q,Ce,Ue,Re,ze,dt,Ft,Ln;if(R=G,q=Rr(),q===t&&(q=null),q!==t){if(Ce=G,r.charCodeAt(G)===35?(Ue=u,G++):(Ue=t,Xe===0&&Te(g)),Ue!==t){if(Re=[],ze=G,dt=G,Xe++,Ft=js(),Xe--,Ft===t?dt=void 0:(G=dt,dt=t),dt!==t?(r.length>G?(Ft=r.charAt(G),G++):(Ft=t,Xe===0&&Te(f)),Ft!==t?(dt=[dt,Ft],ze=dt):(G=ze,ze=t)):(G=ze,ze=t),ze!==t)for(;ze!==t;)Re.push(ze),ze=G,dt=G,Xe++,Ft=js(),Xe--,Ft===t?dt=void 0:(G=dt,dt=t),dt!==t?(r.length>G?(Ft=r.charAt(G),G++):(Ft=t,Xe===0&&Te(f)),Ft!==t?(dt=[dt,Ft],ze=dt):(G=ze,ze=t)):(G=ze,ze=t);else Re=t;Re!==t?(Ue=[Ue,Re],Ce=Ue):(G=Ce,Ce=t)}else G=Ce,Ce=t;if(Ce===t&&(Ce=null),Ce!==t){if(Ue=[],Re=Ys(),Re!==t)for(;Re!==t;)Ue.push(Re),Re=Ys();else Ue=t;Ue!==t?(yt=R,q=h(),R=q):(G=R,R=t)}else G=R,R=t}else G=R,R=t;if(R===t&&(R=G,q=Ca(),q!==t?(Ce=Gl(),Ce!==t?(Ue=Rr(),Ue===t&&(Ue=null),Ue!==t?(r.charCodeAt(G)===58?(Re=p,G++):(Re=t,Xe===0&&Te(C)),Re!==t?(ze=Rr(),ze===t&&(ze=null),ze!==t?(dt=da(),dt!==t?(yt=R,q=y(Ce,dt),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,q=Ca(),q!==t?(Ce=Gs(),Ce!==t?(Ue=Rr(),Ue===t&&(Ue=null),Ue!==t?(r.charCodeAt(G)===58?(Re=p,G++):(Re=t,Xe===0&&Te(C)),Re!==t?(ze=Rr(),ze===t&&(ze=null),ze!==t?(dt=da(),dt!==t?(yt=R,q=y(Ce,dt),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t))){if(R=G,q=Ca(),q!==t)if(Ce=Gs(),Ce!==t)if(Ue=Rr(),Ue!==t)if(Re=UE(),Re!==t){if(ze=[],dt=Ys(),dt!==t)for(;dt!==t;)ze.push(dt),dt=Ys();else ze=t;ze!==t?(yt=R,q=y(Ce,Re),R=q):(G=R,R=t)}else G=R,R=t;else G=R,R=t;else G=R,R=t;else G=R,R=t;if(R===t)if(R=G,q=Ca(),q!==t)if(Ce=Gs(),Ce!==t){if(Ue=[],Re=G,ze=Rr(),ze===t&&(ze=null),ze!==t?(r.charCodeAt(G)===44?(dt=B,G++):(dt=t,Xe===0&&Te(v)),dt!==t?(Ft=Rr(),Ft===t&&(Ft=null),Ft!==t?(Ln=Gs(),Ln!==t?(yt=Re,ze=D(Ce,Ln),Re=ze):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t),Re!==t)for(;Re!==t;)Ue.push(Re),Re=G,ze=Rr(),ze===t&&(ze=null),ze!==t?(r.charCodeAt(G)===44?(dt=B,G++):(dt=t,Xe===0&&Te(v)),dt!==t?(Ft=Rr(),Ft===t&&(Ft=null),Ft!==t?(Ln=Gs(),Ln!==t?(yt=Re,ze=D(Ce,Ln),Re=ze):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t);else Ue=t;Ue!==t?(Re=Rr(),Re===t&&(Re=null),Re!==t?(r.charCodeAt(G)===58?(ze=p,G++):(ze=t,Xe===0&&Te(C)),ze!==t?(dt=Rr(),dt===t&&(dt=null),dt!==t?(Ft=da(),Ft!==t?(yt=R,q=L(Ce,Ue,Ft),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)}else G=R,R=t;else G=R,R=t}return R}function da(){var R,q,Ce,Ue,Re,ze,dt;if(R=G,q=G,Xe++,Ce=G,Ue=js(),Ue!==t?(Re=rt(),Re!==t?(r.charCodeAt(G)===45?(ze=o,G++):(ze=t,Xe===0&&Te(a)),ze!==t?(dt=Rr(),dt!==t?(Ue=[Ue,Re,ze,dt],Ce=Ue):(G=Ce,Ce=t)):(G=Ce,Ce=t)):(G=Ce,Ce=t)):(G=Ce,Ce=t),Xe--,Ce!==t?(G=q,q=void 0):q=t,q!==t?(Ce=Ys(),Ce!==t?(Ue=Bo(),Ue!==t?(Re=Hl(),Re!==t?(ze=wA(),ze!==t?(yt=R,q=H(Re),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,q=js(),q!==t?(Ce=Bo(),Ce!==t?(Ue=Cg(),Ue!==t?(Re=wA(),Re!==t?(yt=R,q=H(Ue),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t))if(R=G,q=Yl(),q!==t){if(Ce=[],Ue=Ys(),Ue!==t)for(;Ue!==t;)Ce.push(Ue),Ue=Ys();else Ce=t;Ce!==t?(yt=R,q=j(q),R=q):(G=R,R=t)}else G=R,R=t;return R}function Ca(){var R,q,Ce;for(Xe++,R=G,q=[],r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));Ce!==t;)q.push(Ce),r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));return q!==t?(yt=G,Ce=_(q),Ce?Ce=void 0:Ce=t,Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)):(G=R,R=t),Xe--,R===t&&(q=t,Xe===0&&Te($)),R}function rt(){var R,q,Ce;for(R=G,q=[],r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));Ce!==t;)q.push(Ce),r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));return q!==t?(yt=G,Ce=A(q),Ce?Ce=void 0:Ce=t,Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)):(G=R,R=t),R}function Bo(){var R;return yt=G,R=Ae(),R?R=void 0:R=t,R}function wA(){var R;return yt=G,R=ge(),R?R=void 0:R=t,R}function Gl(){var R;return R=jl(),R===t&&(R=Rp()),R}function Gs(){var R,q,Ce;if(R=jl(),R===t){if(R=G,q=[],Ce=Eg(),Ce!==t)for(;Ce!==t;)q.push(Ce),Ce=Eg();else q=t;q!==t&&(yt=R,q=re()),R=q}return R}function Yl(){var R;return R=Fp(),R===t&&(R=KE(),R===t&&(R=jl(),R===t&&(R=Rp()))),R}function UE(){var R;return R=Fp(),R===t&&(R=jl(),R===t&&(R=Eg())),R}function Rp(){var R,q,Ce,Ue,Re,ze;if(Xe++,R=G,F.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ue)),q!==t){for(Ce=[],Ue=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(pe.test(r.charAt(G))?(ze=r.charAt(G),G++):(ze=t,Xe===0&&Te(ke)),ze!==t?(Re=[Re,ze],Ue=Re):(G=Ue,Ue=t)):(G=Ue,Ue=t);Ue!==t;)Ce.push(Ue),Ue=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(pe.test(r.charAt(G))?(ze=r.charAt(G),G++):(ze=t,Xe===0&&Te(ke)),ze!==t?(Re=[Re,ze],Ue=Re):(G=Ue,Ue=t)):(G=Ue,Ue=t);Ce!==t?(yt=R,q=Fe(),R=q):(G=R,R=t)}else G=R,R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(O)),R}function Eg(){var R,q,Ce,Ue,Re;if(R=G,r.substr(G,2)===Ne?(q=Ne,G+=2):(q=t,Xe===0&&Te(oe)),q===t&&(q=null),q!==t)if(le.test(r.charAt(G))?(Ce=r.charAt(G),G++):(Ce=t,Xe===0&&Te(Be)),Ce!==t){for(Ue=[],fe.test(r.charAt(G))?(Re=r.charAt(G),G++):(Re=t,Xe===0&&Te(ae));Re!==t;)Ue.push(Re),fe.test(r.charAt(G))?(Re=r.charAt(G),G++):(Re=t,Xe===0&&Te(ae));Ue!==t?(yt=R,q=Fe(),R=q):(G=R,R=t)}else G=R,R=t;else G=R,R=t;return R}function Fp(){var R,q;return R=G,r.substr(G,4)===qe?(q=qe,G+=4):(q=t,Xe===0&&Te(ne)),q!==t&&(yt=R,q=Y()),R=q,R}function KE(){var R,q;return R=G,r.substr(G,4)===he?(q=he,G+=4):(q=t,Xe===0&&Te(ie)),q!==t&&(yt=R,q=de()),R=q,R===t&&(R=G,r.substr(G,5)===_e?(q=_e,G+=5):(q=t,Xe===0&&Te(Pt)),q!==t&&(yt=R,q=It()),R=q),R}function jl(){var R,q,Ce,Ue;return Xe++,R=G,r.charCodeAt(G)===34?(q=ii,G++):(q=t,Xe===0&&Te(gi)),q!==t?(r.charCodeAt(G)===34?(Ce=ii,G++):(Ce=t,Xe===0&&Te(gi)),Ce!==t?(yt=R,q=hr(),R=q):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,r.charCodeAt(G)===34?(q=ii,G++):(q=t,Xe===0&&Te(gi)),q!==t?(Ce=HE(),Ce!==t?(r.charCodeAt(G)===34?(Ue=ii,G++):(Ue=t,Xe===0&&Te(gi)),Ue!==t?(yt=R,q=fi(Ce),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)),Xe--,R===t&&(q=t,Xe===0&&Te(Or)),R}function HE(){var R,q,Ce;if(R=G,q=[],Ce=Ig(),Ce!==t)for(;Ce!==t;)q.push(Ce),Ce=Ig();else q=t;return q!==t&&(yt=R,q=ni(q)),R=q,R}function Ig(){var R,q,Ce,Ue,Re,ze;return Us.test(r.charAt(G))?(R=r.charAt(G),G++):(R=t,Xe===0&&Te(pr)),R===t&&(R=G,r.substr(G,2)===Ii?(q=Ii,G+=2):(q=t,Xe===0&&Te(rs)),q!==t&&(yt=R,q=ga()),R=q,R===t&&(R=G,r.substr(G,2)===dA?(q=dA,G+=2):(q=t,Xe===0&&Te(cg)),q!==t&&(yt=R,q=is()),R=q,R===t&&(R=G,r.substr(G,2)===CA?(q=CA,G+=2):(q=t,Xe===0&&Te(fa)),q!==t&&(yt=R,q=wp()),R=q,R===t&&(R=G,r.substr(G,2)===mA?(q=mA,G+=2):(q=t,Xe===0&&Te(EA)),q!==t&&(yt=R,q=wr()),R=q,R===t&&(R=G,r.substr(G,2)===Ll?(q=Ll,G+=2):(q=t,Xe===0&&Te(ug)),q!==t&&(yt=R,q=Io()),R=q,R===t&&(R=G,r.substr(G,2)===gg?(q=gg,G+=2):(q=t,Xe===0&&Te(Bp)),q!==t&&(yt=R,q=Qp()),R=q,R===t&&(R=G,r.substr(G,2)===vr?(q=vr,G+=2):(q=t,Xe===0&&Te(se)),q!==t&&(yt=R,q=yo()),R=q,R===t&&(R=G,r.substr(G,2)===Rn?(q=Rn,G+=2):(q=t,Xe===0&&Te(fg)),q!==t&&(yt=R,q=Qt()),R=q,R===t&&(R=G,r.substr(G,2)===Tl?(q=Tl,G+=2):(q=t,Xe===0&&Te(Fn)),q!==t?(Ce=BA(),Ce!==t?(Ue=BA(),Ue!==t?(Re=BA(),Re!==t?(ze=BA(),ze!==t?(yt=R,q=ns(Ce,Ue,Re,ze),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)))))))))),R}function BA(){var R;return ss.test(r.charAt(G))?(R=r.charAt(G),G++):(R=t,Xe===0&&Te(gt)),R}function Rr(){var R,q;if(Xe++,R=[],At.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(An)),q!==t)for(;q!==t;)R.push(q),At.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(An));else R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(wo)),R}function GE(){var R,q;if(Xe++,R=[],Tt.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(hg)),q!==t)for(;q!==t;)R.push(q),Tt.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(hg));else R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(S)),R}function Ys(){var R,q,Ce,Ue,Re,ze;if(R=G,q=js(),q!==t){for(Ce=[],Ue=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(ze=js(),ze!==t?(Re=[Re,ze],Ue=Re):(G=Ue,Ue=t)):(G=Ue,Ue=t);Ue!==t;)Ce.push(Ue),Ue=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(ze=js(),ze!==t?(Re=[Re,ze],Ue=Re):(G=Ue,Ue=t)):(G=Ue,Ue=t);Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)}else G=R,R=t;return R}function js(){var R;return r.substr(G,2)===Ol?(R=Ol,G+=2):(R=t,Xe===0&&Te(bp)),R===t&&(r.charCodeAt(G)===10?(R=Sp,G++):(R=t,Xe===0&&Te(vp)),R===t&&(r.charCodeAt(G)===13?(R=xp,G++):(R=t,Xe===0&&Te(Pp)))),R}let yg=2,QA=0;if(ha=n(),ha!==t&&G===r.length)return ha;throw ha!==t&&G{"use strict";var cde=r=>{let e=!1,t=!1,i=!1;for(let n=0;n{if(!(typeof r=="string"||Array.isArray(r)))throw new TypeError("Expected the input to be `string | string[]`");e=Object.assign({pascalCase:!1},e);let t=n=>e.pascalCase?n.charAt(0).toUpperCase()+n.slice(1):n;return Array.isArray(r)?r=r.map(n=>n.trim()).filter(n=>n.length).join("-"):r=r.trim(),r.length===0?"":r.length===1?e.pascalCase?r.toUpperCase():r.toLowerCase():(r!==r.toLowerCase()&&(r=cde(r)),r=r.replace(/^[_.\- ]+/,"").toLowerCase().replace(/[_.\- ]+(\w|$)/g,(n,s)=>s.toUpperCase()).replace(/\d+(\w|$)/g,n=>n.toUpperCase()),t(r))};ev.exports=gH;ev.exports.default=gH});var hH=w((n_e,ude)=>{ude.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Appcircle",constant:"APPCIRCLE",env:"AC_APPCIRCLE"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codefresh",constant:"CODEFRESH",env:"CF_BUILD_ID",pr:{any:["CF_PULL_REQUEST_NUMBER","CF_PULL_REQUEST_ID"]}},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitHub Actions",constant:"GITHUB_ACTIONS",env:"GITHUB_ACTIONS",pr:{GITHUB_EVENT_NAME:"pull_request"}},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI",pr:"CI_MERGE_REQUEST_ID"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"LayerCI",constant:"LAYERCI",env:"LAYERCI",pr:"LAYERCI_PULL_REQUEST"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Nevercode",constant:"NEVERCODE",env:"NEVERCODE",pr:{env:"NEVERCODE_PULL_REQUEST",ne:"false"}},{name:"Render",constant:"RENDER",env:"RENDER",pr:{IS_PULL_REQUEST:"true"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Screwdriver",constant:"SCREWDRIVER",env:"SCREWDRIVER",pr:{env:"SD_PULL_REQUEST",ne:"false"}},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}},{name:"Vercel",constant:"VERCEL",env:"NOW_BUILDER"},{name:"Visual Studio App Center",constant:"APPCENTER",env:"APPCENTER_BUILD_ID"}]});var Ac=w(Un=>{"use strict";var dH=hH(),xo=process.env;Object.defineProperty(Un,"_vendors",{value:dH.map(function(r){return r.constant})});Un.name=null;Un.isPR=null;dH.forEach(function(r){let t=(Array.isArray(r.env)?r.env:[r.env]).every(function(i){return pH(i)});if(Un[r.constant]=t,t)switch(Un.name=r.name,typeof r.pr){case"string":Un.isPR=!!xo[r.pr];break;case"object":"env"in r.pr?Un.isPR=r.pr.env in xo&&xo[r.pr.env]!==r.pr.ne:"any"in r.pr?Un.isPR=r.pr.any.some(function(i){return!!xo[i]}):Un.isPR=pH(r.pr);break;default:Un.isPR=null}});Un.isCI=!!(xo.CI||xo.CONTINUOUS_INTEGRATION||xo.BUILD_NUMBER||xo.RUN_ID||Un.name);function pH(r){return typeof r=="string"?!!xo[r]:Object.keys(r).every(function(e){return xo[e]===r[e]})}});var fn={};ut(fn,{KeyRelationship:()=>lc,applyCascade:()=>od,base64RegExp:()=>yH,colorStringAlphaRegExp:()=>IH,colorStringRegExp:()=>EH,computeKey:()=>RA,getPrintable:()=>Vr,hasExactLength:()=>SH,hasForbiddenKeys:()=>Yde,hasKeyRelationship:()=>av,hasMaxLength:()=>Sde,hasMinLength:()=>bde,hasMutuallyExclusiveKeys:()=>jde,hasRequiredKeys:()=>Gde,hasUniqueItems:()=>vde,isArray:()=>Cde,isAtLeast:()=>Dde,isAtMost:()=>kde,isBase64:()=>Kde,isBoolean:()=>hde,isDate:()=>dde,isDict:()=>Ede,isEnum:()=>Xi,isHexColor:()=>Ude,isISO8601:()=>Mde,isInExclusiveRange:()=>Fde,isInInclusiveRange:()=>Rde,isInstanceOf:()=>yde,isInteger:()=>Nde,isJSON:()=>Hde,isLiteral:()=>gde,isLowerCase:()=>Lde,isNegative:()=>xde,isNullable:()=>Qde,isNumber:()=>pde,isObject:()=>Ide,isOneOf:()=>wde,isOptional:()=>Bde,isPositive:()=>Pde,isString:()=>sd,isTuple:()=>mde,isUUID4:()=>Ode,isUnknown:()=>bH,isUpperCase:()=>Tde,iso8601RegExp:()=>ov,makeCoercionFn:()=>cc,makeSetter:()=>QH,makeTrait:()=>BH,makeValidator:()=>bt,matchesRegExp:()=>ad,plural:()=>kI,pushError:()=>pt,simpleKeyRegExp:()=>mH,uuid4RegExp:()=>wH});function bt({test:r}){return BH(r)()}function Vr(r){return r===null?"null":r===void 0?"undefined":r===""?"an empty string":JSON.stringify(r)}function RA(r,e){var t,i,n;return typeof e=="number"?`${(t=r==null?void 0:r.p)!==null&&t!==void 0?t:"."}[${e}]`:mH.test(e)?`${(i=r==null?void 0:r.p)!==null&&i!==void 0?i:""}.${e}`:`${(n=r==null?void 0:r.p)!==null&&n!==void 0?n:"."}[${JSON.stringify(e)}]`}function cc(r,e){return t=>{let i=r[e];return r[e]=t,cc(r,e).bind(null,i)}}function QH(r,e){return t=>{r[e]=t}}function kI(r,e,t){return r===1?e:t}function pt({errors:r,p:e}={},t){return r==null||r.push(`${e!=null?e:"."}: ${t}`),!1}function gde(r){return bt({test:(e,t)=>e!==r?pt(t,`Expected a literal (got ${Vr(r)})`):!0})}function Xi(r){let e=Array.isArray(r)?r:Object.values(r),t=new Set(e);return bt({test:(i,n)=>t.has(i)?!0:pt(n,`Expected a valid enumeration value (got ${Vr(i)})`)})}var mH,EH,IH,yH,wH,ov,BH,bH,sd,fde,hde,pde,dde,Cde,mde,Ede,Ide,yde,wde,od,Bde,Qde,bde,Sde,SH,vde,xde,Pde,Dde,kde,Rde,Fde,Nde,ad,Lde,Tde,Ode,Mde,Ude,Kde,Hde,Gde,Yde,jde,lc,qde,av,ls=kge(()=>{mH=/^[a-zA-Z_][a-zA-Z0-9_]*$/,EH=/^#[0-9a-f]{6}$/i,IH=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,yH=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,wH=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,ov=/^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/,BH=r=>()=>r;bH=()=>bt({test:(r,e)=>!0});sd=()=>bt({test:(r,e)=>typeof r!="string"?pt(e,`Expected a string (got ${Vr(r)})`):!0});fde=new Map([["true",!0],["True",!0],["1",!0],[1,!0],["false",!1],["False",!1],["0",!1],[0,!1]]),hde=()=>bt({test:(r,e)=>{var t;if(typeof r!="boolean"){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i=fde.get(r);if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a boolean (got ${Vr(r)})`)}return!0}}),pde=()=>bt({test:(r,e)=>{var t;if(typeof r!="number"){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i;if(typeof r=="string"){let n;try{n=JSON.parse(r)}catch{}if(typeof n=="number")if(JSON.stringify(n)===r)i=n;else return pt(e,`Received a number that can't be safely represented by the runtime (${r})`)}if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a number (got ${Vr(r)})`)}return!0}}),dde=()=>bt({test:(r,e)=>{var t;if(!(r instanceof Date)){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i;if(typeof r=="string"&&ov.test(r))i=new Date(r);else{let n;if(typeof r=="string"){let s;try{s=JSON.parse(r)}catch{}typeof s=="number"&&(n=s)}else typeof r=="number"&&(n=r);if(typeof n<"u")if(Number.isSafeInteger(n)||!Number.isSafeInteger(n*1e3))i=new Date(n*1e3);else return pt(e,`Received a timestamp that can't be safely represented by the runtime (${r})`)}if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a date (got ${Vr(r)})`)}return!0}}),Cde=(r,{delimiter:e}={})=>bt({test:(t,i)=>{var n;if(typeof t=="string"&&typeof e<"u"&&typeof(i==null?void 0:i.coercions)<"u"){if(typeof(i==null?void 0:i.coercion)>"u")return pt(i,"Unbound coercion result");t=t.split(e),i.coercions.push([(n=i.p)!==null&&n!==void 0?n:".",i.coercion.bind(null,t)])}if(!Array.isArray(t))return pt(i,`Expected an array (got ${Vr(t)})`);let s=!0;for(let o=0,a=t.length;o{let t=SH(r.length);return bt({test:(i,n)=>{var s;if(typeof i=="string"&&typeof e<"u"&&typeof(n==null?void 0:n.coercions)<"u"){if(typeof(n==null?void 0:n.coercion)>"u")return pt(n,"Unbound coercion result");i=i.split(e),n.coercions.push([(s=n.p)!==null&&s!==void 0?s:".",n.coercion.bind(null,i)])}if(!Array.isArray(i))return pt(n,`Expected a tuple (got ${Vr(i)})`);let o=t(i,Object.assign({},n));for(let a=0,l=i.length;abt({test:(t,i)=>{if(typeof t!="object"||t===null)return pt(i,`Expected an object (got ${Vr(t)})`);let n=Object.keys(t),s=!0;for(let o=0,a=n.length;o{let t=Object.keys(r);return bt({test:(i,n)=>{if(typeof i!="object"||i===null)return pt(n,`Expected an object (got ${Vr(i)})`);let s=new Set([...t,...Object.keys(i)]),o={},a=!0;for(let l of s){if(l==="constructor"||l==="__proto__")a=pt(Object.assign(Object.assign({},n),{p:RA(n,l)}),"Unsafe property name");else{let c=Object.prototype.hasOwnProperty.call(r,l)?r[l]:void 0,u=Object.prototype.hasOwnProperty.call(i,l)?i[l]:void 0;typeof c<"u"?a=c(u,Object.assign(Object.assign({},n),{p:RA(n,l),coercion:cc(i,l)}))&&a:e===null?a=pt(Object.assign(Object.assign({},n),{p:RA(n,l)}),`Extraneous property (got ${Vr(u)})`):Object.defineProperty(o,l,{enumerable:!0,get:()=>u,set:QH(i,l)})}if(!a&&(n==null?void 0:n.errors)==null)break}return e!==null&&(a||(n==null?void 0:n.errors)!=null)&&(a=e(o,n)&&a),a}})},yde=r=>bt({test:(e,t)=>e instanceof r?!0:pt(t,`Expected an instance of ${r.name} (got ${Vr(e)})`)}),wde=(r,{exclusive:e=!1}={})=>bt({test:(t,i)=>{var n,s,o;let a=[],l=typeof(i==null?void 0:i.errors)<"u"?[]:void 0;for(let c=0,u=r.length;c1?pt(i,`Expected to match exactly a single predicate (matched ${a.join(", ")})`):(o=i==null?void 0:i.errors)===null||o===void 0||o.push(...l),!1}}),od=(r,e)=>bt({test:(t,i)=>{var n,s;let o={value:t},a=typeof(i==null?void 0:i.coercions)<"u"?cc(o,"value"):void 0,l=typeof(i==null?void 0:i.coercions)<"u"?[]:void 0;if(!r(t,Object.assign(Object.assign({},i),{coercion:a,coercions:l})))return!1;let c=[];if(typeof l<"u")for(let[,u]of l)c.push(u());try{if(typeof(i==null?void 0:i.coercions)<"u"){if(o.value!==t){if(typeof(i==null?void 0:i.coercion)>"u")return pt(i,"Unbound coercion result");i.coercions.push([(n=i.p)!==null&&n!==void 0?n:".",i.coercion.bind(null,o.value)])}(s=i==null?void 0:i.coercions)===null||s===void 0||s.push(...l)}return e.every(u=>u(o.value,i))}finally{for(let u of c)u()}}}),Bde=r=>bt({test:(e,t)=>typeof e>"u"?!0:r(e,t)}),Qde=r=>bt({test:(e,t)=>e===null?!0:r(e,t)}),bde=r=>bt({test:(e,t)=>e.length>=r?!0:pt(t,`Expected to have a length of at least ${r} elements (got ${e.length})`)}),Sde=r=>bt({test:(e,t)=>e.length<=r?!0:pt(t,`Expected to have a length of at most ${r} elements (got ${e.length})`)}),SH=r=>bt({test:(e,t)=>e.length!==r?pt(t,`Expected to have a length of exactly ${r} elements (got ${e.length})`):!0}),vde=({map:r}={})=>bt({test:(e,t)=>{let i=new Set,n=new Set;for(let s=0,o=e.length;sbt({test:(r,e)=>r<=0?!0:pt(e,`Expected to be negative (got ${r})`)}),Pde=()=>bt({test:(r,e)=>r>=0?!0:pt(e,`Expected to be positive (got ${r})`)}),Dde=r=>bt({test:(e,t)=>e>=r?!0:pt(t,`Expected to be at least ${r} (got ${e})`)}),kde=r=>bt({test:(e,t)=>e<=r?!0:pt(t,`Expected to be at most ${r} (got ${e})`)}),Rde=(r,e)=>bt({test:(t,i)=>t>=r&&t<=e?!0:pt(i,`Expected to be in the [${r}; ${e}] range (got ${t})`)}),Fde=(r,e)=>bt({test:(t,i)=>t>=r&&tbt({test:(e,t)=>e!==Math.round(e)?pt(t,`Expected to be an integer (got ${e})`):Number.isSafeInteger(e)?!0:pt(t,`Expected to be a safe integer (got ${e})`)}),ad=r=>bt({test:(e,t)=>r.test(e)?!0:pt(t,`Expected to match the pattern ${r.toString()} (got ${Vr(e)})`)}),Lde=()=>bt({test:(r,e)=>r!==r.toLowerCase()?pt(e,`Expected to be all-lowercase (got ${r})`):!0}),Tde=()=>bt({test:(r,e)=>r!==r.toUpperCase()?pt(e,`Expected to be all-uppercase (got ${r})`):!0}),Ode=()=>bt({test:(r,e)=>wH.test(r)?!0:pt(e,`Expected to be a valid UUID v4 (got ${Vr(r)})`)}),Mde=()=>bt({test:(r,e)=>ov.test(r)?!1:pt(e,`Expected to be a valid ISO 8601 date string (got ${Vr(r)})`)}),Ude=({alpha:r=!1})=>bt({test:(e,t)=>(r?EH.test(e):IH.test(e))?!0:pt(t,`Expected to be a valid hexadecimal color string (got ${Vr(e)})`)}),Kde=()=>bt({test:(r,e)=>yH.test(r)?!0:pt(e,`Expected to be a valid base 64 string (got ${Vr(r)})`)}),Hde=(r=bH())=>bt({test:(e,t)=>{let i;try{i=JSON.parse(e)}catch{return pt(t,`Expected to be a valid JSON string (got ${Vr(e)})`)}return r(i,t)}}),Gde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)||s.push(o);return s.length>0?pt(i,`Missing required ${kI(s.length,"property","properties")} ${s.map(o=>`"${o}"`).join(", ")}`):!0}})},Yde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)&&s.push(o);return s.length>0?pt(i,`Forbidden ${kI(s.length,"property","properties")} ${s.map(o=>`"${o}"`).join(", ")}`):!0}})},jde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)&&s.push(o);return s.length>1?pt(i,`Mutually exclusive properties ${s.map(o=>`"${o}"`).join(", ")}`):!0}})};(function(r){r.Forbids="Forbids",r.Requires="Requires"})(lc||(lc={}));qde={[lc.Forbids]:{expect:!1,message:"forbids using"},[lc.Requires]:{expect:!0,message:"requires using"}},av=(r,e,t,{ignore:i=[]}={})=>{let n=new Set(i),s=new Set(t),o=qde[e];return bt({test:(a,l)=>{let c=new Set(Object.keys(a));if(!c.has(r)||n.has(a[r]))return!0;let u=[];for(let g of s)(c.has(g)&&!n.has(a[g]))!==o.expect&&u.push(g);return u.length>=1?pt(l,`Property "${r}" ${o.message} ${kI(u.length,"property","properties")} ${u.map(g=>`"${g}"`).join(", ")}`):!0}})}});var YH=w((n$e,GH)=>{"use strict";GH.exports=(r,...e)=>new Promise(t=>{t(r(...e))})});var Jg=w((s$e,pv)=>{"use strict";var ACe=YH(),jH=r=>{if(r<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let e=[],t=0,i=()=>{t--,e.length>0&&e.shift()()},n=(a,l,...c)=>{t++;let u=ACe(a,...c);l(u),u.then(i,i)},s=(a,l,...c)=>{tnew Promise(c=>s(a,c,...l));return Object.defineProperties(o,{activeCount:{get:()=>t},pendingCount:{get:()=>e.length}}),o};pv.exports=jH;pv.exports.default=jH});var gd=w((a$e,qH)=>{var lCe="2.0.0",cCe=Number.MAX_SAFE_INTEGER||9007199254740991,uCe=16;qH.exports={SEMVER_SPEC_VERSION:lCe,MAX_LENGTH:256,MAX_SAFE_INTEGER:cCe,MAX_SAFE_COMPONENT_LENGTH:uCe}});var fd=w((A$e,JH)=>{var gCe=typeof process=="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...r)=>console.error("SEMVER",...r):()=>{};JH.exports=gCe});var uc=w((NA,WH)=>{var{MAX_SAFE_COMPONENT_LENGTH:dv}=gd(),fCe=fd();NA=WH.exports={};var hCe=NA.re=[],et=NA.src=[],tt=NA.t={},pCe=0,St=(r,e,t)=>{let i=pCe++;fCe(i,e),tt[r]=i,et[i]=e,hCe[i]=new RegExp(e,t?"g":void 0)};St("NUMERICIDENTIFIER","0|[1-9]\\d*");St("NUMERICIDENTIFIERLOOSE","[0-9]+");St("NONNUMERICIDENTIFIER","\\d*[a-zA-Z-][a-zA-Z0-9-]*");St("MAINVERSION",`(${et[tt.NUMERICIDENTIFIER]})\\.(${et[tt.NUMERICIDENTIFIER]})\\.(${et[tt.NUMERICIDENTIFIER]})`);St("MAINVERSIONLOOSE",`(${et[tt.NUMERICIDENTIFIERLOOSE]})\\.(${et[tt.NUMERICIDENTIFIERLOOSE]})\\.(${et[tt.NUMERICIDENTIFIERLOOSE]})`);St("PRERELEASEIDENTIFIER",`(?:${et[tt.NUMERICIDENTIFIER]}|${et[tt.NONNUMERICIDENTIFIER]})`);St("PRERELEASEIDENTIFIERLOOSE",`(?:${et[tt.NUMERICIDENTIFIERLOOSE]}|${et[tt.NONNUMERICIDENTIFIER]})`);St("PRERELEASE",`(?:-(${et[tt.PRERELEASEIDENTIFIER]}(?:\\.${et[tt.PRERELEASEIDENTIFIER]})*))`);St("PRERELEASELOOSE",`(?:-?(${et[tt.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${et[tt.PRERELEASEIDENTIFIERLOOSE]})*))`);St("BUILDIDENTIFIER","[0-9A-Za-z-]+");St("BUILD",`(?:\\+(${et[tt.BUILDIDENTIFIER]}(?:\\.${et[tt.BUILDIDENTIFIER]})*))`);St("FULLPLAIN",`v?${et[tt.MAINVERSION]}${et[tt.PRERELEASE]}?${et[tt.BUILD]}?`);St("FULL",`^${et[tt.FULLPLAIN]}$`);St("LOOSEPLAIN",`[v=\\s]*${et[tt.MAINVERSIONLOOSE]}${et[tt.PRERELEASELOOSE]}?${et[tt.BUILD]}?`);St("LOOSE",`^${et[tt.LOOSEPLAIN]}$`);St("GTLT","((?:<|>)?=?)");St("XRANGEIDENTIFIERLOOSE",`${et[tt.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);St("XRANGEIDENTIFIER",`${et[tt.NUMERICIDENTIFIER]}|x|X|\\*`);St("XRANGEPLAIN",`[v=\\s]*(${et[tt.XRANGEIDENTIFIER]})(?:\\.(${et[tt.XRANGEIDENTIFIER]})(?:\\.(${et[tt.XRANGEIDENTIFIER]})(?:${et[tt.PRERELEASE]})?${et[tt.BUILD]}?)?)?`);St("XRANGEPLAINLOOSE",`[v=\\s]*(${et[tt.XRANGEIDENTIFIERLOOSE]})(?:\\.(${et[tt.XRANGEIDENTIFIERLOOSE]})(?:\\.(${et[tt.XRANGEIDENTIFIERLOOSE]})(?:${et[tt.PRERELEASELOOSE]})?${et[tt.BUILD]}?)?)?`);St("XRANGE",`^${et[tt.GTLT]}\\s*${et[tt.XRANGEPLAIN]}$`);St("XRANGELOOSE",`^${et[tt.GTLT]}\\s*${et[tt.XRANGEPLAINLOOSE]}$`);St("COERCE",`(^|[^\\d])(\\d{1,${dv}})(?:\\.(\\d{1,${dv}}))?(?:\\.(\\d{1,${dv}}))?(?:$|[^\\d])`);St("COERCERTL",et[tt.COERCE],!0);St("LONETILDE","(?:~>?)");St("TILDETRIM",`(\\s*)${et[tt.LONETILDE]}\\s+`,!0);NA.tildeTrimReplace="$1~";St("TILDE",`^${et[tt.LONETILDE]}${et[tt.XRANGEPLAIN]}$`);St("TILDELOOSE",`^${et[tt.LONETILDE]}${et[tt.XRANGEPLAINLOOSE]}$`);St("LONECARET","(?:\\^)");St("CARETTRIM",`(\\s*)${et[tt.LONECARET]}\\s+`,!0);NA.caretTrimReplace="$1^";St("CARET",`^${et[tt.LONECARET]}${et[tt.XRANGEPLAIN]}$`);St("CARETLOOSE",`^${et[tt.LONECARET]}${et[tt.XRANGEPLAINLOOSE]}$`);St("COMPARATORLOOSE",`^${et[tt.GTLT]}\\s*(${et[tt.LOOSEPLAIN]})$|^$`);St("COMPARATOR",`^${et[tt.GTLT]}\\s*(${et[tt.FULLPLAIN]})$|^$`);St("COMPARATORTRIM",`(\\s*)${et[tt.GTLT]}\\s*(${et[tt.LOOSEPLAIN]}|${et[tt.XRANGEPLAIN]})`,!0);NA.comparatorTrimReplace="$1$2$3";St("HYPHENRANGE",`^\\s*(${et[tt.XRANGEPLAIN]})\\s+-\\s+(${et[tt.XRANGEPLAIN]})\\s*$`);St("HYPHENRANGELOOSE",`^\\s*(${et[tt.XRANGEPLAINLOOSE]})\\s+-\\s+(${et[tt.XRANGEPLAINLOOSE]})\\s*$`);St("STAR","(<|>)?=?\\s*\\*");St("GTE0","^\\s*>=\\s*0.0.0\\s*$");St("GTE0PRE","^\\s*>=\\s*0.0.0-0\\s*$")});var hd=w((l$e,zH)=>{var dCe=["includePrerelease","loose","rtl"],CCe=r=>r?typeof r!="object"?{loose:!0}:dCe.filter(e=>r[e]).reduce((e,t)=>(e[t]=!0,e),{}):{};zH.exports=CCe});var OI=w((c$e,ZH)=>{var VH=/^[0-9]+$/,XH=(r,e)=>{let t=VH.test(r),i=VH.test(e);return t&&i&&(r=+r,e=+e),r===e?0:t&&!i?-1:i&&!t?1:rXH(e,r);ZH.exports={compareIdentifiers:XH,rcompareIdentifiers:mCe}});var Ti=w((u$e,tG)=>{var MI=fd(),{MAX_LENGTH:_H,MAX_SAFE_INTEGER:UI}=gd(),{re:$H,t:eG}=uc(),ECe=hd(),{compareIdentifiers:pd}=OI(),Gn=class{constructor(e,t){if(t=ECe(t),e instanceof Gn){if(e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease)return e;e=e.version}else if(typeof e!="string")throw new TypeError(`Invalid Version: ${e}`);if(e.length>_H)throw new TypeError(`version is longer than ${_H} characters`);MI("SemVer",e,t),this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease;let i=e.trim().match(t.loose?$H[eG.LOOSE]:$H[eG.FULL]);if(!i)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+i[1],this.minor=+i[2],this.patch=+i[3],this.major>UI||this.major<0)throw new TypeError("Invalid major version");if(this.minor>UI||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>UI||this.patch<0)throw new TypeError("Invalid patch version");i[4]?this.prerelease=i[4].split(".").map(n=>{if(/^[0-9]+$/.test(n)){let s=+n;if(s>=0&&s=0;)typeof this.prerelease[i]=="number"&&(this.prerelease[i]++,i=-2);i===-1&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error(`invalid increment argument: ${e}`)}return this.format(),this.raw=this.version,this}};tG.exports=Gn});var gc=w((g$e,sG)=>{var{MAX_LENGTH:ICe}=gd(),{re:rG,t:iG}=uc(),nG=Ti(),yCe=hd(),wCe=(r,e)=>{if(e=yCe(e),r instanceof nG)return r;if(typeof r!="string"||r.length>ICe||!(e.loose?rG[iG.LOOSE]:rG[iG.FULL]).test(r))return null;try{return new nG(r,e)}catch{return null}};sG.exports=wCe});var aG=w((f$e,oG)=>{var BCe=gc(),QCe=(r,e)=>{let t=BCe(r,e);return t?t.version:null};oG.exports=QCe});var lG=w((h$e,AG)=>{var bCe=gc(),SCe=(r,e)=>{let t=bCe(r.trim().replace(/^[=v]+/,""),e);return t?t.version:null};AG.exports=SCe});var uG=w((p$e,cG)=>{var vCe=Ti(),xCe=(r,e,t,i)=>{typeof t=="string"&&(i=t,t=void 0);try{return new vCe(r,t).inc(e,i).version}catch{return null}};cG.exports=xCe});var cs=w((d$e,fG)=>{var gG=Ti(),PCe=(r,e,t)=>new gG(r,t).compare(new gG(e,t));fG.exports=PCe});var KI=w((C$e,hG)=>{var DCe=cs(),kCe=(r,e,t)=>DCe(r,e,t)===0;hG.exports=kCe});var CG=w((m$e,dG)=>{var pG=gc(),RCe=KI(),FCe=(r,e)=>{if(RCe(r,e))return null;{let t=pG(r),i=pG(e),n=t.prerelease.length||i.prerelease.length,s=n?"pre":"",o=n?"prerelease":"";for(let a in t)if((a==="major"||a==="minor"||a==="patch")&&t[a]!==i[a])return s+a;return o}};dG.exports=FCe});var EG=w((E$e,mG)=>{var NCe=Ti(),LCe=(r,e)=>new NCe(r,e).major;mG.exports=LCe});var yG=w((I$e,IG)=>{var TCe=Ti(),OCe=(r,e)=>new TCe(r,e).minor;IG.exports=OCe});var BG=w((y$e,wG)=>{var MCe=Ti(),UCe=(r,e)=>new MCe(r,e).patch;wG.exports=UCe});var bG=w((w$e,QG)=>{var KCe=gc(),HCe=(r,e)=>{let t=KCe(r,e);return t&&t.prerelease.length?t.prerelease:null};QG.exports=HCe});var vG=w((B$e,SG)=>{var GCe=cs(),YCe=(r,e,t)=>GCe(e,r,t);SG.exports=YCe});var PG=w((Q$e,xG)=>{var jCe=cs(),qCe=(r,e)=>jCe(r,e,!0);xG.exports=qCe});var HI=w((b$e,kG)=>{var DG=Ti(),JCe=(r,e,t)=>{let i=new DG(r,t),n=new DG(e,t);return i.compare(n)||i.compareBuild(n)};kG.exports=JCe});var FG=w((S$e,RG)=>{var WCe=HI(),zCe=(r,e)=>r.sort((t,i)=>WCe(t,i,e));RG.exports=zCe});var LG=w((v$e,NG)=>{var VCe=HI(),XCe=(r,e)=>r.sort((t,i)=>VCe(i,t,e));NG.exports=XCe});var dd=w((x$e,TG)=>{var ZCe=cs(),_Ce=(r,e,t)=>ZCe(r,e,t)>0;TG.exports=_Ce});var GI=w((P$e,OG)=>{var $Ce=cs(),eme=(r,e,t)=>$Ce(r,e,t)<0;OG.exports=eme});var Cv=w((D$e,MG)=>{var tme=cs(),rme=(r,e,t)=>tme(r,e,t)!==0;MG.exports=rme});var YI=w((k$e,UG)=>{var ime=cs(),nme=(r,e,t)=>ime(r,e,t)>=0;UG.exports=nme});var jI=w((R$e,KG)=>{var sme=cs(),ome=(r,e,t)=>sme(r,e,t)<=0;KG.exports=ome});var mv=w((F$e,HG)=>{var ame=KI(),Ame=Cv(),lme=dd(),cme=YI(),ume=GI(),gme=jI(),fme=(r,e,t,i)=>{switch(e){case"===":return typeof r=="object"&&(r=r.version),typeof t=="object"&&(t=t.version),r===t;case"!==":return typeof r=="object"&&(r=r.version),typeof t=="object"&&(t=t.version),r!==t;case"":case"=":case"==":return ame(r,t,i);case"!=":return Ame(r,t,i);case">":return lme(r,t,i);case">=":return cme(r,t,i);case"<":return ume(r,t,i);case"<=":return gme(r,t,i);default:throw new TypeError(`Invalid operator: ${e}`)}};HG.exports=fme});var YG=w((N$e,GG)=>{var hme=Ti(),pme=gc(),{re:qI,t:JI}=uc(),dme=(r,e)=>{if(r instanceof hme)return r;if(typeof r=="number"&&(r=String(r)),typeof r!="string")return null;e=e||{};let t=null;if(!e.rtl)t=r.match(qI[JI.COERCE]);else{let i;for(;(i=qI[JI.COERCERTL].exec(r))&&(!t||t.index+t[0].length!==r.length);)(!t||i.index+i[0].length!==t.index+t[0].length)&&(t=i),qI[JI.COERCERTL].lastIndex=i.index+i[1].length+i[2].length;qI[JI.COERCERTL].lastIndex=-1}return t===null?null:pme(`${t[2]}.${t[3]||"0"}.${t[4]||"0"}`,e)};GG.exports=dme});var qG=w((L$e,jG)=>{"use strict";jG.exports=function(r){r.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var WI=w((T$e,JG)=>{"use strict";JG.exports=Ht;Ht.Node=fc;Ht.create=Ht;function Ht(r){var e=this;if(e instanceof Ht||(e=new Ht),e.tail=null,e.head=null,e.length=0,r&&typeof r.forEach=="function")r.forEach(function(n){e.push(n)});else if(arguments.length>0)for(var t=0,i=arguments.length;t1)t=e;else if(this.head)i=this.head.next,t=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=0;i!==null;n++)t=r(t,i.value,n),i=i.next;return t};Ht.prototype.reduceReverse=function(r,e){var t,i=this.tail;if(arguments.length>1)t=e;else if(this.tail)i=this.tail.prev,t=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=this.length-1;i!==null;n--)t=r(t,i.value,n),i=i.prev;return t};Ht.prototype.toArray=function(){for(var r=new Array(this.length),e=0,t=this.head;t!==null;e++)r[e]=t.value,t=t.next;return r};Ht.prototype.toArrayReverse=function(){for(var r=new Array(this.length),e=0,t=this.tail;t!==null;e++)r[e]=t.value,t=t.prev;return r};Ht.prototype.slice=function(r,e){e=e||this.length,e<0&&(e+=this.length),r=r||0,r<0&&(r+=this.length);var t=new Ht;if(ethis.length&&(e=this.length);for(var i=0,n=this.head;n!==null&&ithis.length&&(e=this.length);for(var i=this.length,n=this.tail;n!==null&&i>e;i--)n=n.prev;for(;n!==null&&i>r;i--,n=n.prev)t.push(n.value);return t};Ht.prototype.splice=function(r,e,...t){r>this.length&&(r=this.length-1),r<0&&(r=this.length+r);for(var i=0,n=this.head;n!==null&&i{"use strict";var Ime=WI(),hc=Symbol("max"),Sa=Symbol("length"),Wg=Symbol("lengthCalculator"),md=Symbol("allowStale"),pc=Symbol("maxAge"),ba=Symbol("dispose"),WG=Symbol("noDisposeOnSet"),di=Symbol("lruList"),Zs=Symbol("cache"),VG=Symbol("updateAgeOnGet"),Ev=()=>1,yv=class{constructor(e){if(typeof e=="number"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!="number"||e.max<0))throw new TypeError("max must be a non-negative number");let t=this[hc]=e.max||1/0,i=e.length||Ev;if(this[Wg]=typeof i!="function"?Ev:i,this[md]=e.stale||!1,e.maxAge&&typeof e.maxAge!="number")throw new TypeError("maxAge must be a number");this[pc]=e.maxAge||0,this[ba]=e.dispose,this[WG]=e.noDisposeOnSet||!1,this[VG]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!="number"||e<0)throw new TypeError("max must be a non-negative number");this[hc]=e||1/0,Cd(this)}get max(){return this[hc]}set allowStale(e){this[md]=!!e}get allowStale(){return this[md]}set maxAge(e){if(typeof e!="number")throw new TypeError("maxAge must be a non-negative number");this[pc]=e,Cd(this)}get maxAge(){return this[pc]}set lengthCalculator(e){typeof e!="function"&&(e=Ev),e!==this[Wg]&&(this[Wg]=e,this[Sa]=0,this[di].forEach(t=>{t.length=this[Wg](t.value,t.key),this[Sa]+=t.length})),Cd(this)}get lengthCalculator(){return this[Wg]}get length(){return this[Sa]}get itemCount(){return this[di].length}rforEach(e,t){t=t||this;for(let i=this[di].tail;i!==null;){let n=i.prev;zG(this,e,i,t),i=n}}forEach(e,t){t=t||this;for(let i=this[di].head;i!==null;){let n=i.next;zG(this,e,i,t),i=n}}keys(){return this[di].toArray().map(e=>e.key)}values(){return this[di].toArray().map(e=>e.value)}reset(){this[ba]&&this[di]&&this[di].length&&this[di].forEach(e=>this[ba](e.key,e.value)),this[Zs]=new Map,this[di]=new Ime,this[Sa]=0}dump(){return this[di].map(e=>zI(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[di]}set(e,t,i){if(i=i||this[pc],i&&typeof i!="number")throw new TypeError("maxAge must be a number");let n=i?Date.now():0,s=this[Wg](t,e);if(this[Zs].has(e)){if(s>this[hc])return zg(this,this[Zs].get(e)),!1;let l=this[Zs].get(e).value;return this[ba]&&(this[WG]||this[ba](e,l.value)),l.now=n,l.maxAge=i,l.value=t,this[Sa]+=s-l.length,l.length=s,this.get(e),Cd(this),!0}let o=new wv(e,t,s,n,i);return o.length>this[hc]?(this[ba]&&this[ba](e,t),!1):(this[Sa]+=o.length,this[di].unshift(o),this[Zs].set(e,this[di].head),Cd(this),!0)}has(e){if(!this[Zs].has(e))return!1;let t=this[Zs].get(e).value;return!zI(this,t)}get(e){return Iv(this,e,!0)}peek(e){return Iv(this,e,!1)}pop(){let e=this[di].tail;return e?(zg(this,e),e.value):null}del(e){zg(this,this[Zs].get(e))}load(e){this.reset();let t=Date.now();for(let i=e.length-1;i>=0;i--){let n=e[i],s=n.e||0;if(s===0)this.set(n.k,n.v);else{let o=s-t;o>0&&this.set(n.k,n.v,o)}}}prune(){this[Zs].forEach((e,t)=>Iv(this,t,!1))}},Iv=(r,e,t)=>{let i=r[Zs].get(e);if(i){let n=i.value;if(zI(r,n)){if(zg(r,i),!r[md])return}else t&&(r[VG]&&(i.value.now=Date.now()),r[di].unshiftNode(i));return n.value}},zI=(r,e)=>{if(!e||!e.maxAge&&!r[pc])return!1;let t=Date.now()-e.now;return e.maxAge?t>e.maxAge:r[pc]&&t>r[pc]},Cd=r=>{if(r[Sa]>r[hc])for(let e=r[di].tail;r[Sa]>r[hc]&&e!==null;){let t=e.prev;zg(r,e),e=t}},zg=(r,e)=>{if(e){let t=e.value;r[ba]&&r[ba](t.key,t.value),r[Sa]-=t.length,r[Zs].delete(t.key),r[di].removeNode(e)}},wv=class{constructor(e,t,i,n,s){this.key=e,this.value=t,this.length=i,this.now=n,this.maxAge=s||0}},zG=(r,e,t,i)=>{let n=t.value;zI(r,n)&&(zg(r,t),r[md]||(n=void 0)),n&&e.call(i,n.value,n.key,r)};XG.exports=yv});var us=w((M$e,tY)=>{var dc=class{constructor(e,t){if(t=wme(t),e instanceof dc)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new dc(e.raw,t);if(e instanceof Bv)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map(i=>this.parseRange(i.trim())).filter(i=>i.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${e}`);if(this.set.length>1){let i=this.set[0];if(this.set=this.set.filter(n=>!$G(n[0])),this.set.length===0)this.set=[i];else if(this.set.length>1){for(let n of this.set)if(n.length===1&&vme(n[0])){this.set=[n];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(" ").trim()).join("||").trim(),this.range}toString(){return this.range}parseRange(e){e=e.trim();let i=`parseRange:${Object.keys(this.options).join(",")}:${e}`,n=_G.get(i);if(n)return n;let s=this.options.loose,o=s?Oi[Qi.HYPHENRANGELOOSE]:Oi[Qi.HYPHENRANGE];e=e.replace(o,Ome(this.options.includePrerelease)),Gr("hyphen replace",e),e=e.replace(Oi[Qi.COMPARATORTRIM],Qme),Gr("comparator trim",e,Oi[Qi.COMPARATORTRIM]),e=e.replace(Oi[Qi.TILDETRIM],bme),e=e.replace(Oi[Qi.CARETTRIM],Sme),e=e.split(/\s+/).join(" ");let a=s?Oi[Qi.COMPARATORLOOSE]:Oi[Qi.COMPARATOR],l=e.split(" ").map(f=>xme(f,this.options)).join(" ").split(/\s+/).map(f=>Tme(f,this.options)).filter(this.options.loose?f=>!!f.match(a):()=>!0).map(f=>new Bv(f,this.options)),c=l.length,u=new Map;for(let f of l){if($G(f))return[f];u.set(f.value,f)}u.size>1&&u.has("")&&u.delete("");let g=[...u.values()];return _G.set(i,g),g}intersects(e,t){if(!(e instanceof dc))throw new TypeError("a Range is required");return this.set.some(i=>eY(i,t)&&e.set.some(n=>eY(n,t)&&i.every(s=>n.every(o=>s.intersects(o,t)))))}test(e){if(!e)return!1;if(typeof e=="string")try{e=new Bme(e,this.options)}catch{return!1}for(let t=0;tr.value==="<0.0.0-0",vme=r=>r.value==="",eY=(r,e)=>{let t=!0,i=r.slice(),n=i.pop();for(;t&&i.length;)t=i.every(s=>n.intersects(s,e)),n=i.pop();return t},xme=(r,e)=>(Gr("comp",r,e),r=kme(r,e),Gr("caret",r),r=Pme(r,e),Gr("tildes",r),r=Fme(r,e),Gr("xrange",r),r=Lme(r,e),Gr("stars",r),r),_i=r=>!r||r.toLowerCase()==="x"||r==="*",Pme=(r,e)=>r.trim().split(/\s+/).map(t=>Dme(t,e)).join(" "),Dme=(r,e)=>{let t=e.loose?Oi[Qi.TILDELOOSE]:Oi[Qi.TILDE];return r.replace(t,(i,n,s,o,a)=>{Gr("tilde",r,i,n,s,o,a);let l;return _i(n)?l="":_i(s)?l=`>=${n}.0.0 <${+n+1}.0.0-0`:_i(o)?l=`>=${n}.${s}.0 <${n}.${+s+1}.0-0`:a?(Gr("replaceTilde pr",a),l=`>=${n}.${s}.${o}-${a} <${n}.${+s+1}.0-0`):l=`>=${n}.${s}.${o} <${n}.${+s+1}.0-0`,Gr("tilde return",l),l})},kme=(r,e)=>r.trim().split(/\s+/).map(t=>Rme(t,e)).join(" "),Rme=(r,e)=>{Gr("caret",r,e);let t=e.loose?Oi[Qi.CARETLOOSE]:Oi[Qi.CARET],i=e.includePrerelease?"-0":"";return r.replace(t,(n,s,o,a,l)=>{Gr("caret",r,n,s,o,a,l);let c;return _i(s)?c="":_i(o)?c=`>=${s}.0.0${i} <${+s+1}.0.0-0`:_i(a)?s==="0"?c=`>=${s}.${o}.0${i} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.0${i} <${+s+1}.0.0-0`:l?(Gr("replaceCaret pr",l),s==="0"?o==="0"?c=`>=${s}.${o}.${a}-${l} <${s}.${o}.${+a+1}-0`:c=`>=${s}.${o}.${a}-${l} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.${a}-${l} <${+s+1}.0.0-0`):(Gr("no pr"),s==="0"?o==="0"?c=`>=${s}.${o}.${a}${i} <${s}.${o}.${+a+1}-0`:c=`>=${s}.${o}.${a}${i} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.${a} <${+s+1}.0.0-0`),Gr("caret return",c),c})},Fme=(r,e)=>(Gr("replaceXRanges",r,e),r.split(/\s+/).map(t=>Nme(t,e)).join(" ")),Nme=(r,e)=>{r=r.trim();let t=e.loose?Oi[Qi.XRANGELOOSE]:Oi[Qi.XRANGE];return r.replace(t,(i,n,s,o,a,l)=>{Gr("xRange",r,i,n,s,o,a,l);let c=_i(s),u=c||_i(o),g=u||_i(a),f=g;return n==="="&&f&&(n=""),l=e.includePrerelease?"-0":"",c?n===">"||n==="<"?i="<0.0.0-0":i="*":n&&f?(u&&(o=0),a=0,n===">"?(n=">=",u?(s=+s+1,o=0,a=0):(o=+o+1,a=0)):n==="<="&&(n="<",u?s=+s+1:o=+o+1),n==="<"&&(l="-0"),i=`${n+s}.${o}.${a}${l}`):u?i=`>=${s}.0.0${l} <${+s+1}.0.0-0`:g&&(i=`>=${s}.${o}.0${l} <${s}.${+o+1}.0-0`),Gr("xRange return",i),i})},Lme=(r,e)=>(Gr("replaceStars",r,e),r.trim().replace(Oi[Qi.STAR],"")),Tme=(r,e)=>(Gr("replaceGTE0",r,e),r.trim().replace(Oi[e.includePrerelease?Qi.GTE0PRE:Qi.GTE0],"")),Ome=r=>(e,t,i,n,s,o,a,l,c,u,g,f,h)=>(_i(i)?t="":_i(n)?t=`>=${i}.0.0${r?"-0":""}`:_i(s)?t=`>=${i}.${n}.0${r?"-0":""}`:o?t=`>=${t}`:t=`>=${t}${r?"-0":""}`,_i(c)?l="":_i(u)?l=`<${+c+1}.0.0-0`:_i(g)?l=`<${c}.${+u+1}.0-0`:f?l=`<=${c}.${u}.${g}-${f}`:r?l=`<${c}.${u}.${+g+1}-0`:l=`<=${l}`,`${t} ${l}`.trim()),Mme=(r,e,t)=>{for(let i=0;i0){let n=r[i].semver;if(n.major===e.major&&n.minor===e.minor&&n.patch===e.patch)return!0}return!1}return!0}});var Ed=w((U$e,oY)=>{var Id=Symbol("SemVer ANY"),Vg=class{static get ANY(){return Id}constructor(e,t){if(t=Ume(t),e instanceof Vg){if(e.loose===!!t.loose)return e;e=e.value}bv("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===Id?this.value="":this.value=this.operator+this.semver.version,bv("comp",this)}parse(e){let t=this.options.loose?rY[iY.COMPARATORLOOSE]:rY[iY.COMPARATOR],i=e.match(t);if(!i)throw new TypeError(`Invalid comparator: ${e}`);this.operator=i[1]!==void 0?i[1]:"",this.operator==="="&&(this.operator=""),i[2]?this.semver=new nY(i[2],this.options.loose):this.semver=Id}toString(){return this.value}test(e){if(bv("Comparator.test",e,this.options.loose),this.semver===Id||e===Id)return!0;if(typeof e=="string")try{e=new nY(e,this.options)}catch{return!1}return Qv(e,this.operator,this.semver,this.options)}intersects(e,t){if(!(e instanceof Vg))throw new TypeError("a Comparator is required");if((!t||typeof t!="object")&&(t={loose:!!t,includePrerelease:!1}),this.operator==="")return this.value===""?!0:new sY(e.value,t).test(this.value);if(e.operator==="")return e.value===""?!0:new sY(this.value,t).test(e.semver);let i=(this.operator===">="||this.operator===">")&&(e.operator===">="||e.operator===">"),n=(this.operator==="<="||this.operator==="<")&&(e.operator==="<="||e.operator==="<"),s=this.semver.version===e.semver.version,o=(this.operator===">="||this.operator==="<=")&&(e.operator===">="||e.operator==="<="),a=Qv(this.semver,"<",e.semver,t)&&(this.operator===">="||this.operator===">")&&(e.operator==="<="||e.operator==="<"),l=Qv(this.semver,">",e.semver,t)&&(this.operator==="<="||this.operator==="<")&&(e.operator===">="||e.operator===">");return i||n||s&&o||a||l}};oY.exports=Vg;var Ume=hd(),{re:rY,t:iY}=uc(),Qv=mv(),bv=fd(),nY=Ti(),sY=us()});var yd=w((K$e,aY)=>{var Kme=us(),Hme=(r,e,t)=>{try{e=new Kme(e,t)}catch{return!1}return e.test(r)};aY.exports=Hme});var lY=w((H$e,AY)=>{var Gme=us(),Yme=(r,e)=>new Gme(r,e).set.map(t=>t.map(i=>i.value).join(" ").trim().split(" "));AY.exports=Yme});var uY=w((G$e,cY)=>{var jme=Ti(),qme=us(),Jme=(r,e,t)=>{let i=null,n=null,s=null;try{s=new qme(e,t)}catch{return null}return r.forEach(o=>{s.test(o)&&(!i||n.compare(o)===-1)&&(i=o,n=new jme(i,t))}),i};cY.exports=Jme});var fY=w((Y$e,gY)=>{var Wme=Ti(),zme=us(),Vme=(r,e,t)=>{let i=null,n=null,s=null;try{s=new zme(e,t)}catch{return null}return r.forEach(o=>{s.test(o)&&(!i||n.compare(o)===1)&&(i=o,n=new Wme(i,t))}),i};gY.exports=Vme});var dY=w((j$e,pY)=>{var Sv=Ti(),Xme=us(),hY=dd(),Zme=(r,e)=>{r=new Xme(r,e);let t=new Sv("0.0.0");if(r.test(t)||(t=new Sv("0.0.0-0"),r.test(t)))return t;t=null;for(let i=0;i{let a=new Sv(o.semver.version);switch(o.operator){case">":a.prerelease.length===0?a.patch++:a.prerelease.push(0),a.raw=a.format();case"":case">=":(!s||hY(a,s))&&(s=a);break;case"<":case"<=":break;default:throw new Error(`Unexpected operation: ${o.operator}`)}}),s&&(!t||hY(t,s))&&(t=s)}return t&&r.test(t)?t:null};pY.exports=Zme});var mY=w((q$e,CY)=>{var _me=us(),$me=(r,e)=>{try{return new _me(r,e).range||"*"}catch{return null}};CY.exports=$me});var VI=w((J$e,wY)=>{var eEe=Ti(),yY=Ed(),{ANY:tEe}=yY,rEe=us(),iEe=yd(),EY=dd(),IY=GI(),nEe=jI(),sEe=YI(),oEe=(r,e,t,i)=>{r=new eEe(r,i),e=new rEe(e,i);let n,s,o,a,l;switch(t){case">":n=EY,s=nEe,o=IY,a=">",l=">=";break;case"<":n=IY,s=sEe,o=EY,a="<",l="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(iEe(r,e,i))return!1;for(let c=0;c{h.semver===tEe&&(h=new yY(">=0.0.0")),g=g||h,f=f||h,n(h.semver,g.semver,i)?g=h:o(h.semver,f.semver,i)&&(f=h)}),g.operator===a||g.operator===l||(!f.operator||f.operator===a)&&s(r,f.semver))return!1;if(f.operator===l&&o(r,f.semver))return!1}return!0};wY.exports=oEe});var QY=w((W$e,BY)=>{var aEe=VI(),AEe=(r,e,t)=>aEe(r,e,">",t);BY.exports=AEe});var SY=w((z$e,bY)=>{var lEe=VI(),cEe=(r,e,t)=>lEe(r,e,"<",t);bY.exports=cEe});var PY=w((V$e,xY)=>{var vY=us(),uEe=(r,e,t)=>(r=new vY(r,t),e=new vY(e,t),r.intersects(e));xY.exports=uEe});var kY=w((X$e,DY)=>{var gEe=yd(),fEe=cs();DY.exports=(r,e,t)=>{let i=[],n=null,s=null,o=r.sort((u,g)=>fEe(u,g,t));for(let u of o)gEe(u,e,t)?(s=u,n||(n=u)):(s&&i.push([n,s]),s=null,n=null);n&&i.push([n,null]);let a=[];for(let[u,g]of i)u===g?a.push(u):!g&&u===o[0]?a.push("*"):g?u===o[0]?a.push(`<=${g}`):a.push(`${u} - ${g}`):a.push(`>=${u}`);let l=a.join(" || "),c=typeof e.raw=="string"?e.raw:String(e);return l.length{var RY=us(),XI=Ed(),{ANY:vv}=XI,wd=yd(),xv=cs(),hEe=(r,e,t={})=>{if(r===e)return!0;r=new RY(r,t),e=new RY(e,t);let i=!1;e:for(let n of r.set){for(let s of e.set){let o=pEe(n,s,t);if(i=i||o!==null,o)continue e}if(i)return!1}return!0},pEe=(r,e,t)=>{if(r===e)return!0;if(r.length===1&&r[0].semver===vv){if(e.length===1&&e[0].semver===vv)return!0;t.includePrerelease?r=[new XI(">=0.0.0-0")]:r=[new XI(">=0.0.0")]}if(e.length===1&&e[0].semver===vv){if(t.includePrerelease)return!0;e=[new XI(">=0.0.0")]}let i=new Set,n,s;for(let h of r)h.operator===">"||h.operator===">="?n=FY(n,h,t):h.operator==="<"||h.operator==="<="?s=NY(s,h,t):i.add(h.semver);if(i.size>1)return null;let o;if(n&&s){if(o=xv(n.semver,s.semver,t),o>0)return null;if(o===0&&(n.operator!==">="||s.operator!=="<="))return null}for(let h of i){if(n&&!wd(h,String(n),t)||s&&!wd(h,String(s),t))return null;for(let p of e)if(!wd(h,String(p),t))return!1;return!0}let a,l,c,u,g=s&&!t.includePrerelease&&s.semver.prerelease.length?s.semver:!1,f=n&&!t.includePrerelease&&n.semver.prerelease.length?n.semver:!1;g&&g.prerelease.length===1&&s.operator==="<"&&g.prerelease[0]===0&&(g=!1);for(let h of e){if(u=u||h.operator===">"||h.operator===">=",c=c||h.operator==="<"||h.operator==="<=",n){if(f&&h.semver.prerelease&&h.semver.prerelease.length&&h.semver.major===f.major&&h.semver.minor===f.minor&&h.semver.patch===f.patch&&(f=!1),h.operator===">"||h.operator===">="){if(a=FY(n,h,t),a===h&&a!==n)return!1}else if(n.operator===">="&&!wd(n.semver,String(h),t))return!1}if(s){if(g&&h.semver.prerelease&&h.semver.prerelease.length&&h.semver.major===g.major&&h.semver.minor===g.minor&&h.semver.patch===g.patch&&(g=!1),h.operator==="<"||h.operator==="<="){if(l=NY(s,h,t),l===h&&l!==s)return!1}else if(s.operator==="<="&&!wd(s.semver,String(h),t))return!1}if(!h.operator&&(s||n)&&o!==0)return!1}return!(n&&c&&!s&&o!==0||s&&u&&!n&&o!==0||f||g)},FY=(r,e,t)=>{if(!r)return e;let i=xv(r.semver,e.semver,t);return i>0?r:i<0||e.operator===">"&&r.operator===">="?e:r},NY=(r,e,t)=>{if(!r)return e;let i=xv(r.semver,e.semver,t);return i<0?r:i>0||e.operator==="<"&&r.operator==="<="?e:r};LY.exports=hEe});var Xr=w((_$e,OY)=>{var Pv=uc();OY.exports={re:Pv.re,src:Pv.src,tokens:Pv.t,SEMVER_SPEC_VERSION:gd().SEMVER_SPEC_VERSION,SemVer:Ti(),compareIdentifiers:OI().compareIdentifiers,rcompareIdentifiers:OI().rcompareIdentifiers,parse:gc(),valid:aG(),clean:lG(),inc:uG(),diff:CG(),major:EG(),minor:yG(),patch:BG(),prerelease:bG(),compare:cs(),rcompare:vG(),compareLoose:PG(),compareBuild:HI(),sort:FG(),rsort:LG(),gt:dd(),lt:GI(),eq:KI(),neq:Cv(),gte:YI(),lte:jI(),cmp:mv(),coerce:YG(),Comparator:Ed(),Range:us(),satisfies:yd(),toComparators:lY(),maxSatisfying:uY(),minSatisfying:fY(),minVersion:dY(),validRange:mY(),outside:VI(),gtr:QY(),ltr:SY(),intersects:PY(),simplifyRange:kY(),subset:TY()}});var Dv=w(ZI=>{"use strict";Object.defineProperty(ZI,"__esModule",{value:!0});ZI.VERSION=void 0;ZI.VERSION="9.1.0"});var Gt=w((exports,module)=>{"use strict";var __spreadArray=exports&&exports.__spreadArray||function(r,e,t){if(t||arguments.length===2)for(var i=0,n=e.length,s;i{(function(r,e){typeof define=="function"&&define.amd?define([],e):typeof _I=="object"&&_I.exports?_I.exports=e():r.regexpToAst=e()})(typeof self<"u"?self:MY,function(){function r(){}r.prototype.saveState=function(){return{idx:this.idx,input:this.input,groupIdx:this.groupIdx}},r.prototype.restoreState=function(p){this.idx=p.idx,this.input=p.input,this.groupIdx=p.groupIdx},r.prototype.pattern=function(p){this.idx=0,this.input=p,this.groupIdx=0,this.consumeChar("/");var C=this.disjunction();this.consumeChar("/");for(var y={type:"Flags",loc:{begin:this.idx,end:p.length},global:!1,ignoreCase:!1,multiLine:!1,unicode:!1,sticky:!1};this.isRegExpFlag();)switch(this.popChar()){case"g":o(y,"global");break;case"i":o(y,"ignoreCase");break;case"m":o(y,"multiLine");break;case"u":o(y,"unicode");break;case"y":o(y,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:y,value:C,loc:this.loc(0)}},r.prototype.disjunction=function(){var p=[],C=this.idx;for(p.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),p.push(this.alternative());return{type:"Disjunction",value:p,loc:this.loc(C)}},r.prototype.alternative=function(){for(var p=[],C=this.idx;this.isTerm();)p.push(this.term());return{type:"Alternative",value:p,loc:this.loc(C)}},r.prototype.term=function(){return this.isAssertion()?this.assertion():this.atom()},r.prototype.assertion=function(){var p=this.idx;switch(this.popChar()){case"^":return{type:"StartAnchor",loc:this.loc(p)};case"$":return{type:"EndAnchor",loc:this.loc(p)};case"\\":switch(this.popChar()){case"b":return{type:"WordBoundary",loc:this.loc(p)};case"B":return{type:"NonWordBoundary",loc:this.loc(p)}}throw Error("Invalid Assertion Escape");case"(":this.consumeChar("?");var C;switch(this.popChar()){case"=":C="Lookahead";break;case"!":C="NegativeLookahead";break}a(C);var y=this.disjunction();return this.consumeChar(")"),{type:C,value:y,loc:this.loc(p)}}l()},r.prototype.quantifier=function(p){var C,y=this.idx;switch(this.popChar()){case"*":C={atLeast:0,atMost:1/0};break;case"+":C={atLeast:1,atMost:1/0};break;case"?":C={atLeast:0,atMost:1};break;case"{":var B=this.integerIncludingZero();switch(this.popChar()){case"}":C={atLeast:B,atMost:B};break;case",":var v;this.isDigit()?(v=this.integerIncludingZero(),C={atLeast:B,atMost:v}):C={atLeast:B,atMost:1/0},this.consumeChar("}");break}if(p===!0&&C===void 0)return;a(C);break}if(!(p===!0&&C===void 0))return a(C),this.peekChar(0)==="?"?(this.consumeChar("?"),C.greedy=!1):C.greedy=!0,C.type="Quantifier",C.loc=this.loc(y),C},r.prototype.atom=function(){var p,C=this.idx;switch(this.peekChar()){case".":p=this.dotAll();break;case"\\":p=this.atomEscape();break;case"[":p=this.characterClass();break;case"(":p=this.group();break}return p===void 0&&this.isPatternCharacter()&&(p=this.patternCharacter()),a(p),p.loc=this.loc(C),this.isQuantifier()&&(p.quantifier=this.quantifier()),p},r.prototype.dotAll=function(){return this.consumeChar("."),{type:"Set",complement:!0,value:[n(` +`),n("\r"),n("\u2028"),n("\u2029")]}},r.prototype.atomEscape=function(){switch(this.consumeChar("\\"),this.peekChar()){case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":return this.decimalEscapeAtom();case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}},r.prototype.decimalEscapeAtom=function(){var p=this.positiveInteger();return{type:"GroupBackReference",value:p}},r.prototype.characterClassEscape=function(){var p,C=!1;switch(this.popChar()){case"d":p=u;break;case"D":p=u,C=!0;break;case"s":p=f;break;case"S":p=f,C=!0;break;case"w":p=g;break;case"W":p=g,C=!0;break}return a(p),{type:"Set",value:p,complement:C}},r.prototype.controlEscapeAtom=function(){var p;switch(this.popChar()){case"f":p=n("\f");break;case"n":p=n(` +`);break;case"r":p=n("\r");break;case"t":p=n(" ");break;case"v":p=n("\v");break}return a(p),{type:"Character",value:p}},r.prototype.controlLetterEscapeAtom=function(){this.consumeChar("c");var p=this.popChar();if(/[a-zA-Z]/.test(p)===!1)throw Error("Invalid ");var C=p.toUpperCase().charCodeAt(0)-64;return{type:"Character",value:C}},r.prototype.nulCharacterAtom=function(){return this.consumeChar("0"),{type:"Character",value:n("\0")}},r.prototype.hexEscapeSequenceAtom=function(){return this.consumeChar("x"),this.parseHexDigits(2)},r.prototype.regExpUnicodeEscapeSequenceAtom=function(){return this.consumeChar("u"),this.parseHexDigits(4)},r.prototype.identityEscapeAtom=function(){var p=this.popChar();return{type:"Character",value:n(p)}},r.prototype.classPatternCharacterAtom=function(){switch(this.peekChar()){case` +`:case"\r":case"\u2028":case"\u2029":case"\\":case"]":throw Error("TBD");default:var p=this.popChar();return{type:"Character",value:n(p)}}},r.prototype.characterClass=function(){var p=[],C=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),C=!0);this.isClassAtom();){var y=this.classAtom(),B=y.type==="Character";if(B&&this.isRangeDash()){this.consumeChar("-");var v=this.classAtom(),D=v.type==="Character";if(D){if(v.value=this.input.length)throw Error("Unexpected end of input");this.idx++},r.prototype.loc=function(p){return{begin:p,end:this.idx}};var e=/[0-9a-fA-F]/,t=/[0-9]/,i=/[1-9]/;function n(p){return p.charCodeAt(0)}function s(p,C){p.length!==void 0?p.forEach(function(y){C.push(y)}):C.push(p)}function o(p,C){if(p[C]===!0)throw"duplicate flag "+C;p[C]=!0}function a(p){if(p===void 0)throw Error("Internal Error - Should never get here!")}function l(){throw Error("Internal Error - Should never get here!")}var c,u=[];for(c=n("0");c<=n("9");c++)u.push(c);var g=[n("_")].concat(u);for(c=n("a");c<=n("z");c++)g.push(c);for(c=n("A");c<=n("Z");c++)g.push(c);var f=[n(" "),n("\f"),n(` +`),n("\r"),n(" "),n("\v"),n(" "),n("\xA0"),n("\u1680"),n("\u2000"),n("\u2001"),n("\u2002"),n("\u2003"),n("\u2004"),n("\u2005"),n("\u2006"),n("\u2007"),n("\u2008"),n("\u2009"),n("\u200A"),n("\u2028"),n("\u2029"),n("\u202F"),n("\u205F"),n("\u3000"),n("\uFEFF")];function h(){}return h.prototype.visitChildren=function(p){for(var C in p){var y=p[C];p.hasOwnProperty(C)&&(y.type!==void 0?this.visit(y):Array.isArray(y)&&y.forEach(function(B){this.visit(B)},this))}},h.prototype.visit=function(p){switch(p.type){case"Pattern":this.visitPattern(p);break;case"Flags":this.visitFlags(p);break;case"Disjunction":this.visitDisjunction(p);break;case"Alternative":this.visitAlternative(p);break;case"StartAnchor":this.visitStartAnchor(p);break;case"EndAnchor":this.visitEndAnchor(p);break;case"WordBoundary":this.visitWordBoundary(p);break;case"NonWordBoundary":this.visitNonWordBoundary(p);break;case"Lookahead":this.visitLookahead(p);break;case"NegativeLookahead":this.visitNegativeLookahead(p);break;case"Character":this.visitCharacter(p);break;case"Set":this.visitSet(p);break;case"Group":this.visitGroup(p);break;case"GroupBackReference":this.visitGroupBackReference(p);break;case"Quantifier":this.visitQuantifier(p);break}this.visitChildren(p)},h.prototype.visitPattern=function(p){},h.prototype.visitFlags=function(p){},h.prototype.visitDisjunction=function(p){},h.prototype.visitAlternative=function(p){},h.prototype.visitStartAnchor=function(p){},h.prototype.visitEndAnchor=function(p){},h.prototype.visitWordBoundary=function(p){},h.prototype.visitNonWordBoundary=function(p){},h.prototype.visitLookahead=function(p){},h.prototype.visitNegativeLookahead=function(p){},h.prototype.visitCharacter=function(p){},h.prototype.visitSet=function(p){},h.prototype.visitGroup=function(p){},h.prototype.visitGroupBackReference=function(p){},h.prototype.visitQuantifier=function(p){},{RegExpParser:r,BaseRegExpVisitor:h,VERSION:"0.5.0"}})});var ty=w(Xg=>{"use strict";Object.defineProperty(Xg,"__esModule",{value:!0});Xg.clearRegExpParserCache=Xg.getRegExpAst=void 0;var dEe=$I(),ey={},CEe=new dEe.RegExpParser;function mEe(r){var e=r.toString();if(ey.hasOwnProperty(e))return ey[e];var t=CEe.pattern(e);return ey[e]=t,t}Xg.getRegExpAst=mEe;function EEe(){ey={}}Xg.clearRegExpParserCache=EEe});var YY=w(dn=>{"use strict";var IEe=dn&&dn.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(dn,"__esModule",{value:!0});dn.canMatchCharCode=dn.firstCharOptimizedIndices=dn.getOptimizedStartCodesIndices=dn.failedOptimizationPrefixMsg=void 0;var KY=$I(),gs=Gt(),HY=ty(),va=Rv(),GY="Complement Sets are not supported for first char optimization";dn.failedOptimizationPrefixMsg=`Unable to use "first char" lexer optimizations: +`;function yEe(r,e){e===void 0&&(e=!1);try{var t=(0,HY.getRegExpAst)(r),i=iy(t.value,{},t.flags.ignoreCase);return i}catch(s){if(s.message===GY)e&&(0,gs.PRINT_WARNING)(""+dn.failedOptimizationPrefixMsg+(" Unable to optimize: < "+r.toString()+` > +`)+` Complement Sets cannot be automatically optimized. + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.`);else{var n="";e&&(n=` + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),(0,gs.PRINT_ERROR)(dn.failedOptimizationPrefixMsg+` +`+(" Failed parsing: < "+r.toString()+` > +`)+(" Using the regexp-to-ast library version: "+KY.VERSION+` +`)+" Please open an issue at: https://github.com/bd82/regexp-to-ast/issues"+n)}}return[]}dn.getOptimizedStartCodesIndices=yEe;function iy(r,e,t){switch(r.type){case"Disjunction":for(var i=0;i=va.minOptimizationVal)for(var f=u.from>=va.minOptimizationVal?u.from:va.minOptimizationVal,h=u.to,p=(0,va.charCodeToOptimizedIndex)(f),C=(0,va.charCodeToOptimizedIndex)(h),y=p;y<=C;y++)e[y]=y}}});break;case"Group":iy(o.value,e,t);break;default:throw Error("Non Exhaustive Match")}var a=o.quantifier!==void 0&&o.quantifier.atLeast===0;if(o.type==="Group"&&kv(o)===!1||o.type!=="Group"&&a===!1)break}break;default:throw Error("non exhaustive match!")}return(0,gs.values)(e)}dn.firstCharOptimizedIndices=iy;function ry(r,e,t){var i=(0,va.charCodeToOptimizedIndex)(r);e[i]=i,t===!0&&wEe(r,e)}function wEe(r,e){var t=String.fromCharCode(r),i=t.toUpperCase();if(i!==t){var n=(0,va.charCodeToOptimizedIndex)(i.charCodeAt(0));e[n]=n}else{var s=t.toLowerCase();if(s!==t){var n=(0,va.charCodeToOptimizedIndex)(s.charCodeAt(0));e[n]=n}}}function UY(r,e){return(0,gs.find)(r.value,function(t){if(typeof t=="number")return(0,gs.contains)(e,t);var i=t;return(0,gs.find)(e,function(n){return i.from<=n&&n<=i.to})!==void 0})}function kv(r){return r.quantifier&&r.quantifier.atLeast===0?!0:r.value?(0,gs.isArray)(r.value)?(0,gs.every)(r.value,kv):kv(r.value):!1}var BEe=function(r){IEe(e,r);function e(t){var i=r.call(this)||this;return i.targetCharCodes=t,i.found=!1,i}return e.prototype.visitChildren=function(t){if(this.found!==!0){switch(t.type){case"Lookahead":this.visitLookahead(t);return;case"NegativeLookahead":this.visitNegativeLookahead(t);return}r.prototype.visitChildren.call(this,t)}},e.prototype.visitCharacter=function(t){(0,gs.contains)(this.targetCharCodes,t.value)&&(this.found=!0)},e.prototype.visitSet=function(t){t.complement?UY(t,this.targetCharCodes)===void 0&&(this.found=!0):UY(t,this.targetCharCodes)!==void 0&&(this.found=!0)},e}(KY.BaseRegExpVisitor);function QEe(r,e){if(e instanceof RegExp){var t=(0,HY.getRegExpAst)(e),i=new BEe(r);return i.visit(t),i.found}else return(0,gs.find)(e,function(n){return(0,gs.contains)(r,n.charCodeAt(0))})!==void 0}dn.canMatchCharCode=QEe});var Rv=w(Ve=>{"use strict";var jY=Ve&&Ve.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Ve,"__esModule",{value:!0});Ve.charCodeToOptimizedIndex=Ve.minOptimizationVal=Ve.buildLineBreakIssueMessage=Ve.LineTerminatorOptimizedTester=Ve.isShortPattern=Ve.isCustomPattern=Ve.cloneEmptyGroups=Ve.performWarningRuntimeChecks=Ve.performRuntimeChecks=Ve.addStickyFlag=Ve.addStartOfInput=Ve.findUnreachablePatterns=Ve.findModesThatDoNotExist=Ve.findInvalidGroupType=Ve.findDuplicatePatterns=Ve.findUnsupportedFlags=Ve.findStartOfInputAnchor=Ve.findEmptyMatchRegExps=Ve.findEndOfInputAnchor=Ve.findInvalidPatterns=Ve.findMissingPatterns=Ve.validatePatterns=Ve.analyzeTokenTypes=Ve.enableSticky=Ve.disableSticky=Ve.SUPPORT_STICKY=Ve.MODES=Ve.DEFAULT_MODE=void 0;var qY=$I(),ir=Bd(),xe=Gt(),Zg=YY(),JY=ty(),Do="PATTERN";Ve.DEFAULT_MODE="defaultMode";Ve.MODES="modes";Ve.SUPPORT_STICKY=typeof new RegExp("(?:)").sticky=="boolean";function bEe(){Ve.SUPPORT_STICKY=!1}Ve.disableSticky=bEe;function SEe(){Ve.SUPPORT_STICKY=!0}Ve.enableSticky=SEe;function vEe(r,e){e=(0,xe.defaults)(e,{useSticky:Ve.SUPPORT_STICKY,debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",` +`],tracer:function(v,D){return D()}});var t=e.tracer;t("initCharCodeToOptimizedIndexMap",function(){OEe()});var i;t("Reject Lexer.NA",function(){i=(0,xe.reject)(r,function(v){return v[Do]===ir.Lexer.NA})});var n=!1,s;t("Transform Patterns",function(){n=!1,s=(0,xe.map)(i,function(v){var D=v[Do];if((0,xe.isRegExp)(D)){var L=D.source;return L.length===1&&L!=="^"&&L!=="$"&&L!=="."&&!D.ignoreCase?L:L.length===2&&L[0]==="\\"&&!(0,xe.contains)(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],L[1])?L[1]:e.useSticky?Lv(D):Nv(D)}else{if((0,xe.isFunction)(D))return n=!0,{exec:D};if((0,xe.has)(D,"exec"))return n=!0,D;if(typeof D=="string"){if(D.length===1)return D;var H=D.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),j=new RegExp(H);return e.useSticky?Lv(j):Nv(j)}else throw Error("non exhaustive match")}})});var o,a,l,c,u;t("misc mapping",function(){o=(0,xe.map)(i,function(v){return v.tokenTypeIdx}),a=(0,xe.map)(i,function(v){var D=v.GROUP;if(D!==ir.Lexer.SKIPPED){if((0,xe.isString)(D))return D;if((0,xe.isUndefined)(D))return!1;throw Error("non exhaustive match")}}),l=(0,xe.map)(i,function(v){var D=v.LONGER_ALT;if(D){var L=(0,xe.isArray)(D)?(0,xe.map)(D,function(H){return(0,xe.indexOf)(i,H)}):[(0,xe.indexOf)(i,D)];return L}}),c=(0,xe.map)(i,function(v){return v.PUSH_MODE}),u=(0,xe.map)(i,function(v){return(0,xe.has)(v,"POP_MODE")})});var g;t("Line Terminator Handling",function(){var v=oj(e.lineTerminatorCharacters);g=(0,xe.map)(i,function(D){return!1}),e.positionTracking!=="onlyOffset"&&(g=(0,xe.map)(i,function(D){if((0,xe.has)(D,"LINE_BREAKS"))return D.LINE_BREAKS;if(nj(D,v)===!1)return(0,Zg.canMatchCharCode)(v,D.PATTERN)}))});var f,h,p,C;t("Misc Mapping #2",function(){f=(0,xe.map)(i,Ov),h=(0,xe.map)(s,ij),p=(0,xe.reduce)(i,function(v,D){var L=D.GROUP;return(0,xe.isString)(L)&&L!==ir.Lexer.SKIPPED&&(v[L]=[]),v},{}),C=(0,xe.map)(s,function(v,D){return{pattern:s[D],longerAlt:l[D],canLineTerminator:g[D],isCustom:f[D],short:h[D],group:a[D],push:c[D],pop:u[D],tokenTypeIdx:o[D],tokenType:i[D]}})});var y=!0,B=[];return e.safeMode||t("First Char Optimization",function(){B=(0,xe.reduce)(i,function(v,D,L){if(typeof D.PATTERN=="string"){var H=D.PATTERN.charCodeAt(0),j=Tv(H);Fv(v,j,C[L])}else if((0,xe.isArray)(D.START_CHARS_HINT)){var $;(0,xe.forEach)(D.START_CHARS_HINT,function(W){var _=typeof W=="string"?W.charCodeAt(0):W,A=Tv(_);$!==A&&($=A,Fv(v,A,C[L]))})}else if((0,xe.isRegExp)(D.PATTERN))if(D.PATTERN.unicode)y=!1,e.ensureOptimizations&&(0,xe.PRINT_ERROR)(""+Zg.failedOptimizationPrefixMsg+(" Unable to analyze < "+D.PATTERN.toString()+` > pattern. +`)+` The regexp unicode flag is not currently supported by the regexp-to-ast library. + This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNICODE_OPTIMIZE`);else{var V=(0,Zg.getOptimizedStartCodesIndices)(D.PATTERN,e.ensureOptimizations);(0,xe.isEmpty)(V)&&(y=!1),(0,xe.forEach)(V,function(W){Fv(v,W,C[L])})}else e.ensureOptimizations&&(0,xe.PRINT_ERROR)(""+Zg.failedOptimizationPrefixMsg+(" TokenType: <"+D.name+`> is using a custom token pattern without providing parameter. +`)+` This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),y=!1;return v},[])}),t("ArrayPacking",function(){B=(0,xe.packArray)(B)}),{emptyGroups:p,patternIdxToConfig:C,charCodeToPatternIdxToConfig:B,hasCustom:n,canBeOptimized:y}}Ve.analyzeTokenTypes=vEe;function xEe(r,e){var t=[],i=WY(r);t=t.concat(i.errors);var n=zY(i.valid),s=n.valid;return t=t.concat(n.errors),t=t.concat(PEe(s)),t=t.concat(ej(s)),t=t.concat(tj(s,e)),t=t.concat(rj(s)),t}Ve.validatePatterns=xEe;function PEe(r){var e=[],t=(0,xe.filter)(r,function(i){return(0,xe.isRegExp)(i[Do])});return e=e.concat(VY(t)),e=e.concat(ZY(t)),e=e.concat(_Y(t)),e=e.concat($Y(t)),e=e.concat(XY(t)),e}function WY(r){var e=(0,xe.filter)(r,function(n){return!(0,xe.has)(n,Do)}),t=(0,xe.map)(e,function(n){return{message:"Token Type: ->"+n.name+"<- missing static 'PATTERN' property",type:ir.LexerDefinitionErrorType.MISSING_PATTERN,tokenTypes:[n]}}),i=(0,xe.difference)(r,e);return{errors:t,valid:i}}Ve.findMissingPatterns=WY;function zY(r){var e=(0,xe.filter)(r,function(n){var s=n[Do];return!(0,xe.isRegExp)(s)&&!(0,xe.isFunction)(s)&&!(0,xe.has)(s,"exec")&&!(0,xe.isString)(s)}),t=(0,xe.map)(e,function(n){return{message:"Token Type: ->"+n.name+"<- static 'PATTERN' can only be a RegExp, a Function matching the {CustomPatternMatcherFunc} type or an Object matching the {ICustomPattern} interface.",type:ir.LexerDefinitionErrorType.INVALID_PATTERN,tokenTypes:[n]}}),i=(0,xe.difference)(r,e);return{errors:t,valid:i}}Ve.findInvalidPatterns=zY;var DEe=/[^\\][\$]/;function VY(r){var e=function(n){jY(s,n);function s(){var o=n!==null&&n.apply(this,arguments)||this;return o.found=!1,o}return s.prototype.visitEndAnchor=function(o){this.found=!0},s}(qY.BaseRegExpVisitor),t=(0,xe.filter)(r,function(n){var s=n[Do];try{var o=(0,JY.getRegExpAst)(s),a=new e;return a.visit(o),a.found}catch{return DEe.test(s.source)}}),i=(0,xe.map)(t,function(n){return{message:`Unexpected RegExp Anchor Error: + Token Type: ->`+n.name+`<- static 'PATTERN' cannot contain end of input anchor '$' + See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:ir.LexerDefinitionErrorType.EOI_ANCHOR_FOUND,tokenTypes:[n]}});return i}Ve.findEndOfInputAnchor=VY;function XY(r){var e=(0,xe.filter)(r,function(i){var n=i[Do];return n.test("")}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'PATTERN' must not match an empty string",type:ir.LexerDefinitionErrorType.EMPTY_MATCH_PATTERN,tokenTypes:[i]}});return t}Ve.findEmptyMatchRegExps=XY;var kEe=/[^\\[][\^]|^\^/;function ZY(r){var e=function(n){jY(s,n);function s(){var o=n!==null&&n.apply(this,arguments)||this;return o.found=!1,o}return s.prototype.visitStartAnchor=function(o){this.found=!0},s}(qY.BaseRegExpVisitor),t=(0,xe.filter)(r,function(n){var s=n[Do];try{var o=(0,JY.getRegExpAst)(s),a=new e;return a.visit(o),a.found}catch{return kEe.test(s.source)}}),i=(0,xe.map)(t,function(n){return{message:`Unexpected RegExp Anchor Error: + Token Type: ->`+n.name+`<- static 'PATTERN' cannot contain start of input anchor '^' + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:ir.LexerDefinitionErrorType.SOI_ANCHOR_FOUND,tokenTypes:[n]}});return i}Ve.findStartOfInputAnchor=ZY;function _Y(r){var e=(0,xe.filter)(r,function(i){var n=i[Do];return n instanceof RegExp&&(n.multiline||n.global)}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:ir.LexerDefinitionErrorType.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[i]}});return t}Ve.findUnsupportedFlags=_Y;function $Y(r){var e=[],t=(0,xe.map)(r,function(s){return(0,xe.reduce)(r,function(o,a){return s.PATTERN.source===a.PATTERN.source&&!(0,xe.contains)(e,a)&&a.PATTERN!==ir.Lexer.NA&&(e.push(a),o.push(a)),o},[])});t=(0,xe.compact)(t);var i=(0,xe.filter)(t,function(s){return s.length>1}),n=(0,xe.map)(i,function(s){var o=(0,xe.map)(s,function(l){return l.name}),a=(0,xe.first)(s).PATTERN;return{message:"The same RegExp pattern ->"+a+"<-"+("has been used in all of the following Token Types: "+o.join(", ")+" <-"),type:ir.LexerDefinitionErrorType.DUPLICATE_PATTERNS_FOUND,tokenTypes:s}});return n}Ve.findDuplicatePatterns=$Y;function ej(r){var e=(0,xe.filter)(r,function(i){if(!(0,xe.has)(i,"GROUP"))return!1;var n=i.GROUP;return n!==ir.Lexer.SKIPPED&&n!==ir.Lexer.NA&&!(0,xe.isString)(n)}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:ir.LexerDefinitionErrorType.INVALID_GROUP_TYPE_FOUND,tokenTypes:[i]}});return t}Ve.findInvalidGroupType=ej;function tj(r,e){var t=(0,xe.filter)(r,function(n){return n.PUSH_MODE!==void 0&&!(0,xe.contains)(e,n.PUSH_MODE)}),i=(0,xe.map)(t,function(n){var s="Token Type: ->"+n.name+"<- static 'PUSH_MODE' value cannot refer to a Lexer Mode ->"+n.PUSH_MODE+"<-which does not exist";return{message:s,type:ir.LexerDefinitionErrorType.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[n]}});return i}Ve.findModesThatDoNotExist=tj;function rj(r){var e=[],t=(0,xe.reduce)(r,function(i,n,s){var o=n.PATTERN;return o===ir.Lexer.NA||((0,xe.isString)(o)?i.push({str:o,idx:s,tokenType:n}):(0,xe.isRegExp)(o)&&FEe(o)&&i.push({str:o.source,idx:s,tokenType:n})),i},[]);return(0,xe.forEach)(r,function(i,n){(0,xe.forEach)(t,function(s){var o=s.str,a=s.idx,l=s.tokenType;if(n"+i.name+"<-")+`in the lexer's definition. +See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;e.push({message:c,type:ir.LexerDefinitionErrorType.UNREACHABLE_PATTERN,tokenTypes:[i,l]})}})}),e}Ve.findUnreachablePatterns=rj;function REe(r,e){if((0,xe.isRegExp)(e)){var t=e.exec(r);return t!==null&&t.index===0}else{if((0,xe.isFunction)(e))return e(r,0,[],{});if((0,xe.has)(e,"exec"))return e.exec(r,0,[],{});if(typeof e=="string")return e===r;throw Error("non exhaustive match")}}function FEe(r){var e=[".","\\","[","]","|","^","$","(",")","?","*","+","{"];return(0,xe.find)(e,function(t){return r.source.indexOf(t)!==-1})===void 0}function Nv(r){var e=r.ignoreCase?"i":"";return new RegExp("^(?:"+r.source+")",e)}Ve.addStartOfInput=Nv;function Lv(r){var e=r.ignoreCase?"iy":"y";return new RegExp(""+r.source,e)}Ve.addStickyFlag=Lv;function NEe(r,e,t){var i=[];return(0,xe.has)(r,Ve.DEFAULT_MODE)||i.push({message:"A MultiMode Lexer cannot be initialized without a <"+Ve.DEFAULT_MODE+`> property in its definition +`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),(0,xe.has)(r,Ve.MODES)||i.push({message:"A MultiMode Lexer cannot be initialized without a <"+Ve.MODES+`> property in its definition +`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),(0,xe.has)(r,Ve.MODES)&&(0,xe.has)(r,Ve.DEFAULT_MODE)&&!(0,xe.has)(r.modes,r.defaultMode)&&i.push({message:"A MultiMode Lexer cannot be initialized with a "+Ve.DEFAULT_MODE+": <"+r.defaultMode+`>which does not exist +`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),(0,xe.has)(r,Ve.MODES)&&(0,xe.forEach)(r.modes,function(n,s){(0,xe.forEach)(n,function(o,a){(0,xe.isUndefined)(o)&&i.push({message:"A Lexer cannot be initialized using an undefined Token Type. Mode:"+("<"+s+"> at index: <"+a+`> +`),type:ir.LexerDefinitionErrorType.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED})})}),i}Ve.performRuntimeChecks=NEe;function LEe(r,e,t){var i=[],n=!1,s=(0,xe.compact)((0,xe.flatten)((0,xe.mapValues)(r.modes,function(l){return l}))),o=(0,xe.reject)(s,function(l){return l[Do]===ir.Lexer.NA}),a=oj(t);return e&&(0,xe.forEach)(o,function(l){var c=nj(l,a);if(c!==!1){var u=sj(l,c),g={message:u,type:c.issue,tokenType:l};i.push(g)}else(0,xe.has)(l,"LINE_BREAKS")?l.LINE_BREAKS===!0&&(n=!0):(0,Zg.canMatchCharCode)(a,l.PATTERN)&&(n=!0)}),e&&!n&&i.push({message:`Warning: No LINE_BREAKS Found. + This Lexer has been defined to track line and column information, + But none of the Token Types can be identified as matching a line terminator. + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#LINE_BREAKS + for details.`,type:ir.LexerDefinitionErrorType.NO_LINE_BREAKS_FLAGS}),i}Ve.performWarningRuntimeChecks=LEe;function TEe(r){var e={},t=(0,xe.keys)(r);return(0,xe.forEach)(t,function(i){var n=r[i];if((0,xe.isArray)(n))e[i]=[];else throw Error("non exhaustive match")}),e}Ve.cloneEmptyGroups=TEe;function Ov(r){var e=r.PATTERN;if((0,xe.isRegExp)(e))return!1;if((0,xe.isFunction)(e))return!0;if((0,xe.has)(e,"exec"))return!0;if((0,xe.isString)(e))return!1;throw Error("non exhaustive match")}Ve.isCustomPattern=Ov;function ij(r){return(0,xe.isString)(r)&&r.length===1?r.charCodeAt(0):!1}Ve.isShortPattern=ij;Ve.LineTerminatorOptimizedTester={test:function(r){for(var e=r.length,t=this.lastIndex;t Token Type +`)+(" Root cause: "+e.errMsg+`. +`)+" For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR";if(e.issue===ir.LexerDefinitionErrorType.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the option. +`+(" The problem is in the <"+r.name+`> Token Type +`)+" For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK";throw Error("non exhaustive match")}Ve.buildLineBreakIssueMessage=sj;function oj(r){var e=(0,xe.map)(r,function(t){return(0,xe.isString)(t)&&t.length>0?t.charCodeAt(0):t});return e}function Fv(r,e,t){r[e]===void 0?r[e]=[t]:r[e].push(t)}Ve.minOptimizationVal=256;var ny=[];function Tv(r){return r255?255+~~(r/255):r}}});var _g=w(Nt=>{"use strict";Object.defineProperty(Nt,"__esModule",{value:!0});Nt.isTokenType=Nt.hasExtendingTokensTypesMapProperty=Nt.hasExtendingTokensTypesProperty=Nt.hasCategoriesProperty=Nt.hasShortKeyProperty=Nt.singleAssignCategoriesToksMap=Nt.assignCategoriesMapProp=Nt.assignCategoriesTokensProp=Nt.assignTokenDefaultProps=Nt.expandCategories=Nt.augmentTokenTypes=Nt.tokenIdxToClass=Nt.tokenShortNameIdx=Nt.tokenStructuredMatcherNoCategories=Nt.tokenStructuredMatcher=void 0;var Zr=Gt();function MEe(r,e){var t=r.tokenTypeIdx;return t===e.tokenTypeIdx?!0:e.isParent===!0&&e.categoryMatchesMap[t]===!0}Nt.tokenStructuredMatcher=MEe;function UEe(r,e){return r.tokenTypeIdx===e.tokenTypeIdx}Nt.tokenStructuredMatcherNoCategories=UEe;Nt.tokenShortNameIdx=1;Nt.tokenIdxToClass={};function KEe(r){var e=aj(r);Aj(e),cj(e),lj(e),(0,Zr.forEach)(e,function(t){t.isParent=t.categoryMatches.length>0})}Nt.augmentTokenTypes=KEe;function aj(r){for(var e=(0,Zr.cloneArr)(r),t=r,i=!0;i;){t=(0,Zr.compact)((0,Zr.flatten)((0,Zr.map)(t,function(s){return s.CATEGORIES})));var n=(0,Zr.difference)(t,e);e=e.concat(n),(0,Zr.isEmpty)(n)?i=!1:t=n}return e}Nt.expandCategories=aj;function Aj(r){(0,Zr.forEach)(r,function(e){uj(e)||(Nt.tokenIdxToClass[Nt.tokenShortNameIdx]=e,e.tokenTypeIdx=Nt.tokenShortNameIdx++),Mv(e)&&!(0,Zr.isArray)(e.CATEGORIES)&&(e.CATEGORIES=[e.CATEGORIES]),Mv(e)||(e.CATEGORIES=[]),gj(e)||(e.categoryMatches=[]),fj(e)||(e.categoryMatchesMap={})})}Nt.assignTokenDefaultProps=Aj;function lj(r){(0,Zr.forEach)(r,function(e){e.categoryMatches=[],(0,Zr.forEach)(e.categoryMatchesMap,function(t,i){e.categoryMatches.push(Nt.tokenIdxToClass[i].tokenTypeIdx)})})}Nt.assignCategoriesTokensProp=lj;function cj(r){(0,Zr.forEach)(r,function(e){Uv([],e)})}Nt.assignCategoriesMapProp=cj;function Uv(r,e){(0,Zr.forEach)(r,function(t){e.categoryMatchesMap[t.tokenTypeIdx]=!0}),(0,Zr.forEach)(e.CATEGORIES,function(t){var i=r.concat(e);(0,Zr.contains)(i,t)||Uv(i,t)})}Nt.singleAssignCategoriesToksMap=Uv;function uj(r){return(0,Zr.has)(r,"tokenTypeIdx")}Nt.hasShortKeyProperty=uj;function Mv(r){return(0,Zr.has)(r,"CATEGORIES")}Nt.hasCategoriesProperty=Mv;function gj(r){return(0,Zr.has)(r,"categoryMatches")}Nt.hasExtendingTokensTypesProperty=gj;function fj(r){return(0,Zr.has)(r,"categoryMatchesMap")}Nt.hasExtendingTokensTypesMapProperty=fj;function HEe(r){return(0,Zr.has)(r,"tokenTypeIdx")}Nt.isTokenType=HEe});var Kv=w(sy=>{"use strict";Object.defineProperty(sy,"__esModule",{value:!0});sy.defaultLexerErrorProvider=void 0;sy.defaultLexerErrorProvider={buildUnableToPopLexerModeMessage:function(r){return"Unable to pop Lexer Mode after encountering Token ->"+r.image+"<- The Mode Stack is empty"},buildUnexpectedCharactersMessage:function(r,e,t,i,n){return"unexpected character: ->"+r.charAt(e)+"<- at offset: "+e+","+(" skipped "+t+" characters.")}}});var Bd=w(Cc=>{"use strict";Object.defineProperty(Cc,"__esModule",{value:!0});Cc.Lexer=Cc.LexerDefinitionErrorType=void 0;var _s=Rv(),nr=Gt(),GEe=_g(),YEe=Kv(),jEe=ty(),qEe;(function(r){r[r.MISSING_PATTERN=0]="MISSING_PATTERN",r[r.INVALID_PATTERN=1]="INVALID_PATTERN",r[r.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",r[r.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",r[r.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",r[r.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",r[r.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",r[r.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",r[r.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",r[r.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",r[r.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",r[r.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",r[r.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",r[r.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",r[r.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",r[r.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",r[r.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK"})(qEe=Cc.LexerDefinitionErrorType||(Cc.LexerDefinitionErrorType={}));var Qd={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[` +`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:YEe.defaultLexerErrorProvider,traceInitPerf:!1,skipValidations:!1};Object.freeze(Qd);var JEe=function(){function r(e,t){var i=this;if(t===void 0&&(t=Qd),this.lexerDefinition=e,this.lexerDefinitionErrors=[],this.lexerDefinitionWarning=[],this.patternIdxToConfig={},this.charCodeToPatternIdxToConfig={},this.modes=[],this.emptyGroups={},this.config=void 0,this.trackStartLines=!0,this.trackEndLines=!0,this.hasCustom=!1,this.canModeBeOptimized={},typeof t=="boolean")throw Error(`The second argument to the Lexer constructor is now an ILexerConfig Object. +a boolean 2nd argument is no longer supported`);this.config=(0,nr.merge)(Qd,t);var n=this.config.traceInitPerf;n===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof n=="number"&&(this.traceInitMaxIdent=n,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",function(){var s,o=!0;i.TRACE_INIT("Lexer Config handling",function(){if(i.config.lineTerminatorsPattern===Qd.lineTerminatorsPattern)i.config.lineTerminatorsPattern=_s.LineTerminatorOptimizedTester;else if(i.config.lineTerminatorCharacters===Qd.lineTerminatorCharacters)throw Error(`Error: Missing property on the Lexer config. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(t.safeMode&&t.ensureOptimizations)throw Error('"safeMode" and "ensureOptimizations" flags are mutually exclusive.');i.trackStartLines=/full|onlyStart/i.test(i.config.positionTracking),i.trackEndLines=/full/i.test(i.config.positionTracking),(0,nr.isArray)(e)?(s={modes:{}},s.modes[_s.DEFAULT_MODE]=(0,nr.cloneArr)(e),s[_s.DEFAULT_MODE]=_s.DEFAULT_MODE):(o=!1,s=(0,nr.cloneObj)(e))}),i.config.skipValidations===!1&&(i.TRACE_INIT("performRuntimeChecks",function(){i.lexerDefinitionErrors=i.lexerDefinitionErrors.concat((0,_s.performRuntimeChecks)(s,i.trackStartLines,i.config.lineTerminatorCharacters))}),i.TRACE_INIT("performWarningRuntimeChecks",function(){i.lexerDefinitionWarning=i.lexerDefinitionWarning.concat((0,_s.performWarningRuntimeChecks)(s,i.trackStartLines,i.config.lineTerminatorCharacters))})),s.modes=s.modes?s.modes:{},(0,nr.forEach)(s.modes,function(u,g){s.modes[g]=(0,nr.reject)(u,function(f){return(0,nr.isUndefined)(f)})});var a=(0,nr.keys)(s.modes);if((0,nr.forEach)(s.modes,function(u,g){i.TRACE_INIT("Mode: <"+g+"> processing",function(){if(i.modes.push(g),i.config.skipValidations===!1&&i.TRACE_INIT("validatePatterns",function(){i.lexerDefinitionErrors=i.lexerDefinitionErrors.concat((0,_s.validatePatterns)(u,a))}),(0,nr.isEmpty)(i.lexerDefinitionErrors)){(0,GEe.augmentTokenTypes)(u);var f;i.TRACE_INIT("analyzeTokenTypes",function(){f=(0,_s.analyzeTokenTypes)(u,{lineTerminatorCharacters:i.config.lineTerminatorCharacters,positionTracking:t.positionTracking,ensureOptimizations:t.ensureOptimizations,safeMode:t.safeMode,tracer:i.TRACE_INIT.bind(i)})}),i.patternIdxToConfig[g]=f.patternIdxToConfig,i.charCodeToPatternIdxToConfig[g]=f.charCodeToPatternIdxToConfig,i.emptyGroups=(0,nr.merge)(i.emptyGroups,f.emptyGroups),i.hasCustom=f.hasCustom||i.hasCustom,i.canModeBeOptimized[g]=f.canBeOptimized}})}),i.defaultMode=s.defaultMode,!(0,nr.isEmpty)(i.lexerDefinitionErrors)&&!i.config.deferDefinitionErrorsHandling){var l=(0,nr.map)(i.lexerDefinitionErrors,function(u){return u.message}),c=l.join(`----------------------- +`);throw new Error(`Errors detected in definition of Lexer: +`+c)}(0,nr.forEach)(i.lexerDefinitionWarning,function(u){(0,nr.PRINT_WARNING)(u.message)}),i.TRACE_INIT("Choosing sub-methods implementations",function(){if(_s.SUPPORT_STICKY?(i.chopInput=nr.IDENTITY,i.match=i.matchWithTest):(i.updateLastIndex=nr.NOOP,i.match=i.matchWithExec),o&&(i.handleModes=nr.NOOP),i.trackStartLines===!1&&(i.computeNewColumn=nr.IDENTITY),i.trackEndLines===!1&&(i.updateTokenEndLineColumnLocation=nr.NOOP),/full/i.test(i.config.positionTracking))i.createTokenInstance=i.createFullToken;else if(/onlyStart/i.test(i.config.positionTracking))i.createTokenInstance=i.createStartOnlyToken;else if(/onlyOffset/i.test(i.config.positionTracking))i.createTokenInstance=i.createOffsetOnlyToken;else throw Error('Invalid config option: "'+i.config.positionTracking+'"');i.hasCustom?(i.addToken=i.addTokenUsingPush,i.handlePayload=i.handlePayloadWithCustom):(i.addToken=i.addTokenUsingMemberAccess,i.handlePayload=i.handlePayloadNoCustom)}),i.TRACE_INIT("Failed Optimization Warnings",function(){var u=(0,nr.reduce)(i.canModeBeOptimized,function(g,f,h){return f===!1&&g.push(h),g},[]);if(t.ensureOptimizations&&!(0,nr.isEmpty)(u))throw Error("Lexer Modes: < "+u.join(", ")+` > cannot be optimized. + Disable the "ensureOptimizations" lexer config flag to silently ignore this and run the lexer in an un-optimized mode. + Or inspect the console log for details on how to resolve these issues.`)}),i.TRACE_INIT("clearRegExpParserCache",function(){(0,jEe.clearRegExpParserCache)()}),i.TRACE_INIT("toFastProperties",function(){(0,nr.toFastProperties)(i)})})}return r.prototype.tokenize=function(e,t){if(t===void 0&&(t=this.defaultMode),!(0,nr.isEmpty)(this.lexerDefinitionErrors)){var i=(0,nr.map)(this.lexerDefinitionErrors,function(o){return o.message}),n=i.join(`----------------------- +`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer: +`+n)}var s=this.tokenizeInternal(e,t);return s},r.prototype.tokenizeInternal=function(e,t){var i=this,n,s,o,a,l,c,u,g,f,h,p,C,y,B,v,D,L=e,H=L.length,j=0,$=0,V=this.hasCustom?0:Math.floor(e.length/10),W=new Array(V),_=[],A=this.trackStartLines?1:void 0,Ae=this.trackStartLines?1:void 0,ge=(0,_s.cloneEmptyGroups)(this.emptyGroups),re=this.trackStartLines,O=this.config.lineTerminatorsPattern,F=0,ue=[],pe=[],ke=[],Fe=[];Object.freeze(Fe);var Ne=void 0;function oe(){return ue}function le(pr){var Ii=(0,_s.charCodeToOptimizedIndex)(pr),rs=pe[Ii];return rs===void 0?Fe:rs}var Be=function(pr){if(ke.length===1&&pr.tokenType.PUSH_MODE===void 0){var Ii=i.config.errorMessageProvider.buildUnableToPopLexerModeMessage(pr);_.push({offset:pr.startOffset,line:pr.startLine!==void 0?pr.startLine:void 0,column:pr.startColumn!==void 0?pr.startColumn:void 0,length:pr.image.length,message:Ii})}else{ke.pop();var rs=(0,nr.last)(ke);ue=i.patternIdxToConfig[rs],pe=i.charCodeToPatternIdxToConfig[rs],F=ue.length;var ga=i.canModeBeOptimized[rs]&&i.config.safeMode===!1;pe&&ga?Ne=le:Ne=oe}};function fe(pr){ke.push(pr),pe=this.charCodeToPatternIdxToConfig[pr],ue=this.patternIdxToConfig[pr],F=ue.length,F=ue.length;var Ii=this.canModeBeOptimized[pr]&&this.config.safeMode===!1;pe&&Ii?Ne=le:Ne=oe}fe.call(this,t);for(var ae;jc.length){c=a,u=g,ae=_e;break}}}break}}if(c!==null){if(f=c.length,h=ae.group,h!==void 0&&(p=ae.tokenTypeIdx,C=this.createTokenInstance(c,j,p,ae.tokenType,A,Ae,f),this.handlePayload(C,u),h===!1?$=this.addToken(W,$,C):ge[h].push(C)),e=this.chopInput(e,f),j=j+f,Ae=this.computeNewColumn(Ae,f),re===!0&&ae.canLineTerminator===!0){var It=0,Or=void 0,ii=void 0;O.lastIndex=0;do Or=O.test(c),Or===!0&&(ii=O.lastIndex-1,It++);while(Or===!0);It!==0&&(A=A+It,Ae=f-ii,this.updateTokenEndLineColumnLocation(C,h,ii,It,A,Ae,f))}this.handleModes(ae,Be,fe,C)}else{for(var gi=j,hr=A,fi=Ae,ni=!1;!ni&&j <"+e+">");var n=(0,nr.timer)(t),s=n.time,o=n.value,a=s>10?console.warn:console.log;return this.traceInitIndent time: "+s+"ms"),this.traceInitIndent--,o}else return t()},r.SKIPPED="This marks a skipped Token pattern, this means each token identified by it willbe consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.",r.NA=/NOT_APPLICABLE/,r}();Cc.Lexer=JEe});var LA=w(bi=>{"use strict";Object.defineProperty(bi,"__esModule",{value:!0});bi.tokenMatcher=bi.createTokenInstance=bi.EOF=bi.createToken=bi.hasTokenLabel=bi.tokenName=bi.tokenLabel=void 0;var $s=Gt(),WEe=Bd(),Hv=_g();function zEe(r){return wj(r)?r.LABEL:r.name}bi.tokenLabel=zEe;function VEe(r){return r.name}bi.tokenName=VEe;function wj(r){return(0,$s.isString)(r.LABEL)&&r.LABEL!==""}bi.hasTokenLabel=wj;var XEe="parent",hj="categories",pj="label",dj="group",Cj="push_mode",mj="pop_mode",Ej="longer_alt",Ij="line_breaks",yj="start_chars_hint";function Bj(r){return ZEe(r)}bi.createToken=Bj;function ZEe(r){var e=r.pattern,t={};if(t.name=r.name,(0,$s.isUndefined)(e)||(t.PATTERN=e),(0,$s.has)(r,XEe))throw`The parent property is no longer supported. +See: https://github.com/chevrotain/chevrotain/issues/564#issuecomment-349062346 for details.`;return(0,$s.has)(r,hj)&&(t.CATEGORIES=r[hj]),(0,Hv.augmentTokenTypes)([t]),(0,$s.has)(r,pj)&&(t.LABEL=r[pj]),(0,$s.has)(r,dj)&&(t.GROUP=r[dj]),(0,$s.has)(r,mj)&&(t.POP_MODE=r[mj]),(0,$s.has)(r,Cj)&&(t.PUSH_MODE=r[Cj]),(0,$s.has)(r,Ej)&&(t.LONGER_ALT=r[Ej]),(0,$s.has)(r,Ij)&&(t.LINE_BREAKS=r[Ij]),(0,$s.has)(r,yj)&&(t.START_CHARS_HINT=r[yj]),t}bi.EOF=Bj({name:"EOF",pattern:WEe.Lexer.NA});(0,Hv.augmentTokenTypes)([bi.EOF]);function _Ee(r,e,t,i,n,s,o,a){return{image:e,startOffset:t,endOffset:i,startLine:n,endLine:s,startColumn:o,endColumn:a,tokenTypeIdx:r.tokenTypeIdx,tokenType:r}}bi.createTokenInstance=_Ee;function $Ee(r,e){return(0,Hv.tokenStructuredMatcher)(r,e)}bi.tokenMatcher=$Ee});var Cn=w(zt=>{"use strict";var xa=zt&&zt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(zt,"__esModule",{value:!0});zt.serializeProduction=zt.serializeGrammar=zt.Terminal=zt.Alternation=zt.RepetitionWithSeparator=zt.Repetition=zt.RepetitionMandatoryWithSeparator=zt.RepetitionMandatory=zt.Option=zt.Alternative=zt.Rule=zt.NonTerminal=zt.AbstractProduction=void 0;var Ar=Gt(),eIe=LA(),ko=function(){function r(e){this._definition=e}return Object.defineProperty(r.prototype,"definition",{get:function(){return this._definition},set:function(e){this._definition=e},enumerable:!1,configurable:!0}),r.prototype.accept=function(e){e.visit(this),(0,Ar.forEach)(this.definition,function(t){t.accept(e)})},r}();zt.AbstractProduction=ko;var Qj=function(r){xa(e,r);function e(t){var i=r.call(this,[])||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return Object.defineProperty(e.prototype,"definition",{get:function(){return this.referencedRule!==void 0?this.referencedRule.definition:[]},set:function(t){},enumerable:!1,configurable:!0}),e.prototype.accept=function(t){t.visit(this)},e}(ko);zt.NonTerminal=Qj;var bj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.orgText="",(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.Rule=bj;var Sj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.ignoreAmbiguities=!1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.Alternative=Sj;var vj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.Option=vj;var xj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.RepetitionMandatory=xj;var Pj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.RepetitionMandatoryWithSeparator=Pj;var Dj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.Repetition=Dj;var kj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(ko);zt.RepetitionWithSeparator=kj;var Rj=function(r){xa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,i.ignoreAmbiguities=!1,i.hasPredicates=!1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return Object.defineProperty(e.prototype,"definition",{get:function(){return this._definition},set:function(t){this._definition=t},enumerable:!1,configurable:!0}),e}(ko);zt.Alternation=Rj;var oy=function(){function r(e){this.idx=1,(0,Ar.assign)(this,(0,Ar.pick)(e,function(t){return t!==void 0}))}return r.prototype.accept=function(e){e.visit(this)},r}();zt.Terminal=oy;function tIe(r){return(0,Ar.map)(r,bd)}zt.serializeGrammar=tIe;function bd(r){function e(s){return(0,Ar.map)(s,bd)}if(r instanceof Qj){var t={type:"NonTerminal",name:r.nonTerminalName,idx:r.idx};return(0,Ar.isString)(r.label)&&(t.label=r.label),t}else{if(r instanceof Sj)return{type:"Alternative",definition:e(r.definition)};if(r instanceof vj)return{type:"Option",idx:r.idx,definition:e(r.definition)};if(r instanceof xj)return{type:"RepetitionMandatory",idx:r.idx,definition:e(r.definition)};if(r instanceof Pj)return{type:"RepetitionMandatoryWithSeparator",idx:r.idx,separator:bd(new oy({terminalType:r.separator})),definition:e(r.definition)};if(r instanceof kj)return{type:"RepetitionWithSeparator",idx:r.idx,separator:bd(new oy({terminalType:r.separator})),definition:e(r.definition)};if(r instanceof Dj)return{type:"Repetition",idx:r.idx,definition:e(r.definition)};if(r instanceof Rj)return{type:"Alternation",idx:r.idx,definition:e(r.definition)};if(r instanceof oy){var i={type:"Terminal",name:r.terminalType.name,label:(0,eIe.tokenLabel)(r.terminalType),idx:r.idx};(0,Ar.isString)(r.label)&&(i.terminalLabel=r.label);var n=r.terminalType.PATTERN;return r.terminalType.PATTERN&&(i.pattern=(0,Ar.isRegExp)(n)?n.source:n),i}else{if(r instanceof bj)return{type:"Rule",name:r.name,orgText:r.orgText,definition:e(r.definition)};throw Error("non exhaustive match")}}}zt.serializeProduction=bd});var Ay=w(ay=>{"use strict";Object.defineProperty(ay,"__esModule",{value:!0});ay.RestWalker=void 0;var Gv=Gt(),mn=Cn(),rIe=function(){function r(){}return r.prototype.walk=function(e,t){var i=this;t===void 0&&(t=[]),(0,Gv.forEach)(e.definition,function(n,s){var o=(0,Gv.drop)(e.definition,s+1);if(n instanceof mn.NonTerminal)i.walkProdRef(n,o,t);else if(n instanceof mn.Terminal)i.walkTerminal(n,o,t);else if(n instanceof mn.Alternative)i.walkFlat(n,o,t);else if(n instanceof mn.Option)i.walkOption(n,o,t);else if(n instanceof mn.RepetitionMandatory)i.walkAtLeastOne(n,o,t);else if(n instanceof mn.RepetitionMandatoryWithSeparator)i.walkAtLeastOneSep(n,o,t);else if(n instanceof mn.RepetitionWithSeparator)i.walkManySep(n,o,t);else if(n instanceof mn.Repetition)i.walkMany(n,o,t);else if(n instanceof mn.Alternation)i.walkOr(n,o,t);else throw Error("non exhaustive match")})},r.prototype.walkTerminal=function(e,t,i){},r.prototype.walkProdRef=function(e,t,i){},r.prototype.walkFlat=function(e,t,i){var n=t.concat(i);this.walk(e,n)},r.prototype.walkOption=function(e,t,i){var n=t.concat(i);this.walk(e,n)},r.prototype.walkAtLeastOne=function(e,t,i){var n=[new mn.Option({definition:e.definition})].concat(t,i);this.walk(e,n)},r.prototype.walkAtLeastOneSep=function(e,t,i){var n=Fj(e,t,i);this.walk(e,n)},r.prototype.walkMany=function(e,t,i){var n=[new mn.Option({definition:e.definition})].concat(t,i);this.walk(e,n)},r.prototype.walkManySep=function(e,t,i){var n=Fj(e,t,i);this.walk(e,n)},r.prototype.walkOr=function(e,t,i){var n=this,s=t.concat(i);(0,Gv.forEach)(e.definition,function(o){var a=new mn.Alternative({definition:[o]});n.walk(a,s)})},r}();ay.RestWalker=rIe;function Fj(r,e,t){var i=[new mn.Option({definition:[new mn.Terminal({terminalType:r.separator})].concat(r.definition)})],n=i.concat(e,t);return n}});var $g=w(ly=>{"use strict";Object.defineProperty(ly,"__esModule",{value:!0});ly.GAstVisitor=void 0;var Ro=Cn(),iIe=function(){function r(){}return r.prototype.visit=function(e){var t=e;switch(t.constructor){case Ro.NonTerminal:return this.visitNonTerminal(t);case Ro.Alternative:return this.visitAlternative(t);case Ro.Option:return this.visitOption(t);case Ro.RepetitionMandatory:return this.visitRepetitionMandatory(t);case Ro.RepetitionMandatoryWithSeparator:return this.visitRepetitionMandatoryWithSeparator(t);case Ro.RepetitionWithSeparator:return this.visitRepetitionWithSeparator(t);case Ro.Repetition:return this.visitRepetition(t);case Ro.Alternation:return this.visitAlternation(t);case Ro.Terminal:return this.visitTerminal(t);case Ro.Rule:return this.visitRule(t);default:throw Error("non exhaustive match")}},r.prototype.visitNonTerminal=function(e){},r.prototype.visitAlternative=function(e){},r.prototype.visitOption=function(e){},r.prototype.visitRepetition=function(e){},r.prototype.visitRepetitionMandatory=function(e){},r.prototype.visitRepetitionMandatoryWithSeparator=function(e){},r.prototype.visitRepetitionWithSeparator=function(e){},r.prototype.visitAlternation=function(e){},r.prototype.visitTerminal=function(e){},r.prototype.visitRule=function(e){},r}();ly.GAstVisitor=iIe});var vd=w(Mi=>{"use strict";var nIe=Mi&&Mi.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Mi,"__esModule",{value:!0});Mi.collectMethods=Mi.DslMethodsCollectorVisitor=Mi.getProductionDslName=Mi.isBranchingProd=Mi.isOptionalProd=Mi.isSequenceProd=void 0;var Sd=Gt(),Qr=Cn(),sIe=$g();function oIe(r){return r instanceof Qr.Alternative||r instanceof Qr.Option||r instanceof Qr.Repetition||r instanceof Qr.RepetitionMandatory||r instanceof Qr.RepetitionMandatoryWithSeparator||r instanceof Qr.RepetitionWithSeparator||r instanceof Qr.Terminal||r instanceof Qr.Rule}Mi.isSequenceProd=oIe;function Yv(r,e){e===void 0&&(e=[]);var t=r instanceof Qr.Option||r instanceof Qr.Repetition||r instanceof Qr.RepetitionWithSeparator;return t?!0:r instanceof Qr.Alternation?(0,Sd.some)(r.definition,function(i){return Yv(i,e)}):r instanceof Qr.NonTerminal&&(0,Sd.contains)(e,r)?!1:r instanceof Qr.AbstractProduction?(r instanceof Qr.NonTerminal&&e.push(r),(0,Sd.every)(r.definition,function(i){return Yv(i,e)})):!1}Mi.isOptionalProd=Yv;function aIe(r){return r instanceof Qr.Alternation}Mi.isBranchingProd=aIe;function AIe(r){if(r instanceof Qr.NonTerminal)return"SUBRULE";if(r instanceof Qr.Option)return"OPTION";if(r instanceof Qr.Alternation)return"OR";if(r instanceof Qr.RepetitionMandatory)return"AT_LEAST_ONE";if(r instanceof Qr.RepetitionMandatoryWithSeparator)return"AT_LEAST_ONE_SEP";if(r instanceof Qr.RepetitionWithSeparator)return"MANY_SEP";if(r instanceof Qr.Repetition)return"MANY";if(r instanceof Qr.Terminal)return"CONSUME";throw Error("non exhaustive match")}Mi.getProductionDslName=AIe;var Nj=function(r){nIe(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.separator="-",t.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]},t}return e.prototype.reset=function(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}},e.prototype.visitTerminal=function(t){var i=t.terminalType.name+this.separator+"Terminal";(0,Sd.has)(this.dslMethods,i)||(this.dslMethods[i]=[]),this.dslMethods[i].push(t)},e.prototype.visitNonTerminal=function(t){var i=t.nonTerminalName+this.separator+"Terminal";(0,Sd.has)(this.dslMethods,i)||(this.dslMethods[i]=[]),this.dslMethods[i].push(t)},e.prototype.visitOption=function(t){this.dslMethods.option.push(t)},e.prototype.visitRepetitionWithSeparator=function(t){this.dslMethods.repetitionWithSeparator.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.dslMethods.repetitionMandatory.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.dslMethods.repetitionMandatoryWithSeparator.push(t)},e.prototype.visitRepetition=function(t){this.dslMethods.repetition.push(t)},e.prototype.visitAlternation=function(t){this.dslMethods.alternation.push(t)},e}(sIe.GAstVisitor);Mi.DslMethodsCollectorVisitor=Nj;var cy=new Nj;function lIe(r){cy.reset(),r.accept(cy);var e=cy.dslMethods;return cy.reset(),e}Mi.collectMethods=lIe});var qv=w(Fo=>{"use strict";Object.defineProperty(Fo,"__esModule",{value:!0});Fo.firstForTerminal=Fo.firstForBranching=Fo.firstForSequence=Fo.first=void 0;var uy=Gt(),Lj=Cn(),jv=vd();function gy(r){if(r instanceof Lj.NonTerminal)return gy(r.referencedRule);if(r instanceof Lj.Terminal)return Mj(r);if((0,jv.isSequenceProd)(r))return Tj(r);if((0,jv.isBranchingProd)(r))return Oj(r);throw Error("non exhaustive match")}Fo.first=gy;function Tj(r){for(var e=[],t=r.definition,i=0,n=t.length>i,s,o=!0;n&&o;)s=t[i],o=(0,jv.isOptionalProd)(s),e=e.concat(gy(s)),i=i+1,n=t.length>i;return(0,uy.uniq)(e)}Fo.firstForSequence=Tj;function Oj(r){var e=(0,uy.map)(r.definition,function(t){return gy(t)});return(0,uy.uniq)((0,uy.flatten)(e))}Fo.firstForBranching=Oj;function Mj(r){return[r.terminalType]}Fo.firstForTerminal=Mj});var Jv=w(fy=>{"use strict";Object.defineProperty(fy,"__esModule",{value:!0});fy.IN=void 0;fy.IN="_~IN~_"});var Yj=w(fs=>{"use strict";var cIe=fs&&fs.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(fs,"__esModule",{value:!0});fs.buildInProdFollowPrefix=fs.buildBetweenProdsFollowPrefix=fs.computeAllProdsFollows=fs.ResyncFollowsWalker=void 0;var uIe=Ay(),gIe=qv(),Uj=Gt(),Kj=Jv(),fIe=Cn(),Hj=function(r){cIe(e,r);function e(t){var i=r.call(this)||this;return i.topProd=t,i.follows={},i}return e.prototype.startWalking=function(){return this.walk(this.topProd),this.follows},e.prototype.walkTerminal=function(t,i,n){},e.prototype.walkProdRef=function(t,i,n){var s=Gj(t.referencedRule,t.idx)+this.topProd.name,o=i.concat(n),a=new fIe.Alternative({definition:o}),l=(0,gIe.first)(a);this.follows[s]=l},e}(uIe.RestWalker);fs.ResyncFollowsWalker=Hj;function hIe(r){var e={};return(0,Uj.forEach)(r,function(t){var i=new Hj(t).startWalking();(0,Uj.assign)(e,i)}),e}fs.computeAllProdsFollows=hIe;function Gj(r,e){return r.name+e+Kj.IN}fs.buildBetweenProdsFollowPrefix=Gj;function pIe(r){var e=r.terminalType.name;return e+r.idx+Kj.IN}fs.buildInProdFollowPrefix=pIe});var xd=w(Pa=>{"use strict";Object.defineProperty(Pa,"__esModule",{value:!0});Pa.defaultGrammarValidatorErrorProvider=Pa.defaultGrammarResolverErrorProvider=Pa.defaultParserErrorProvider=void 0;var ef=LA(),dIe=Gt(),eo=Gt(),Wv=Cn(),jj=vd();Pa.defaultParserErrorProvider={buildMismatchTokenMessage:function(r){var e=r.expected,t=r.actual,i=r.previous,n=r.ruleName,s=(0,ef.hasTokenLabel)(e),o=s?"--> "+(0,ef.tokenLabel)(e)+" <--":"token of type --> "+e.name+" <--",a="Expecting "+o+" but found --> '"+t.image+"' <--";return a},buildNotAllInputParsedMessage:function(r){var e=r.firstRedundant,t=r.ruleName;return"Redundant input, expecting EOF but found: "+e.image},buildNoViableAltMessage:function(r){var e=r.expectedPathsPerAlt,t=r.actual,i=r.previous,n=r.customUserDescription,s=r.ruleName,o="Expecting: ",a=(0,eo.first)(t).image,l=` +but found: '`+a+"'";if(n)return o+n+l;var c=(0,eo.reduce)(e,function(h,p){return h.concat(p)},[]),u=(0,eo.map)(c,function(h){return"["+(0,eo.map)(h,function(p){return(0,ef.tokenLabel)(p)}).join(", ")+"]"}),g=(0,eo.map)(u,function(h,p){return" "+(p+1)+". "+h}),f=`one of these possible Token sequences: +`+g.join(` +`);return o+f+l},buildEarlyExitMessage:function(r){var e=r.expectedIterationPaths,t=r.actual,i=r.customUserDescription,n=r.ruleName,s="Expecting: ",o=(0,eo.first)(t).image,a=` +but found: '`+o+"'";if(i)return s+i+a;var l=(0,eo.map)(e,function(u){return"["+(0,eo.map)(u,function(g){return(0,ef.tokenLabel)(g)}).join(",")+"]"}),c=`expecting at least one iteration which starts with one of these possible Token sequences:: + `+("<"+l.join(" ,")+">");return s+c+a}};Object.freeze(Pa.defaultParserErrorProvider);Pa.defaultGrammarResolverErrorProvider={buildRuleNotFoundError:function(r,e){var t="Invalid grammar, reference to a rule which is not defined: ->"+e.nonTerminalName+`<- +inside top level rule: ->`+r.name+"<-";return t}};Pa.defaultGrammarValidatorErrorProvider={buildDuplicateFoundError:function(r,e){function t(u){return u instanceof Wv.Terminal?u.terminalType.name:u instanceof Wv.NonTerminal?u.nonTerminalName:""}var i=r.name,n=(0,eo.first)(e),s=n.idx,o=(0,jj.getProductionDslName)(n),a=t(n),l=s>0,c="->"+o+(l?s:"")+"<- "+(a?"with argument: ->"+a+"<-":"")+` + appears more than once (`+e.length+" times) in the top level rule: ->"+i+`<-. + For further details see: https://chevrotain.io/docs/FAQ.html#NUMERICAL_SUFFIXES + `;return c=c.replace(/[ \t]+/g," "),c=c.replace(/\s\s+/g,` +`),c},buildNamespaceConflictError:function(r){var e=`Namespace conflict found in grammar. +`+("The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <"+r.name+`>. +`)+`To resolve this make sure each Terminal and Non-Terminal names are unique +This is easy to accomplish by using the convention that Terminal names start with an uppercase letter +and Non-Terminal names start with a lower case letter.`;return e},buildAlternationPrefixAmbiguityError:function(r){var e=(0,eo.map)(r.prefixPath,function(n){return(0,ef.tokenLabel)(n)}).join(", "),t=r.alternation.idx===0?"":r.alternation.idx,i="Ambiguous alternatives: <"+r.ambiguityIndices.join(" ,")+`> due to common lookahead prefix +`+("in inside <"+r.topLevelRule.name+`> Rule, +`)+("<"+e+`> may appears as a prefix path in all these alternatives. +`)+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#COMMON_PREFIX +For Further details.`;return i},buildAlternationAmbiguityError:function(r){var e=(0,eo.map)(r.prefixPath,function(n){return(0,ef.tokenLabel)(n)}).join(", "),t=r.alternation.idx===0?"":r.alternation.idx,i="Ambiguous Alternatives Detected: <"+r.ambiguityIndices.join(" ,")+"> in "+(" inside <"+r.topLevelRule.name+`> Rule, +`)+("<"+e+`> may appears as a prefix path in all these alternatives. +`);return i=i+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES +For Further details.`,i},buildEmptyRepetitionError:function(r){var e=(0,jj.getProductionDslName)(r.repetition);r.repetition.idx!==0&&(e+=r.repetition.idx);var t="The repetition <"+e+"> within Rule <"+r.topLevelRule.name+`> can never consume any tokens. +This could lead to an infinite loop.`;return t},buildTokenNameError:function(r){return"deprecated"},buildEmptyAlternationError:function(r){var e="Ambiguous empty alternative: <"+(r.emptyChoiceIdx+1)+">"+(" in inside <"+r.topLevelRule.name+`> Rule. +`)+"Only the last alternative may be an empty alternative.";return e},buildTooManyAlternativesError:function(r){var e=`An Alternation cannot have more than 256 alternatives: +`+(" inside <"+r.topLevelRule.name+`> Rule. + has `+(r.alternation.definition.length+1)+" alternatives.");return e},buildLeftRecursionError:function(r){var e=r.topLevelRule.name,t=dIe.map(r.leftRecursionPath,function(s){return s.name}),i=e+" --> "+t.concat([e]).join(" --> "),n=`Left Recursion found in grammar. +`+("rule: <"+e+`> can be invoked from itself (directly or indirectly) +`)+(`without consuming any Tokens. The grammar path that causes this is: + `+i+` +`)+` To fix this refactor your grammar to remove the left recursion. +see: https://en.wikipedia.org/wiki/LL_parser#Left_Factoring.`;return n},buildInvalidRuleNameError:function(r){return"deprecated"},buildDuplicateRuleNameError:function(r){var e;r.topLevelRule instanceof Wv.Rule?e=r.topLevelRule.name:e=r.topLevelRule;var t="Duplicate definition, rule: ->"+e+"<- is already defined in the grammar: ->"+r.grammarName+"<-";return t}}});var Wj=w(TA=>{"use strict";var CIe=TA&&TA.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(TA,"__esModule",{value:!0});TA.GastRefResolverVisitor=TA.resolveGrammar=void 0;var mIe=Yn(),qj=Gt(),EIe=$g();function IIe(r,e){var t=new Jj(r,e);return t.resolveRefs(),t.errors}TA.resolveGrammar=IIe;var Jj=function(r){CIe(e,r);function e(t,i){var n=r.call(this)||this;return n.nameToTopRule=t,n.errMsgProvider=i,n.errors=[],n}return e.prototype.resolveRefs=function(){var t=this;(0,qj.forEach)((0,qj.values)(this.nameToTopRule),function(i){t.currTopLevel=i,i.accept(t)})},e.prototype.visitNonTerminal=function(t){var i=this.nameToTopRule[t.nonTerminalName];if(i)t.referencedRule=i;else{var n=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,t);this.errors.push({message:n,type:mIe.ParserDefinitionErrorType.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:t.nonTerminalName})}},e}(EIe.GAstVisitor);TA.GastRefResolverVisitor=Jj});var Dd=w(Nr=>{"use strict";var mc=Nr&&Nr.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Nr,"__esModule",{value:!0});Nr.nextPossibleTokensAfter=Nr.possiblePathsFrom=Nr.NextTerminalAfterAtLeastOneSepWalker=Nr.NextTerminalAfterAtLeastOneWalker=Nr.NextTerminalAfterManySepWalker=Nr.NextTerminalAfterManyWalker=Nr.AbstractNextTerminalAfterProductionWalker=Nr.NextAfterTokenWalker=Nr.AbstractNextPossibleTokensWalker=void 0;var zj=Ay(),Ut=Gt(),yIe=qv(),kt=Cn(),Vj=function(r){mc(e,r);function e(t,i){var n=r.call(this)||this;return n.topProd=t,n.path=i,n.possibleTokTypes=[],n.nextProductionName="",n.nextProductionOccurrence=0,n.found=!1,n.isAtEndOfPath=!1,n}return e.prototype.startWalking=function(){if(this.found=!1,this.path.ruleStack[0]!==this.topProd.name)throw Error("The path does not start with the walker's top Rule!");return this.ruleStack=(0,Ut.cloneArr)(this.path.ruleStack).reverse(),this.occurrenceStack=(0,Ut.cloneArr)(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes},e.prototype.walk=function(t,i){i===void 0&&(i=[]),this.found||r.prototype.walk.call(this,t,i)},e.prototype.walkProdRef=function(t,i,n){if(t.referencedRule.name===this.nextProductionName&&t.idx===this.nextProductionOccurrence){var s=i.concat(n);this.updateExpectedNext(),this.walk(t.referencedRule,s)}},e.prototype.updateExpectedNext=function(){(0,Ut.isEmpty)(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())},e}(zj.RestWalker);Nr.AbstractNextPossibleTokensWalker=Vj;var wIe=function(r){mc(e,r);function e(t,i){var n=r.call(this,t,i)||this;return n.path=i,n.nextTerminalName="",n.nextTerminalOccurrence=0,n.nextTerminalName=n.path.lastTok.name,n.nextTerminalOccurrence=n.path.lastTokOccurrence,n}return e.prototype.walkTerminal=function(t,i,n){if(this.isAtEndOfPath&&t.terminalType.name===this.nextTerminalName&&t.idx===this.nextTerminalOccurrence&&!this.found){var s=i.concat(n),o=new kt.Alternative({definition:s});this.possibleTokTypes=(0,yIe.first)(o),this.found=!0}},e}(Vj);Nr.NextAfterTokenWalker=wIe;var Pd=function(r){mc(e,r);function e(t,i){var n=r.call(this)||this;return n.topRule=t,n.occurrence=i,n.result={token:void 0,occurrence:void 0,isEndOfRule:void 0},n}return e.prototype.startWalking=function(){return this.walk(this.topRule),this.result},e}(zj.RestWalker);Nr.AbstractNextTerminalAfterProductionWalker=Pd;var BIe=function(r){mc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkMany=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Ut.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkMany.call(this,t,i,n)},e}(Pd);Nr.NextTerminalAfterManyWalker=BIe;var QIe=function(r){mc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkManySep=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Ut.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkManySep.call(this,t,i,n)},e}(Pd);Nr.NextTerminalAfterManySepWalker=QIe;var bIe=function(r){mc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkAtLeastOne=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Ut.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkAtLeastOne.call(this,t,i,n)},e}(Pd);Nr.NextTerminalAfterAtLeastOneWalker=bIe;var SIe=function(r){mc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkAtLeastOneSep=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Ut.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkAtLeastOneSep.call(this,t,i,n)},e}(Pd);Nr.NextTerminalAfterAtLeastOneSepWalker=SIe;function Xj(r,e,t){t===void 0&&(t=[]),t=(0,Ut.cloneArr)(t);var i=[],n=0;function s(c){return c.concat((0,Ut.drop)(r,n+1))}function o(c){var u=Xj(s(c),e,t);return i.concat(u)}for(;t.length=0;ge--){var re=B.definition[ge],O={idx:p,def:re.definition.concat((0,Ut.drop)(h)),ruleStack:C,occurrenceStack:y};g.push(O),g.push(o)}else if(B instanceof kt.Alternative)g.push({idx:p,def:B.definition.concat((0,Ut.drop)(h)),ruleStack:C,occurrenceStack:y});else if(B instanceof kt.Rule)g.push(xIe(B,p,C,y));else throw Error("non exhaustive match")}}return u}Nr.nextPossibleTokensAfter=vIe;function xIe(r,e,t,i){var n=(0,Ut.cloneArr)(t);n.push(r.name);var s=(0,Ut.cloneArr)(i);return s.push(1),{idx:e,def:r.definition,ruleStack:n,occurrenceStack:s}}});var kd=w(Zt=>{"use strict";var $j=Zt&&Zt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Zt,"__esModule",{value:!0});Zt.areTokenCategoriesNotUsed=Zt.isStrictPrefixOfPath=Zt.containsPath=Zt.getLookaheadPathsForOptionalProd=Zt.getLookaheadPathsForOr=Zt.lookAheadSequenceFromAlternatives=Zt.buildSingleAlternativeLookaheadFunction=Zt.buildAlternativesLookAheadFunc=Zt.buildLookaheadFuncForOptionalProd=Zt.buildLookaheadFuncForOr=Zt.getProdType=Zt.PROD_TYPE=void 0;var sr=Gt(),Zj=Dd(),PIe=Ay(),hy=_g(),OA=Cn(),DIe=$g(),oi;(function(r){r[r.OPTION=0]="OPTION",r[r.REPETITION=1]="REPETITION",r[r.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",r[r.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",r[r.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",r[r.ALTERNATION=5]="ALTERNATION"})(oi=Zt.PROD_TYPE||(Zt.PROD_TYPE={}));function kIe(r){if(r instanceof OA.Option)return oi.OPTION;if(r instanceof OA.Repetition)return oi.REPETITION;if(r instanceof OA.RepetitionMandatory)return oi.REPETITION_MANDATORY;if(r instanceof OA.RepetitionMandatoryWithSeparator)return oi.REPETITION_MANDATORY_WITH_SEPARATOR;if(r instanceof OA.RepetitionWithSeparator)return oi.REPETITION_WITH_SEPARATOR;if(r instanceof OA.Alternation)return oi.ALTERNATION;throw Error("non exhaustive match")}Zt.getProdType=kIe;function RIe(r,e,t,i,n,s){var o=tq(r,e,t),a=Xv(o)?hy.tokenStructuredMatcherNoCategories:hy.tokenStructuredMatcher;return s(o,i,a,n)}Zt.buildLookaheadFuncForOr=RIe;function FIe(r,e,t,i,n,s){var o=rq(r,e,n,t),a=Xv(o)?hy.tokenStructuredMatcherNoCategories:hy.tokenStructuredMatcher;return s(o[0],a,i)}Zt.buildLookaheadFuncForOptionalProd=FIe;function NIe(r,e,t,i){var n=r.length,s=(0,sr.every)(r,function(l){return(0,sr.every)(l,function(c){return c.length===1})});if(e)return function(l){for(var c=(0,sr.map)(l,function(D){return D.GATE}),u=0;u{"use strict";var Zv=Vt&&Vt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Vt,"__esModule",{value:!0});Vt.checkPrefixAlternativesAmbiguities=Vt.validateSomeNonEmptyLookaheadPath=Vt.validateTooManyAlts=Vt.RepetionCollector=Vt.validateAmbiguousAlternationAlternatives=Vt.validateEmptyOrAlternative=Vt.getFirstNoneTerminal=Vt.validateNoLeftRecursion=Vt.validateRuleIsOverridden=Vt.validateRuleDoesNotAlreadyExist=Vt.OccurrenceValidationCollector=Vt.identifyProductionForDuplicates=Vt.validateGrammar=void 0;var er=Gt(),br=Gt(),No=Yn(),_v=vd(),tf=kd(),UIe=Dd(),to=Cn(),$v=$g();function KIe(r,e,t,i,n){var s=er.map(r,function(h){return HIe(h,i)}),o=er.map(r,function(h){return ex(h,h,i)}),a=[],l=[],c=[];(0,br.every)(o,br.isEmpty)&&(a=(0,br.map)(r,function(h){return Aq(h,i)}),l=(0,br.map)(r,function(h){return lq(h,e,i)}),c=gq(r,e,i));var u=jIe(r,t,i),g=(0,br.map)(r,function(h){return uq(h,i)}),f=(0,br.map)(r,function(h){return aq(h,r,n,i)});return er.flatten(s.concat(c,o,a,l,u,g,f))}Vt.validateGrammar=KIe;function HIe(r,e){var t=new oq;r.accept(t);var i=t.allProductions,n=er.groupBy(i,nq),s=er.pick(n,function(a){return a.length>1}),o=er.map(er.values(s),function(a){var l=er.first(a),c=e.buildDuplicateFoundError(r,a),u=(0,_v.getProductionDslName)(l),g={message:c,type:No.ParserDefinitionErrorType.DUPLICATE_PRODUCTIONS,ruleName:r.name,dslName:u,occurrence:l.idx},f=sq(l);return f&&(g.parameter=f),g});return o}function nq(r){return(0,_v.getProductionDslName)(r)+"_#_"+r.idx+"_#_"+sq(r)}Vt.identifyProductionForDuplicates=nq;function sq(r){return r instanceof to.Terminal?r.terminalType.name:r instanceof to.NonTerminal?r.nonTerminalName:""}var oq=function(r){Zv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.allProductions=[],t}return e.prototype.visitNonTerminal=function(t){this.allProductions.push(t)},e.prototype.visitOption=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetition=function(t){this.allProductions.push(t)},e.prototype.visitAlternation=function(t){this.allProductions.push(t)},e.prototype.visitTerminal=function(t){this.allProductions.push(t)},e}($v.GAstVisitor);Vt.OccurrenceValidationCollector=oq;function aq(r,e,t,i){var n=[],s=(0,br.reduce)(e,function(a,l){return l.name===r.name?a+1:a},0);if(s>1){var o=i.buildDuplicateRuleNameError({topLevelRule:r,grammarName:t});n.push({message:o,type:No.ParserDefinitionErrorType.DUPLICATE_RULE_NAME,ruleName:r.name})}return n}Vt.validateRuleDoesNotAlreadyExist=aq;function GIe(r,e,t){var i=[],n;return er.contains(e,r)||(n="Invalid rule override, rule: ->"+r+"<- cannot be overridden in the grammar: ->"+t+"<-as it is not defined in any of the super grammars ",i.push({message:n,type:No.ParserDefinitionErrorType.INVALID_RULE_OVERRIDE,ruleName:r})),i}Vt.validateRuleIsOverridden=GIe;function ex(r,e,t,i){i===void 0&&(i=[]);var n=[],s=Rd(e.definition);if(er.isEmpty(s))return[];var o=r.name,a=er.contains(s,r);a&&n.push({message:t.buildLeftRecursionError({topLevelRule:r,leftRecursionPath:i}),type:No.ParserDefinitionErrorType.LEFT_RECURSION,ruleName:o});var l=er.difference(s,i.concat([r])),c=er.map(l,function(u){var g=er.cloneArr(i);return g.push(u),ex(r,u,t,g)});return n.concat(er.flatten(c))}Vt.validateNoLeftRecursion=ex;function Rd(r){var e=[];if(er.isEmpty(r))return e;var t=er.first(r);if(t instanceof to.NonTerminal)e.push(t.referencedRule);else if(t instanceof to.Alternative||t instanceof to.Option||t instanceof to.RepetitionMandatory||t instanceof to.RepetitionMandatoryWithSeparator||t instanceof to.RepetitionWithSeparator||t instanceof to.Repetition)e=e.concat(Rd(t.definition));else if(t instanceof to.Alternation)e=er.flatten(er.map(t.definition,function(o){return Rd(o.definition)}));else if(!(t instanceof to.Terminal))throw Error("non exhaustive match");var i=(0,_v.isOptionalProd)(t),n=r.length>1;if(i&&n){var s=er.drop(r);return e.concat(Rd(s))}else return e}Vt.getFirstNoneTerminal=Rd;var tx=function(r){Zv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.alternations=[],t}return e.prototype.visitAlternation=function(t){this.alternations.push(t)},e}($v.GAstVisitor);function Aq(r,e){var t=new tx;r.accept(t);var i=t.alternations,n=er.reduce(i,function(s,o){var a=er.dropRight(o.definition),l=er.map(a,function(c,u){var g=(0,UIe.nextPossibleTokensAfter)([c],[],null,1);return er.isEmpty(g)?{message:e.buildEmptyAlternationError({topLevelRule:r,alternation:o,emptyChoiceIdx:u}),type:No.ParserDefinitionErrorType.NONE_LAST_EMPTY_ALT,ruleName:r.name,occurrence:o.idx,alternative:u+1}:null});return s.concat(er.compact(l))},[]);return n}Vt.validateEmptyOrAlternative=Aq;function lq(r,e,t){var i=new tx;r.accept(i);var n=i.alternations;n=(0,br.reject)(n,function(o){return o.ignoreAmbiguities===!0});var s=er.reduce(n,function(o,a){var l=a.idx,c=a.maxLookahead||e,u=(0,tf.getLookaheadPathsForOr)(l,r,c,a),g=YIe(u,a,r,t),f=fq(u,a,r,t);return o.concat(g,f)},[]);return s}Vt.validateAmbiguousAlternationAlternatives=lq;var cq=function(r){Zv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.allProductions=[],t}return e.prototype.visitRepetitionWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetition=function(t){this.allProductions.push(t)},e}($v.GAstVisitor);Vt.RepetionCollector=cq;function uq(r,e){var t=new tx;r.accept(t);var i=t.alternations,n=er.reduce(i,function(s,o){return o.definition.length>255&&s.push({message:e.buildTooManyAlternativesError({topLevelRule:r,alternation:o}),type:No.ParserDefinitionErrorType.TOO_MANY_ALTS,ruleName:r.name,occurrence:o.idx}),s},[]);return n}Vt.validateTooManyAlts=uq;function gq(r,e,t){var i=[];return(0,br.forEach)(r,function(n){var s=new cq;n.accept(s);var o=s.allProductions;(0,br.forEach)(o,function(a){var l=(0,tf.getProdType)(a),c=a.maxLookahead||e,u=a.idx,g=(0,tf.getLookaheadPathsForOptionalProd)(u,n,l,c),f=g[0];if((0,br.isEmpty)((0,br.flatten)(f))){var h=t.buildEmptyRepetitionError({topLevelRule:n,repetition:a});i.push({message:h,type:No.ParserDefinitionErrorType.NO_NON_EMPTY_LOOKAHEAD,ruleName:n.name})}})}),i}Vt.validateSomeNonEmptyLookaheadPath=gq;function YIe(r,e,t,i){var n=[],s=(0,br.reduce)(r,function(a,l,c){return e.definition[c].ignoreAmbiguities===!0||(0,br.forEach)(l,function(u){var g=[c];(0,br.forEach)(r,function(f,h){c!==h&&(0,tf.containsPath)(f,u)&&e.definition[h].ignoreAmbiguities!==!0&&g.push(h)}),g.length>1&&!(0,tf.containsPath)(n,u)&&(n.push(u),a.push({alts:g,path:u}))}),a},[]),o=er.map(s,function(a){var l=(0,br.map)(a.alts,function(u){return u+1}),c=i.buildAlternationAmbiguityError({topLevelRule:t,alternation:e,ambiguityIndices:l,prefixPath:a.path});return{message:c,type:No.ParserDefinitionErrorType.AMBIGUOUS_ALTS,ruleName:t.name,occurrence:e.idx,alternatives:[a.alts]}});return o}function fq(r,e,t,i){var n=[],s=(0,br.reduce)(r,function(o,a,l){var c=(0,br.map)(a,function(u){return{idx:l,path:u}});return o.concat(c)},[]);return(0,br.forEach)(s,function(o){var a=e.definition[o.idx];if(a.ignoreAmbiguities!==!0){var l=o.idx,c=o.path,u=(0,br.findAll)(s,function(f){return e.definition[f.idx].ignoreAmbiguities!==!0&&f.idx{"use strict";Object.defineProperty(rf,"__esModule",{value:!0});rf.validateGrammar=rf.resolveGrammar=void 0;var ix=Gt(),qIe=Wj(),JIe=rx(),hq=xd();function WIe(r){r=(0,ix.defaults)(r,{errMsgProvider:hq.defaultGrammarResolverErrorProvider});var e={};return(0,ix.forEach)(r.rules,function(t){e[t.name]=t}),(0,qIe.resolveGrammar)(e,r.errMsgProvider)}rf.resolveGrammar=WIe;function zIe(r){return r=(0,ix.defaults)(r,{errMsgProvider:hq.defaultGrammarValidatorErrorProvider}),(0,JIe.validateGrammar)(r.rules,r.maxLookahead,r.tokenTypes,r.errMsgProvider,r.grammarName)}rf.validateGrammar=zIe});var nf=w(En=>{"use strict";var Fd=En&&En.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(En,"__esModule",{value:!0});En.EarlyExitException=En.NotAllInputParsedException=En.NoViableAltException=En.MismatchedTokenException=En.isRecognitionException=void 0;var VIe=Gt(),dq="MismatchedTokenException",Cq="NoViableAltException",mq="EarlyExitException",Eq="NotAllInputParsedException",Iq=[dq,Cq,mq,Eq];Object.freeze(Iq);function XIe(r){return(0,VIe.contains)(Iq,r.name)}En.isRecognitionException=XIe;var py=function(r){Fd(e,r);function e(t,i){var n=this.constructor,s=r.call(this,t)||this;return s.token=i,s.resyncedTokens=[],Object.setPrototypeOf(s,n.prototype),Error.captureStackTrace&&Error.captureStackTrace(s,s.constructor),s}return e}(Error),ZIe=function(r){Fd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=dq,s}return e}(py);En.MismatchedTokenException=ZIe;var _Ie=function(r){Fd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Cq,s}return e}(py);En.NoViableAltException=_Ie;var $Ie=function(r){Fd(e,r);function e(t,i){var n=r.call(this,t,i)||this;return n.name=Eq,n}return e}(py);En.NotAllInputParsedException=$Ie;var eye=function(r){Fd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=mq,s}return e}(py);En.EarlyExitException=eye});var sx=w(Ui=>{"use strict";Object.defineProperty(Ui,"__esModule",{value:!0});Ui.attemptInRepetitionRecovery=Ui.Recoverable=Ui.InRuleRecoveryException=Ui.IN_RULE_RECOVERY_EXCEPTION=Ui.EOF_FOLLOW_KEY=void 0;var dy=LA(),hs=Gt(),tye=nf(),rye=Jv(),iye=Yn();Ui.EOF_FOLLOW_KEY={};Ui.IN_RULE_RECOVERY_EXCEPTION="InRuleRecoveryException";function nx(r){this.name=Ui.IN_RULE_RECOVERY_EXCEPTION,this.message=r}Ui.InRuleRecoveryException=nx;nx.prototype=Error.prototype;var nye=function(){function r(){}return r.prototype.initRecoverable=function(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=(0,hs.has)(e,"recoveryEnabled")?e.recoveryEnabled:iye.DEFAULT_PARSER_CONFIG.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=yq)},r.prototype.getTokenToInsert=function(e){var t=(0,dy.createTokenInstance)(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return t.isInsertedInRecovery=!0,t},r.prototype.canTokenTypeBeInsertedInRecovery=function(e){return!0},r.prototype.tryInRepetitionRecovery=function(e,t,i,n){for(var s=this,o=this.findReSyncTokenType(),a=this.exportLexerState(),l=[],c=!1,u=this.LA(1),g=this.LA(1),f=function(){var h=s.LA(0),p=s.errorMessageProvider.buildMismatchTokenMessage({expected:n,actual:u,previous:h,ruleName:s.getCurrRuleFullName()}),C=new tye.MismatchedTokenException(p,u,s.LA(0));C.resyncedTokens=(0,hs.dropRight)(l),s.SAVE_ERROR(C)};!c;)if(this.tokenMatcher(g,n)){f();return}else if(i.call(this)){f(),e.apply(this,t);return}else this.tokenMatcher(g,o)?c=!0:(g=this.SKIP_TOKEN(),this.addToResyncTokens(g,l));this.importLexerState(a)},r.prototype.shouldInRepetitionRecoveryBeTried=function(e,t,i){return!(i===!1||e===void 0||t===void 0||this.tokenMatcher(this.LA(1),e)||this.isBackTracking()||this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,t)))},r.prototype.getFollowsForInRuleRecovery=function(e,t){var i=this.getCurrentGrammarPath(e,t),n=this.getNextPossibleTokenTypes(i);return n},r.prototype.tryInRuleRecovery=function(e,t){if(this.canRecoverWithSingleTokenInsertion(e,t)){var i=this.getTokenToInsert(e);return i}if(this.canRecoverWithSingleTokenDeletion(e)){var n=this.SKIP_TOKEN();return this.consumeToken(),n}throw new nx("sad sad panda")},r.prototype.canPerformInRuleRecovery=function(e,t){return this.canRecoverWithSingleTokenInsertion(e,t)||this.canRecoverWithSingleTokenDeletion(e)},r.prototype.canRecoverWithSingleTokenInsertion=function(e,t){var i=this;if(!this.canTokenTypeBeInsertedInRecovery(e)||(0,hs.isEmpty)(t))return!1;var n=this.LA(1),s=(0,hs.find)(t,function(o){return i.tokenMatcher(n,o)})!==void 0;return s},r.prototype.canRecoverWithSingleTokenDeletion=function(e){var t=this.tokenMatcher(this.LA(2),e);return t},r.prototype.isInCurrentRuleReSyncSet=function(e){var t=this.getCurrFollowKey(),i=this.getFollowSetFromFollowKey(t);return(0,hs.contains)(i,e)},r.prototype.findReSyncTokenType=function(){for(var e=this.flattenFollowSet(),t=this.LA(1),i=2;;){var n=t.tokenType;if((0,hs.contains)(e,n))return n;t=this.LA(i),i++}},r.prototype.getCurrFollowKey=function(){if(this.RULE_STACK.length===1)return Ui.EOF_FOLLOW_KEY;var e=this.getLastExplicitRuleShortName(),t=this.getLastExplicitRuleOccurrenceIndex(),i=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:t,inRule:this.shortRuleNameToFullName(i)}},r.prototype.buildFullFollowKeyStack=function(){var e=this,t=this.RULE_STACK,i=this.RULE_OCCURRENCE_STACK;return(0,hs.map)(t,function(n,s){return s===0?Ui.EOF_FOLLOW_KEY:{ruleName:e.shortRuleNameToFullName(n),idxInCallingRule:i[s],inRule:e.shortRuleNameToFullName(t[s-1])}})},r.prototype.flattenFollowSet=function(){var e=this,t=(0,hs.map)(this.buildFullFollowKeyStack(),function(i){return e.getFollowSetFromFollowKey(i)});return(0,hs.flatten)(t)},r.prototype.getFollowSetFromFollowKey=function(e){if(e===Ui.EOF_FOLLOW_KEY)return[dy.EOF];var t=e.ruleName+e.idxInCallingRule+rye.IN+e.inRule;return this.resyncFollows[t]},r.prototype.addToResyncTokens=function(e,t){return this.tokenMatcher(e,dy.EOF)||t.push(e),t},r.prototype.reSyncTo=function(e){for(var t=[],i=this.LA(1);this.tokenMatcher(i,e)===!1;)i=this.SKIP_TOKEN(),this.addToResyncTokens(i,t);return(0,hs.dropRight)(t)},r.prototype.attemptInRepetitionRecovery=function(e,t,i,n,s,o,a){},r.prototype.getCurrentGrammarPath=function(e,t){var i=this.getHumanReadableRuleStack(),n=(0,hs.cloneArr)(this.RULE_OCCURRENCE_STACK),s={ruleStack:i,occurrenceStack:n,lastTok:e,lastTokOccurrence:t};return s},r.prototype.getHumanReadableRuleStack=function(){var e=this;return(0,hs.map)(this.RULE_STACK,function(t){return e.shortRuleNameToFullName(t)})},r}();Ui.Recoverable=nye;function yq(r,e,t,i,n,s,o){var a=this.getKeyForAutomaticLookahead(i,n),l=this.firstAfterRepMap[a];if(l===void 0){var c=this.getCurrRuleFullName(),u=this.getGAstProductions()[c],g=new s(u,n);l=g.startWalking(),this.firstAfterRepMap[a]=l}var f=l.token,h=l.occurrence,p=l.isEndOfRule;this.RULE_STACK.length===1&&p&&f===void 0&&(f=dy.EOF,h=1),this.shouldInRepetitionRecoveryBeTried(f,h,o)&&this.tryInRepetitionRecovery(r,e,t,f)}Ui.attemptInRepetitionRecovery=yq});var Cy=w(Jt=>{"use strict";Object.defineProperty(Jt,"__esModule",{value:!0});Jt.getKeyForAutomaticLookahead=Jt.AT_LEAST_ONE_SEP_IDX=Jt.MANY_SEP_IDX=Jt.AT_LEAST_ONE_IDX=Jt.MANY_IDX=Jt.OPTION_IDX=Jt.OR_IDX=Jt.BITS_FOR_ALT_IDX=Jt.BITS_FOR_RULE_IDX=Jt.BITS_FOR_OCCURRENCE_IDX=Jt.BITS_FOR_METHOD_TYPE=void 0;Jt.BITS_FOR_METHOD_TYPE=4;Jt.BITS_FOR_OCCURRENCE_IDX=8;Jt.BITS_FOR_RULE_IDX=12;Jt.BITS_FOR_ALT_IDX=8;Jt.OR_IDX=1<{"use strict";Object.defineProperty(my,"__esModule",{value:!0});my.LooksAhead=void 0;var Da=kd(),ro=Gt(),wq=Yn(),ka=Cy(),Ec=vd(),oye=function(){function r(){}return r.prototype.initLooksAhead=function(e){this.dynamicTokensEnabled=(0,ro.has)(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:wq.DEFAULT_PARSER_CONFIG.dynamicTokensEnabled,this.maxLookahead=(0,ro.has)(e,"maxLookahead")?e.maxLookahead:wq.DEFAULT_PARSER_CONFIG.maxLookahead,this.lookAheadFuncsCache=(0,ro.isES2015MapSupported)()?new Map:[],(0,ro.isES2015MapSupported)()?(this.getLaFuncFromCache=this.getLaFuncFromMap,this.setLaFuncCache=this.setLaFuncCacheUsingMap):(this.getLaFuncFromCache=this.getLaFuncFromObj,this.setLaFuncCache=this.setLaFuncUsingObj)},r.prototype.preComputeLookaheadFunctions=function(e){var t=this;(0,ro.forEach)(e,function(i){t.TRACE_INIT(i.name+" Rule Lookahead",function(){var n=(0,Ec.collectMethods)(i),s=n.alternation,o=n.repetition,a=n.option,l=n.repetitionMandatory,c=n.repetitionMandatoryWithSeparator,u=n.repetitionWithSeparator;(0,ro.forEach)(s,function(g){var f=g.idx===0?"":g.idx;t.TRACE_INIT(""+(0,Ec.getProductionDslName)(g)+f,function(){var h=(0,Da.buildLookaheadFuncForOr)(g.idx,i,g.maxLookahead||t.maxLookahead,g.hasPredicates,t.dynamicTokensEnabled,t.lookAheadBuilderForAlternatives),p=(0,ka.getKeyForAutomaticLookahead)(t.fullRuleNameToShort[i.name],ka.OR_IDX,g.idx);t.setLaFuncCache(p,h)})}),(0,ro.forEach)(o,function(g){t.computeLookaheadFunc(i,g.idx,ka.MANY_IDX,Da.PROD_TYPE.REPETITION,g.maxLookahead,(0,Ec.getProductionDslName)(g))}),(0,ro.forEach)(a,function(g){t.computeLookaheadFunc(i,g.idx,ka.OPTION_IDX,Da.PROD_TYPE.OPTION,g.maxLookahead,(0,Ec.getProductionDslName)(g))}),(0,ro.forEach)(l,function(g){t.computeLookaheadFunc(i,g.idx,ka.AT_LEAST_ONE_IDX,Da.PROD_TYPE.REPETITION_MANDATORY,g.maxLookahead,(0,Ec.getProductionDslName)(g))}),(0,ro.forEach)(c,function(g){t.computeLookaheadFunc(i,g.idx,ka.AT_LEAST_ONE_SEP_IDX,Da.PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR,g.maxLookahead,(0,Ec.getProductionDslName)(g))}),(0,ro.forEach)(u,function(g){t.computeLookaheadFunc(i,g.idx,ka.MANY_SEP_IDX,Da.PROD_TYPE.REPETITION_WITH_SEPARATOR,g.maxLookahead,(0,Ec.getProductionDslName)(g))})})})},r.prototype.computeLookaheadFunc=function(e,t,i,n,s,o){var a=this;this.TRACE_INIT(""+o+(t===0?"":t),function(){var l=(0,Da.buildLookaheadFuncForOptionalProd)(t,e,s||a.maxLookahead,a.dynamicTokensEnabled,n,a.lookAheadBuilderForOptional),c=(0,ka.getKeyForAutomaticLookahead)(a.fullRuleNameToShort[e.name],i,t);a.setLaFuncCache(c,l)})},r.prototype.lookAheadBuilderForOptional=function(e,t,i){return(0,Da.buildSingleAlternativeLookaheadFunction)(e,t,i)},r.prototype.lookAheadBuilderForAlternatives=function(e,t,i,n){return(0,Da.buildAlternativesLookAheadFunc)(e,t,i,n)},r.prototype.getKeyForAutomaticLookahead=function(e,t){var i=this.getLastExplicitRuleShortName();return(0,ka.getKeyForAutomaticLookahead)(i,e,t)},r.prototype.getLaFuncFromCache=function(e){},r.prototype.getLaFuncFromMap=function(e){return this.lookAheadFuncsCache.get(e)},r.prototype.getLaFuncFromObj=function(e){return this.lookAheadFuncsCache[e]},r.prototype.setLaFuncCache=function(e,t){},r.prototype.setLaFuncCacheUsingMap=function(e,t){this.lookAheadFuncsCache.set(e,t)},r.prototype.setLaFuncUsingObj=function(e,t){this.lookAheadFuncsCache[e]=t},r}();my.LooksAhead=oye});var Qq=w(Lo=>{"use strict";Object.defineProperty(Lo,"__esModule",{value:!0});Lo.addNoneTerminalToCst=Lo.addTerminalToCst=Lo.setNodeLocationFull=Lo.setNodeLocationOnlyOffset=void 0;function aye(r,e){isNaN(r.startOffset)===!0?(r.startOffset=e.startOffset,r.endOffset=e.endOffset):r.endOffset{"use strict";Object.defineProperty(MA,"__esModule",{value:!0});MA.defineNameProp=MA.functionName=MA.classNameFromInstance=void 0;var uye=Gt();function gye(r){return Sq(r.constructor)}MA.classNameFromInstance=gye;var bq="name";function Sq(r){var e=r.name;return e||"anonymous"}MA.functionName=Sq;function fye(r,e){var t=Object.getOwnPropertyDescriptor(r,bq);return(0,uye.isUndefined)(t)||t.configurable?(Object.defineProperty(r,bq,{enumerable:!1,configurable:!0,writable:!1,value:e}),!0):!1}MA.defineNameProp=fye});var kq=w(Si=>{"use strict";Object.defineProperty(Si,"__esModule",{value:!0});Si.validateRedundantMethods=Si.validateMissingCstMethods=Si.validateVisitor=Si.CstVisitorDefinitionError=Si.createBaseVisitorConstructorWithDefaults=Si.createBaseSemanticVisitorConstructor=Si.defaultVisit=void 0;var ps=Gt(),Nd=ox();function vq(r,e){for(var t=(0,ps.keys)(r),i=t.length,n=0;n: + `+(""+s.join(` + +`).replace(/\n/g,` + `)))}}};return t.prototype=i,t.prototype.constructor=t,t._RULE_NAMES=e,t}Si.createBaseSemanticVisitorConstructor=hye;function pye(r,e,t){var i=function(){};(0,Nd.defineNameProp)(i,r+"BaseSemanticsWithDefaults");var n=Object.create(t.prototype);return(0,ps.forEach)(e,function(s){n[s]=vq}),i.prototype=n,i.prototype.constructor=i,i}Si.createBaseVisitorConstructorWithDefaults=pye;var ax;(function(r){r[r.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",r[r.MISSING_METHOD=1]="MISSING_METHOD"})(ax=Si.CstVisitorDefinitionError||(Si.CstVisitorDefinitionError={}));function xq(r,e){var t=Pq(r,e),i=Dq(r,e);return t.concat(i)}Si.validateVisitor=xq;function Pq(r,e){var t=(0,ps.map)(e,function(i){if(!(0,ps.isFunction)(r[i]))return{msg:"Missing visitor method: <"+i+"> on "+(0,Nd.functionName)(r.constructor)+" CST Visitor.",type:ax.MISSING_METHOD,methodName:i}});return(0,ps.compact)(t)}Si.validateMissingCstMethods=Pq;var dye=["constructor","visit","validateVisitor"];function Dq(r,e){var t=[];for(var i in r)(0,ps.isFunction)(r[i])&&!(0,ps.contains)(dye,i)&&!(0,ps.contains)(e,i)&&t.push({msg:"Redundant visitor method: <"+i+"> on "+(0,Nd.functionName)(r.constructor)+` CST Visitor +There is no Grammar Rule corresponding to this method's name. +`,type:ax.REDUNDANT_METHOD,methodName:i});return t}Si.validateRedundantMethods=Dq});var Fq=w(Ey=>{"use strict";Object.defineProperty(Ey,"__esModule",{value:!0});Ey.TreeBuilder=void 0;var sf=Qq(),_r=Gt(),Rq=kq(),Cye=Yn(),mye=function(){function r(){}return r.prototype.initTreeBuilder=function(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=(0,_r.has)(e,"nodeLocationTracking")?e.nodeLocationTracking:Cye.DEFAULT_PARSER_CONFIG.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=_r.NOOP,this.cstFinallyStateUpdate=_r.NOOP,this.cstPostTerminal=_r.NOOP,this.cstPostNonTerminal=_r.NOOP,this.cstPostRule=_r.NOOP;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=sf.setNodeLocationFull,this.setNodeLocationFromNode=sf.setNodeLocationFull,this.cstPostRule=_r.NOOP,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=_r.NOOP,this.setNodeLocationFromNode=_r.NOOP,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=sf.setNodeLocationOnlyOffset,this.setNodeLocationFromNode=sf.setNodeLocationOnlyOffset,this.cstPostRule=_r.NOOP,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=_r.NOOP,this.setNodeLocationFromNode=_r.NOOP,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=_r.NOOP,this.setNodeLocationFromNode=_r.NOOP,this.cstPostRule=_r.NOOP,this.setInitialNodeLocation=_r.NOOP;else throw Error('Invalid config option: "'+e.nodeLocationTracking+'"')},r.prototype.setInitialNodeLocationOnlyOffsetRecovery=function(e){e.location={startOffset:NaN,endOffset:NaN}},r.prototype.setInitialNodeLocationOnlyOffsetRegular=function(e){e.location={startOffset:this.LA(1).startOffset,endOffset:NaN}},r.prototype.setInitialNodeLocationFullRecovery=function(e){e.location={startOffset:NaN,startLine:NaN,startColumn:NaN,endOffset:NaN,endLine:NaN,endColumn:NaN}},r.prototype.setInitialNodeLocationFullRegular=function(e){var t=this.LA(1);e.location={startOffset:t.startOffset,startLine:t.startLine,startColumn:t.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}},r.prototype.cstInvocationStateUpdate=function(e,t){var i={name:e,children:{}};this.setInitialNodeLocation(i),this.CST_STACK.push(i)},r.prototype.cstFinallyStateUpdate=function(){this.CST_STACK.pop()},r.prototype.cstPostRuleFull=function(e){var t=this.LA(0),i=e.location;i.startOffset<=t.startOffset?(i.endOffset=t.endOffset,i.endLine=t.endLine,i.endColumn=t.endColumn):(i.startOffset=NaN,i.startLine=NaN,i.startColumn=NaN)},r.prototype.cstPostRuleOnlyOffset=function(e){var t=this.LA(0),i=e.location;i.startOffset<=t.startOffset?i.endOffset=t.endOffset:i.startOffset=NaN},r.prototype.cstPostTerminal=function(e,t){var i=this.CST_STACK[this.CST_STACK.length-1];(0,sf.addTerminalToCst)(i,t,e),this.setNodeLocationFromToken(i.location,t)},r.prototype.cstPostNonTerminal=function(e,t){var i=this.CST_STACK[this.CST_STACK.length-1];(0,sf.addNoneTerminalToCst)(i,t,e),this.setNodeLocationFromNode(i.location,e.location)},r.prototype.getBaseCstVisitorConstructor=function(){if((0,_r.isUndefined)(this.baseCstVisitorConstructor)){var e=(0,Rq.createBaseSemanticVisitorConstructor)(this.className,(0,_r.keys)(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor},r.prototype.getBaseCstVisitorConstructorWithDefaults=function(){if((0,_r.isUndefined)(this.baseCstVisitorWithDefaultsConstructor)){var e=(0,Rq.createBaseVisitorConstructorWithDefaults)(this.className,(0,_r.keys)(this.gastProductionsCache),this.getBaseCstVisitorConstructor());return this.baseCstVisitorWithDefaultsConstructor=e,e}return this.baseCstVisitorWithDefaultsConstructor},r.prototype.getLastExplicitRuleShortName=function(){var e=this.RULE_STACK;return e[e.length-1]},r.prototype.getPreviousExplicitRuleShortName=function(){var e=this.RULE_STACK;return e[e.length-2]},r.prototype.getLastExplicitRuleOccurrenceIndex=function(){var e=this.RULE_OCCURRENCE_STACK;return e[e.length-1]},r}();Ey.TreeBuilder=mye});var Lq=w(Iy=>{"use strict";Object.defineProperty(Iy,"__esModule",{value:!0});Iy.LexerAdapter=void 0;var Nq=Yn(),Eye=function(){function r(){}return r.prototype.initLexerAdapter=function(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1},Object.defineProperty(r.prototype,"input",{get:function(){return this.tokVector},set:function(e){if(this.selfAnalysisDone!==!0)throw Error("Missing invocation at the end of the Parser's constructor.");this.reset(),this.tokVector=e,this.tokVectorLength=e.length},enumerable:!1,configurable:!0}),r.prototype.SKIP_TOKEN=function(){return this.currIdx<=this.tokVector.length-2?(this.consumeToken(),this.LA(1)):Nq.END_OF_FILE},r.prototype.LA=function(e){var t=this.currIdx+e;return t<0||this.tokVectorLength<=t?Nq.END_OF_FILE:this.tokVector[t]},r.prototype.consumeToken=function(){this.currIdx++},r.prototype.exportLexerState=function(){return this.currIdx},r.prototype.importLexerState=function(e){this.currIdx=e},r.prototype.resetLexerState=function(){this.currIdx=-1},r.prototype.moveToTerminatedState=function(){this.currIdx=this.tokVector.length-1},r.prototype.getLexerPosition=function(){return this.exportLexerState()},r}();Iy.LexerAdapter=Eye});var Oq=w(yy=>{"use strict";Object.defineProperty(yy,"__esModule",{value:!0});yy.RecognizerApi=void 0;var Tq=Gt(),Iye=nf(),Ax=Yn(),yye=xd(),wye=rx(),Bye=Cn(),Qye=function(){function r(){}return r.prototype.ACTION=function(e){return e.call(this)},r.prototype.consume=function(e,t,i){return this.consumeInternal(t,e,i)},r.prototype.subrule=function(e,t,i){return this.subruleInternal(t,e,i)},r.prototype.option=function(e,t){return this.optionInternal(t,e)},r.prototype.or=function(e,t){return this.orInternal(t,e)},r.prototype.many=function(e,t){return this.manyInternal(e,t)},r.prototype.atLeastOne=function(e,t){return this.atLeastOneInternal(e,t)},r.prototype.CONSUME=function(e,t){return this.consumeInternal(e,0,t)},r.prototype.CONSUME1=function(e,t){return this.consumeInternal(e,1,t)},r.prototype.CONSUME2=function(e,t){return this.consumeInternal(e,2,t)},r.prototype.CONSUME3=function(e,t){return this.consumeInternal(e,3,t)},r.prototype.CONSUME4=function(e,t){return this.consumeInternal(e,4,t)},r.prototype.CONSUME5=function(e,t){return this.consumeInternal(e,5,t)},r.prototype.CONSUME6=function(e,t){return this.consumeInternal(e,6,t)},r.prototype.CONSUME7=function(e,t){return this.consumeInternal(e,7,t)},r.prototype.CONSUME8=function(e,t){return this.consumeInternal(e,8,t)},r.prototype.CONSUME9=function(e,t){return this.consumeInternal(e,9,t)},r.prototype.SUBRULE=function(e,t){return this.subruleInternal(e,0,t)},r.prototype.SUBRULE1=function(e,t){return this.subruleInternal(e,1,t)},r.prototype.SUBRULE2=function(e,t){return this.subruleInternal(e,2,t)},r.prototype.SUBRULE3=function(e,t){return this.subruleInternal(e,3,t)},r.prototype.SUBRULE4=function(e,t){return this.subruleInternal(e,4,t)},r.prototype.SUBRULE5=function(e,t){return this.subruleInternal(e,5,t)},r.prototype.SUBRULE6=function(e,t){return this.subruleInternal(e,6,t)},r.prototype.SUBRULE7=function(e,t){return this.subruleInternal(e,7,t)},r.prototype.SUBRULE8=function(e,t){return this.subruleInternal(e,8,t)},r.prototype.SUBRULE9=function(e,t){return this.subruleInternal(e,9,t)},r.prototype.OPTION=function(e){return this.optionInternal(e,0)},r.prototype.OPTION1=function(e){return this.optionInternal(e,1)},r.prototype.OPTION2=function(e){return this.optionInternal(e,2)},r.prototype.OPTION3=function(e){return this.optionInternal(e,3)},r.prototype.OPTION4=function(e){return this.optionInternal(e,4)},r.prototype.OPTION5=function(e){return this.optionInternal(e,5)},r.prototype.OPTION6=function(e){return this.optionInternal(e,6)},r.prototype.OPTION7=function(e){return this.optionInternal(e,7)},r.prototype.OPTION8=function(e){return this.optionInternal(e,8)},r.prototype.OPTION9=function(e){return this.optionInternal(e,9)},r.prototype.OR=function(e){return this.orInternal(e,0)},r.prototype.OR1=function(e){return this.orInternal(e,1)},r.prototype.OR2=function(e){return this.orInternal(e,2)},r.prototype.OR3=function(e){return this.orInternal(e,3)},r.prototype.OR4=function(e){return this.orInternal(e,4)},r.prototype.OR5=function(e){return this.orInternal(e,5)},r.prototype.OR6=function(e){return this.orInternal(e,6)},r.prototype.OR7=function(e){return this.orInternal(e,7)},r.prototype.OR8=function(e){return this.orInternal(e,8)},r.prototype.OR9=function(e){return this.orInternal(e,9)},r.prototype.MANY=function(e){this.manyInternal(0,e)},r.prototype.MANY1=function(e){this.manyInternal(1,e)},r.prototype.MANY2=function(e){this.manyInternal(2,e)},r.prototype.MANY3=function(e){this.manyInternal(3,e)},r.prototype.MANY4=function(e){this.manyInternal(4,e)},r.prototype.MANY5=function(e){this.manyInternal(5,e)},r.prototype.MANY6=function(e){this.manyInternal(6,e)},r.prototype.MANY7=function(e){this.manyInternal(7,e)},r.prototype.MANY8=function(e){this.manyInternal(8,e)},r.prototype.MANY9=function(e){this.manyInternal(9,e)},r.prototype.MANY_SEP=function(e){this.manySepFirstInternal(0,e)},r.prototype.MANY_SEP1=function(e){this.manySepFirstInternal(1,e)},r.prototype.MANY_SEP2=function(e){this.manySepFirstInternal(2,e)},r.prototype.MANY_SEP3=function(e){this.manySepFirstInternal(3,e)},r.prototype.MANY_SEP4=function(e){this.manySepFirstInternal(4,e)},r.prototype.MANY_SEP5=function(e){this.manySepFirstInternal(5,e)},r.prototype.MANY_SEP6=function(e){this.manySepFirstInternal(6,e)},r.prototype.MANY_SEP7=function(e){this.manySepFirstInternal(7,e)},r.prototype.MANY_SEP8=function(e){this.manySepFirstInternal(8,e)},r.prototype.MANY_SEP9=function(e){this.manySepFirstInternal(9,e)},r.prototype.AT_LEAST_ONE=function(e){this.atLeastOneInternal(0,e)},r.prototype.AT_LEAST_ONE1=function(e){return this.atLeastOneInternal(1,e)},r.prototype.AT_LEAST_ONE2=function(e){this.atLeastOneInternal(2,e)},r.prototype.AT_LEAST_ONE3=function(e){this.atLeastOneInternal(3,e)},r.prototype.AT_LEAST_ONE4=function(e){this.atLeastOneInternal(4,e)},r.prototype.AT_LEAST_ONE5=function(e){this.atLeastOneInternal(5,e)},r.prototype.AT_LEAST_ONE6=function(e){this.atLeastOneInternal(6,e)},r.prototype.AT_LEAST_ONE7=function(e){this.atLeastOneInternal(7,e)},r.prototype.AT_LEAST_ONE8=function(e){this.atLeastOneInternal(8,e)},r.prototype.AT_LEAST_ONE9=function(e){this.atLeastOneInternal(9,e)},r.prototype.AT_LEAST_ONE_SEP=function(e){this.atLeastOneSepFirstInternal(0,e)},r.prototype.AT_LEAST_ONE_SEP1=function(e){this.atLeastOneSepFirstInternal(1,e)},r.prototype.AT_LEAST_ONE_SEP2=function(e){this.atLeastOneSepFirstInternal(2,e)},r.prototype.AT_LEAST_ONE_SEP3=function(e){this.atLeastOneSepFirstInternal(3,e)},r.prototype.AT_LEAST_ONE_SEP4=function(e){this.atLeastOneSepFirstInternal(4,e)},r.prototype.AT_LEAST_ONE_SEP5=function(e){this.atLeastOneSepFirstInternal(5,e)},r.prototype.AT_LEAST_ONE_SEP6=function(e){this.atLeastOneSepFirstInternal(6,e)},r.prototype.AT_LEAST_ONE_SEP7=function(e){this.atLeastOneSepFirstInternal(7,e)},r.prototype.AT_LEAST_ONE_SEP8=function(e){this.atLeastOneSepFirstInternal(8,e)},r.prototype.AT_LEAST_ONE_SEP9=function(e){this.atLeastOneSepFirstInternal(9,e)},r.prototype.RULE=function(e,t,i){if(i===void 0&&(i=Ax.DEFAULT_RULE_CONFIG),(0,Tq.contains)(this.definedRulesNames,e)){var n=yye.defaultGrammarValidatorErrorProvider.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),s={message:n,type:Ax.ParserDefinitionErrorType.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(s)}this.definedRulesNames.push(e);var o=this.defineRule(e,t,i);return this[e]=o,o},r.prototype.OVERRIDE_RULE=function(e,t,i){i===void 0&&(i=Ax.DEFAULT_RULE_CONFIG);var n=[];n=n.concat((0,wye.validateRuleIsOverridden)(e,this.definedRulesNames,this.className)),this.definitionErrors=this.definitionErrors.concat(n);var s=this.defineRule(e,t,i);return this[e]=s,s},r.prototype.BACKTRACK=function(e,t){return function(){this.isBackTrackingStack.push(1);var i=this.saveRecogState();try{return e.apply(this,t),!0}catch(n){if((0,Iye.isRecognitionException)(n))return!1;throw n}finally{this.reloadRecogState(i),this.isBackTrackingStack.pop()}}},r.prototype.getGAstProductions=function(){return this.gastProductionsCache},r.prototype.getSerializedGastProductions=function(){return(0,Bye.serializeGrammar)((0,Tq.values)(this.gastProductionsCache))},r}();yy.RecognizerApi=Qye});var Hq=w(By=>{"use strict";Object.defineProperty(By,"__esModule",{value:!0});By.RecognizerEngine=void 0;var Pr=Gt(),jn=Cy(),wy=nf(),Mq=kd(),of=Dd(),Uq=Yn(),bye=sx(),Kq=LA(),Ld=_g(),Sye=ox(),vye=function(){function r(){}return r.prototype.initRecognizerEngine=function(e,t){if(this.className=(0,Sye.classNameFromInstance)(this),this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=Ld.tokenStructuredMatcherNoCategories,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},(0,Pr.has)(t,"serializedGrammar"))throw Error(`The Parser's configuration can no longer contain a property. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0 + For Further details.`);if((0,Pr.isArray)(e)){if((0,Pr.isEmpty)(e))throw Error(`A Token Vocabulary cannot be empty. + Note that the first argument for the parser constructor + is no longer a Token vector (since v4.0).`);if(typeof e[0].startOffset=="number")throw Error(`The Parser constructor no longer accepts a token vector as the first argument. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_4-0-0 + For Further details.`)}if((0,Pr.isArray)(e))this.tokensMap=(0,Pr.reduce)(e,function(o,a){return o[a.name]=a,o},{});else if((0,Pr.has)(e,"modes")&&(0,Pr.every)((0,Pr.flatten)((0,Pr.values)(e.modes)),Ld.isTokenType)){var i=(0,Pr.flatten)((0,Pr.values)(e.modes)),n=(0,Pr.uniq)(i);this.tokensMap=(0,Pr.reduce)(n,function(o,a){return o[a.name]=a,o},{})}else if((0,Pr.isObject)(e))this.tokensMap=(0,Pr.cloneObj)(e);else throw new Error(" argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=Kq.EOF;var s=(0,Pr.every)((0,Pr.values)(e),function(o){return(0,Pr.isEmpty)(o.categoryMatches)});this.tokenMatcher=s?Ld.tokenStructuredMatcherNoCategories:Ld.tokenStructuredMatcher,(0,Ld.augmentTokenTypes)((0,Pr.values)(this.tokensMap))},r.prototype.defineRule=function(e,t,i){if(this.selfAnalysisDone)throw Error("Grammar rule <"+e+`> may not be defined after the 'performSelfAnalysis' method has been called' +Make sure that all grammar rule definitions are done before 'performSelfAnalysis' is called.`);var n=(0,Pr.has)(i,"resyncEnabled")?i.resyncEnabled:Uq.DEFAULT_RULE_CONFIG.resyncEnabled,s=(0,Pr.has)(i,"recoveryValueFunc")?i.recoveryValueFunc:Uq.DEFAULT_RULE_CONFIG.recoveryValueFunc,o=this.ruleShortNameIdx<t},r.prototype.orInternal=function(e,t){var i=this.getKeyForAutomaticLookahead(jn.OR_IDX,t),n=(0,Pr.isArray)(e)?e:e.DEF,s=this.getLaFuncFromCache(i),o=s.call(this,n);if(o!==void 0){var a=n[o];return a.ALT.call(this)}this.raiseNoAltException(t,e.ERR_MSG)},r.prototype.ruleFinallyStateUpdate=function(){if(this.RULE_STACK.pop(),this.RULE_OCCURRENCE_STACK.pop(),this.cstFinallyStateUpdate(),this.RULE_STACK.length===0&&this.isAtEndOfInput()===!1){var e=this.LA(1),t=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new wy.NotAllInputParsedException(t,e))}},r.prototype.subruleInternal=function(e,t,i){var n;try{var s=i!==void 0?i.ARGS:void 0;return n=e.call(this,t,s),this.cstPostNonTerminal(n,i!==void 0&&i.LABEL!==void 0?i.LABEL:e.ruleName),n}catch(o){this.subruleInternalError(o,i,e.ruleName)}},r.prototype.subruleInternalError=function(e,t,i){throw(0,wy.isRecognitionException)(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstResult,t!==void 0&&t.LABEL!==void 0?t.LABEL:i),delete e.partialCstResult),e},r.prototype.consumeInternal=function(e,t,i){var n;try{var s=this.LA(1);this.tokenMatcher(s,e)===!0?(this.consumeToken(),n=s):this.consumeInternalError(e,s,i)}catch(o){n=this.consumeInternalRecovery(e,t,o)}return this.cstPostTerminal(i!==void 0&&i.LABEL!==void 0?i.LABEL:e.name,n),n},r.prototype.consumeInternalError=function(e,t,i){var n,s=this.LA(0);throw i!==void 0&&i.ERR_MSG?n=i.ERR_MSG:n=this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:t,previous:s,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new wy.MismatchedTokenException(n,t,s))},r.prototype.consumeInternalRecovery=function(e,t,i){if(this.recoveryEnabled&&i.name==="MismatchedTokenException"&&!this.isBackTracking()){var n=this.getFollowsForInRuleRecovery(e,t);try{return this.tryInRuleRecovery(e,n)}catch(s){throw s.name===bye.IN_RULE_RECOVERY_EXCEPTION?i:s}}else throw i},r.prototype.saveRecogState=function(){var e=this.errors,t=(0,Pr.cloneArr)(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:t,CST_STACK:this.CST_STACK}},r.prototype.reloadRecogState=function(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK},r.prototype.ruleInvocationStateUpdate=function(e,t,i){this.RULE_OCCURRENCE_STACK.push(i),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(t,e)},r.prototype.isBackTracking=function(){return this.isBackTrackingStack.length!==0},r.prototype.getCurrRuleFullName=function(){var e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]},r.prototype.shortRuleNameToFullName=function(e){return this.shortRuleNameToFull[e]},r.prototype.isAtEndOfInput=function(){return this.tokenMatcher(this.LA(1),Kq.EOF)},r.prototype.reset=function(){this.resetLexerState(),this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]},r}();By.RecognizerEngine=vye});var Yq=w(Qy=>{"use strict";Object.defineProperty(Qy,"__esModule",{value:!0});Qy.ErrorHandler=void 0;var lx=nf(),cx=Gt(),Gq=kd(),xye=Yn(),Pye=function(){function r(){}return r.prototype.initErrorHandler=function(e){this._errors=[],this.errorMessageProvider=(0,cx.has)(e,"errorMessageProvider")?e.errorMessageProvider:xye.DEFAULT_PARSER_CONFIG.errorMessageProvider},r.prototype.SAVE_ERROR=function(e){if((0,lx.isRecognitionException)(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:(0,cx.cloneArr)(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")},Object.defineProperty(r.prototype,"errors",{get:function(){return(0,cx.cloneArr)(this._errors)},set:function(e){this._errors=e},enumerable:!1,configurable:!0}),r.prototype.raiseEarlyExitException=function(e,t,i){for(var n=this.getCurrRuleFullName(),s=this.getGAstProductions()[n],o=(0,Gq.getLookaheadPathsForOptionalProd)(e,s,t,this.maxLookahead),a=o[0],l=[],c=1;c<=this.maxLookahead;c++)l.push(this.LA(c));var u=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:a,actual:l,previous:this.LA(0),customUserDescription:i,ruleName:n});throw this.SAVE_ERROR(new lx.EarlyExitException(u,this.LA(1),this.LA(0)))},r.prototype.raiseNoAltException=function(e,t){for(var i=this.getCurrRuleFullName(),n=this.getGAstProductions()[i],s=(0,Gq.getLookaheadPathsForOr)(e,n,this.maxLookahead),o=[],a=1;a<=this.maxLookahead;a++)o.push(this.LA(a));var l=this.LA(0),c=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:s,actual:o,previous:l,customUserDescription:t,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new lx.NoViableAltException(c,this.LA(1),l))},r}();Qy.ErrorHandler=Pye});var Jq=w(by=>{"use strict";Object.defineProperty(by,"__esModule",{value:!0});by.ContentAssist=void 0;var jq=Dd(),qq=Gt(),Dye=function(){function r(){}return r.prototype.initContentAssist=function(){},r.prototype.computeContentAssist=function(e,t){var i=this.gastProductionsCache[e];if((0,qq.isUndefined)(i))throw Error("Rule ->"+e+"<- does not exist in this grammar.");return(0,jq.nextPossibleTokensAfter)([i],t,this.tokenMatcher,this.maxLookahead)},r.prototype.getNextPossibleTokenTypes=function(e){var t=(0,qq.first)(e.ruleStack),i=this.getGAstProductions(),n=i[t],s=new jq.NextAfterTokenWalker(n,e).startWalking();return s},r}();by.ContentAssist=Dye});var eJ=w(xy=>{"use strict";Object.defineProperty(xy,"__esModule",{value:!0});xy.GastRecorder=void 0;var In=Gt(),To=Cn(),kye=Bd(),Xq=_g(),Zq=LA(),Rye=Yn(),Fye=Cy(),vy={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(vy);var Wq=!0,zq=Math.pow(2,Fye.BITS_FOR_OCCURRENCE_IDX)-1,_q=(0,Zq.createToken)({name:"RECORDING_PHASE_TOKEN",pattern:kye.Lexer.NA});(0,Xq.augmentTokenTypes)([_q]);var $q=(0,Zq.createTokenInstance)(_q,`This IToken indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze($q);var Nye={name:`This CSTNode indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},Lye=function(){function r(){}return r.prototype.initGastRecorder=function(e){this.recordingProdStack=[],this.RECORDING_PHASE=!1},r.prototype.enableRecording=function(){var e=this;this.RECORDING_PHASE=!0,this.TRACE_INIT("Enable Recording",function(){for(var t=function(n){var s=n>0?n:"";e["CONSUME"+s]=function(o,a){return this.consumeInternalRecord(o,n,a)},e["SUBRULE"+s]=function(o,a){return this.subruleInternalRecord(o,n,a)},e["OPTION"+s]=function(o){return this.optionInternalRecord(o,n)},e["OR"+s]=function(o){return this.orInternalRecord(o,n)},e["MANY"+s]=function(o){this.manyInternalRecord(n,o)},e["MANY_SEP"+s]=function(o){this.manySepFirstInternalRecord(n,o)},e["AT_LEAST_ONE"+s]=function(o){this.atLeastOneInternalRecord(n,o)},e["AT_LEAST_ONE_SEP"+s]=function(o){this.atLeastOneSepFirstInternalRecord(n,o)}},i=0;i<10;i++)t(i);e.consume=function(n,s,o){return this.consumeInternalRecord(s,n,o)},e.subrule=function(n,s,o){return this.subruleInternalRecord(s,n,o)},e.option=function(n,s){return this.optionInternalRecord(s,n)},e.or=function(n,s){return this.orInternalRecord(s,n)},e.many=function(n,s){this.manyInternalRecord(n,s)},e.atLeastOne=function(n,s){this.atLeastOneInternalRecord(n,s)},e.ACTION=e.ACTION_RECORD,e.BACKTRACK=e.BACKTRACK_RECORD,e.LA=e.LA_RECORD})},r.prototype.disableRecording=function(){var e=this;this.RECORDING_PHASE=!1,this.TRACE_INIT("Deleting Recording methods",function(){for(var t=0;t<10;t++){var i=t>0?t:"";delete e["CONSUME"+i],delete e["SUBRULE"+i],delete e["OPTION"+i],delete e["OR"+i],delete e["MANY"+i],delete e["MANY_SEP"+i],delete e["AT_LEAST_ONE"+i],delete e["AT_LEAST_ONE_SEP"+i]}delete e.consume,delete e.subrule,delete e.option,delete e.or,delete e.many,delete e.atLeastOne,delete e.ACTION,delete e.BACKTRACK,delete e.LA})},r.prototype.ACTION_RECORD=function(e){},r.prototype.BACKTRACK_RECORD=function(e,t){return function(){return!0}},r.prototype.LA_RECORD=function(e){return Rye.END_OF_FILE},r.prototype.topLevelRuleRecord=function(e,t){try{var i=new To.Rule({definition:[],name:e});return i.name=e,this.recordingProdStack.push(i),t.call(this),this.recordingProdStack.pop(),i}catch(n){if(n.KNOWN_RECORDER_ERROR!==!0)try{n.message=n.message+` + This error was thrown during the "grammar recording phase" For more info see: + https://chevrotain.io/docs/guide/internals.html#grammar-recording`}catch{throw n}throw n}},r.prototype.optionInternalRecord=function(e,t){return Td.call(this,To.Option,e,t)},r.prototype.atLeastOneInternalRecord=function(e,t){Td.call(this,To.RepetitionMandatory,t,e)},r.prototype.atLeastOneSepFirstInternalRecord=function(e,t){Td.call(this,To.RepetitionMandatoryWithSeparator,t,e,Wq)},r.prototype.manyInternalRecord=function(e,t){Td.call(this,To.Repetition,t,e)},r.prototype.manySepFirstInternalRecord=function(e,t){Td.call(this,To.RepetitionWithSeparator,t,e,Wq)},r.prototype.orInternalRecord=function(e,t){return Tye.call(this,e,t)},r.prototype.subruleInternalRecord=function(e,t,i){if(Sy(t),!e||(0,In.has)(e,"ruleName")===!1){var n=new Error(" argument is invalid"+(" expecting a Parser method reference but got: <"+JSON.stringify(e)+">")+(` + inside top level rule: <`+this.recordingProdStack[0].name+">"));throw n.KNOWN_RECORDER_ERROR=!0,n}var s=(0,In.peek)(this.recordingProdStack),o=e.ruleName,a=new To.NonTerminal({idx:t,nonTerminalName:o,label:i==null?void 0:i.LABEL,referencedRule:void 0});return s.definition.push(a),this.outputCst?Nye:vy},r.prototype.consumeInternalRecord=function(e,t,i){if(Sy(t),!(0,Xq.hasShortKeyProperty)(e)){var n=new Error(" argument is invalid"+(" expecting a TokenType reference but got: <"+JSON.stringify(e)+">")+(` + inside top level rule: <`+this.recordingProdStack[0].name+">"));throw n.KNOWN_RECORDER_ERROR=!0,n}var s=(0,In.peek)(this.recordingProdStack),o=new To.Terminal({idx:t,terminalType:e,label:i==null?void 0:i.LABEL});return s.definition.push(o),$q},r}();xy.GastRecorder=Lye;function Td(r,e,t,i){i===void 0&&(i=!1),Sy(t);var n=(0,In.peek)(this.recordingProdStack),s=(0,In.isFunction)(e)?e:e.DEF,o=new r({definition:[],idx:t});return i&&(o.separator=e.SEP),(0,In.has)(e,"MAX_LOOKAHEAD")&&(o.maxLookahead=e.MAX_LOOKAHEAD),this.recordingProdStack.push(o),s.call(this),n.definition.push(o),this.recordingProdStack.pop(),vy}function Tye(r,e){var t=this;Sy(e);var i=(0,In.peek)(this.recordingProdStack),n=(0,In.isArray)(r)===!1,s=n===!1?r:r.DEF,o=new To.Alternation({definition:[],idx:e,ignoreAmbiguities:n&&r.IGNORE_AMBIGUITIES===!0});(0,In.has)(r,"MAX_LOOKAHEAD")&&(o.maxLookahead=r.MAX_LOOKAHEAD);var a=(0,In.some)(s,function(l){return(0,In.isFunction)(l.GATE)});return o.hasPredicates=a,i.definition.push(o),(0,In.forEach)(s,function(l){var c=new To.Alternative({definition:[]});o.definition.push(c),(0,In.has)(l,"IGNORE_AMBIGUITIES")?c.ignoreAmbiguities=l.IGNORE_AMBIGUITIES:(0,In.has)(l,"GATE")&&(c.ignoreAmbiguities=!0),t.recordingProdStack.push(c),l.ALT.call(t),t.recordingProdStack.pop()}),vy}function Vq(r){return r===0?"":""+r}function Sy(r){if(r<0||r>zq){var e=new Error("Invalid DSL Method idx value: <"+r+`> + `+("Idx value must be a none negative value smaller than "+(zq+1)));throw e.KNOWN_RECORDER_ERROR=!0,e}}});var rJ=w(Py=>{"use strict";Object.defineProperty(Py,"__esModule",{value:!0});Py.PerformanceTracer=void 0;var tJ=Gt(),Oye=Yn(),Mye=function(){function r(){}return r.prototype.initPerformanceTracer=function(e){if((0,tJ.has)(e,"traceInitPerf")){var t=e.traceInitPerf,i=typeof t=="number";this.traceInitMaxIdent=i?t:1/0,this.traceInitPerf=i?t>0:t}else this.traceInitMaxIdent=0,this.traceInitPerf=Oye.DEFAULT_PARSER_CONFIG.traceInitPerf;this.traceInitIndent=-1},r.prototype.TRACE_INIT=function(e,t){if(this.traceInitPerf===!0){this.traceInitIndent++;var i=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <"+e+">");var n=(0,tJ.timer)(t),s=n.time,o=n.value,a=s>10?console.warn:console.log;return this.traceInitIndent time: "+s+"ms"),this.traceInitIndent--,o}else return t()},r}();Py.PerformanceTracer=Mye});var iJ=w(Dy=>{"use strict";Object.defineProperty(Dy,"__esModule",{value:!0});Dy.applyMixins=void 0;function Uye(r,e){e.forEach(function(t){var i=t.prototype;Object.getOwnPropertyNames(i).forEach(function(n){if(n!=="constructor"){var s=Object.getOwnPropertyDescriptor(i,n);s&&(s.get||s.set)?Object.defineProperty(r.prototype,n,s):r.prototype[n]=t.prototype[n]}})})}Dy.applyMixins=Uye});var Yn=w(dr=>{"use strict";var oJ=dr&&dr.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(dr,"__esModule",{value:!0});dr.EmbeddedActionsParser=dr.CstParser=dr.Parser=dr.EMPTY_ALT=dr.ParserDefinitionErrorType=dr.DEFAULT_RULE_CONFIG=dr.DEFAULT_PARSER_CONFIG=dr.END_OF_FILE=void 0;var $i=Gt(),Kye=Yj(),nJ=LA(),aJ=xd(),sJ=pq(),Hye=sx(),Gye=Bq(),Yye=Fq(),jye=Lq(),qye=Oq(),Jye=Hq(),Wye=Yq(),zye=Jq(),Vye=eJ(),Xye=rJ(),Zye=iJ();dr.END_OF_FILE=(0,nJ.createTokenInstance)(nJ.EOF,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(dr.END_OF_FILE);dr.DEFAULT_PARSER_CONFIG=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:aJ.defaultParserErrorProvider,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1});dr.DEFAULT_RULE_CONFIG=Object.freeze({recoveryValueFunc:function(){},resyncEnabled:!0});var _ye;(function(r){r[r.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",r[r.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",r[r.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",r[r.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",r[r.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",r[r.LEFT_RECURSION=5]="LEFT_RECURSION",r[r.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",r[r.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",r[r.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",r[r.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",r[r.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",r[r.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",r[r.TOO_MANY_ALTS=12]="TOO_MANY_ALTS"})(_ye=dr.ParserDefinitionErrorType||(dr.ParserDefinitionErrorType={}));function $ye(r){return r===void 0&&(r=void 0),function(){return r}}dr.EMPTY_ALT=$ye;var ky=function(){function r(e,t){this.definitionErrors=[],this.selfAnalysisDone=!1;var i=this;if(i.initErrorHandler(t),i.initLexerAdapter(),i.initLooksAhead(t),i.initRecognizerEngine(e,t),i.initRecoverable(t),i.initTreeBuilder(t),i.initContentAssist(),i.initGastRecorder(t),i.initPerformanceTracer(t),(0,$i.has)(t,"ignoredIssues"))throw new Error(`The IParserConfig property has been deprecated. + Please use the flag on the relevant DSL method instead. + See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES + For further details.`);this.skipValidations=(0,$i.has)(t,"skipValidations")?t.skipValidations:dr.DEFAULT_PARSER_CONFIG.skipValidations}return r.performSelfAnalysis=function(e){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")},r.prototype.performSelfAnalysis=function(){var e=this;this.TRACE_INIT("performSelfAnalysis",function(){var t;e.selfAnalysisDone=!0;var i=e.className;e.TRACE_INIT("toFastProps",function(){(0,$i.toFastProperties)(e)}),e.TRACE_INIT("Grammar Recording",function(){try{e.enableRecording(),(0,$i.forEach)(e.definedRulesNames,function(s){var o=e[s],a=o.originalGrammarAction,l=void 0;e.TRACE_INIT(s+" Rule",function(){l=e.topLevelRuleRecord(s,a)}),e.gastProductionsCache[s]=l})}finally{e.disableRecording()}});var n=[];if(e.TRACE_INIT("Grammar Resolving",function(){n=(0,sJ.resolveGrammar)({rules:(0,$i.values)(e.gastProductionsCache)}),e.definitionErrors=e.definitionErrors.concat(n)}),e.TRACE_INIT("Grammar Validations",function(){if((0,$i.isEmpty)(n)&&e.skipValidations===!1){var s=(0,sJ.validateGrammar)({rules:(0,$i.values)(e.gastProductionsCache),maxLookahead:e.maxLookahead,tokenTypes:(0,$i.values)(e.tokensMap),errMsgProvider:aJ.defaultGrammarValidatorErrorProvider,grammarName:i});e.definitionErrors=e.definitionErrors.concat(s)}}),(0,$i.isEmpty)(e.definitionErrors)&&(e.recoveryEnabled&&e.TRACE_INIT("computeAllProdsFollows",function(){var s=(0,Kye.computeAllProdsFollows)((0,$i.values)(e.gastProductionsCache));e.resyncFollows=s}),e.TRACE_INIT("ComputeLookaheadFunctions",function(){e.preComputeLookaheadFunctions((0,$i.values)(e.gastProductionsCache))})),!r.DEFER_DEFINITION_ERRORS_HANDLING&&!(0,$i.isEmpty)(e.definitionErrors))throw t=(0,$i.map)(e.definitionErrors,function(s){return s.message}),new Error(`Parser Definition Errors detected: + `+t.join(` +------------------------------- +`))})},r.DEFER_DEFINITION_ERRORS_HANDLING=!1,r}();dr.Parser=ky;(0,Zye.applyMixins)(ky,[Hye.Recoverable,Gye.LooksAhead,Yye.TreeBuilder,jye.LexerAdapter,Jye.RecognizerEngine,qye.RecognizerApi,Wye.ErrorHandler,zye.ContentAssist,Vye.GastRecorder,Xye.PerformanceTracer]);var ewe=function(r){oJ(e,r);function e(t,i){i===void 0&&(i=dr.DEFAULT_PARSER_CONFIG);var n=this,s=(0,$i.cloneObj)(i);return s.outputCst=!0,n=r.call(this,t,s)||this,n}return e}(ky);dr.CstParser=ewe;var twe=function(r){oJ(e,r);function e(t,i){i===void 0&&(i=dr.DEFAULT_PARSER_CONFIG);var n=this,s=(0,$i.cloneObj)(i);return s.outputCst=!1,n=r.call(this,t,s)||this,n}return e}(ky);dr.EmbeddedActionsParser=twe});var lJ=w(Ry=>{"use strict";Object.defineProperty(Ry,"__esModule",{value:!0});Ry.createSyntaxDiagramsCode=void 0;var AJ=Dv();function rwe(r,e){var t=e===void 0?{}:e,i=t.resourceBase,n=i===void 0?"https://unpkg.com/chevrotain@"+AJ.VERSION+"/diagrams/":i,s=t.css,o=s===void 0?"https://unpkg.com/chevrotain@"+AJ.VERSION+"/diagrams/diagrams.css":s,a=` + + + + + +`,l=` + +`,c=` +