diff --git a/.github/workflows/mirror_noir_subrepo.yml b/.github/workflows/mirror_noir_subrepo.yml index 94499d1e205..1a48080265b 100644 --- a/.github/workflows/mirror_noir_subrepo.yml +++ b/.github/workflows/mirror_noir_subrepo.yml @@ -34,7 +34,7 @@ jobs: - name: Push to branch run: | SUBREPO_PATH=noir - BRANCH=aztec + BRANCH=aztec-packages # identify ourselves, needed to commit git config --global user.name AztecBot git config --global user.email tech@aztecprotocol.com @@ -57,4 +57,4 @@ jobs: pr_title: 'feat: aztec-packages' pr_body: 'Development from Aztec.' destination_branch: 'master' - source_branch: 'aztec' + source_branch: 'aztec-packages' diff --git a/.github/workflows/protocol-circuits-gate-diff.yml b/.github/workflows/protocol-circuits-gate-diff.yml index 1d8c445c9af..ec1760c58ee 100644 --- a/.github/workflows/protocol-circuits-gate-diff.yml +++ b/.github/workflows/protocol-circuits-gate-diff.yml @@ -53,7 +53,7 @@ jobs: uses: TomAFrench/noir-gates-diff@e7cf131b7e7f044c01615f93f0b855f65ddc02d4 with: report: protocol_circuits_report.json - summaryQuantile: 1 # Display any diff in gate count + summaryQuantile: 0 # Display any diff in gate count - name: Add gates diff to sticky comment if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' diff --git a/boxes/blank/src/contracts/src/main.nr b/boxes/blank/src/contracts/src/main.nr index dadd500538f..ce978d35d1b 100644 --- a/boxes/blank/src/contracts/src/main.nr +++ b/boxes/blank/src/contracts/src/main.nr @@ -10,18 +10,21 @@ contract Blank { fn constructor() {} #[aztec(private)] - fn getPublicKey( - address: Field, - ) -> [Field; 2]{ + fn getPublicKey(address: Field) -> [Field; 2] { let pub_key = get_public_key(address); - + [pub_key.x, pub_key.y] } // A function which needs to be implemented by every contract working with storage. Replace it's content with your // own logic once you start working with private storage. // TODO: Remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } } diff --git a/boxes/token/src/contracts/src/main.nr b/boxes/token/src/contracts/src/main.nr index d19b1da706b..4c2fd6f2431 100644 --- a/boxes/token/src/contracts/src/main.nr +++ b/boxes/token/src/contracts/src/main.nr @@ -128,9 +128,7 @@ contract Token { // docs:start:set_admin #[aztec(public)] - fn set_admin( - new_admin: AztecAddress, - ) { + fn set_admin(new_admin: AztecAddress) { assert(storage.admin.read().eq(AztecAddress::new(context.msg_sender())), "caller is not admin"); // docs:start:write_admin storage.admin.write(new_admin); @@ -140,10 +138,7 @@ contract Token { // docs:start:set_minter #[aztec(public)] - fn set_minter( - minter: AztecAddress, - approve: bool, - ) { + fn set_minter(minter: AztecAddress, approve: bool) { // docs:start:read_admin assert(storage.admin.read().eq(AztecAddress::new(context.msg_sender())), "caller is not admin"); // docs:end:read_admin @@ -155,10 +150,7 @@ contract Token { // docs:start:mint_public #[aztec(public)] - fn mint_public( - to: AztecAddress, - amount: Field, - ) -> Field { + fn mint_public(to: AztecAddress, amount: Field) -> Field { // docs:start:read_minter assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); // docs:end:read_minter @@ -174,10 +166,7 @@ contract Token { // docs:start:mint_private #[aztec(public)] - fn mint_private( - amount: Field, - secret_hash: Field, - ) -> Field { + fn mint_private(amount: Field, secret_hash: Field) -> Field { assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter"); let pending_shields = storage.pending_shields; let mut note = TransparentNote::new(amount, secret_hash); @@ -193,12 +182,7 @@ contract Token { // docs:start:shield #[aztec(public)] - fn shield( - from: AztecAddress, - amount: Field, - secret_hash: Field, - nonce: Field, - ) -> Field { + fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) -> Field { if (from.address != context.msg_sender()) { // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. assert_current_call_valid_authwit_public(&mut context, from); @@ -220,12 +204,7 @@ contract Token { // docs:start:transfer_public #[aztec(public)] - fn transfer_public( - from: AztecAddress, - to: AztecAddress, - amount: Field, - nonce: Field, - ) -> Field { + fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field { if (from.address != context.msg_sender()) { assert_current_call_valid_authwit_public(&mut context, from); } else { @@ -245,11 +224,7 @@ contract Token { // docs:start:burn_public #[aztec(public)] - fn burn_public( - from: AztecAddress, - amount: Field, - nonce: Field, - ) -> Field { + fn burn_public(from: AztecAddress, amount: Field, nonce: Field) -> Field { if (from.address != context.msg_sender()) { assert_current_call_valid_authwit_public(&mut context, from); } else { @@ -269,11 +244,7 @@ contract Token { // docs:start:redeem_shield #[aztec(private)] - fn redeem_shield( - to: AztecAddress, - amount: Field, - secret: Field, - ) -> Field { + fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) -> Field { let pending_shields = storage.pending_shields; let secret_hash = compute_secret_hash(secret); let options = NoteGetterOptions::new().select(0, amount).select(1, secret_hash).set_limit(1); @@ -289,12 +260,7 @@ contract Token { // docs:start:unshield #[aztec(private)] - fn unshield( - from: AztecAddress, - to: AztecAddress, - amount: Field, - nonce: Field, - ) -> Field { + fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field { if (from.address != context.msg_sender()) { assert_current_call_valid_authwit(&mut context, from); } else { @@ -312,12 +278,7 @@ contract Token { // docs:start:transfer #[aztec(private)] - fn transfer( - from: AztecAddress, - to: AztecAddress, - amount: Field, - nonce: Field, - ) -> Field { + fn transfer(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field { if (from.address != context.msg_sender()) { assert_current_call_valid_authwit(&mut context, from); } else { @@ -334,11 +295,7 @@ contract Token { // docs:start:burn #[aztec(private)] - fn burn( - from: AztecAddress, - amount: Field, - nonce: Field, - ) -> Field { + fn burn(from: AztecAddress, amount: Field, nonce: Field) -> Field { if (from.address != context.msg_sender()) { assert_current_call_valid_authwit(&mut context, from); } else { @@ -356,9 +313,7 @@ contract Token { // docs:start:initialize #[aztec(public)] - internal fn _initialize( - new_admin: AztecAddress, - ) { + internal fn _initialize(new_admin: AztecAddress) { storage.admin.write(new_admin); storage.minters.at(new_admin.address).write(true); } @@ -368,10 +323,7 @@ contract Token { // docs:start:increase_public_balance #[aztec(public)] - internal fn _increase_public_balance( - to: AztecAddress, - amount: Field, - ) { + internal fn _increase_public_balance(to: AztecAddress, amount: Field) { let new_balance = storage.public_balances.at(to.address).read().add(SafeU120::new(amount)); storage.public_balances.at(to.address).write(new_balance); } @@ -379,9 +331,7 @@ contract Token { // docs:start:reduce_total_supply #[aztec(public)] - internal fn _reduce_total_supply( - amount: Field, - ) { + internal fn _reduce_total_supply(amount: Field) { // Only to be called from burn. let new_supply = storage.total_supply.read().sub(SafeU120::new(amount)); storage.total_supply.write(new_supply); @@ -391,37 +341,31 @@ contract Token { /// Unconstrained /// // docs:start:admin - unconstrained fn admin() -> Field { + unconstrained fn admin() -> pub Field { storage.admin.read().address } // docs:end:admin // docs:start:is_minter - unconstrained fn is_minter( - minter: AztecAddress, - ) -> bool { + unconstrained fn is_minter(minter: AztecAddress) -> pub bool { storage.minters.at(minter.address).read() } // docs:end:is_minter // docs:start:total_supply - unconstrained fn total_supply() -> u120 { + unconstrained fn total_supply() -> pub u120 { storage.total_supply.read().value } // docs:end:total_supply // docs:start:balance_of_private - unconstrained fn balance_of_private( - owner: AztecAddress, - ) -> u120 { + unconstrained fn balance_of_private(owner: AztecAddress) -> pub u120 { storage.balances.at(owner).balance_of().value } // docs:end:balance_of_private // docs:start:balance_of_public - unconstrained fn balance_of_public( - owner: AztecAddress, - ) -> u120 { + unconstrained fn balance_of_public(owner: AztecAddress) -> pub u120 { storage.public_balances.at(owner.address).read().value } // docs:end:balance_of_public @@ -433,7 +377,12 @@ contract Token { // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; TOKEN_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; TOKEN_NOTE_LEN] + ) -> pub [Field; 4] { let note_header = NoteHeader::new(contract_address, nonce, storage_slot); if (storage_slot == 5) { note_utils::compute_note_hash_and_nullifier(TransparentNoteMethods, note_header, serialized_note) diff --git a/noir/.dockerignore b/noir/.dockerignore index 25dd24f015c..8bea0aeeb1a 100644 --- a/noir/.dockerignore +++ b/noir/.dockerignore @@ -7,10 +7,6 @@ packages **/node_modules **/outputs -# Source resolver -compiler/source-resolver/lib -compiler/source-resolver/lib-node - # Noir.js tooling/noir_js/lib @@ -19,4 +15,4 @@ compiler/wasm/nodejs compiler/wasm/web tooling/noirc_abi_wasm/nodejs tooling/noirc_abi_wasm/web -tooling/noir_js/lib \ No newline at end of file +tooling/noir_js/lib diff --git a/noir/.eslintrc.js b/noir/.eslintrc.js index f47f171561c..0f20016d862 100644 --- a/noir/.eslintrc.js +++ b/noir/.eslintrc.js @@ -1,4 +1,9 @@ module.exports = { + env: { + browser: true, + es6: true, + node: true, + }, root: true, parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'prettier'], diff --git a/noir/.github/actions/setup/action.yml b/noir/.github/actions/setup/action.yml index 5efe115ddcf..8e24b6738a9 100644 --- a/noir/.github/actions/setup/action.yml +++ b/noir/.github/actions/setup/action.yml @@ -4,13 +4,13 @@ description: Installs the workspace's yarn dependencies and caches them runs: using: composite steps: - - name: Cache - uses: actions/cache@v3 - id: cache + - uses: actions/setup-node@v3 + id: node with: - path: "**/node_modules" - key: yarn-v1-${{ hashFiles('**/yarn.lock') }} + node-version: 18.17.1 + cache: 'yarn' + cache-dependency-path: 'yarn.lock' + - name: Install run: yarn --immutable shell: bash - if: steps.cache.outputs.cache-hit != 'true' diff --git a/noir/.github/workflows/auto-pr-rebuild-script.yml b/noir/.github/workflows/auto-pr-rebuild-script.yml deleted file mode 100644 index 336f2288878..00000000000 --- a/noir/.github/workflows/auto-pr-rebuild-script.yml +++ /dev/null @@ -1,130 +0,0 @@ -name: Rebuild ACIR artifacts - -on: - pull_request: - push: - branches: - - master - -jobs: - check-artifacts-requested: - name: Check if artifacts should be published - runs-on: ubuntu-22.04 - outputs: - publish: ${{ steps.check.outputs.result }} - - steps: - - name: Check if artifacts should be published - id: check - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { REF_NAME } = process.env; - if (REF_NAME == "master") { - console.log(`publish = true`) - return true; - } - - const labels = context.payload.pull_request.labels.map(label => label.name); - const publish = labels.includes('publish-acir'); - - console.log(`publish = ${publish}`) - return publish; - result-encoding: string - env: - REF_NAME: ${{ github.ref_name }} - - build-nargo: - name: Build nargo binary - if: ${{ needs.check-artifacts-requested.outputs.publish == 'true' }} - runs-on: ubuntu-22.04 - needs: [check-artifacts-requested] - 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.71.1 - - - 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 - - auto-pr-rebuild-script: - name: Rebuild ACIR artifacts - needs: [build-nargo] - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Download nargo binary - uses: actions/download-artifact@v3 - with: - name: nargo - path: ./nargo - - - name: Add Nargo to $PATH - run: | - chmod +x ${{ github.workspace }}/nargo/nargo - echo "${{ github.workspace }}/nargo" >> $GITHUB_PATH - - - name: Set up Git user (Github Action) - run: | - git config --local user.name kevaundray - git config --local user.email kevtheappdev@gmail.com - - - name: Run rebuild script - working-directory: test_programs - run: | - chmod +x ./rebuild.sh - ./rebuild.sh - - - name: Upload ACIR artifacts - uses: actions/upload-artifact@v3 - with: - name: acir-artifacts - path: ./test_programs/acir_artifacts - retention-days: 10 - - - name: Check for changes in acir_artifacts directory - id: check_changes - if: ${{ github.ref_name }} == "master" - run: | - git diff --quiet test_programs/acir_artifacts/ || echo "::set-output name=changes::true" - - - name: Create or Update PR - if: steps.check_changes.outputs.changes == 'true' - uses: peter-evans/create-pull-request@v3 - with: - token: ${{ secrets.NOIR_REPO_TOKEN }} - commit-message: "chore: update acir artifacts" - title: "chore: Update ACIR artifacts" - body: "Automatic PR to update acir artifacts" - add-paths: test_programs/acir_artifacts/*.gz - labels: "auto-pr" - branch: "auto-pr-rebuild-script-branch" diff --git a/noir/.github/workflows/build-aztec-feature-flag.yml b/noir/.github/workflows/build-aztec-feature-flag.yml deleted file mode 100644 index bacf74ba7b1..00000000000 --- a/noir/.github/workflows/build-aztec-feature-flag.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Build with aztec feature flag - -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-aztec-feature-flag: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.runner }} - timeout-minutes: 30 - - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu - runner: ubuntu-latest - target: x86_64-unknown-linux-gnu - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup toolchain - uses: dtolnay/rust-toolchain@1.71.1 - with: - targets: ${{ matrix.target }} - - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.target }} - cache-on-failure: true - save-if: ${{ github.event_name != 'merge_group' }} - - - name: Build with feature flag - run: cargo build --features="noirc_driver/aztec" diff --git a/noir/.github/workflows/docs-new-version.yml b/noir/.github/workflows/docs-new-version.yml deleted file mode 100644 index 9b109e170bb..00000000000 --- a/noir/.github/workflows/docs-new-version.yml +++ /dev/null @@ -1,112 +0,0 @@ -name: Cut a new version of the docs - -on: - workflow_dispatch: - inputs: - tag: - description: The tag to build Docs for - required: false - -jobs: - publish-docs: - runs-on: ubuntu-latest - if: ${{ inputs.tag != '' }} - permissions: - pull-requests: write - contents: write - steps: - - name: Checkout sources - uses: actions/checkout@v4 - with: - ref: ${{ inputs.tag }} - - - name: Create new branch - run: | - git checkout -b new-docs-version-${{ github.event.inputs.tag }} - - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: '18' - - - 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 Yarn - run: npm install -g yarn - - - name: Install Yarn dependencies - run: yarn - - - 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: Build noir_js_types - run: yarn workspace @noir-lang/types build - - - name: Build barretenberg wrapper - run: yarn workspace @noir-lang/backend_barretenberg build - - - name: Run noir_js - run: | - yarn workspace @noir-lang/noir_js build - - - name: Build docs - run: - yarn workspace docs build - - - name: Cut a new version - working-directory: ./docs - run: yarn docusaurus docs:version ${{ inputs.tag }} - - - name: Remove pre-releases - id: get_version - run: | - cd docs && yarn setStable - - - name: Commit new documentation version - run: | - git config --local user.name 'signorecello' - git config --local user.email 'github@zepedro.me' - git add . - git commit -m "chore(docs): cut new docs version for tag ${{ github.event.inputs.tag }}" - - - name: Push changes to new branch - run: git push origin new-docs-version-${{ github.event.inputs.tag }} - - - name: Create Pull Request - run: | - gh pr create \ - --title "chore(docs): docs for ${{ github.event.inputs.tag }}" \ - --body "Updates documentation to new version for tag ${{ github.event.inputs.tag }}." \ - --base master \ - --head new-docs-version-${{ github.event.inputs.tag }} \ - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Build docs - run: yarn workspace docs build - - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v2.1 - with: - publish-dir: './docs/build' - production-branch: master - production-deploy: true - github-token: ${{ secrets.GITHUB_TOKEN }} - enable-github-deployment: false - deploy-message: "Deploy from GitHub Actions for tag ${{ inputs.tag }}" - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - timeout-minutes: 1 - diff --git a/noir/.github/workflows/docs-pr.yml b/noir/.github/workflows/docs-pr.yml index 2b304b72b6f..a16487a49ef 100644 --- a/noir/.github/workflows/docs-pr.yml +++ b/noir/.github/workflows/docs-pr.yml @@ -74,14 +74,7 @@ jobs: - name: Install Yarn dependencies uses: ./.github/actions/setup - - name: Remove pre-releases - working-directory: docs - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: yarn setStable - - name: Build docs - working-directory: docs run: yarn workspaces foreach -Rt run build diff --git a/noir/.github/workflows/docs-release.yml b/noir/.github/workflows/docs-release.yml deleted file mode 100644 index 4cd9d9998cb..00000000000 --- a/noir/.github/workflows/docs-release.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Rebuild docs with the latest release - -on: - release: - types: [released] - workflow_dispatch: - -jobs: - build_and_deploy: - runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: '18' - - - 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 dependencies - run: yarn - - - 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: Build noir_js_types - run: yarn workspace @noir-lang/types build - - - name: Build barretenberg wrapper - run: yarn workspace @noir-lang/backend_barretenberg build - - - name: Run noir_js - run: | - yarn workspace @noir-lang/noir_js build - - - name: Remove pre-releases - working-directory: docs - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: yarn setStable - - - name: Build docs - run: - yarn workspace docs build - - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v2.1 - with: - publish-dir: './docs/build' - production-branch: master - production-deploy: true - github-token: ${{ secrets.GITHUB_TOKEN }} - enable-github-deployment: false - deploy-message: "Deploy from GitHub Actions for release" - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - timeout-minutes: 1 diff --git a/noir/.github/workflows/publish-acvm.yml b/noir/.github/workflows/publish-acvm.yml index ded669f13d0..59a104e3f75 100644 --- a/noir/.github/workflows/publish-acvm.yml +++ b/noir/.github/workflows/publish-acvm.yml @@ -3,7 +3,7 @@ name: Publish ACVM crates on: workflow_dispatch: inputs: - acvm-ref: + noir-ref: description: The acvm reference to checkout required: true @@ -15,7 +15,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 with: - ref: ${{ inputs.acvm-ref }} + ref: ${{ inputs.noir-ref }} - name: Setup toolchain uses: dtolnay/rust-toolchain@1.71.1 @@ -51,12 +51,6 @@ jobs: 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 diff --git a/noir/.github/workflows/publish-docs.yml b/noir/.github/workflows/publish-docs.yml new file mode 100644 index 00000000000..4ef7dd89777 --- /dev/null +++ b/noir/.github/workflows/publish-docs.yml @@ -0,0 +1,57 @@ +name: Publish documentation + +on: + workflow_dispatch: + inputs: + noir-ref: + description: The noir reference to checkout + required: false + default: 'master' + +jobs: + publish-docs: + name: Publish docs + runs-on: ubuntu-latest + + steps: + - name: Checkout release branch + uses: actions/checkout@v4 + with: + ref: ${{ inputs.noir-ref }} + token: ${{ secrets.NOIR_RELEASES_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '18' + + - 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 Yarn dependencies + uses: ./.github/actions/setup + + - name: Build docs for deploying + working-directory: docs + run: + yarn workspaces foreach -Rt run build + + - name: Deploy to Netlify + uses: nwtgck/actions-netlify@v2.1 + with: + publish-dir: './docs/build' + production-branch: master + production-deploy: true + github-token: ${{ secrets.GITHUB_TOKEN }} + enable-github-deployment: false + deploy-message: "Deploy from GitHub Actions for tag ${{ inputs.noir-ref }}" + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + timeout-minutes: 1 diff --git a/noir/.github/workflows/publish-es-packages.yml b/noir/.github/workflows/publish-es-packages.yml index f421672c799..e360654b46a 100644 --- a/noir/.github/workflows/publish-es-packages.yml +++ b/noir/.github/workflows/publish-es-packages.yml @@ -30,11 +30,6 @@ jobs: nix-cache-name: "noir" cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} - - name: Enable aztec features - if: ${{ inputs.npm-tag == 'aztec' }} - run: | - echo $'\n'"default = [\"aztec\"]"$'\n' >> compiler/noirc_driver/Cargo.toml - - name: Build wasm package run: | nix build -L .#noir_wasm diff --git a/noir/.github/workflows/publish-nargo.yml b/noir/.github/workflows/publish-nargo.yml index 59d4fe4cc48..3bcc9a13570 100644 --- a/noir/.github/workflows/publish-nargo.yml +++ b/noir/.github/workflows/publish-nargo.yml @@ -30,6 +30,7 @@ jobs: strategy: matrix: target: [x86_64-apple-darwin, aarch64-apple-darwin] + timeout-minutes: 30 steps: - name: Checkout @@ -120,6 +121,7 @@ jobs: fail-fast: false matrix: target: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl] + timeout-minutes: 30 steps: - name: Checkout diff --git a/noir/.github/workflows/release.yml b/noir/.github/workflows/release.yml index 95da6792f04..3b2393eaa8f 100644 --- a/noir/.github/workflows/release.yml +++ b/noir/.github/workflows/release.yml @@ -11,6 +11,7 @@ jobs: outputs: release-pr: ${{ steps.release.outputs.pr }} tag-name: ${{ steps.release.outputs.tag_name }} + pending-release-semver: v${{ steps.release.outputs.major }}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}} runs-on: ubuntu-latest steps: - name: Run release-please @@ -20,8 +21,8 @@ jobs: token: ${{ secrets.NOIR_RELEASES_TOKEN }} command: manifest - update-lockfile: - name: Update lockfile + update-acvm-workspace-package-versions: + name: Update acvm workspace package versions needs: [release-please] if: ${{ needs.release-please.outputs.release-pr }} runs-on: ubuntu-latest @@ -35,9 +36,13 @@ jobs: - name: Setup toolchain uses: dtolnay/rust-toolchain@1.65.0 + - name: Update ACVM workspace root versions + run: | + ./scripts/update-acvm-workspace-versions.sh + - name: Update lockfile run: | - cargo update --workspace + cargo update --workspace - name: Configure git run: | @@ -46,8 +51,44 @@ jobs: - name: Commit updates run: | - git add Cargo.lock - git commit -m 'chore: Update lockfile' + git add . + git commit -m 'chore: Update root workspace acvm versions and lockfile' + git push + + update-docs: + name: Update docs + needs: [release-please, update-acvm-workspace-package-versions] + if: ${{ needs.release-please.outputs.release-pr }} + runs-on: ubuntu-latest + + steps: + - name: Checkout release branch + uses: actions/checkout@v4 + with: + ref: ${{ fromJSON(needs.release-please.outputs.release-pr).headBranchName }} + token: ${{ secrets.NOIR_RELEASES_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '18' + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Cut a new version + working-directory: ./docs + run: yarn docusaurus docs:version ${{ needs.release-please.outputs.pending-release-semver }} + + - name: Configure git + run: | + git config --local user.name 'kevaundray' + git config --local user.email 'kevtheappdev@gmail.com' + + - name: Commit new documentation version + run: | + git add . + git commit -m "chore(docs): cut new docs version for tag ${{ needs.release-please.outputs.pending-release-semver }}" git push build-binaries: @@ -78,19 +119,33 @@ jobs: ref: master token: ${{ secrets.NOIR_REPO_TOKEN }} inputs: '{ "noir-ref": "${{ needs.release-please.outputs.tag-name }}", "npm-tag": "latest" }' - publish-docs: name: Publish docs needs: [release-please] if: ${{ needs.release-please.outputs.tag-name }} runs-on: ubuntu-latest + steps: - - name: Dispatch to publish workflow + - name: Dispatch to publish-docs uses: benc-uk/workflow-dispatch@v1 with: - workflow: docs-new-version.yml - repo: noir-lang/noir + workflow: publish-docs.yml ref: master - token: ${{ secrets.GITHUB_TOKEN }} - inputs: '{ "tag": "${{ needs.release-please.outputs.tag-name }}"}' + token: ${{ secrets.NOIR_REPO_TOKEN }} + inputs: '{ "noir-ref": "${{ needs.release-please.outputs.tag-name }}" }' + + publish-acvm: + name: Publish acvm + needs: [release-please] + if: ${{ needs.release-please.outputs.tag-name }} + runs-on: ubuntu-latest + + steps: + - name: Dispatch to publish-acvm + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: publish-acvm.yml + ref: master + token: ${{ secrets.NOIR_REPO_TOKEN }} + inputs: '{ "noir-ref": "${{ needs.release-please.outputs.tag-name }}" }' diff --git a/noir/.github/workflows/test-cargo.yml b/noir/.github/workflows/test-cargo.yml new file mode 100644 index 00000000000..8d414daa75b --- /dev/null +++ b/noir/.github/workflows/test-cargo.yml @@ -0,0 +1,51 @@ +name: Test cargo + +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: + name: Test cargo + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Get current date + id: date + run: echo "date=$(date +'%Y.%m.%d.%H.%M')" >> $GITHUB_STATE + - name: prepare docker images tags + id: prep + run: | + REGISTRY="ghcr.io" + IMG="${REGISTRY}/${{ github.repository }}" + IMAGE=$(echo "$IMG" | tr '[:upper:]' '[:lower:]') + TAGS="${IMAGE}:${{ github.sha }}" + TAGS="${TAGS},${IMAGE}:latest,${IMAGE}:v${{ steps.date.outputs.date }}" + echo ::set-output name=tags::${TAGS} + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Test cargo + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.ci + tags: ${{ steps.prep.outputs.tags }} + target: test-cargo + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/noir/.github/workflows/test-js-packages.yml b/noir/.github/workflows/test-js-packages.yml index 9ac61f34203..a298d67a485 100644 --- a/noir/.github/workflows/test-js-packages.yml +++ b/noir/.github/workflows/test-js-packages.yml @@ -15,6 +15,7 @@ concurrency: jobs: build-nargo: runs-on: ubuntu-22.04 + timeout-minutes: 30 steps: - name: Checkout Noir repo @@ -47,6 +48,7 @@ jobs: build-noir-wasm: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout sources @@ -76,6 +78,8 @@ jobs: build-acvm-js: runs-on: ubuntu-latest + timeout-minutes: 30 + steps: - name: Checkout sources uses: actions/checkout@v4 @@ -103,6 +107,7 @@ jobs: build-noirc-abi: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout sources @@ -133,6 +138,7 @@ jobs: needs: [build-acvm-js] name: ACVM JS (Node.js) runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout sources @@ -154,6 +160,7 @@ jobs: needs: [build-acvm-js] name: ACVM JS (Browser) runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout sources @@ -180,6 +187,7 @@ jobs: needs: [build-noirc-abi] name: noirc_abi runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout sources @@ -265,27 +273,12 @@ jobs: yarn workspace @noir-lang/noir_js build yarn workspace @noir-lang/noir_js test - test-source-resolver: - name: source-resolver - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Yarn dependencies - uses: ./.github/actions/setup - - - name: Build @noir-lang/source-resolver - run: yarn workspace @noir-lang/source-resolver build - - - name: Run tests - run: yarn workspace @noir-lang/source-resolver test - test-noir-wasm: needs: [build-noir-wasm, build-nargo] name: noir_wasm runs-on: ubuntu-latest + timeout-minutes: 30 + steps: - name: Checkout sources uses: actions/checkout@v4 @@ -319,10 +312,6 @@ jobs: - name: Install Playwright uses: ./.github/actions/install-playwright - - name: Install dependencies - run: | - yarn workspace @noir-lang/source-resolver build - - name: Run node tests run: yarn workspace @noir-lang/noir_wasm test:node @@ -333,6 +322,8 @@ jobs: needs: [build-acvm-js, build-noirc-abi] name: noir_codegen runs-on: ubuntu-latest + timeout-minutes: 30 + steps: - name: Checkout uses: actions/checkout@v4 @@ -365,7 +356,8 @@ jobs: name: Integration Tests runs-on: ubuntu-latest needs: [build-acvm-js, build-noir-wasm, build-nargo, build-noirc-abi] - + timeout-minutes: 30 + steps: - name: Checkout uses: actions/checkout@v4 @@ -411,29 +403,38 @@ jobs: - name: Setup `integration-tests` run: | # Note the lack of spaces between package names. - PACKAGES_TO_BUILD="@noir-lang/source-resolver,@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js" - yarn workspaces foreach -vp --from "{$PACKAGES_TO_BUILD}" run build + PACKAGES_TO_BUILD="@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js" + yarn workspaces foreach -vtp --from "{$PACKAGES_TO_BUILD}" run build - name: Run `integration-tests` run: | yarn test:integration - # This is a noop job which depends on all test jobs + # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. tests-end: name: End runs-on: ubuntu-latest + # We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping. + if: ${{ always() }} needs: - test-acvm_js-node - test-acvm_js-browser - test-noirc-abi - test-noir-js-backend-barretenberg - test-noir-js - - test-source-resolver - test-noir-wasm - test-noir-codegen - test-integration steps: - - name: Noop - run: echo "noop" + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + env: + # We treat any skipped or failing jobs as a failure for the workflow as a whole. + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') }} diff --git a/noir/.gitignore b/noir/.gitignore index 11f0ae3b975..8d02d34d463 100644 --- a/noir/.gitignore +++ b/noir/.gitignore @@ -14,11 +14,6 @@ pkg/ !.yarn/sdks !.yarn/versions -# Source resolver -compiler/source-resolver/node_modules -compiler/source-resolver/lib -compiler/source-resolver/lib-node - # Noir.js tooling/noir_js/lib diff --git a/noir/.gitrepo b/noir/.gitrepo index aad24b3ab70..f63e0726b19 100644 --- a/noir/.gitrepo +++ b/noir/.gitrepo @@ -5,8 +5,8 @@ ; [subrepo] remote = https://github.com/noir-lang/noir - branch = aztec - commit = 454b140cfa276656ed9b8900a05771d5f48d052c + branch = aztec-packages + commit = d788414744ffc5767de22cca4196cda711138afe parent = 8a4db03077a16443b7dd0fb25916cbc8ee8c38c9 method = merge cmdver = 0.4.6 diff --git a/noir/.prettierrc b/noir/.prettierrc index ef937f9697a..052c0657b3b 100644 --- a/noir/.prettierrc +++ b/noir/.prettierrc @@ -3,4 +3,4 @@ "printWidth": 120, "singleQuote": true, "trailingComma": "all" -} \ No newline at end of file +} diff --git a/noir/.release-please-manifest.json b/noir/.release-please-manifest.json index 8a6f95c33e0..01f6fb140b1 100644 --- a/noir/.release-please-manifest.json +++ b/noir/.release-please-manifest.json @@ -1,4 +1,4 @@ { - ".": "0.19.4", - "acvm-repo": "0.35.0" + ".": "0.22.0", + "acvm-repo": "0.38.0" } \ No newline at end of file diff --git a/noir/CHANGELOG.md b/noir/CHANGELOG.md index 077c9973806..0f3f6b02245 100644 --- a/noir/CHANGELOG.md +++ b/noir/CHANGELOG.md @@ -1,5 +1,343 @@ # Changelog +## [0.22.0](https://github.com/noir-lang/noir/compare/v0.21.0...v0.22.0) (2023-12-18) + + +### ⚠ BREAKING CHANGES + +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) +* Remove backend field from artifacts ([#3819](https://github.com/noir-lang/noir/issues/3819)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) + +### Features + +* Add context-centric based API for noir_wasm ([#3798](https://github.com/noir-lang/noir/issues/3798)) ([19155d0](https://github.com/noir-lang/noir/commit/19155d02a1248c85e94f14a2a0bb383a4edeb16f)) + + +### Miscellaneous Chores + +* Remove backend field from artifacts ([#3819](https://github.com/noir-lang/noir/issues/3819)) ([fa1cf5f](https://github.com/noir-lang/noir/commit/fa1cf5f03aa21b001c31ebb9ce405e3c2859bb57)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) ([0383100](https://github.com/noir-lang/noir/commit/0383100853a80a5b28b797cdfeae0d271f1b7805)) +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) ([9e5d0e8](https://github.com/noir-lang/noir/commit/9e5d0e813d61a0bfb5ee68174ed287c5a20f1579)) + +## [0.21.0](https://github.com/noir-lang/noir/compare/v0.20.0...v0.21.0) (2023-12-15) + + +### ⚠ BREAKING CHANGES + +* remove unused `source-resolver` package ([#3791](https://github.com/noir-lang/noir/issues/3791)) +* Make file manager read-only to the compiler ([#3760](https://github.com/noir-lang/noir/issues/3760)) + +### Features + +* Add `prelude.nr` ([#3693](https://github.com/noir-lang/noir/issues/3693)) ([5f0f81f](https://github.com/noir-lang/noir/commit/5f0f81f7f49b021880e0bff648aa6c6d0fede46c)) +* Add some traits to the stdlib ([#3796](https://github.com/noir-lang/noir/issues/3796)) ([8e11352](https://github.com/noir-lang/noir/commit/8e113526a2d78d27ed4e489f16d5604a2aaa18ea)) +* Add support for writing tracing debug info to file ([#3790](https://github.com/noir-lang/noir/issues/3790)) ([98a5004](https://github.com/noir-lang/noir/commit/98a500436a68652a367ccbf77e32f8544aff73bc)) +* Allow passing custom foreign call handlers when creating proofs in NoirJS ([#3764](https://github.com/noir-lang/noir/issues/3764)) ([6076e08](https://github.com/noir-lang/noir/commit/6076e08a0814bb6f3836af3c65a7b40c066b9494)) +* Allow underscores in integer literals ([#3746](https://github.com/noir-lang/noir/issues/3746)) ([2c06a64](https://github.com/noir-lang/noir/commit/2c06a64e502bac6839375c5636d39a172a609a5f)) +* Avoid overflow checks on boolean multiplication ([#3745](https://github.com/noir-lang/noir/issues/3745)) ([9b5b686](https://github.com/noir-lang/noir/commit/9b5b6861c3aa0e154e17598ac9994d3970f0e752)) +* Aztec-packages ([#3754](https://github.com/noir-lang/noir/issues/3754)) ([c043265](https://github.com/noir-lang/noir/commit/c043265e550b59bd4296504826fe15d3ce3e9ad2)) +* Dockerfile to test cargo and JS packages ([#3684](https://github.com/noir-lang/noir/issues/3684)) ([513d619](https://github.com/noir-lang/noir/commit/513d6196a0766082a3c88a4050498bae2cfa7e13)) +* Docs landing page with a playground ([#3667](https://github.com/noir-lang/noir/issues/3667)) ([9a95fbe](https://github.com/noir-lang/noir/commit/9a95fbeefb2ecd5a898006530a1e054cd345bfe8)) +* Enhance test information output ([#3696](https://github.com/noir-lang/noir/issues/3696)) ([468fbbc](https://github.com/noir-lang/noir/commit/468fbbca43e33b23bc662bf1d36dcb79830a291c)) +* Implement print without newline ([#3650](https://github.com/noir-lang/noir/issues/3650)) ([9827dfe](https://github.com/noir-lang/noir/commit/9827dfe51118ba55da6da51ab8bf45cffd2ca756)) +* **lsp:** Add goto definition for locals ([#3705](https://github.com/noir-lang/noir/issues/3705)) ([9dd465c](https://github.com/noir-lang/noir/commit/9dd465c23e286481fa9a35632d133901f86d5883)) +* **lsp:** Add goto definition for structs ([#3718](https://github.com/noir-lang/noir/issues/3718)) ([a576c5b](https://github.com/noir-lang/noir/commit/a576c5bba6ab92eb4798715a43475808ac954fba)) +* Optimize out unnecessary truncation instructions ([#3717](https://github.com/noir-lang/noir/issues/3717)) ([c9c72ae](https://github.com/noir-lang/noir/commit/c9c72ae7b80aa9504a082dd083b19d4b80d954c5)) +* Remove experimental feature warning for traits ([#3783](https://github.com/noir-lang/noir/issues/3783)) ([cb52242](https://github.com/noir-lang/noir/commit/cb522429592477c2b0544f3b3026a1a946b0e5b1)) +* Reorganizing docs to fit diataxis framework ([#3711](https://github.com/noir-lang/noir/issues/3711)) ([54a1ed5](https://github.com/noir-lang/noir/commit/54a1ed58c991eefa7ac9304b894c7046c294487b)) +* Simplify explicit equality assertions to assert equality directly ([#3708](https://github.com/noir-lang/noir/issues/3708)) ([2fc46e2](https://github.com/noir-lang/noir/commit/2fc46e2269bba8d9ad6ae5fcea10e64dce9b3745)) +* Speed up transformation of debug messages ([#3815](https://github.com/noir-lang/noir/issues/3815)) ([2a8af1e](https://github.com/noir-lang/noir/commit/2a8af1e4141ffff61547ee1c2837a6392bd5db48)) + + +### Bug Fixes + +* `try_unify` no longer binds types on failure ([#3697](https://github.com/noir-lang/noir/issues/3697)) ([f03e581](https://github.com/noir-lang/noir/commit/f03e5812439bdf9d1aedc69debdc50ba5dba2049)) +* Add missing assertion to test ([#3765](https://github.com/noir-lang/noir/issues/3765)) ([bcbe116](https://github.com/noir-lang/noir/commit/bcbe11613b7205476a49ad0d588b868b4fc43ba1)) +* Add negative integer literals ([#3690](https://github.com/noir-lang/noir/issues/3690)) ([8b3a68f](https://github.com/noir-lang/noir/commit/8b3a68f5286c09e1f612dbcfff3fe41023ab7109)) +* Allow trait method references from the trait name ([#3774](https://github.com/noir-lang/noir/issues/3774)) ([cfa34d4](https://github.com/noir-lang/noir/commit/cfa34d4d913dbd35f8329430e0d58830e069d6ff)) +* Deserialize odd length hex literals ([#3747](https://github.com/noir-lang/noir/issues/3747)) ([4000fb2](https://github.com/noir-lang/noir/commit/4000fb279221eb07187d657bfaa7f1c7b311abf2)) +* **docs:** Trigger `update-docs` workflow when the `release-please` PR gets merged and not on every merge to master ([#3677](https://github.com/noir-lang/noir/issues/3677)) ([9a3d1d2](https://github.com/noir-lang/noir/commit/9a3d1d2cf647cd583344f8da122fed1acbca9397)) +* Initialise strings as u8 array ([#3682](https://github.com/noir-lang/noir/issues/3682)) ([8da40b7](https://github.com/noir-lang/noir/commit/8da40b75a36ebac51d5377311db3c55fa339dcac)) +* **lsp:** Package resolution on save ([#3794](https://github.com/noir-lang/noir/issues/3794)) ([14f2fff](https://github.com/noir-lang/noir/commit/14f2fffeb3de5f653c11694ee3c5e5d62aaa34ec)) +* Parse negative integer literals ([#3698](https://github.com/noir-lang/noir/issues/3698)) ([463ab06](https://github.com/noir-lang/noir/commit/463ab060075db1915127c3f6cef11bfed9d40109)) +* Pub is required on return for entry points ([#3616](https://github.com/noir-lang/noir/issues/3616)) ([7f1d796](https://github.com/noir-lang/noir/commit/7f1d7968368734e02b152e2e907dc7af9e1604c8)) +* Remove `noirc_driver/aztec` feature flag in docker ([#3784](https://github.com/noir-lang/noir/issues/3784)) ([a48d562](https://github.com/noir-lang/noir/commit/a48d562b59aa2009a9c9b65dd71e11cdd8d06cf0)) +* Remove include-keys option ([#3692](https://github.com/noir-lang/noir/issues/3692)) ([95d7ce2](https://github.com/noir-lang/noir/commit/95d7ce21016e3603bf279efb970536ad32d89a3a)) +* Revert chnage to modify version in workspace file for acvm dependencies ([#3673](https://github.com/noir-lang/noir/issues/3673)) ([0696f75](https://github.com/noir-lang/noir/commit/0696f755364293bcc7ebc7a0def0dcafede2e543)) +* Sequence update-lockfile workflow so it gets modified after the ACVM version in the root has been changed ([#3676](https://github.com/noir-lang/noir/issues/3676)) ([c00cd85](https://github.com/noir-lang/noir/commit/c00cd8537836f8e4d8559b01d16dfdd1b5cad519)) +* **ssa:** Handle array arguments to side effectual constrain statements ([#3740](https://github.com/noir-lang/noir/issues/3740)) ([028d65e](https://github.com/noir-lang/noir/commit/028d65ea71f9c11e69784d06e0f9768668455f83)) +* Stop cloning Traits! ([#3736](https://github.com/noir-lang/noir/issues/3736)) ([fcff412](https://github.com/noir-lang/noir/commit/fcff412bb39a04a5c88506ae5a5ee2fbdefd93ef)) +* Stop issuing unused variable warnings for variables in trait definitions ([#3797](https://github.com/noir-lang/noir/issues/3797)) ([0bb44c3](https://github.com/noir-lang/noir/commit/0bb44c3bbc63d385d77d93da6abd07214bcfd700)) +* Unsigned integers cannot be negated ([#3688](https://github.com/noir-lang/noir/issues/3688)) ([f904ae1](https://github.com/noir-lang/noir/commit/f904ae1065af74652b2111ea17b72f994de37472)) + + +### Miscellaneous Chores + +* Make file manager read-only to the compiler ([#3760](https://github.com/noir-lang/noir/issues/3760)) ([e3dcc21](https://github.com/noir-lang/noir/commit/e3dcc21cb2c0fef7f28f50b018747c4f09609b11)) +* Remove unused `source-resolver` package ([#3791](https://github.com/noir-lang/noir/issues/3791)) ([57d2505](https://github.com/noir-lang/noir/commit/57d2505d53e2233becd1e2a7de882c4acb518eff)) + +## [0.20.0](https://github.com/noir-lang/noir/compare/v0.19.5...v0.20.0) (2023-12-01) + + +### ⚠ BREAKING CHANGES + +* avoid integer overflows ([#2713](https://github.com/noir-lang/noir/issues/2713)) +* return Pedersen structure in stdlib ([#3190](https://github.com/noir-lang/noir/issues/3190)) +* noir-wasm outputs debug symbols ([#3317](https://github.com/noir-lang/noir/issues/3317)) +* move mimc to hash submodule ([#3361](https://github.com/noir-lang/noir/issues/3361)) +* bump MSRV to 1.71.1 ([#3353](https://github.com/noir-lang/noir/issues/3353)) +* Add semver checks for the compiler version in Nargo.toml ([#3336](https://github.com/noir-lang/noir/issues/3336)) +* Move circuit serialization circuit into acir ([#3345](https://github.com/noir-lang/noir/issues/3345)) +* change stdlib function `pedersen` to `pedersen_commitment` ([#3341](https://github.com/noir-lang/noir/issues/3341)) +* expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) +* Make for loops a statement ([#2975](https://github.com/noir-lang/noir/issues/2975)) +* **traits:** trait functions with a default implementation must not be followed by a semicolon ([#2987](https://github.com/noir-lang/noir/issues/2987)) +* **wasm:** improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) +* **wasm:** update wasm artifacts to match cli artifacts ([#2973](https://github.com/noir-lang/noir/issues/2973)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) +* update to `bb` version 0.7.3 ([#2729](https://github.com/noir-lang/noir/issues/2729)) +* **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 + +* `compute_note_hash_and_nullifier` check ([#3216](https://github.com/noir-lang/noir/issues/3216)) ([4963c6c](https://github.com/noir-lang/noir/commit/4963c6c024bba710dd8907147f631f5c26094f0a)) +* **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)) +* **abi:** Tuples as inputs/outputs to main ([#2899](https://github.com/noir-lang/noir/issues/2899)) ([d8bd78f](https://github.com/noir-lang/noir/commit/d8bd78f60c447bb8488a844d779e8aaf4150afe7)) +* **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)) +* **acir:** Handle dynamic array operations for nested slices ([#3187](https://github.com/noir-lang/noir/issues/3187)) ([e026319](https://github.com/noir-lang/noir/commit/e026319fc25763d30781b90e6a4454ddb5d3bc7b)) +* **acir:** Set dynamic array values ([#3054](https://github.com/noir-lang/noir/issues/3054)) ([e871866](https://github.com/noir-lang/noir/commit/e871866d2203f0f0f49f3b273d99d385b950b65f)) +* **acvm_js:** Export black box solver functions ([#2812](https://github.com/noir-lang/noir/issues/2812)) ([da8a98e](https://github.com/noir-lang/noir/commit/da8a98ed312fe69cb0bdb8f9d0a70ee7a981398f)) +* **acvm:** Separate ACVM optimizations and transformations ([#2979](https://github.com/noir-lang/noir/issues/2979)) ([5865d1a](https://github.com/noir-lang/noir/commit/5865d1a1bca16e1853663c71f893ff81fa3f7185)) +* Add --check option to nargo fmt for dry-run formatting verification ([#3530](https://github.com/noir-lang/noir/issues/3530)) ([4469707](https://github.com/noir-lang/noir/commit/4469707d97085fab0f7ade8d015dc827c56156ee)) +* Add `destroy` method to `Noir` ([#3105](https://github.com/noir-lang/noir/issues/3105)) ([7e40274](https://github.com/noir-lang/noir/commit/7e402744a7d64ffcac6db026cec1631230204f0f)) +* Add `execute` method to `Noir` class ([#3081](https://github.com/noir-lang/noir/issues/3081)) ([17bdd7e](https://github.com/noir-lang/noir/commit/17bdd7e3909f0ddd195e5cb7095cd0d30758ed43)) +* Add `FieldElement::from<usize>` implementation ([#3647](https://github.com/noir-lang/noir/issues/3647)) ([8b7c5aa](https://github.com/noir-lang/noir/commit/8b7c5aa5311f4e6811438f67bd552b641b13fc9a)) +* Add `noir_codegen` package ([#3392](https://github.com/noir-lang/noir/issues/3392)) ([6c4cd4d](https://github.com/noir-lang/noir/commit/6c4cd4d37e4af38dccf899bcbd3950d1e236b35d)) +* Add ACIR serializer C++ codegen ([#2961](https://github.com/noir-lang/noir/issues/2961)) ([7556982](https://github.com/noir-lang/noir/commit/7556982dbebe25eaa17240abbe270b771b55de45)) +* Add an options object to `BarretenbergBackend` constructor ([#3105](https://github.com/noir-lang/noir/issues/3105)) ([7e40274](https://github.com/noir-lang/noir/commit/7e402744a7d64ffcac6db026cec1631230204f0f)) +* Add aztec selectors for event structs ([#2983](https://github.com/noir-lang/noir/issues/2983)) ([982380e](https://github.com/noir-lang/noir/commit/982380e54bb4d696688522c540f1234734ae2e80)) +* Add bb interface implementation ([#2902](https://github.com/noir-lang/noir/issues/2902)) ([fe92dc0](https://github.com/noir-lang/noir/commit/fe92dc0df57b2cbc0e7b8cd1f3a91cba6b0f3049)) +* Add check for overlapping generic traits ([#3307](https://github.com/noir-lang/noir/issues/3307)) ([8cf81b6](https://github.com/noir-lang/noir/commit/8cf81b659bed9522aede29c1ebb4a4ed2bfa1205)) +* Add conditional compilation of methods based on the underlying field being used ([#3045](https://github.com/noir-lang/noir/issues/3045)) ([2e008e2](https://github.com/noir-lang/noir/commit/2e008e2438795bbc41b0641e830378b76bf2e194)) +* Add crate for pub modifier ([#3271](https://github.com/noir-lang/noir/issues/3271)) ([e7a1a1a](https://github.com/noir-lang/noir/commit/e7a1a1a4b42b6b72c16f2204e33af80dbabba6b5)) +* Add debugger commands to introspect (and modify) the current state ([#3391](https://github.com/noir-lang/noir/issues/3391)) ([9e1ad85](https://github.com/noir-lang/noir/commit/9e1ad858cf8a1d9aba0137abe6a749267498bfaf)) +* Add experimental REPL-based debugger ([#2995](https://github.com/noir-lang/noir/issues/2995)) ([281c696](https://github.com/noir-lang/noir/commit/281c696da61c64b42b9525b8756ffc195f70d775)) +* Add exports of JS black box solvers to noirJS ([#3295](https://github.com/noir-lang/noir/issues/3295)) ([8369871](https://github.com/noir-lang/noir/commit/836987150f82354d3dfc01cfaad69f70240ca80c)) +* Add generic count check for trait methods ([#3382](https://github.com/noir-lang/noir/issues/3382)) ([a9f9717](https://github.com/noir-lang/noir/commit/a9f9717ba69c0dd8e4fc7045fe6aea2077b84c95)) +* Add JS types for ABI and input maps ([#3023](https://github.com/noir-lang/noir/issues/3023)) ([599e7a1](https://github.com/noir-lang/noir/commit/599e7a1d6bae5d93273e9ef1265024eac909660d)) +* Add LSP command to profile opcodes in vscode ([#3496](https://github.com/noir-lang/noir/issues/3496)) ([6fbf77a](https://github.com/noir-lang/noir/commit/6fbf77ae2b87a55db92344f5066a82ccaf6c2086)) +* Add lsp formatting ([#3433](https://github.com/noir-lang/noir/issues/3433)) ([286c876](https://github.com/noir-lang/noir/commit/286c87694fda185f25b05cec5504142643bc207f)) +* Add noir types package ([#2893](https://github.com/noir-lang/noir/issues/2893)) ([e8fc868](https://github.com/noir-lang/noir/commit/e8fc8687e6dd89295fd023201443f1197963a243)) +* Add package version to Nargo.toml metadata ([#3427](https://github.com/noir-lang/noir/issues/3427)) ([9e1717c](https://github.com/noir-lang/noir/commit/9e1717c2d96a0b9e394e5cb2fb9e1d09b5259ca0)) +* Add profile info print out ([#3425](https://github.com/noir-lang/noir/issues/3425)) ([a8b5fa8](https://github.com/noir-lang/noir/commit/a8b5fa8e30dc27e64666381b7451569f350967d1)) +* Add semver checks for the compiler version in Nargo.toml ([#3336](https://github.com/noir-lang/noir/issues/3336)) ([0e530cf](https://github.com/noir-lang/noir/commit/0e530cfe86f87a532be30a02f4353d010e47e458)) +* Add special case for boolean AND in acir-gen ([#3615](https://github.com/noir-lang/noir/issues/3615)) ([824039b](https://github.com/noir-lang/noir/commit/824039bcc0a3275f333ea94aecc701d129f99fe5)) +* Add support for tuple values in `noir_codegen` ([#3592](https://github.com/noir-lang/noir/issues/3592)) ([346d75f](https://github.com/noir-lang/noir/commit/346d75f9dd9261996d4d7bb80eb7e4118e8f8ce2)) +* Allow a trait to be implemented multiple times for the same struct ([#3292](https://github.com/noir-lang/noir/issues/3292)) ([51831df](https://github.com/noir-lang/noir/commit/51831df68bc20460c6d05d55469002db06113925)) +* Allow providing custom foreign call executors to `execute_circuit` ([#3506](https://github.com/noir-lang/noir/issues/3506)) ([d27db33](https://github.com/noir-lang/noir/commit/d27db332f8c320ffd9b5520bebbd83ae09e31de7)) +* Allow traits to have generic functions ([#3365](https://github.com/noir-lang/noir/issues/3365)) ([0f9af65](https://github.com/noir-lang/noir/commit/0f9af652efc6b7628784a397a9df674eaa30de61)) +* Avoid integer overflows ([#2713](https://github.com/noir-lang/noir/issues/2713)) ([7d7d632](https://github.com/noir-lang/noir/commit/7d7d63291d712137f97e6d44a774acdf2bd20512)) +* Aztec-packages ([#3599](https://github.com/noir-lang/noir/issues/3599)) ([2cd6dc3](https://github.com/noir-lang/noir/commit/2cd6dc39e3a956aa5dff721d47aaf1921f98fded)) +* Aztec-packages ([#3626](https://github.com/noir-lang/noir/issues/3626)) ([e0a96ea](https://github.com/noir-lang/noir/commit/e0a96ea70b17c8c898dd72ac929f3969a4cec1d3)) +* Cache debug artifacts ([#3133](https://github.com/noir-lang/noir/issues/3133)) ([c5a6229](https://github.com/noir-lang/noir/commit/c5a622983e4049d82589f185be5e96c63ed6066d)) +* Check where clauses when searching for trait impls ([#3407](https://github.com/noir-lang/noir/issues/3407)) ([84c6604](https://github.com/noir-lang/noir/commit/84c6604397f262c09ba4bac157fead38b8280313)) +* Codegen typed interfaces for functions in `noir_codegen` ([#3533](https://github.com/noir-lang/noir/issues/3533)) ([290c463](https://github.com/noir-lang/noir/commit/290c463622a93a34293f73b5bf2aea7ade30a11c)) +* Compile without a backend ([#3437](https://github.com/noir-lang/noir/issues/3437)) ([d69cf5d](https://github.com/noir-lang/noir/commit/d69cf5debcc430bb019b6cc95774aac084776dda)) +* Complex slice inputs for dynamic slice builtins ([#3617](https://github.com/noir-lang/noir/issues/3617)) ([8b23b34](https://github.com/noir-lang/noir/commit/8b23b349ae15afa48f6cbe8962586bbe79e79890)) +* Contract events in artifacts ([#2873](https://github.com/noir-lang/noir/issues/2873)) ([4765c82](https://github.com/noir-lang/noir/commit/4765c8288c583a61a81ff97eea1ef49df13eeca0)) +* Copy on write optimization for brillig ([#3522](https://github.com/noir-lang/noir/issues/3522)) ([da29c02](https://github.com/noir-lang/noir/commit/da29c02327acb2f46f5a7a25c7404dfa44c82616)) +* Data bus ([#3508](https://github.com/noir-lang/noir/issues/3508)) ([6b0bdbc](https://github.com/noir-lang/noir/commit/6b0bdbced1bfe2c92e90dd7b70ca8f9e5ccb7c0d)) +* **debugger:** Highlight current src code loc ([#3174](https://github.com/noir-lang/noir/issues/3174)) ([6b87582](https://github.com/noir-lang/noir/commit/6b87582dfe872ad6c248cf9995d76b0ef1580625)) +* **debugger:** Print limited source code context ([#3217](https://github.com/noir-lang/noir/issues/3217)) ([dcda1c7](https://github.com/noir-lang/noir/commit/dcda1c7aed69ae8f55cd3f680e3cc1ece9de7541)) +* Default integers to u64 ([#2764](https://github.com/noir-lang/noir/issues/2764)) ([01cb041](https://github.com/noir-lang/noir/commit/01cb041a92ef6043dd5a160e0a56a63400801980)) +* Dynamic indexing of non-homogenous slices ([#2883](https://github.com/noir-lang/noir/issues/2883)) ([72c3661](https://github.com/noir-lang/noir/commit/72c3661c86712b99236eafaac99f76f13d42b9d9)) +* Enable the `fmt` command in the help menu ([#3328](https://github.com/noir-lang/noir/issues/3328)) ([63d414c](https://github.com/noir-lang/noir/commit/63d414c06a399525601e3db11dc48b180e93c2d8)) +* Expand trait impl overlap check to cover generic types ([#3320](https://github.com/noir-lang/noir/issues/3320)) ([a01549b](https://github.com/noir-lang/noir/commit/a01549b78a2c5de3e64ce5d3e5c4bb73a8c8b4fb)) +* Export `CompiledCircuit` from codegened TS ([#3589](https://github.com/noir-lang/noir/issues/3589)) ([e06c675](https://github.com/noir-lang/noir/commit/e06c67500da11518caffe0e98bdb9cd7f5f89049)) +* Expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) ([0108b6c](https://github.com/noir-lang/noir/commit/0108b6c1e8dc0dfc766ab3c4944deae9354dec36)) +* Extract Brillig VM to allow step debugging ([#3259](https://github.com/noir-lang/noir/issues/3259)) ([f6431f9](https://github.com/noir-lang/noir/commit/f6431f99711f15a96a4f7fed2f413daece94b5e1)) +* Format infix expressions ([#3001](https://github.com/noir-lang/noir/issues/3001)) ([7926ada](https://github.com/noir-lang/noir/commit/7926ada88ed08ac9d874604834533d900fbb16b0)) +* **formatter:** Add formatter support for array literals ([#3061](https://github.com/noir-lang/noir/issues/3061)) ([a535321](https://github.com/noir-lang/noir/commit/a5353217a1f49b83daf11d5fa55e0bcccebf0271)) +* Handle constant index operations on simple slices ([#3464](https://github.com/noir-lang/noir/issues/3464)) ([7ae12f8](https://github.com/noir-lang/noir/commit/7ae12f8c5243d31b2f410c246ed6b9e2fcea5d4c)) +* Handle warnings in evaluator ([#3205](https://github.com/noir-lang/noir/issues/3205)) ([5cfd156](https://github.com/noir-lang/noir/commit/5cfd156ca2035038a226bdd81a51636d3de3c34e)) +* Implement `bound_constraint_with_offset` in terms of `AcirVar`s ([#3233](https://github.com/noir-lang/noir/issues/3233)) ([8d89cb5](https://github.com/noir-lang/noir/commit/8d89cb59fe710859a96eaed4f988952bd727fb7d)) +* Implement automatic dereferencing for index expressions ([#3082](https://github.com/noir-lang/noir/issues/3082)) ([8221bfd](https://github.com/noir-lang/noir/commit/8221bfd2ffde7d1dbf71a72d95257acf76ecca74)) +* Implement automatic dereferencing for indexing lvalues ([#3083](https://github.com/noir-lang/noir/issues/3083)) ([6e2b70a](https://github.com/noir-lang/noir/commit/6e2b70ae90b686158957ea29ef1b2a5f0ed38e5f)) +* Implement euclidean division and signed division in terms of `AcirVar`s ([#3230](https://github.com/noir-lang/noir/issues/3230)) ([b8b7782](https://github.com/noir-lang/noir/commit/b8b77825410c0e1f95549259a51e2c40de1ec342)) +* Implement impl specialization ([#3087](https://github.com/noir-lang/noir/issues/3087)) ([44716fa](https://github.com/noir-lang/noir/commit/44716fae0bae0f78ceee76f7231af49c4abeace1)) +* Implement integer printing ([#3577](https://github.com/noir-lang/noir/issues/3577)) ([6601408](https://github.com/noir-lang/noir/commit/6601408e378b2afe4fdfd8e04482c39311ccc7e9)) +* Implement raw string literals ([#3556](https://github.com/noir-lang/noir/issues/3556)) ([87a302f](https://github.com/noir-lang/noir/commit/87a302fbc26d5fd42694953935d95a7ccb3d50a0)) +* Implement string escape sequences ([#2803](https://github.com/noir-lang/noir/issues/2803)) ([f7529b8](https://github.com/noir-lang/noir/commit/f7529b80f0958fd47a525f25a123f16438bbb892)) +* Implement where clauses on impls ([#3324](https://github.com/noir-lang/noir/issues/3324)) ([4c3d1de](https://github.com/noir-lang/noir/commit/4c3d1dea27726133335538443df3dbbd2c8f2d58)) +* **lsp:** Add "info" codelens ([#2982](https://github.com/noir-lang/noir/issues/2982)) ([80770d9](https://github.com/noir-lang/noir/commit/80770d9fae7c42e69a62cf01babfc69449600ac5)) +* **lsp:** Add goto definition for functions ([#3656](https://github.com/noir-lang/noir/issues/3656)) ([7bb7356](https://github.com/noir-lang/noir/commit/7bb735662c86e6533ac58f448ad748e34f02edb7)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) ([f7869e6](https://github.com/noir-lang/noir/commit/f7869e6fb492b617e776e538ac4babfa56261d26)) +* Make generic impls callable ([#3297](https://github.com/noir-lang/noir/issues/3297)) ([8d9b738](https://github.com/noir-lang/noir/commit/8d9b738ea958320a16946ebe6fcfb6bbf2dda42e)) +* Manage breakpoints and allow restarting a debugging session ([#3325](https://github.com/noir-lang/noir/issues/3325)) ([f502108](https://github.com/noir-lang/noir/commit/f502108a59e2141f4898b0a25e84d7ed7d2bff58)) +* Nargo test runtime callstacks and assert messages without string matching ([#2953](https://github.com/noir-lang/noir/issues/2953)) ([1b6a4e6](https://github.com/noir-lang/noir/commit/1b6a4e6021929c23a1bca5dff02c004422cc71f8)) +* **noir_js:** Allow providing foreign call handlers in noirJS ([#3294](https://github.com/noir-lang/noir/issues/3294)) ([c76b0f8](https://github.com/noir-lang/noir/commit/c76b0f81b89ae02c39c13c3bd400b5d13f083759)) +* Noir-wasm outputs debug symbols ([#3317](https://github.com/noir-lang/noir/issues/3317)) ([f9933fa](https://github.com/noir-lang/noir/commit/f9933fa50c42aade8ddc13d29deef7645ddcf586)) +* Noir-wasm takes dependency graph ([#3213](https://github.com/noir-lang/noir/issues/3213)) ([a2c8ebd](https://github.com/noir-lang/noir/commit/a2c8ebd4a800d7ef042ac9cbe5ee6a837c715634)) +* Old docs issues ([#3195](https://github.com/noir-lang/noir/issues/3195)) ([26746c5](https://github.com/noir-lang/noir/commit/26746c59e12a60f3869a5b885b05926c94f01215)) +* Optimize euclidean division acir-gen ([#3121](https://github.com/noir-lang/noir/issues/3121)) ([2c175c0](https://github.com/noir-lang/noir/commit/2c175c0d886eea390ef97ada1c2a5b0e1bef15e8)) +* Oracle mocker for nargo test ([#2928](https://github.com/noir-lang/noir/issues/2928)) ([0dd1e77](https://github.com/noir-lang/noir/commit/0dd1e77c0e625805e15fa56b4738c93ebae19b6d)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) ([b3a9c34](https://github.com/noir-lang/noir/commit/b3a9c343993ce3207de62106bda6cb2b2ef3de50)) +* Pass brillig bytecode to VM by reference ([#3030](https://github.com/noir-lang/noir/issues/3030)) ([4ee290b](https://github.com/noir-lang/noir/commit/4ee290b8b6f75bc1974a5750248570eeca8d244e)) +* Perform compile-time euclidean division on constants ([#3231](https://github.com/noir-lang/noir/issues/3231)) ([3866d7e](https://github.com/noir-lang/noir/commit/3866d7ea32dcdabbdb5ba85478d97fd51a6850f3)) +* Prevent unnecessary witness creation in euclidean division ([#2980](https://github.com/noir-lang/noir/issues/2980)) ([c6f660e](https://github.com/noir-lang/noir/commit/c6f660e86d40a106930483f1d6161814e3c0de10)) +* Properly track equivalence of witnesses generated for black box functions ([#3428](https://github.com/noir-lang/noir/issues/3428)) ([20b70c2](https://github.com/noir-lang/noir/commit/20b70c29b4bd323d67ef56ab1933341a7747d3cb)) +* Provide formatting subcommand ([#2640](https://github.com/noir-lang/noir/issues/2640)) ([a38b15f](https://github.com/noir-lang/noir/commit/a38b15f5d8e69faff125d363f2fd1f2f90ae6830)) +* Publish aztec build of noir_wasm ([#3049](https://github.com/noir-lang/noir/issues/3049)) ([3b51f4d](https://github.com/noir-lang/noir/commit/3b51f4df7e808233f6987baec93f4b5de7e5b304)) +* Refactor debugger and separate core from UI ([#3308](https://github.com/noir-lang/noir/issues/3308)) ([8466810](https://github.com/noir-lang/noir/commit/846681079ab7295b201480a5c8baebc45e858c6f)) +* Remove redundant predicate from brillig quotients ([#2784](https://github.com/noir-lang/noir/issues/2784)) ([a8f18c5](https://github.com/noir-lang/noir/commit/a8f18c55b35f47c6fa3ebfebcd827aeb55e5c850)) +* Remove type arrays for flat slices ([#3466](https://github.com/noir-lang/noir/issues/3466)) ([8225b2b](https://github.com/noir-lang/noir/commit/8225b2b379ddf145f9418f8517478704f9aac350)) +* Remove unnecessary truncation of boolean multiplication ([#3122](https://github.com/noir-lang/noir/issues/3122)) ([39dbcf1](https://github.com/noir-lang/noir/commit/39dbcf1ab80d2bb472d08db4de15d4e0c1f2eb52)) +* Replace boolean range constraints with arithmetic opcodes ([#3234](https://github.com/noir-lang/noir/issues/3234)) ([949222c](https://github.com/noir-lang/noir/commit/949222c20d9e65152e3814d02da1c4c41ffc23a5)) +* Return compilation errors from noir_wasm ([#3091](https://github.com/noir-lang/noir/issues/3091)) ([55f63c9](https://github.com/noir-lang/noir/commit/55f63c935cec62fbba63eed421812a4372c1aa4d)) +* Return Pedersen structure in stdlib ([#3190](https://github.com/noir-lang/noir/issues/3190)) ([be30d59](https://github.com/noir-lang/noir/commit/be30d59e61a9dff6ab94ffb97365c1282c331643)) +* Reuse witnesses more when interacting with memory ([#3658](https://github.com/noir-lang/noir/issues/3658)) ([5a4a73d](https://github.com/noir-lang/noir/commit/5a4a73d24ddd7d2bb46c85714397ee6e031c97a6)) +* Reuse witnesses which have been assigned constant values during ACIR gen ([#3137](https://github.com/noir-lang/noir/issues/3137)) ([9eb43e2](https://github.com/noir-lang/noir/commit/9eb43e2a4665397295e74a593f73d19fa9fa5d27)) +* Save Brillig execution state in ACVM ([#3026](https://github.com/noir-lang/noir/issues/3026)) ([88682da](https://github.com/noir-lang/noir/commit/88682da87ffc9e26da5c9e4b5a4d8e62a6ee43c6)) +* Send and receive unflattened public inputs to backend ([#3543](https://github.com/noir-lang/noir/issues/3543)) ([a7bdc67](https://github.com/noir-lang/noir/commit/a7bdc67ef3ec2037bffc4f1f472907cad786c319)) +* Solve `fixed_base_scalar_mul` black box functions in rust ([#3153](https://github.com/noir-lang/noir/issues/3153)) ([1c1afbc](https://github.com/noir-lang/noir/commit/1c1afbcddf0b5fdb39f00ad28ae90caf699d1265)) +* **ssa:** Multiple slice mergers ([#2753](https://github.com/noir-lang/noir/issues/2753)) ([8f76fe5](https://github.com/noir-lang/noir/commit/8f76fe5819e95ed111587090e15add48a2b4e859)) +* **stdlib:** Optimize constraint counts in sha256/sha512 ([#3253](https://github.com/noir-lang/noir/issues/3253)) ([d3be552](https://github.com/noir-lang/noir/commit/d3be552149ab375b24b509603fcd7237b374ca5a)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) ([35fb3f7](https://github.com/noir-lang/noir/commit/35fb3f7076d52db7ca3bef0a70a3dbccaf82f58d)) +* **traits:** Add impl Trait as function return type [#2397](https://github.com/noir-lang/noir/issues/2397) ([#3176](https://github.com/noir-lang/noir/issues/3176)) ([4cb2024](https://github.com/noir-lang/noir/commit/4cb20244abba0abc49be0376611979a786563565)) +* **traits:** Add trait impl for buildin types ([#2964](https://github.com/noir-lang/noir/issues/2964)) ([2c87b27](https://github.com/noir-lang/noir/commit/2c87b273dfdf033dd8c79b78f006a0e9813559d7)) +* **traits:** Added checks for duplicated trait associated items (types, consts, functions) ([#2927](https://github.com/noir-lang/noir/issues/2927)) ([d49492c](https://github.com/noir-lang/noir/commit/d49492cd80d04ee6acc01247b06b088deefcd0c6)) +* **traits:** Allow multiple traits to share the same associated function name and to be implemented for the same type ([#3126](https://github.com/noir-lang/noir/issues/3126)) ([004f8dd](https://github.com/noir-lang/noir/commit/004f8dd733cb23da4ed57b160f6b86d53bc0b5f1)) +* **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)) +* **traits:** Improve support for traits static method resolution ([#2958](https://github.com/noir-lang/noir/issues/2958)) ([0d0d8f7](https://github.com/noir-lang/noir/commit/0d0d8f7d2b401eb6b534dbb175dfd4b26d2a5f7d)) +* **traits:** Multi module support for traits ([#2844](https://github.com/noir-lang/noir/issues/2844)) ([4deb07f](https://github.com/noir-lang/noir/commit/4deb07f80ce110187b66a46dd5624af3b8df3dbd)) +* Use ranges instead of a vector for input witness ([#3314](https://github.com/noir-lang/noir/issues/3314)) ([b12b7ec](https://github.com/noir-lang/noir/commit/b12b7ecb995988c731be5f1f2f67fda952f1a228)) +* **wasm:** Improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) ([1b5124b](https://github.com/noir-lang/noir/commit/1b5124bc74f7ac5360db04b34d1b7b2284061fd3)) +* **wasm:** Update wasm artifacts to match cli artifacts ([#2973](https://github.com/noir-lang/noir/issues/2973)) ([ce16c0b](https://github.com/noir-lang/noir/commit/ce16c0b14565cfe1bc2c9f09ae71643d2657440b)) + + +### Bug Fixes + +* "Missing trait impl" error in trait dispatch ([#3440](https://github.com/noir-lang/noir/issues/3440)) ([52daaec](https://github.com/noir-lang/noir/commit/52daaec504101fe3c0caa30441c17f30a34af475)) +* `compute_note_hash_and_nullifier` compiler check ([#3351](https://github.com/noir-lang/noir/issues/3351)) ([4e2d35f](https://github.com/noir-lang/noir/commit/4e2d35f256bea2fee3a6cbd7af0c0c15a37c0a2e)) +* **3275:** Activate brillig modulo test with negative integers ([#3318](https://github.com/noir-lang/noir/issues/3318)) ([31c493c](https://github.com/noir-lang/noir/commit/31c493ce2082a571d147f707837beb4f3ed2ca64)) +* **3300:** Cache warnings into debug artefacts ([#3313](https://github.com/noir-lang/noir/issues/3313)) ([cb5a15b](https://github.com/noir-lang/noir/commit/cb5a15b9dbcfdaac5d656a122c73dca23855307d)) +* ACIR optimizer should update assertion messages ([#3010](https://github.com/noir-lang/noir/issues/3010)) ([758b6b6](https://github.com/noir-lang/noir/commit/758b6b62918907c1a39f3090a77419003551745e)) +* **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)) +* Add `pub` modifier to grumpkin functions ([#3036](https://github.com/noir-lang/noir/issues/3036)) ([f8990d7](https://github.com/noir-lang/noir/commit/f8990d75b948ce0a6968db659370f7ece7f5db08)) +* Add compiler error message for invalid input types ([#3220](https://github.com/noir-lang/noir/issues/3220)) ([989e80d](https://github.com/noir-lang/noir/commit/989e80d4ea62e68cfab69a1cd16d481cbccc6c02)) +* Add size checks to integer literals ([#3236](https://github.com/noir-lang/noir/issues/3236)) ([7f8fe8c](https://github.com/noir-lang/noir/commit/7f8fe8c88eb2d26ae3a93e2f74430fadc74b4836)) +* Adding proving key initialization ([#3322](https://github.com/noir-lang/noir/issues/3322)) ([3383740](https://github.com/noir-lang/noir/commit/3383740f9a0004f2ee77c9686f81baed6cd1917c)) +* Allow `where` clause on all functions and improve error message ([#3465](https://github.com/noir-lang/noir/issues/3465)) ([1647e33](https://github.com/noir-lang/noir/commit/1647e33564bf56ab8721a365f5fc6bcb38901412)) +* Allow constructors in parentheses in `if` conditions and `for` ranges ([#3219](https://github.com/noir-lang/noir/issues/3219)) ([ad192d1](https://github.com/noir-lang/noir/commit/ad192d1b7492f6ecd5fc98bb88201d6c442dc052)) +* Allow two `TypeVariable::Constant(N)` to unify even if their constants are not equal ([#3225](https://github.com/noir-lang/noir/issues/3225)) ([cc4ca4b](https://github.com/noir-lang/noir/commit/cc4ca4bb5f4fed5f531a2040501fcc6ed53a9ab4)) +* Apply predicate to over/underflow checks ([#3494](https://github.com/noir-lang/noir/issues/3494)) ([fc3edf7](https://github.com/noir-lang/noir/commit/fc3edf7aa5da9074614fa900bbcb57e512e3d56b)) +* **aztec_nr:** Serialise arrays of structs ([#3401](https://github.com/noir-lang/noir/issues/3401)) ([e979a58](https://github.com/noir-lang/noir/commit/e979a587e755d4b715ebacba715d778938026ac0)) +* Change non-constant argument errors from `to_be_radix` from ICE to proper error ([#3048](https://github.com/noir-lang/noir/issues/3048)) ([19ce286](https://github.com/noir-lang/noir/commit/19ce28638fe3ea42ab4984cb99e3898cd17fa8d9)) +* Check for overflow with hexadecimal inputs ([#3004](https://github.com/noir-lang/noir/issues/3004)) ([db1e736](https://github.com/noir-lang/noir/commit/db1e736240c0b74f6f59504db5a50de1c749d395)) +* Compiler version error message ([#3558](https://github.com/noir-lang/noir/issues/3558)) ([026a358](https://github.com/noir-lang/noir/commit/026a3587b01ddc8f444ff588a7b3f3fd1a0bb386)) +* Complete debug metadata ([#3228](https://github.com/noir-lang/noir/issues/3228)) ([2f6509d](https://github.com/noir-lang/noir/commit/2f6509d2acdee5014d65efaca9e6a9e0df3ca160)) +* 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)) +* Corrected the formatting of error message parameters in index out of bounds error ([#3630](https://github.com/noir-lang/noir/issues/3630)) ([3bba386](https://github.com/noir-lang/noir/commit/3bba3862dc8703410681300be894bfd1ebca7336)) +* **debugger:** Step through foreign calls and breakpoints inside Brillig blocks ([#3511](https://github.com/noir-lang/noir/issues/3511)) ([5d77d7a](https://github.com/noir-lang/noir/commit/5d77d7ac82a4df6995ca151b2c8070044cb1fe9d)) +* Determinism of fallback transformer ([#3100](https://github.com/noir-lang/noir/issues/3100)) ([12daad1](https://github.com/noir-lang/noir/commit/12daad19c902caf5ee9e2eb4b6847bde5a924353)) +* Disable modulo for fields ([#3009](https://github.com/noir-lang/noir/issues/3009)) ([7e68976](https://github.com/noir-lang/noir/commit/7e689768f4af1188e01a1a300a0d2fa152cea504)) +* Disallow returning constant values ([#2978](https://github.com/noir-lang/noir/issues/2978)) ([79c2e88](https://github.com/noir-lang/noir/commit/79c2e88ebefe71ebc0fe457347570df31b24ac36)) +* Do not perform dead instruction elimination on mod,div unless rhs is constant ([#3141](https://github.com/noir-lang/noir/issues/3141)) ([af3d771](https://github.com/noir-lang/noir/commit/af3d77182054845303fa59de92d783453079a048)) +* Do not simply divisions ([#3664](https://github.com/noir-lang/noir/issues/3664)) ([e5b981b](https://github.com/noir-lang/noir/commit/e5b981b08c2b345f00426acafe47b76d5262254d)) +* Docker builds ([#3620](https://github.com/noir-lang/noir/issues/3620)) ([f3eac52](https://github.com/noir-lang/noir/commit/f3eac5282860c1954ea2cee6a21633df5b1865fd)) +* **docs:** Update `editUrl` path for docusaurus ([#3184](https://github.com/noir-lang/noir/issues/3184)) ([4646a93](https://github.com/noir-lang/noir/commit/4646a93f5e95604b5710353764b2c4295efaef6b)) +* Download expected `bb` version if installed backend has version mismatch ([#3150](https://github.com/noir-lang/noir/issues/3150)) ([3f03435](https://github.com/noir-lang/noir/commit/3f03435552fe75b5c7a49bfc8d63d06573381220)) +* 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)) +* Finer bit size in bound constrain ([#2869](https://github.com/noir-lang/noir/issues/2869)) ([68385e2](https://github.com/noir-lang/noir/commit/68385e294a1501b19b28f3f5510e973283ed0821)) +* Fix aztec library after nargo fmt ([#3014](https://github.com/noir-lang/noir/issues/3014)) ([f43083c](https://github.com/noir-lang/noir/commit/f43083c744ff13aefa4d294a090c9445a9b70aac)) +* Fix crash when using undeclared traits ([#3509](https://github.com/noir-lang/noir/issues/3509)) ([8bb095a](https://github.com/noir-lang/noir/commit/8bb095af77d3b4043855841f1ae5799d75ed94f0)) +* Fix lexer error formatting ([#3274](https://github.com/noir-lang/noir/issues/3274)) ([74bd517](https://github.com/noir-lang/noir/commit/74bd517fe7839465ff086ffe622462bed5159006)) +* Fix method `program_counter`, change method signature ([#3012](https://github.com/noir-lang/noir/issues/3012)) ([5ea522b](https://github.com/noir-lang/noir/commit/5ea522b840ca0f6f90d02ca00f0de32f515d450f)) +* 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 panic when using repeated arrays which define variables ([#3221](https://github.com/noir-lang/noir/issues/3221)) ([c4faf3a](https://github.com/noir-lang/noir/commit/c4faf3a0a40eea1ee02e11dfe08b48c6b4438bbf)) +* Fix should_fail_with ([#2940](https://github.com/noir-lang/noir/issues/2940)) ([4f07b84](https://github.com/noir-lang/noir/commit/4f07b84458dba97530d8179a3b9b19101b472616)) +* 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)) +* Fixing versioning workflow ([#3296](https://github.com/noir-lang/noir/issues/3296)) ([3d5e43a](https://github.com/noir-lang/noir/commit/3d5e43a4b8cd9d2bb67d44a2eff93374c3603e42)) +* Flatten public inputs according to their index in numerial rather than ascii order ([#3605](https://github.com/noir-lang/noir/issues/3605)) ([a1f6343](https://github.com/noir-lang/noir/commit/a1f6343b7df1b166b1be4db09527694a3df2738a)) +* Follow dependencies when looking for a struct ([#3405](https://github.com/noir-lang/noir/issues/3405)) ([561b1b8](https://github.com/noir-lang/noir/commit/561b1b8f0b22d8b1800cb3552942a442a27c2a2c)) +* Force recompilation when `output_debug` flag is set. ([#2898](https://github.com/noir-lang/noir/issues/2898)) ([9854416](https://github.com/noir-lang/noir/commit/9854416f5ac03c9da6538edc6a0a540ccccb4b61)) +* **frontend:** Error on unsupported integer annotation ([#2778](https://github.com/noir-lang/noir/issues/2778)) ([90c3d8b](https://github.com/noir-lang/noir/commit/90c3d8baa3b7ae10bc99f6a767121f556ff75967)) +* Impl methods are no longer placed in contracts ([#3255](https://github.com/noir-lang/noir/issues/3255)) ([b673b07](https://github.com/noir-lang/noir/commit/b673b071663d9756d6346954fce7d4ec6e1577dd)) +* Improve error message when multiplying unit values ([#2950](https://github.com/noir-lang/noir/issues/2950)) ([57b7c55](https://github.com/noir-lang/noir/commit/57b7c55e7005876dc2e070c64e1b8115ca8a4242)) +* Include .nr and .sol files in builds ([#3039](https://github.com/noir-lang/noir/issues/3039)) ([ae8d0e9](https://github.com/noir-lang/noir/commit/ae8d0e9013f26b52e8f0bdc9f84866ffec50872d)) +* 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)) +* Make for loops a statement ([#2975](https://github.com/noir-lang/noir/issues/2975)) ([0e266eb](https://github.com/noir-lang/noir/commit/0e266ebc7328866b0b10554e37c9d9012a7b501c)) +* Match rust behaviour for left-shift overflow ([#3518](https://github.com/noir-lang/noir/issues/3518)) ([2d7ceb1](https://github.com/noir-lang/noir/commit/2d7ceb17edda1d9e70901cfd13f45cdc0df0d28d)) +* Minor problems with `aztec` publishing ([#3095](https://github.com/noir-lang/noir/issues/3095)) ([0fc8f20](https://github.com/noir-lang/noir/commit/0fc8f20b8b87d033d27ce18db039399c17f81837)) +* Move mimc to hash submodule ([#3361](https://github.com/noir-lang/noir/issues/3361)) ([3ec29f1](https://github.com/noir-lang/noir/commit/3ec29f17464703716978daacfa9f00c4f5013551)) +* Overflow checks for constant folding ([#3420](https://github.com/noir-lang/noir/issues/3420)) ([b7a6383](https://github.com/noir-lang/noir/commit/b7a6383cf9dc3bc4a71b9644352340c1e9339c81)) +* Parse parenthesized lvalues ([#3058](https://github.com/noir-lang/noir/issues/3058)) ([50ca58c](https://github.com/noir-lang/noir/commit/50ca58c7b133f8b21091dfd304379429284b0d60)) +* Prevent duplicated assert message transformation ([#3038](https://github.com/noir-lang/noir/issues/3038)) ([082a6d0](https://github.com/noir-lang/noir/commit/082a6d02dad67a25692bed15c340a16a848a320e)) +* Prevent mutating immutable bindings to mutable types ([#3075](https://github.com/noir-lang/noir/issues/3075)) ([d5ee20e](https://github.com/noir-lang/noir/commit/d5ee20ea43ccf1130f7d34231562f13e98ea636b)) +* **println:** Enable printing of arrays/strings >2 in fmt strings ([#2947](https://github.com/noir-lang/noir/issues/2947)) ([309fa70](https://github.com/noir-lang/noir/commit/309fa70823535c5340f986a17f4ddddcb8723bb8)) +* Recompile artefacts from a different noir version ([#3248](https://github.com/noir-lang/noir/issues/3248)) ([7347b27](https://github.com/noir-lang/noir/commit/7347b2742a5ad38d3d252e657810d061bab83e24)) +* 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)) +* Remove quotes from println output ([#3574](https://github.com/noir-lang/noir/issues/3574)) ([127b6aa](https://github.com/noir-lang/noir/commit/127b6aa1ec8893275fdfa7795db7c52c4fc1d4dd)) +* Remove sha2_block test ([#3360](https://github.com/noir-lang/noir/issues/3360)) ([a48c03b](https://github.com/noir-lang/noir/commit/a48c03bec786d1fb85eef46eeddeccf29e81fe76)) +* Restrict fill_internal_slices pass to acir functions ([#3634](https://github.com/noir-lang/noir/issues/3634)) ([0cad9aa](https://github.com/noir-lang/noir/commit/0cad9aa9c19091b3679bdc6e7fe044194c5db7e0)) +* Return error rather than panicking on unreadable circuits ([#3179](https://github.com/noir-lang/noir/issues/3179)) ([d4f61d3](https://github.com/noir-lang/noir/commit/d4f61d3d51d515e40a5fd02d35315889f841bf53)) +* Show println output before an error occurs in `nargo execute` ([#3211](https://github.com/noir-lang/noir/issues/3211)) ([2f0b80d](https://github.com/noir-lang/noir/commit/2f0b80dda8401ce8962c857dbcd9548e7fdde4aa)) +* Silence unused variable warnings in stdlib ([#2795](https://github.com/noir-lang/noir/issues/2795)) ([5747bfe](https://github.com/noir-lang/noir/commit/5747bfed256f9179321ec0bd1e02f5f82723a4c7)) +* Somewhat reduce mem2reg memory usage ([#3572](https://github.com/noir-lang/noir/issues/3572)) ([9b9ed89](https://github.com/noir-lang/noir/commit/9b9ed890e68b6c7f0671b05919bdc86f593c5df5)) +* 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)) +* **traits:** Trait functions with a default implementation must not be followed by a semicolon ([#2987](https://github.com/noir-lang/noir/issues/2987)) ([a3593c0](https://github.com/noir-lang/noir/commit/a3593c042163d89bd012b7f901f3b18446209e82)) +* Transform hir before type checks ([#2994](https://github.com/noir-lang/noir/issues/2994)) ([a29b568](https://github.com/noir-lang/noir/commit/a29b568295e40e19dd354bbe47e31f922e08d8c9)) +* Update link to recursion example ([#3224](https://github.com/noir-lang/noir/issues/3224)) ([10eae15](https://github.com/noir-lang/noir/commit/10eae15c6992442876e184c7d2bd36a34f639ea1)) +* Use 128 bits for constant bit shift ([#3586](https://github.com/noir-lang/noir/issues/3586)) ([2ca9b05](https://github.com/noir-lang/noir/commit/2ca9b059317f0513ea21153ebdb468c4f6633de5)) +* Use pedersen_hash for merkle tree ([#3357](https://github.com/noir-lang/noir/issues/3357)) ([6b74d31](https://github.com/noir-lang/noir/commit/6b74d316fec3b379dd7b51064f1acb1a0e6a15cc)) +* Verify impls arising from function calls exist ([#3472](https://github.com/noir-lang/noir/issues/3472)) ([d7f919d](https://github.com/noir-lang/noir/commit/d7f919dcc001080ed24616ebbc37426ef7ac7638)) + + +### 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)) +* Bump MSRV to 1.71.1 ([#3353](https://github.com/noir-lang/noir/issues/3353)) ([78f2127](https://github.com/noir-lang/noir/commit/78f2127dd12e36e831e63fd670d9f9d870818af7)) +* Change stdlib function `pedersen` to `pedersen_commitment` ([#3341](https://github.com/noir-lang/noir/issues/3341)) ([964b777](https://github.com/noir-lang/noir/commit/964b7771506bdf8408d8917ab32bf51db8ce09d2)) +* Move circuit serialization circuit into acir ([#3345](https://github.com/noir-lang/noir/issues/3345)) ([122119b](https://github.com/noir-lang/noir/commit/122119b7377cec1b7c42c586c64b69b3bdf4d539)) +* **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)) +* Update to `bb` version 0.7.3 ([#2729](https://github.com/noir-lang/noir/issues/2729)) ([fce68d1](https://github.com/noir-lang/noir/commit/fce68d1404ae66bd7a71417d791dd70545bf24f2)) + +## [0.19.5](https://github.com/noir-lang/noir/compare/v0.19.4...v0.19.5) (2023-12-01) + + +### Features + +* Add `FieldElement::from<usize>` implementation ([#3647](https://github.com/noir-lang/noir/issues/3647)) ([8b7c5aa](https://github.com/noir-lang/noir/commit/8b7c5aa5311f4e6811438f67bd552b641b13fc9a)) +* Add package version to Nargo.toml metadata ([#3427](https://github.com/noir-lang/noir/issues/3427)) ([9e1717c](https://github.com/noir-lang/noir/commit/9e1717c2d96a0b9e394e5cb2fb9e1d09b5259ca0)) +* Add special case for boolean AND in acir-gen ([#3615](https://github.com/noir-lang/noir/issues/3615)) ([824039b](https://github.com/noir-lang/noir/commit/824039bcc0a3275f333ea94aecc701d129f99fe5)) +* Aztec-packages ([#3599](https://github.com/noir-lang/noir/issues/3599)) ([2cd6dc3](https://github.com/noir-lang/noir/commit/2cd6dc39e3a956aa5dff721d47aaf1921f98fded)) +* Aztec-packages ([#3626](https://github.com/noir-lang/noir/issues/3626)) ([e0a96ea](https://github.com/noir-lang/noir/commit/e0a96ea70b17c8c898dd72ac929f3969a4cec1d3)) +* Complex slice inputs for dynamic slice builtins ([#3617](https://github.com/noir-lang/noir/issues/3617)) ([8b23b34](https://github.com/noir-lang/noir/commit/8b23b349ae15afa48f6cbe8962586bbe79e79890)) +* Copy on write optimization for brillig ([#3522](https://github.com/noir-lang/noir/issues/3522)) ([da29c02](https://github.com/noir-lang/noir/commit/da29c02327acb2f46f5a7a25c7404dfa44c82616)) +* Data bus ([#3508](https://github.com/noir-lang/noir/issues/3508)) ([6b0bdbc](https://github.com/noir-lang/noir/commit/6b0bdbced1bfe2c92e90dd7b70ca8f9e5ccb7c0d)) +* Implement integer printing ([#3577](https://github.com/noir-lang/noir/issues/3577)) ([6601408](https://github.com/noir-lang/noir/commit/6601408e378b2afe4fdfd8e04482c39311ccc7e9)) +* Implement raw string literals ([#3556](https://github.com/noir-lang/noir/issues/3556)) ([87a302f](https://github.com/noir-lang/noir/commit/87a302fbc26d5fd42694953935d95a7ccb3d50a0)) +* **lsp:** Add goto definition for functions ([#3656](https://github.com/noir-lang/noir/issues/3656)) ([7bb7356](https://github.com/noir-lang/noir/commit/7bb735662c86e6533ac58f448ad748e34f02edb7)) +* Reuse witnesses more when interacting with memory ([#3658](https://github.com/noir-lang/noir/issues/3658)) ([5a4a73d](https://github.com/noir-lang/noir/commit/5a4a73d24ddd7d2bb46c85714397ee6e031c97a6)) + + +### Bug Fixes + +* Corrected the formatting of error message parameters in index out of bounds error ([#3630](https://github.com/noir-lang/noir/issues/3630)) ([3bba386](https://github.com/noir-lang/noir/commit/3bba3862dc8703410681300be894bfd1ebca7336)) +* Do not simply divisions ([#3664](https://github.com/noir-lang/noir/issues/3664)) ([e5b981b](https://github.com/noir-lang/noir/commit/e5b981b08c2b345f00426acafe47b76d5262254d)) +* Docker builds ([#3620](https://github.com/noir-lang/noir/issues/3620)) ([f3eac52](https://github.com/noir-lang/noir/commit/f3eac5282860c1954ea2cee6a21633df5b1865fd)) +* Flatten public inputs according to their index in numerial rather than ascii order ([#3605](https://github.com/noir-lang/noir/issues/3605)) ([a1f6343](https://github.com/noir-lang/noir/commit/a1f6343b7df1b166b1be4db09527694a3df2738a)) +* Restrict fill_internal_slices pass to acir functions ([#3634](https://github.com/noir-lang/noir/issues/3634)) ([0cad9aa](https://github.com/noir-lang/noir/commit/0cad9aa9c19091b3679bdc6e7fe044194c5db7e0)) + ## [0.19.4](https://github.com/noir-lang/noir/compare/v0.19.3...v0.19.4) (2023-11-28) diff --git a/noir/Cargo.lock b/noir/Cargo.lock index 3bab28cd1c5..f1fb11aea6a 100644 --- a/noir/Cargo.lock +++ b/noir/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acir" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acir_field", "base64", @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.35.0" +version = "0.38.0" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -37,13 +37,13 @@ dependencies = [ [[package]] name = "acvm" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acir", "acvm_blackbox_solver", - "acvm_stdlib", "brillig_vm", "indexmap 1.9.3", + "log", "num-bigint", "num-traits", "paste", @@ -54,7 +54,7 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acir", "blake2", @@ -67,7 +67,7 @@ dependencies = [ [[package]] name = "acvm_js" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acvm", "barretenberg_blackbox_solver", @@ -86,13 +86,6 @@ dependencies = [ "wasm-logger", ] -[[package]] -name = "acvm_stdlib" -version = "0.35.0" -dependencies = [ - "acir", -] - [[package]] name = "addr2line" version = "0.20.0" @@ -217,7 +210,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arena" -version = "0.19.4" +version = "0.22.0" dependencies = [ "generational-arena", ] @@ -407,6 +400,17 @@ dependencies = [ "waitpid-any", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -415,7 +419,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aztec_macros" -version = "0.19.4" +version = "0.22.0" dependencies = [ "iter-extended", "noirc_frontend", @@ -431,6 +435,7 @@ dependencies = [ "const_format", "dirs", "flate2", + "log", "reqwest", "serde", "serde_json", @@ -457,7 +462,7 @@ dependencies = [ [[package]] name = "barretenberg_blackbox_solver" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -581,7 +586,7 @@ dependencies = [ [[package]] name = "brillig" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acir_field", "serde", @@ -589,7 +594,7 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.35.0" +version = "0.38.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -1123,6 +1128,16 @@ dependencies = [ "itertools", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -1481,6 +1496,19 @@ dependencies = [ "syn 2.0.26", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1604,11 +1632,10 @@ dependencies = [ [[package]] name = "fm" -version = "0.19.4" +version = "0.22.0" dependencies = [ "codespan-reporting", "iter-extended", - "rust-embed", "serde", "tempfile", ] @@ -1907,6 +1934,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.2" @@ -1962,6 +1998,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.27" @@ -2159,14 +2201,14 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "rustix", "windows-sys 0.48.0", ] [[package]] name = "iter-extended" -version = "0.19.4" +version = "0.22.0" [[package]] name = "itertools" @@ -2388,12 +2430,13 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "nargo" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "codespan-reporting", "fm", "iter-extended", + "log", "noirc_abi", "noirc_driver", "noirc_errors", @@ -2403,12 +2446,13 @@ dependencies = [ "rayon", "rustc_version", "serde", + "tempfile", "thiserror", ] [[package]] name = "nargo_cli" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "assert_cmd", @@ -2423,6 +2467,7 @@ dependencies = [ "const_format", "criterion", "dirs", + "env_logger", "fm", "hex", "iai", @@ -2453,11 +2498,14 @@ dependencies = [ "tokio-util", "toml", "tower", + "tracing", + "tracing-appender", + "tracing-subscriber", ] [[package]] name = "nargo_fmt" -version = "0.19.4" +version = "0.22.0" dependencies = [ "bytecount", "noirc_frontend", @@ -2469,7 +2517,7 @@ dependencies = [ [[package]] name = "nargo_toml" -version = "0.19.4" +version = "0.22.0" dependencies = [ "dirs", "fm", @@ -2518,7 +2566,7 @@ dependencies = [ [[package]] name = "noir_debugger" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "codespan-reporting", @@ -2532,13 +2580,11 @@ dependencies = [ [[package]] name = "noir_lsp" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "async-lsp", - "cfg-if", "codespan-lsp", - "codespan-reporting", "fm", "lsp-types 0.94.1", "nargo", @@ -2557,11 +2603,10 @@ dependencies = [ [[package]] name = "noir_wasm" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "build-data", - "cfg-if", "console_error_panic_hook", "fm", "getrandom", @@ -2579,7 +2624,7 @@ dependencies = [ [[package]] name = "noirc_abi" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "iter-extended", @@ -2596,7 +2641,7 @@ dependencies = [ [[package]] name = "noirc_abi_wasm" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "build-data", @@ -2613,7 +2658,7 @@ dependencies = [ [[package]] name = "noirc_driver" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "aztec_macros", @@ -2622,34 +2667,38 @@ dependencies = [ "fm", "fxhash", "iter-extended", + "log", "noirc_abi", "noirc_errors", "noirc_evaluator", "noirc_frontend", + "rust-embed", "serde", ] [[package]] name = "noirc_errors" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "chumsky", "codespan", "codespan-reporting", "fm", + "log", "serde", "serde_with", ] [[package]] name = "noirc_evaluator" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "fxhash", "im", "iter-extended", + "log", "noirc_errors", "noirc_frontend", "num-bigint", @@ -2659,13 +2708,14 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "arena", "chumsky", "fm", "iter-extended", + "log", "noirc_errors", "noirc_printable_type", "regex", @@ -2676,12 +2726,13 @@ dependencies = [ "smol_str", "strum", "strum_macros", + "tempfile", "thiserror", ] [[package]] name = "noirc_printable_type" -version = "0.19.4" +version = "0.22.0" dependencies = [ "acvm", "iter-extended", @@ -2697,6 +2748,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -2744,7 +2805,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "libc", ] @@ -2769,6 +2830,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owo-colors" version = "3.5.0" @@ -4377,22 +4444,33 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -4401,9 +4479,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -4419,15 +4497,29 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "nu-ansi-term", "sharded-slab", + "smallvec", "thread_local", "tracing-core", + "tracing-log", ] [[package]] diff --git a/noir/Cargo.toml b/noir/Cargo.toml index 1a37a4f53e1..aaf060552e7 100644 --- a/noir/Cargo.toml +++ b/noir/Cargo.toml @@ -28,7 +28,6 @@ members = [ "acvm-repo/acir", "acvm-repo/acvm", "acvm-repo/acvm_js", - "acvm-repo/stdlib", "acvm-repo/brillig", "acvm-repo/brillig_vm", "acvm-repo/blackbox_solver", @@ -39,7 +38,7 @@ resolver = "2" [workspace.package] # x-release-please-start-version -version = "0.19.4" +version = "0.22.0" # x-release-please-end authors = ["The Noir Team "] edition = "2021" @@ -50,14 +49,14 @@ repository = "https://github.com/noir-lang/noir/" [workspace.dependencies] # ACVM workspace dependencies -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 } +acir_field = { version = "0.38.0", path = "acvm-repo/acir_field", default-features = false } +acir = { version = "0.38.0", path = "acvm-repo/acir", default-features = false } +acvm = { version = "0.38.0", path = "acvm-repo/acvm" } +stdlib = { version = "0.37.1", package = "acvm_stdlib", path = "acvm-repo/stdlib", default-features = false } +brillig = { version = "0.38.0", path = "acvm-repo/brillig", default-features = false } +brillig_vm = { version = "0.38.0", path = "acvm-repo/brillig_vm", default-features = false } +acvm_blackbox_solver = { version = "0.38.0", path = "acvm-repo/blackbox_solver", default-features = false } +barretenberg_blackbox_solver = { version = "0.38.0", path = "acvm-repo/barretenberg_blackbox_solver", default-features = false } # Noir compiler workspace dependencies arena = { path = "compiler/utils/arena" } @@ -96,7 +95,7 @@ getrandom = "0.2" cfg-if = "1.0.0" -clap = { version = "4.3.19", features = ["derive"] } +clap = { version = "4.3.19", features = ["derive", "env"] } codespan = { version = "0.11.1", features = ["serialization"] } codespan-lsp = "0.11.1" codespan-reporting = "0.11.1" @@ -120,6 +119,10 @@ const_format = "0.2.30" num-bigint = "0.4" num-traits = "0.2" similar-asserts = "1.5.0" +log = "0.4.17" +tempfile = "3.6.0" + +tracing = "0.1.40" [profile.dev] # This is required to be able to run `cargo test` in acvm_js due to the `locals exceeds maximum` error. diff --git a/noir/Dockerfile.ci b/noir/Dockerfile.ci new file mode 100644 index 00000000000..9ca995fd94f --- /dev/null +++ b/noir/Dockerfile.ci @@ -0,0 +1,40 @@ +FROM rust:1-slim-bookworm as test-base +RUN apt-get update && apt-get upgrade -y && apt-get install build-essential git -y +WORKDIR /usr/src/noir +COPY . . +RUN ./scripts/bootstrap_native.sh +ENV PATH="${PATH}:/usr/src/noir/target/release/" + +FROM test-base as test-cargo +RUN apt-get install -y curl libc++-dev +RUN ./scripts/test_native.sh + +FROM test-base as test-js +RUN apt-get install pkg-config libssl-dev -y +RUN ./scripts/install_wasm-bindgen.sh +RUN apt-get install -y ca-certificates curl gnupg +RUN mkdir -p /etc/apt/keyrings +RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg +RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list +RUN apt-get update && apt-get install nodejs -y +RUN corepack enable +RUN yarn --immutable +RUN apt-get install -y jq +RUN yarn build +RUN yarn workspace @noir-lang/acvm_js test +RUN npx playwright install && npx playwright install-deps +RUN yarn workspace @noir-lang/acvm_js test:browser +RUN yarn workspace @noir-lang/noirc_abi test +RUN yarn workspace @noir-lang/noirc_abi test:browser +RUN yarn workspace @noir-lang/backend_barretenberg test +RUN ./scripts/nargo_compile_noir_js_assert_lt.sh +RUN rm -rf /usr/src/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/debug_assert_lt.json +RUN yarn workspace @noir-lang/noir_js test +RUN ./scripts/nargo_compile_wasm_fixtures.sh +RUN yarn workspace @noir-lang/noir_wasm test:node +RUN yarn workspace @noir-lang/noir_wasm test:browser +RUN ./scripts/nargo_compile_noir_codegen_assert_lt.sh +RUN rm -rf /usr/src/noir/tooling/noir_codegen/test/assert_lt/target/debug_assert_lt.json +RUN yarn workspace @noir-lang/noir_codegen test +RUN apt-get install -y libc++-dev +RUN yarn test:integration diff --git a/noir/Dockerfile.packages b/noir/Dockerfile.packages index 11737014e3d..17eb0bcd648 100644 --- a/noir/Dockerfile.packages +++ b/noir/Dockerfile.packages @@ -8,7 +8,9 @@ RUN apk update \ npm \ yarn \ bash \ - jq + jq \ + git + WORKDIR /usr/src/noir COPY . . RUN ./scripts/bootstrap_packages.sh diff --git a/noir/README.md b/noir/README.md index c48c9110187..2fc47f16fef 100644 --- a/noir/README.md +++ b/noir/README.md @@ -58,7 +58,7 @@ This crate's minimum supported rustc version is 1.71.1. ## Working on this project -This project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. Please follow [our guidelines](https://noir-lang.org/getting_started/nargo_installation/#option-4-compile-from-source) to setup your environment for working on the project. +This project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. Please follow [our guidelines](https://noir-lang.org/getting_started/nargo_installation/#option-3-compile-from-source) to setup your environment for working on the project. ### Building against a different local/remote version of Barretenberg diff --git a/noir/acvm-repo/CHANGELOG.md b/noir/acvm-repo/CHANGELOG.md index ff3ba716680..0bd38fd3307 100644 --- a/noir/acvm-repo/CHANGELOG.md +++ b/noir/acvm-repo/CHANGELOG.md @@ -5,6 +5,143 @@ 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.38.0](https://github.com/noir-lang/noir/compare/v0.37.1...v0.38.0) (2023-12-18) + + +### ⚠ BREAKING CHANGES + +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) + +### Features + +* Aztec-packages ([#3754](https://github.com/noir-lang/noir/issues/3754)) ([c043265](https://github.com/noir-lang/noir/commit/c043265e550b59bd4296504826fe15d3ce3e9ad2)) +* Speed up transformation of debug messages ([#3815](https://github.com/noir-lang/noir/issues/3815)) ([2a8af1e](https://github.com/noir-lang/noir/commit/2a8af1e4141ffff61547ee1c2837a6392bd5db48)) + + +### Bug Fixes + +* Deserialize odd length hex literals ([#3747](https://github.com/noir-lang/noir/issues/3747)) ([4000fb2](https://github.com/noir-lang/noir/commit/4000fb279221eb07187d657bfaa7f1c7b311abf2)) + + +### Miscellaneous Chores + +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) ([0383100](https://github.com/noir-lang/noir/commit/0383100853a80a5b28b797cdfeae0d271f1b7805)) +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) ([9e5d0e8](https://github.com/noir-lang/noir/commit/9e5d0e813d61a0bfb5ee68174ed287c5a20f1579)) + +## [0.37.1](https://github.com/noir-lang/noir/compare/v0.37.0...v0.37.1) (2023-12-15) + + +### Features + +* Aztec-packages ([#3754](https://github.com/noir-lang/noir/issues/3754)) ([c043265](https://github.com/noir-lang/noir/commit/c043265e550b59bd4296504826fe15d3ce3e9ad2)) +* Speed up transformation of debug messages ([#3815](https://github.com/noir-lang/noir/issues/3815)) ([2a8af1e](https://github.com/noir-lang/noir/commit/2a8af1e4141ffff61547ee1c2837a6392bd5db48)) + + +### Bug Fixes + +* Deserialize odd length hex literals ([#3747](https://github.com/noir-lang/noir/issues/3747)) ([4000fb2](https://github.com/noir-lang/noir/commit/4000fb279221eb07187d657bfaa7f1c7b311abf2)) + +## [0.37.0](https://github.com/noir-lang/noir/compare/v0.36.0...v0.37.0) (2023-12-01) + + +### ⚠ BREAKING CHANGES + +* Move circuit serialization circuit into acir ([#3345](https://github.com/noir-lang/noir/issues/3345)) +* expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) +* **wasm:** improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) + +### Features + +* **acvm_js:** Export black box solver functions ([#2812](https://github.com/noir-lang/noir/issues/2812)) ([da8a98e](https://github.com/noir-lang/noir/commit/da8a98ed312fe69cb0bdb8f9d0a70ee7a981398f)) +* **acvm:** Separate ACVM optimizations and transformations ([#2979](https://github.com/noir-lang/noir/issues/2979)) ([5865d1a](https://github.com/noir-lang/noir/commit/5865d1a1bca16e1853663c71f893ff81fa3f7185)) +* Add `FieldElement::from<usize>` implementation ([#3647](https://github.com/noir-lang/noir/issues/3647)) ([8b7c5aa](https://github.com/noir-lang/noir/commit/8b7c5aa5311f4e6811438f67bd552b641b13fc9a)) +* Add ACIR serializer C++ codegen ([#2961](https://github.com/noir-lang/noir/issues/2961)) ([7556982](https://github.com/noir-lang/noir/commit/7556982dbebe25eaa17240abbe270b771b55de45)) +* Add conditional compilation of methods based on the underlying field being used ([#3045](https://github.com/noir-lang/noir/issues/3045)) ([2e008e2](https://github.com/noir-lang/noir/commit/2e008e2438795bbc41b0641e830378b76bf2e194)) +* Add debugger commands to introspect (and modify) the current state ([#3391](https://github.com/noir-lang/noir/issues/3391)) ([9e1ad85](https://github.com/noir-lang/noir/commit/9e1ad858cf8a1d9aba0137abe6a749267498bfaf)) +* Aztec-packages ([#3599](https://github.com/noir-lang/noir/issues/3599)) ([2cd6dc3](https://github.com/noir-lang/noir/commit/2cd6dc39e3a956aa5dff721d47aaf1921f98fded)) +* Expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) ([0108b6c](https://github.com/noir-lang/noir/commit/0108b6c1e8dc0dfc766ab3c4944deae9354dec36)) +* Extract Brillig VM to allow step debugging ([#3259](https://github.com/noir-lang/noir/issues/3259)) ([f6431f9](https://github.com/noir-lang/noir/commit/f6431f99711f15a96a4f7fed2f413daece94b5e1)) +* Implement euclidean division and signed division in terms of `AcirVar`s ([#3230](https://github.com/noir-lang/noir/issues/3230)) ([b8b7782](https://github.com/noir-lang/noir/commit/b8b77825410c0e1f95549259a51e2c40de1ec342)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) ([f7869e6](https://github.com/noir-lang/noir/commit/f7869e6fb492b617e776e538ac4babfa56261d26)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) ([b3a9c34](https://github.com/noir-lang/noir/commit/b3a9c343993ce3207de62106bda6cb2b2ef3de50)) +* Pass brillig bytecode to VM by reference ([#3030](https://github.com/noir-lang/noir/issues/3030)) ([4ee290b](https://github.com/noir-lang/noir/commit/4ee290b8b6f75bc1974a5750248570eeca8d244e)) +* Refactor debugger and separate core from UI ([#3308](https://github.com/noir-lang/noir/issues/3308)) ([8466810](https://github.com/noir-lang/noir/commit/846681079ab7295b201480a5c8baebc45e858c6f)) +* Replace boolean range constraints with arithmetic opcodes ([#3234](https://github.com/noir-lang/noir/issues/3234)) ([949222c](https://github.com/noir-lang/noir/commit/949222c20d9e65152e3814d02da1c4c41ffc23a5)) +* Save Brillig execution state in ACVM ([#3026](https://github.com/noir-lang/noir/issues/3026)) ([88682da](https://github.com/noir-lang/noir/commit/88682da87ffc9e26da5c9e4b5a4d8e62a6ee43c6)) +* Solve `fixed_base_scalar_mul` black box functions in rust ([#3153](https://github.com/noir-lang/noir/issues/3153)) ([1c1afbc](https://github.com/noir-lang/noir/commit/1c1afbcddf0b5fdb39f00ad28ae90caf699d1265)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) ([35fb3f7](https://github.com/noir-lang/noir/commit/35fb3f7076d52db7ca3bef0a70a3dbccaf82f58d)) +* **wasm:** Improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) ([1b5124b](https://github.com/noir-lang/noir/commit/1b5124bc74f7ac5360db04b34d1b7b2284061fd3)) + + +### Bug Fixes + +* ACIR optimizer should update assertion messages ([#3010](https://github.com/noir-lang/noir/issues/3010)) ([758b6b6](https://github.com/noir-lang/noir/commit/758b6b62918907c1a39f3090a77419003551745e)) +* **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)) +* Determinism of fallback transformer ([#3100](https://github.com/noir-lang/noir/issues/3100)) ([12daad1](https://github.com/noir-lang/noir/commit/12daad19c902caf5ee9e2eb4b6847bde5a924353)) +* Fix method `program_counter`, change method signature ([#3012](https://github.com/noir-lang/noir/issues/3012)) ([5ea522b](https://github.com/noir-lang/noir/commit/5ea522b840ca0f6f90d02ca00f0de32f515d450f)) +* Minor problems with `aztec` publishing ([#3095](https://github.com/noir-lang/noir/issues/3095)) ([0fc8f20](https://github.com/noir-lang/noir/commit/0fc8f20b8b87d033d27ce18db039399c17f81837)) +* Prevent duplicated assert message transformation ([#3038](https://github.com/noir-lang/noir/issues/3038)) ([082a6d0](https://github.com/noir-lang/noir/commit/082a6d02dad67a25692bed15c340a16a848a320e)) +* Return error rather than panicking on unreadable circuits ([#3179](https://github.com/noir-lang/noir/issues/3179)) ([d4f61d3](https://github.com/noir-lang/noir/commit/d4f61d3d51d515e40a5fd02d35315889f841bf53)) + + +### Miscellaneous Chores + +* Move circuit serialization circuit into acir ([#3345](https://github.com/noir-lang/noir/issues/3345)) ([122119b](https://github.com/noir-lang/noir/commit/122119b7377cec1b7c42c586c64b69b3bdf4d539)) + +## [0.36.0](https://github.com/noir-lang/noir/compare/v0.35.0...v0.36.0) (2023-12-01) + + +### ⚠ BREAKING CHANGES + +* Move circuit serialization circuit into acir ([#3345](https://github.com/noir-lang/noir/issues/3345)) +* expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) +* **wasm:** improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) + +### Features + +* **acvm_js:** Export black box solver functions ([#2812](https://github.com/noir-lang/noir/issues/2812)) ([da8a98e](https://github.com/noir-lang/noir/commit/da8a98ed312fe69cb0bdb8f9d0a70ee7a981398f)) +* **acvm:** Separate ACVM optimizations and transformations ([#2979](https://github.com/noir-lang/noir/issues/2979)) ([5865d1a](https://github.com/noir-lang/noir/commit/5865d1a1bca16e1853663c71f893ff81fa3f7185)) +* Add `FieldElement::from<usize>` implementation ([#3647](https://github.com/noir-lang/noir/issues/3647)) ([8b7c5aa](https://github.com/noir-lang/noir/commit/8b7c5aa5311f4e6811438f67bd552b641b13fc9a)) +* Add ACIR serializer C++ codegen ([#2961](https://github.com/noir-lang/noir/issues/2961)) ([7556982](https://github.com/noir-lang/noir/commit/7556982dbebe25eaa17240abbe270b771b55de45)) +* Add conditional compilation of methods based on the underlying field being used ([#3045](https://github.com/noir-lang/noir/issues/3045)) ([2e008e2](https://github.com/noir-lang/noir/commit/2e008e2438795bbc41b0641e830378b76bf2e194)) +* Add debugger commands to introspect (and modify) the current state ([#3391](https://github.com/noir-lang/noir/issues/3391)) ([9e1ad85](https://github.com/noir-lang/noir/commit/9e1ad858cf8a1d9aba0137abe6a749267498bfaf)) +* Aztec-packages ([#3599](https://github.com/noir-lang/noir/issues/3599)) ([2cd6dc3](https://github.com/noir-lang/noir/commit/2cd6dc39e3a956aa5dff721d47aaf1921f98fded)) +* Expose pedersen hash in acir and bb solver ([#3269](https://github.com/noir-lang/noir/issues/3269)) ([0108b6c](https://github.com/noir-lang/noir/commit/0108b6c1e8dc0dfc766ab3c4944deae9354dec36)) +* Extract Brillig VM to allow step debugging ([#3259](https://github.com/noir-lang/noir/issues/3259)) ([f6431f9](https://github.com/noir-lang/noir/commit/f6431f99711f15a96a4f7fed2f413daece94b5e1)) +* Implement euclidean division and signed division in terms of `AcirVar`s ([#3230](https://github.com/noir-lang/noir/issues/3230)) ([b8b7782](https://github.com/noir-lang/noir/commit/b8b77825410c0e1f95549259a51e2c40de1ec342)) +* Maintain shape of foreign call arguments ([#2935](https://github.com/noir-lang/noir/issues/2935)) ([f7869e6](https://github.com/noir-lang/noir/commit/f7869e6fb492b617e776e538ac4babfa56261d26)) +* Pass ACIR to ACVM by reference rather than passing ownership ([#2872](https://github.com/noir-lang/noir/issues/2872)) ([b3a9c34](https://github.com/noir-lang/noir/commit/b3a9c343993ce3207de62106bda6cb2b2ef3de50)) +* Pass brillig bytecode to VM by reference ([#3030](https://github.com/noir-lang/noir/issues/3030)) ([4ee290b](https://github.com/noir-lang/noir/commit/4ee290b8b6f75bc1974a5750248570eeca8d244e)) +* Refactor debugger and separate core from UI ([#3308](https://github.com/noir-lang/noir/issues/3308)) ([8466810](https://github.com/noir-lang/noir/commit/846681079ab7295b201480a5c8baebc45e858c6f)) +* Replace boolean range constraints with arithmetic opcodes ([#3234](https://github.com/noir-lang/noir/issues/3234)) ([949222c](https://github.com/noir-lang/noir/commit/949222c20d9e65152e3814d02da1c4c41ffc23a5)) +* Save Brillig execution state in ACVM ([#3026](https://github.com/noir-lang/noir/issues/3026)) ([88682da](https://github.com/noir-lang/noir/commit/88682da87ffc9e26da5c9e4b5a4d8e62a6ee43c6)) +* Solve `fixed_base_scalar_mul` black box functions in rust ([#3153](https://github.com/noir-lang/noir/issues/3153)) ([1c1afbc](https://github.com/noir-lang/noir/commit/1c1afbcddf0b5fdb39f00ad28ae90caf699d1265)) +* Switch to new pedersen implementation ([#3151](https://github.com/noir-lang/noir/issues/3151)) ([35fb3f7](https://github.com/noir-lang/noir/commit/35fb3f7076d52db7ca3bef0a70a3dbccaf82f58d)) +* **wasm:** Improve and simplify wasm compiler interface ([#2976](https://github.com/noir-lang/noir/issues/2976)) ([1b5124b](https://github.com/noir-lang/noir/commit/1b5124bc74f7ac5360db04b34d1b7b2284061fd3)) + + +### Bug Fixes + +* ACIR optimizer should update assertion messages ([#3010](https://github.com/noir-lang/noir/issues/3010)) ([758b6b6](https://github.com/noir-lang/noir/commit/758b6b62918907c1a39f3090a77419003551745e)) +* **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)) +* Determinism of fallback transformer ([#3100](https://github.com/noir-lang/noir/issues/3100)) ([12daad1](https://github.com/noir-lang/noir/commit/12daad19c902caf5ee9e2eb4b6847bde5a924353)) +* Fix method `program_counter`, change method signature ([#3012](https://github.com/noir-lang/noir/issues/3012)) ([5ea522b](https://github.com/noir-lang/noir/commit/5ea522b840ca0f6f90d02ca00f0de32f515d450f)) +* Minor problems with `aztec` publishing ([#3095](https://github.com/noir-lang/noir/issues/3095)) ([0fc8f20](https://github.com/noir-lang/noir/commit/0fc8f20b8b87d033d27ce18db039399c17f81837)) +* Prevent duplicated assert message transformation ([#3038](https://github.com/noir-lang/noir/issues/3038)) ([082a6d0](https://github.com/noir-lang/noir/commit/082a6d02dad67a25692bed15c340a16a848a320e)) +* Return error rather than panicking on unreadable circuits ([#3179](https://github.com/noir-lang/noir/issues/3179)) ([d4f61d3](https://github.com/noir-lang/noir/commit/d4f61d3d51d515e40a5fd02d35315889f841bf53)) + + +### Miscellaneous Chores + +* Move circuit serialization circuit into acir ([#3345](https://github.com/noir-lang/noir/issues/3345)) ([122119b](https://github.com/noir-lang/noir/commit/122119b7377cec1b7c42c586c64b69b3bdf4d539)) + ## [0.35.0](https://github.com/noir-lang/noir/compare/v0.34.0...v0.35.0) (2023-11-28) diff --git a/noir/acvm-repo/acir/Cargo.toml b/noir/acvm-repo/acir/Cargo.toml index 8dd6a69a07d..a0877120a58 100644 --- a/noir/acvm-repo/acir/Cargo.toml +++ b/noir/acvm-repo/acir/Cargo.toml @@ -2,7 +2,7 @@ name = "acir" description = "ACIR is the IR that the VM processes, it is analogous to LLVM IR" # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/noir/acvm-repo/acir/acir_docs.md b/noir/acvm-repo/acir/acir_docs.md new file mode 100644 index 00000000000..eb532c9ae0c --- /dev/null +++ b/noir/acvm-repo/acir/acir_docs.md @@ -0,0 +1,206 @@ +# ACIR documentation (draft) + +## Abstract +This document describes the purpose of ACIR, what it is and how ACIR programs can be used by compilers and proving systems. It is intended to be a reference documentation for ACIR. + +## Introduction +The purpose of ACIR is to make the link between a generic proving system, such as Aztec's Barretenberg, and a frontend, such as Noir, which describes user-specific computations. + +More precisely, Noir is a programming language for zero-knowledge proofs (ZKP) which allows users to write programs in an intuitive way using a high-level language close to Rust syntax. Noir is able to generate a proof of execution of a Noir program, using an external proving system. However, proving systems uses specific low-level constrain-based languages. Similarly, frontends have their own internal representation in order to represent user programs. + +The goal of ACIR is to provide a generic open-source intermediate representation close to proving system 'languages', but agnostic to a specific proving system, that can be used both by proving system as well as a target for frontends. So, at the end of the day, an ACIR program is just another representation of a program, dedicated to proving systems. + +## Abstract Circuit Intermediate Representation +ACIR stands for abstract circuit intermediate representation: +- **abstract circuit**: circuits are a simple computation model where basic computation units, named gates, are connected with wires. Data flows through the wires while gates compute output wires based on their input. More formally, they are directed acyclic graphs (DAG) where the vertices are the gates and the edges are the wires. Due to the immutability nature of the wires (their value does not change during an execution), they are well suited for describing computations for ZKPs. Furthermore, we do not lose any expressiveness when using a circuit as it is well known that any bounded computation can be translated into an arithmetic circuit (i.e a circuit with only addition and multiplication gates). +The term abstract here simply mean that we do not refer to an actual physical circuit (such as an electronic circuit). Furthermore, we will not exactly use the circuit model, but another model even better suited to ZKPs, the constraint model (see below). +- **intermediate representation**: The ACIR representation is intermediate because it lies between a frontend and its proving system. ACIR bytecode makes the link between noir compiler output and the proving system backend input. + +## The constraint model +The first step for generating a proof that a specific program was executed, is to execute this program. Since the proving system is going to handle ACIR programs, we need in fact to execute an ACIR program, using the user-supplied inputs. + +In ACIR terminology, the gates are called opcodes and the wires are called partial witnesses. However, instead of connecting the opcodes together through wires, we create constraints: an opcode constraints together a set of wires. +This constraint model trivially supersedes the circuit model. For instance, an addition gate output_wire = input_wire_1 + input_wire_2 can be expressed with the following arithmetic constraint: output_wire - (input_wire_1 + input_wire_2) = 0 + + + +## Solving +Because of these constraints, executing an ACIR program is called solving the witnesses. From the witnesses representing the inputs of the program, whose values are supplied by the user, we find out what the other witnesses should be by executing/solving the constraints one-by-one in the order they were defined. + +For instance, if input_wire_1 and input_wire_2 values are supplied as 3 and 8, then we can solve the opcode output_wire - (input_wire_1 + input_wire_2) = 0 by saying that output_wire is 11. + +In summary, the workflow is the following: +1. user program -> (compilation) ACIR, a list of opcodes which constrain (partial) witnesses +2. user inputs + ACIR -> (execution/solving) assign values to all the (partial) witnesses +3. witness assignement + ACIR -> (proving system) proof + + +Although the ordering of opcode does not matter in theory, since a system of equations is not dependent on its ordering, in practice it matters a lot for the solving (i.e the performance of the execution). ACIR opcodes **must be ordered** so that each opcode can be resolved one after the other. + + +The values of the witnesses lie in the scalar field of the proving system. We will refer to it as FieldElement or ACIR field. The proving system need the values of all the partial witnesses and all the constraints in order to generate a proof. + + +*Remark*: The value of a partial witness is unique and fixed throughout a program execution, although in some rare cases, multiple values are possible for a same execution and witness (when there are several valid solutions to the constraints). Having multiple possible values for a witness may indicate that the circuit is not safe. + +*Remark*: Why do we use the term partial witnesses? It is because the proving system may create other constraints and witnesses (especially with BlackBoxFuncCall, see below). A proof refers to a full witness assignements and their constraints. ACIR opcodes and their partial witnesses are still an intermediate representation before getting the full list of constraints and witnesses. For the sake of simplicity, we will refer to witness instead of partial witness from now on. + + +## ACIR Reference +We assume here that the proving system is Barretenberg. Some parameters may slightly change with another proving system, in particular the bit size of FieldElement, which is 254 for Barretenberg. + +Some opcodes have inputs and outputs, which means that the output is constrained to be the result of the opcode computation from the inputs. The solver expects that all inputs are known when solving such opcodes. + +Some opcodes are not constrained, which mean they will not be used by the proving system and are only used by the solver. + +Finally, some opcodes will have a predicate, whose value is 0 or 1. Its purpose is to nullify the opcode when the value is 0, so that it has no effect. Note that removing the opcode is not a solution because this modifies the circuit (the circuit being mainly the list of the opcodes). + +*Remark*: Opcodes operate on witnesses, but we will see that some opcode work on Arithmetic expressions of witnesses. We call an arithmetic expression a linear combination of witnesses and/or products of two witnesses (and also a constant term). A single witness is a (simple) arithmetic expression, and conversly, an arithmetic expression can be turned into a single witness using an arithmetic opcode (see below). So basically, using witnesses or arithmetic expressions is equivalent, but the latter can avoid the creation of witness in some cases. + +### Arithmetic opcode +An arithmetic opcode adds the constraint that P(w) = 0, where w=(w_1,..w_n) is a tuple of n witnesses, and P is a multi-variate polynomial of total degree at most 2. +The coefficients ${q_M}_{i,j}, q_i,q_c$ of the polynomial are known values which define the opcode. +A general expression of arithmetic opcode is the following: $\sum_{i,j} {q_M}_{i,j}w_iw_j + \sum_i q_iw_i +q_c = 0$ + +An arithmetic opcode can be used to: +- **express a constraint** on witnesses; for instance to express that a witness $w$ is a boolean, you can add the opcode: $w*w-w=0$ +- or, to **compute the value** of an arithmetic operation of some inputs. For instance, to multiply two witnesses $x$ and $y$, you would use the opcode $z-x*y=0$, which would constraint $z$ to be $x*y$. + + +The solver expects that at most one witness is not known when executing the opcode. + +### BlackBoxFuncCall opcode +These opcodes represent a specific computation. Even if any computation can be done using only arithmetic opcodes, it is not always efficient. Some proving systems, and in particular the proving system from Aztec, can implement several computations more efficiently using for instance look-up tables. The BlackBoxFuncCall opcode is used to ask the proving system to handle the computation by itself. +All black box functions takes as input a tuple (witness, num_bits), where num_bits is a constant representing the bit size of the input witness, and they have one or several witnesses as output. +Some more advanced computations assume that the proving system has an 'embedded curve'. It is a curve that cycle with the main curve of the proving system, i.e the scalar field of the embedded curve is the base field of the main one, and vice-versa. The curves used by the proving system are dependent on the proving system (and/or its configuration). Aztec's Barretenberg uses BN254 as the main curve and Grumpkin as the embedded curve. + +The black box functions supported by ACIR are: + +**AND**: performs the bitwise AND of lhs and rhs. bit_size must be the same for both inputs. +- lhs: (witness, bit_size) +- rhs: (witness, bit_size) +- output: a witness whose value is constrained to be lhs AND rhs, as bit_size bit integers + +**XOR**: performs the bitwise XOR of lhs and rhs. bit_size must be the same for both inputs. +- lhs: (witness, bit_size) +- rhs: (witness, bit_size) +- output: a witness whose value is constrained to be lhs XOR rhs, as bit_size bit integers + +**RANGE**: constraint the input to be of the provided bit size +input: (witness, bit_size) + +**SHA256**: computes sha256 of the inputs +- inputs are a byte array, i.e a vector of (FieldElement, 8) +- output is a byte array of len 32, i.e a vector of 32 (FieldElement, 8), constrainted to be the sha256 of the inputs. + +**Blake2s**: computes the Blake2s hash of the inputs, as specified in https://tools.ietf.org/html/rfc7693 +- inputs are a byte array, i.e a vector of (FieldElement, 8) +- output is a byte array of length 32, i.e a vector of 32 (FieldElement, 8), constrainted to be the blake2s of the inputs. + + +**SchnorrVerify**: Verify a Schnorr signature over the embedded curve +- inputs are: + - Public key as 2 (FieldElement, 254) + - signature as a vector of 64 bytes (FieldElement, 8) + - message as a vector of (FieldElement, 8) +- output: A witness representing the result of the signature verification; 0 for failure and 1 for success. + +Since the scalar field of the embedded curve is NOT the ACIR field, the (r,s) signature is represented as a 64 bytes array for the two field elements. On the other hand, the public key coordinates are ACIR fields. +The proving system decides how the message is to be hashed. Barretenberg uses Blake2s. + + +**PedersenCommitment**: Computes a Pedersen commitments of the inputs using generators of the embedded curve +- input: vector of (FieldElement, 254) +- output: 2 witnesses representing the x,y coordinates of the resulting Grumpkin point +- domain separator: a constant public value (a field element) that you can use so that the commitment also depends on the domain separator. Noir uses 0 as domain separator. + +The backend should handle proper conversion between the inputs being ACIR field elements and the scalar field of the embedded curve. In the case of Aztec's Barretenberg, the latter is bigger than the ACIR field so it is straightforward. The Peredersen generators are managed by the proving system. + + +**PedersenHash**: Computes a Pedersen commitments of the inputs and their number, using generators of the embedded curve +- input: vector of (FieldElement, 254) +- output: the x-coordinate of the pedersen commitment of the 'prepended input' (see below) +- domain separator: a constant public value (a field element) that you can use so that the hash also depends on the domain separator. Noir uses 0 as domain separator. + +In Barretenberg, PedersenHash is doing the same as PedersenCommitment, except that it prepends the inputs with their length. + + +**HashToField128Security**: This opcode is deprecated and will be removed. + +**EcdsaSecp256k1**: Verify an ECDSA signature over Secp256k1 +- inputs: + - x coordinate of public key as 32 bytes + - y coordinate of public key as 32 bytes + - the signature, as a 64 bytes array + - the hash of the message, as a vector of bytes +- output: 0 for failure and 1 for success + +Inputs and outputs are similar to SchnorrVerify, except that because we use a different curve (secp256k1), the field elements involved in the signature and the public key are defined as an array of 32 bytes. Another difference is that we assume the message is already hashed. + +**EcdsaSecp256r1**: Same as EcdsaSecp256k1, but done over another curve. + +**FixedBaseScalarMul**: scalar multiplication with a fixed generator of the embedded curve +- input: low, high are 2 (field , 254), representing the low and high part of the input. For Barretenberg, they must both be less than 128 bits. +- output: x and y coordinates of $low*G+high*2^{128}*G$, where G is a fixed generator + +Because the Grumpkin scalar field is bigger than the ACIR field, we provide 2 ACIR fields representing the low and high parts of the Grumpkin scalar $a$: +$a=low+high*2^{128},$ with $low, high < 2^{128}$ + +**Keccak256**: Computes the Keccak-256 (Ethereum version) of the inputs. +- inputs: Vector of bytes (FieldElement, 8) +- outputs: Vector of 32 bytes (FieldElement, 8) + + +**Keccak256VariableLength**: Computes the Keccak-256 (Ethereum version) of the inputs, restricted to the given length. +- inputs: Vector of bytes (FieldElement, 8) +- var_message_size: number of inputs to hash; it must be less (or equal) than the inputs length +- outputs: a vector of 32 bytes (FieldElement, 8) + + + +**RecursiveAggregation**: verify a proof inside the circuit. +**Warning: this opcode is subject to change.** +- verification_key: Vector of (FieldElement, 254) representing the verification key of the circuit being verified +- public_inputs: Vector of (FieldElement, 254) representing the public inputs corresponding to the proof being verified +- key_hash: one (FieldElement, 254). It should be the hash of the verification key. Barretenberg expects the Pedersen hash of the verification key +- input_aggregation_object: an optional vector of (FieldElement, 254). It is a blob of data specific to the proving sytem. +- output_aggregation_object: Some witnesses returned by the function, representing some data internal to the proving system. + +This black box function does not fully verify a proof, what it does is verifying that the key_hash is indeed a hash of verification_key, allowing the user to use the verification key as private inputs and only have the key_hash as public input, which is more performant. +Another thing that it does is preparing the verification of the proof. In order to fully verify a proof, some operations may still be required to be done by the final verifier. This is why this black box function does not say if verification is passing or not. +If you have several proofs to verify in one ACIR program, you would call RecursiveAggregation() multiple times and passing the output_aggregation_object as input_aggregation_object to the next RecursiveAggregation() call, except for the first call where you do not have any input_aggregation_object. +If one of the proof you verify with the black box function does not verify, then the verification of the proof of the main ACIR program will ultimately fail. + + +### Brillig +This opcode is used as a hint for the solver when executing (solving) the circuit. The opcode does not generate any constraint and is usually the result of the compilation of an unconstrained noir function. +- inputs: inputs to the opcode, as 'arithmetic expressions'. +- outputs: opcode outputs, as witnesses +- bytecode: assembly code representing the computation to perform within this opcode. The noir assembly specification is not part of this document. +- predicate: an arithmetic expression that disable the opcode when it is null. + +Let's see an example with euclidian division. +The normal way to compute a/b, where a and b are 8-bits integers, is to implement Euclid algorithm which computes in a loop (or recursively) modulos of the kind 'a mod b'. Doing this computation requires a lot of steps to be properly implemented in ACIR, especially the loop with a condition. However, euclidian division can be easily constrained with one arithmetic opcode: a = bq+r, assuming q is 8 bits and r "sha256", BlackBoxFunc::SchnorrVerify => "schnorr_verify", BlackBoxFunc::Blake2s => "blake2s", - BlackBoxFunc::PedersenCommitment => "pedersen", + BlackBoxFunc::PedersenCommitment => "pedersen_commitment", BlackBoxFunc::PedersenHash => "pedersen_hash", BlackBoxFunc::HashToField128Security => "hash_to_field_128_security", BlackBoxFunc::EcdsaSecp256k1 => "ecdsa_secp256k1", @@ -82,7 +79,7 @@ impl BlackBoxFunc { "sha256" => Some(BlackBoxFunc::SHA256), "schnorr_verify" => Some(BlackBoxFunc::SchnorrVerify), "blake2s" => Some(BlackBoxFunc::Blake2s), - "pedersen" => Some(BlackBoxFunc::PedersenCommitment), + "pedersen_commitment" => Some(BlackBoxFunc::PedersenCommitment), "pedersen_hash" => Some(BlackBoxFunc::PedersenHash), "hash_to_field_128_security" => Some(BlackBoxFunc::HashToField128Security), "ecdsa_secp256k1" => Some(BlackBoxFunc::EcdsaSecp256k1), diff --git a/noir/acvm-repo/acir/src/circuit/directives.rs b/noir/acvm-repo/acir/src/circuit/directives.rs index a86eb525c1f..c3a5b055f19 100644 --- a/noir/acvm-repo/acir/src/circuit/directives.rs +++ b/noir/acvm-repo/acir/src/circuit/directives.rs @@ -34,13 +34,3 @@ pub enum Directive { 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/noir/acvm-repo/acir/src/circuit/opcodes.rs b/noir/acvm-repo/acir/src/circuit/opcodes.rs index dc7f73b47e5..0e15fe3757c 100644 --- a/noir/acvm-repo/acir/src/circuit/opcodes.rs +++ b/noir/acvm-repo/acir/src/circuit/opcodes.rs @@ -33,58 +33,6 @@ pub enum Opcode { }, } -#[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 { diff --git a/noir/acvm-repo/acir_field/Cargo.toml b/noir/acvm-repo/acir_field/Cargo.toml index 4039a14ce73..cedfc66e734 100644 --- a/noir/acvm-repo/acir_field/Cargo.toml +++ b/noir/acvm-repo/acir_field/Cargo.toml @@ -2,7 +2,7 @@ name = "acir_field" description = "The field implementation being used by ACIR." # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/noir/acvm-repo/acir_field/src/generic_ark.rs b/noir/acvm-repo/acir_field/src/generic_ark.rs index 0f4be21ad54..5c70d3cda37 100644 --- a/noir/acvm-repo/acir_field/src/generic_ark.rs +++ b/noir/acvm-repo/acir_field/src/generic_ark.rs @@ -143,6 +143,12 @@ impl From for FieldElement { } } +impl From for FieldElement { + fn from(a: usize) -> FieldElement { + FieldElement::from(a as u128) + } +} + impl From for FieldElement { fn from(boolean: bool) -> FieldElement { if boolean { @@ -266,7 +272,10 @@ impl FieldElement { } 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()?; + // Values of odd length require an additional "0" prefix + let sanitized_value = + if value.len() % 2 == 0 { value.to_string() } else { format!("0{}", value) }; + let hex_as_bytes = hex::decode(sanitized_value).ok()?; Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes)) } @@ -440,6 +449,25 @@ mod tests { assert_eq!(minus_i_field_element.to_hex(), string); } } + + #[test] + fn deserialize_even_and_odd_length_hex() { + // Test cases of (odd, even) length hex strings + let hex_strings = + vec![("0x0", "0x00"), ("0x1", "0x01"), ("0x002", "0x0002"), ("0x00003", "0x000003")]; + for (i, case) in hex_strings.into_iter().enumerate() { + let i_field_element = + crate::generic_ark::FieldElement::::from(i as i128); + let odd_field_element = + crate::generic_ark::FieldElement::::from_hex(case.0).unwrap(); + let even_field_element = + crate::generic_ark::FieldElement::::from_hex(case.1).unwrap(); + + assert_eq!(i_field_element, odd_field_element); + assert_eq!(odd_field_element, even_field_element); + } + } + #[test] fn max_num_bits_smoke() { let max_num_bits_bn254 = crate::generic_ark::FieldElement::::max_num_bits(); diff --git a/noir/acvm-repo/acvm/Cargo.toml b/noir/acvm-repo/acvm/Cargo.toml index ca43c54b204..5fdf44cbd5e 100644 --- a/noir/acvm-repo/acvm/Cargo.toml +++ b/noir/acvm-repo/acvm/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm" description = "The virtual machine that processes ACIR given a backend/proof system." # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true @@ -16,30 +16,26 @@ repository.workspace = true num-bigint.workspace = true num-traits.workspace = true thiserror.workspace = true +log.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"] +default = ["bn254"] 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" diff --git a/noir/acvm-repo/acvm/src/compiler/mod.rs b/noir/acvm-repo/acvm/src/compiler/mod.rs index 4abf94a2e78..ccb043914d6 100644 --- a/noir/acvm-repo/acvm/src/compiler/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/mod.rs @@ -1,10 +1,8 @@ -use acir::{ - circuit::{opcodes::UnsupportedMemoryOpcode, Circuit, Opcode, OpcodeLocation}, - BlackBoxFunc, -}; -use thiserror::Error; +use std::collections::HashMap; -use crate::Language; +use acir::circuit::{Circuit, OpcodeLocation}; + +use crate::ExpressionWidth; // The various passes that we can use over ACIR mod optimizers; @@ -15,24 +13,26 @@ use optimizers::optimize_internal; pub use transformers::transform; use transformers::transform_internal; -#[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, + /// Maps the old acir indices to the new acir indices + old_indices_to_new_indices: HashMap>, } impl AcirTransformationMap { + /// Builds a map from 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. + fn new(acir_opcode_positions: Vec) -> Self { + let mut old_indices_to_new_indices = HashMap::with_capacity(acir_opcode_positions.len()); + for (new_index, old_index) in acir_opcode_positions.into_iter().enumerate() { + old_indices_to_new_indices.entry(old_index).or_insert_with(Vec::new).push(new_index); + } + AcirTransformationMap { old_indices_to_new_indices } + } + pub fn new_locations( &self, old_location: OpcodeLocation, @@ -42,16 +42,16 @@ impl AcirTransformationMap { 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 } - } - }) + self.old_indices_to_new_indices.get(&old_acir_index).into_iter().flat_map( + move |new_indices| { + new_indices.iter().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 } + } + }) + }, + ) } } @@ -71,15 +71,16 @@ fn transform_assert_messages( /// 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> { - let (acir, AcirTransformationMap { acir_opcode_positions }) = optimize_internal(acir); + expression_width: ExpressionWidth, +) -> (Circuit, AcirTransformationMap) { + let (acir, acir_opcode_positions) = optimize_internal(acir); + + let (mut acir, acir_opcode_positions) = + transform_internal(acir, expression_width, acir_opcode_positions); - let (mut acir, transformation_map) = - transform_internal(acir, np_language, is_opcode_supported, acir_opcode_positions)?; + let transformation_map = AcirTransformationMap::new(acir_opcode_positions); acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map); - Ok((acir, transformation_map)) + (acir, transformation_map) } diff --git a/noir/acvm-repo/acvm/src/compiler/optimizers/mod.rs b/noir/acvm-repo/acvm/src/compiler/optimizers/mod.rs index 627ddbb4117..85a97c2c7dc 100644 --- a/noir/acvm-repo/acvm/src/compiler/optimizers/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/optimizers/mod.rs @@ -13,7 +13,9 @@ use super::{transform_assert_messages, AcirTransformationMap}; /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] independent optimizations to a [`Circuit`]. pub fn optimize(acir: Circuit) -> (Circuit, AcirTransformationMap) { - let (mut acir, transformation_map) = optimize_internal(acir); + let (mut acir, new_opcode_positions) = optimize_internal(acir); + + let transformation_map = AcirTransformationMap::new(new_opcode_positions); acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map); @@ -21,7 +23,9 @@ pub fn optimize(acir: Circuit) -> (Circuit, AcirTransformationMap) { } /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] independent optimizations to a [`Circuit`]. -pub(super) fn optimize_internal(acir: Circuit) -> (Circuit, AcirTransformationMap) { +pub(super) fn optimize_internal(acir: Circuit) -> (Circuit, Vec) { + log::trace!("Start circuit optimization"); + // General optimizer pass let opcodes: Vec = acir .opcodes @@ -50,7 +54,7 @@ pub(super) fn optimize_internal(acir: Circuit) -> (Circuit, AcirTransformationMa let (acir, acir_opcode_positions) = range_optimizer.replace_redundant_ranges(acir_opcode_positions); - let transformation_map = AcirTransformationMap { acir_opcode_positions }; + log::trace!("Finish circuit optimization"); - (acir, transformation_map) + (acir, acir_opcode_positions) } diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/csat.rs b/noir/acvm-repo/acvm/src/compiler/transformers/csat.rs index 9f89ac4671a..0d1ab87aae5 100644 --- a/noir/acvm-repo/acvm/src/compiler/transformers/csat.rs +++ b/noir/acvm-repo/acvm/src/compiler/transformers/csat.rs @@ -9,7 +9,7 @@ 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 transformer is only used when targeting the [`Bounded`][crate::ExpressionWidth::Bounded] configuration. /// /// This is done by creating intermediate variables to hold partial calculations and then combining them /// to calculate the original expression. diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/fallback.rs b/noir/acvm-repo/acvm/src/compiler/transformers/fallback.rs deleted file mode 100644 index 06dfc84a798..00000000000 --- a/noir/acvm-repo/acvm/src/compiler/transformers/fallback.rs +++ /dev/null @@ -1,158 +0,0 @@ -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 - 1, - 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/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs index d827b759666..2a3e28c536a 100644 --- a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -5,34 +5,33 @@ use acir::{ }; use indexmap::IndexMap; -use crate::Language; +use crate::ExpressionWidth; mod csat; -mod fallback; mod r1cs; pub(crate) use csat::CSatTransformer; -pub(crate) use fallback::FallbackTransformer; pub(crate) use r1cs::R1CSTransformer; -use super::{transform_assert_messages, AcirTransformationMap, CompileError}; +use super::{transform_assert_messages, AcirTransformationMap}; /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. pub fn transform( acir: Circuit, - np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool, -) -> Result<(Circuit, AcirTransformationMap), CompileError> { + expression_width: ExpressionWidth, +) -> (Circuit, AcirTransformationMap) { // 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(); - let (mut acir, transformation_map) = - transform_internal(acir, np_language, is_opcode_supported, acir_opcode_positions)?; + let (mut acir, acir_opcode_positions) = + transform_internal(acir, expression_width, acir_opcode_positions); + + let transformation_map = AcirTransformationMap::new(acir_opcode_positions); acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map); - Ok((acir, transformation_map)) + (acir, transformation_map) } /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. @@ -40,21 +39,17 @@ pub fn transform( /// Accepts an injected `acir_opcode_positions` to allow transformations to be applied directly after optimizations. pub(super) fn transform_internal( acir: Circuit, - np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool, + expression_width: ExpressionWidth, acir_opcode_positions: Vec, -) -> Result<(Circuit, AcirTransformationMap), CompileError> { - // Fallback transformer pass - let (acir, acir_opcode_positions) = - FallbackTransformer::transform(acir, is_opcode_supported, acir_opcode_positions)?; - - let mut transformer = match &np_language { - crate::Language::R1CS => { - let transformation_map = AcirTransformationMap { acir_opcode_positions }; +) -> (Circuit, Vec) { + log::trace!("Start circuit transformation"); + + let mut transformer = match &expression_width { + crate::ExpressionWidth::Unbounded => { let transformer = R1CSTransformer::new(acir); - return Ok((transformer.transform(), transformation_map)); + return (transformer.transform(), acir_opcode_positions); } - crate::Language::PLONKCSat { width } => { + crate::ExpressionWidth::Bounded { width } => { let mut csat = CSatTransformer::new(*width); for value in acir.circuit_arguments() { csat.mark_solvable(value); @@ -214,8 +209,7 @@ pub(super) fn transform_internal( ..acir }; - let transformation_map = - AcirTransformationMap { acir_opcode_positions: new_acir_opcode_positions }; + log::trace!("Finish circuit transformation"); - Ok((acir, transformation_map)) + (acir, new_acir_opcode_positions) } diff --git a/noir/acvm-repo/acvm/src/lib.rs b/noir/acvm-repo/acvm/src/lib.rs index 0ab037a2e4b..626bb2c9b91 100644 --- a/noir/acvm-repo/acvm/src/lib.rs +++ b/noir/acvm-repo/acvm/src/lib.rs @@ -18,10 +18,16 @@ 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 +/// Specifies the maximum width of the expressions which will be constrained. +/// +/// Unbounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports R1CS. +/// +/// Bounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports PLONK, where arithmetic expressions have a +/// finite fan-in. #[derive(Debug, Clone, Copy)] -pub enum Language { - R1CS, - PLONKCSat { width: usize }, +pub enum ExpressionWidth { + Unbounded, + Bounded { width: usize }, } diff --git a/noir/acvm-repo/acvm/src/pwg/mod.rs b/noir/acvm-repo/acvm/src/pwg/mod.rs index c1edf60161a..859ad010dcd 100644 --- a/noir/acvm-repo/acvm/src/pwg/mod.rs +++ b/noir/acvm-repo/acvm/src/pwg/mod.rs @@ -11,7 +11,7 @@ use acir::{ use acvm_blackbox_solver::BlackBoxResolutionError; use self::{arithmetic::ArithmeticSolver, directives::solve_directives, memory_op::MemoryOpSolver}; -use crate::{BlackBoxFunctionSolver, Language}; +use crate::BlackBoxFunctionSolver; use thiserror::Error; @@ -104,8 +104,6 @@ impl std::fmt::Display for ErrorLocation { 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:?}")] @@ -122,9 +120,6 @@ impl From for OpcodeResolutionError { BlackBoxResolutionError::Failed(func, reason) => { OpcodeResolutionError::BlackBoxFunctionFailed(func, reason) } - BlackBoxResolutionError::Unsupported(func) => { - OpcodeResolutionError::UnsupportedBlackBoxFunc(func) - } } } } @@ -450,30 +445,3 @@ fn any_witness_from_expression(expr: &Expression) -> Option { 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/noir/acvm-repo/acvm/tests/stdlib.rs b/noir/acvm-repo/acvm/tests/stdlib.rs deleted file mode 100644 index c96c55f9401..00000000000 --- a/noir/acvm-repo/acvm/tests/stdlib.rs +++ /dev/null @@ -1,354 +0,0 @@ -#![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/noir/acvm-repo/acvm_js/Cargo.toml b/noir/acvm-repo/acvm_js/Cargo.toml index 190675da35c..22bd6e5aa7e 100644 --- a/noir/acvm-repo/acvm_js/Cargo.toml +++ b/noir/acvm-repo/acvm_js/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_js" description = "Typescript wrapper around the ACVM allowing execution of ACIR code" # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true @@ -26,9 +26,9 @@ wasm-bindgen-futures.workspace = true console_error_panic_hook.workspace = true gloo-utils.workspace = true js-sys.workspace = true +log.workspace = true serde = { version = "1.0.136", features = ["derive"] } -log = "0.4.17" wasm-logger = "0.2.0" const-str = "0.5.5" diff --git a/noir/acvm-repo/acvm_js/package.json b/noir/acvm-repo/acvm_js/package.json index 6b3efc35d1a..9f265dd676a 100644 --- a/noir/acvm-repo/acvm_js/package.json +++ b/noir/acvm-repo/acvm_js/package.json @@ -1,6 +1,6 @@ { "name": "@noir-lang/acvm_js", - "version": "0.35.0", + "version": "0.38.0", "repository": { "type": "git", "url": "https://github.com/noir-lang/acvm.git" diff --git a/noir/acvm-repo/barretenberg_blackbox_solver/Cargo.toml b/noir/acvm-repo/barretenberg_blackbox_solver/Cargo.toml index 9669a4184a4..01f5e6ca950 100644 --- a/noir/acvm-repo/barretenberg_blackbox_solver/Cargo.toml +++ b/noir/acvm-repo/barretenberg_blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "barretenberg_blackbox_solver" description = "A wrapper around a barretenberg WASM binary to execute black box functions for which there is no rust implementation" # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/noir/acvm-repo/blackbox_solver/Cargo.toml b/noir/acvm-repo/blackbox_solver/Cargo.toml index 170de76875b..be2a58417f4 100644 --- a/noir/acvm-repo/blackbox_solver/Cargo.toml +++ b/noir/acvm-repo/blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_blackbox_solver" description = "A solver for the blackbox functions found in ACIR and Brillig" # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/noir/acvm-repo/blackbox_solver/src/lib.rs b/noir/acvm-repo/blackbox_solver/src/lib.rs index 13d0f562415..8b7c6343962 100644 --- a/noir/acvm-repo/blackbox_solver/src/lib.rs +++ b/noir/acvm-repo/blackbox_solver/src/lib.rs @@ -16,8 +16,6 @@ use thiserror::Error; #[derive(Clone, PartialEq, Eq, Debug, Error)] pub enum BlackBoxResolutionError { - #[error("unsupported blackbox function: {0}")] - Unsupported(BlackBoxFunc), #[error("failed to solve blackbox function: {0}, reason: {1}")] Failed(BlackBoxFunc, String), } diff --git a/noir/acvm-repo/brillig/Cargo.toml b/noir/acvm-repo/brillig/Cargo.toml index 19488c8fbe8..ee8651faeec 100644 --- a/noir/acvm-repo/brillig/Cargo.toml +++ b/noir/acvm-repo/brillig/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig" description = "Brillig is the bytecode ACIR uses for non-determinism." # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/noir/acvm-repo/brillig/src/opcodes.rs b/noir/acvm-repo/brillig/src/opcodes.rs index 44d90acde47..79295cc6e5d 100644 --- a/noir/acvm-repo/brillig/src/opcodes.rs +++ b/noir/acvm-repo/brillig/src/opcodes.rs @@ -133,28 +133,6 @@ pub enum BrilligOpcode { Stop, } -impl BrilligOpcode { - pub fn name(&self) -> &'static str { - match self { - BrilligOpcode::BinaryFieldOp { .. } => "binary_field_op", - BrilligOpcode::BinaryIntOp { .. } => "binary_int_op", - BrilligOpcode::JumpIfNot { .. } => "jmp_if_not", - BrilligOpcode::JumpIf { .. } => "jmp_if", - BrilligOpcode::Jump { .. } => "jmp", - BrilligOpcode::Call { .. } => "call", - BrilligOpcode::Const { .. } => "const", - BrilligOpcode::Return => "return", - BrilligOpcode::ForeignCall { .. } => "foreign_call", - BrilligOpcode::Mov { .. } => "mov", - BrilligOpcode::Load { .. } => "load", - BrilligOpcode::Store { .. } => "store", - BrilligOpcode::BlackBox(_) => "black_box", - BrilligOpcode::Trap => "trap", - BrilligOpcode::Stop => "stop", - } - } -} - /// Binary fixed-length field expressions #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum BinaryFieldOp { diff --git a/noir/acvm-repo/brillig_vm/Cargo.toml b/noir/acvm-repo/brillig_vm/Cargo.toml index 21c5cd3a5f5..91bef2572bb 100644 --- a/noir/acvm-repo/brillig_vm/Cargo.toml +++ b/noir/acvm-repo/brillig_vm/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig_vm" description = "The virtual machine that processes Brillig bytecode, used to introduce non-determinism to the ACVM" # x-release-please-start-version -version = "0.35.0" +version = "0.38.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/noir/acvm-repo/stdlib/CHANGELOG.md b/noir/acvm-repo/stdlib/CHANGELOG.md deleted file mode 100644 index bea80c95d1e..00000000000 --- a/noir/acvm-repo/stdlib/CHANGELOG.md +++ /dev/null @@ -1,350 +0,0 @@ -# Changelog - -## [0.27.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.26.1...acvm_stdlib-v0.27.0) (2023-09-19) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.26.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.26.0...acvm_stdlib-v0.26.1) (2023-09-12) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.26.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.25.0...acvm_stdlib-v0.26.0) (2023-09-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.25.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.24.1...acvm_stdlib-v0.25.0) (2023-09-04) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.24.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.24.0...acvm_stdlib-v0.24.1) (2023-09-03) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.24.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.23.0...acvm_stdlib-v0.24.0) (2023-08-31) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.23.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.22.0...acvm_stdlib-v0.23.0) (2023-08-30) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.22.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.21.0...acvm_stdlib-v0.22.0) (2023-08-18) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.21.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.20.1...acvm_stdlib-v0.21.0) (2023-07-26) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.20.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.20.0...acvm_stdlib-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/acvm_stdlib-v0.19.1...acvm_stdlib-v0.20.0) (2023-07-20) - - -### Features - -* **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/acvm_stdlib-v0.19.0...acvm_stdlib-v0.19.1) (2023-07-17) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.19.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.18.2...acvm_stdlib-v0.19.0) (2023-07-15) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.18.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.18.1...acvm_stdlib-v0.18.2) (2023-07-12) - - -### Features - -* **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/acvm_stdlib-v0.18.0...acvm_stdlib-v0.18.1) (2023-07-12) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.18.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.17.0...acvm_stdlib-v0.18.0) (2023-07-12) - - -### Features - -* **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)) - -## [0.17.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.16.0...acvm_stdlib-v0.17.0) (2023-07-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.16.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.15.1...acvm_stdlib-v0.16.0) (2023-07-06) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.15.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.15.0...acvm_stdlib-v0.15.1) (2023-06-20) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.15.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.14.2...acvm_stdlib-v0.15.0) (2023-06-15) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.14.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.14.1...acvm_stdlib-v0.14.2) (2023-06-08) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.14.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.14.0...acvm_stdlib-v0.14.1) (2023-06-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.14.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.3...acvm_stdlib-v0.14.0) (2023-06-06) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.13.3](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.2...acvm_stdlib-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_stdlib-v0.13.1...acvm_stdlib-v0.13.2) (2023-06-02) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.13.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.13.0...acvm_stdlib-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/acvm_stdlib-v0.12.0...acvm_stdlib-v0.13.0) (2023-06-01) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.12.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.11.0...acvm_stdlib-v0.12.0) (2023-05-17) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.11.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.3...acvm_stdlib-v0.11.0) (2023-05-04) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.10.3](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.2...acvm_stdlib-v0.10.3) (2023-04-28) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.10.2](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.10.1...acvm_stdlib-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/acvm_stdlib-v0.10.0...acvm_stdlib-v0.10.1) (2023-04-28) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - -## [0.10.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.9.0...acvm_stdlib-v0.10.0) (2023-04-26) - - -### ⚠ BREAKING CHANGES - -* organise operator implementations for Expression ([#190](https://github.com/noir-lang/acvm/issues/190)) - -### 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 - -* 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_stdlib-v0.8.1...acvm_stdlib-v0.9.0) (2023-04-07) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.8.1 to 0.9.0 - -## [0.8.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.8.0...acvm_stdlib-v0.8.1) (2023-03-30) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.8.0 to 0.8.1 - -## [0.8.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.7.1...acvm_stdlib-v0.8.0) (2023-03-28) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.7.1 to 0.8.0 - -## [0.7.1](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.7.0...acvm_stdlib-v0.7.1) (2023-03-27) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.7.0 to 0.7.1 - -## [0.7.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.6.0...acvm_stdlib-v0.7.0) (2023-03-23) - - -### Miscellaneous Chores - -* **acvm_stdlib:** Synchronize acvm versions - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.6.0 to 0.7.0 - -## [0.6.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.5.0...acvm_stdlib-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)) - -### Miscellaneous Chores - -* **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)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.5.0 to 0.6.0 - -## [0.5.0](https://github.com/noir-lang/acvm/compare/acvm_stdlib-v0.4.1...acvm_stdlib-v0.5.0) (2023-02-22) - - -### ⚠ BREAKING CHANGES - -* refactor ToRadix to ToRadixLe and ToRadixBe ([#58](https://github.com/noir-lang/acvm/issues/58)) - -### 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)) - - -### Dependencies - -* The following workspace dependencies were updated - * dependencies - * acir bumped from 0.4.1 to 0.5.0 diff --git a/noir/acvm-repo/stdlib/Cargo.toml b/noir/acvm-repo/stdlib/Cargo.toml deleted file mode 100644 index 9e0e08e1338..00000000000 --- a/noir/acvm-repo/stdlib/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "acvm_stdlib" -description = "The ACVM standard library." -# x-release-please-start-version -version = "0.35.0" -# 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.workspace = true - -[features] -default = ["bn254"] -bn254 = ["acir/bn254"] -bls12_381 = ["acir/bls12_381"] -testing = ["bn254"] diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/blake2s.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/blake2s.rs deleted file mode 100644 index 92bf93d2d56..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/blake2s.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Blake2s fallback function. -use super::{ - utils::{byte_decomposition, round_to_nearest_byte}, - UInt32, -}; -use acir::{ - circuit::Opcode, - native_types::{Expression, Witness}, - FieldElement, -}; -use std::vec; - -const BLAKE2S_BLOCKBYTES_USIZE: usize = 64; -const MSG_SCHEDULE_BLAKE2: [[usize; 16]; 10] = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], - [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], - [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], - [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], - [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], - [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], - [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], - [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], -]; -const INITIAL_H: [u32; 8] = [ - 0x6b08e647, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; -const IV_VALUE: [u32; 8] = [ - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, -]; - -pub fn blake2s( - inputs: Vec<(Expression, u32)>, - outputs: Vec, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = create_blake2s_constraint(new_inputs, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - for i in 0..outputs.len() { - let mut expr = Expression::from(outputs[i]); - expr.push_addition_term(-FieldElement::one(), result[i]); - new_opcodes.push(Opcode::Arithmetic(expr)); - } - (num_witness, new_opcodes) -} - -pub(crate) fn create_blake2s_constraint( - input: Vec, - num_witness: u32, -) -> (Vec, u32, Vec) { - let mut new_opcodes = Vec::new(); - - // prepare constants - let (mut blake2s_state, extra_opcodes, num_witness) = Blake2sState::init(num_witness); - new_opcodes.extend(extra_opcodes); - let (blake2s_constants, extra_opcodes, num_witness) = - Blake2sConstantsInCircuit::init(num_witness); - new_opcodes.extend(extra_opcodes); - let (blake2s_iv, extra_opcodes, mut num_witness) = Blake2sIV::init(num_witness); - new_opcodes.extend(extra_opcodes); - - let mut offset = 0; - let mut size = input.len(); - - while size > BLAKE2S_BLOCKBYTES_USIZE { - let (extra_opcodes, updated_witness_counter) = blake2s_increment_counter( - &mut blake2s_state, - &blake2s_constants.blake2s_blockbytes_uint32, - num_witness, - ); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, updated_witness_counter) = blake2s_compress( - &mut blake2s_state, - &blake2s_iv, - input.get(offset..offset + BLAKE2S_BLOCKBYTES_USIZE).unwrap(), - updated_witness_counter, - ); - new_opcodes.extend(extra_opcodes); - offset += BLAKE2S_BLOCKBYTES_USIZE; - size -= BLAKE2S_BLOCKBYTES_USIZE; - num_witness = updated_witness_counter; - } - - let (u32_max, extra_opcodes, mut num_witness) = UInt32::load_constant(u32::MAX, num_witness); - new_opcodes.extend(extra_opcodes); - blake2s_state.f[0] = u32_max; - - // pad final block - let mut final_block = input.get(offset..).unwrap().to_vec(); - for _ in 0..BLAKE2S_BLOCKBYTES_USIZE - final_block.len() { - let (pad, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(0_u32, num_witness); - new_opcodes.extend(extra_opcodes); - final_block.push(pad.inner); - num_witness = updated_witness_counter; - } - - let (size_w, extra_opcodes, num_witness) = UInt32::load_constant(size as u32, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - blake2s_increment_counter(&mut blake2s_state, &size_w, num_witness); - new_opcodes.extend(extra_opcodes); - - let (extra_opcodes, num_witness) = - blake2s_compress(&mut blake2s_state, &blake2s_iv, &final_block, num_witness); - new_opcodes.extend(extra_opcodes); - - // decompose the result bytes in u32 to u8 - let (extra_opcodes, mut byte1, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[0].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte2, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[1].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte3, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[2].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte4, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[3].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte5, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[4].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte6, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[5].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte7, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[6].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut byte8, num_witness) = - byte_decomposition(Expression::from(blake2s_state.h[7].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - - byte1.reverse(); - byte2.reverse(); - byte3.reverse(); - byte4.reverse(); - byte5.reverse(); - byte6.reverse(); - byte7.reverse(); - byte8.reverse(); - - let result = vec![byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8] - .into_iter() - .flatten() - .collect(); - - (result, num_witness, new_opcodes) -} - -fn blake2s_increment_counter( - state: &mut Blake2sState, - inc: &UInt32, - num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - - // t0 + inc - let (state_t0, extra_opcodes, num_witness) = state.t[0].add(inc, num_witness); - new_opcodes.extend(extra_opcodes); - state.t[0] = state_t0; - - // t1 + (t0 < inc) - let (to_inc, extra_opcodes, num_witness) = state.t[0].less_than_comparison(inc, num_witness); - new_opcodes.extend(extra_opcodes); - let (state_t1, extra_opcodes, num_witness) = state.t[1].add(&to_inc, num_witness); - new_opcodes.extend(extra_opcodes); - state.t[1] = state_t1; - - (new_opcodes, num_witness) -} - -fn blake2s_compress( - state: &mut Blake2sState, - blake2s_iv: &Blake2sIV, - input: &[Witness], - mut num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut m = Vec::new(); - let mut v = Vec::new(); - - for i in 0..16 { - let mut mi_bytes = input.get(i * 4..i * 4 + 4).unwrap().to_vec(); - mi_bytes.reverse(); - let (mi, extra_opcodes, updated_witness_counter) = - UInt32::from_witnesses(&mi_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - m.push(mi[0]); - num_witness = updated_witness_counter; - } - - for i in 0..8 { - v.push(state.h[i]); - } - - v.push(blake2s_iv.iv[0]); - v.push(blake2s_iv.iv[1]); - v.push(blake2s_iv.iv[2]); - v.push(blake2s_iv.iv[3]); - let (v12, extra_opcodes, num_witness) = state.t[0].xor(&blake2s_iv.iv[4], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v12); - let (v13, extra_opcodes, num_witness) = state.t[1].xor(&blake2s_iv.iv[5], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v13); - let (v14, extra_opcodes, num_witness) = state.f[0].xor(&blake2s_iv.iv[6], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v14); - let (v15, extra_opcodes, num_witness) = state.f[1].xor(&blake2s_iv.iv[7], num_witness); - new_opcodes.extend(extra_opcodes); - v.push(v15); - - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 0, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 1, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 2, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 3, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 5, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 6, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 7, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = blake2s_round(&mut v, &m, 8, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, mut num_witness) = blake2s_round(&mut v, &m, 9, num_witness); - new_opcodes.extend(extra_opcodes); - - for i in 0..8 { - let (a, extra_opcodes, updated_witness_counter) = state.h[i].xor(&v[i], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_hi, extra_opcodes, updated_witness_counter) = - a.xor(&v[i + 8], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - state.h[i] = state_hi; - num_witness = updated_witness_counter; - } - - (new_opcodes, num_witness) -} - -fn blake2s_round( - state: &mut [UInt32], - msg: &[UInt32], - round: usize, - num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - let schedule = &MSG_SCHEDULE_BLAKE2[round]; - - // Mix the columns. - let (extra_opcodes, num_witness) = - g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]], num_witness); - new_opcodes.extend(extra_opcodes); - - // Mix the rows. - let (extra_opcodes, num_witness) = - g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]], num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, num_witness) = - g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]], num_witness); - new_opcodes.extend(extra_opcodes); - - (new_opcodes, num_witness) -} - -#[allow(clippy::too_many_arguments)] -fn g( - state: &mut [UInt32], - a: usize, - b: usize, - c: usize, - d: usize, - x: UInt32, - y: UInt32, - num_witness: u32, -) -> (Vec, u32) { - let mut new_opcodes = Vec::new(); - - // calculate state[a] as `state[a] + state[b] + x` - let (state_a_1, extra_opcodes, num_witness) = state[a].add(&state[b], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_a, extra_opcodes, num_witness) = state_a_1.add(&x, num_witness); - new_opcodes.extend(extra_opcodes); - state[a] = state_a; - - // calculate state[d] as `(state[d] ^ state[a]).ror(16)` - let (state_d_1, extra_opcodes, num_witness) = state[d].xor(&state[a], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_d, extra_opcodes, num_witness) = state_d_1.ror(16, num_witness); - new_opcodes.extend(extra_opcodes); - state[d] = state_d; - - // calculate state[c] as `state[c] + state[d]` - let (state_c, extra_opcodes, num_witness) = state[c].add(&state[d], num_witness); - new_opcodes.extend(extra_opcodes); - state[c] = state_c; - - // caclulate state[b] as `(state[b] ^ state[c]).ror(12)` - let (state_b_1, extra_opcodes, num_witness) = state[b].xor(&state[c], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_b, extra_opcodes, num_witness) = state_b_1.ror(12, num_witness); - new_opcodes.extend(extra_opcodes); - state[b] = state_b; - - // calculate state[a] as `state[a] + state[b] + y` - let (state_a_1, extra_opcodes, num_witness) = state[a].add(&state[b], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_a, extra_opcodes, num_witness) = state_a_1.add(&y, num_witness); - new_opcodes.extend(extra_opcodes); - state[a] = state_a; - - // calculate state[d] as `(state[d] ^ state[a]).ror(8)` - let (state_d_1, extra_opcodes, num_witness) = state[d].xor(&state[a], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_d, extra_opcodes, num_witness) = state_d_1.ror(8, num_witness); - new_opcodes.extend(extra_opcodes); - state[d] = state_d; - - // calculate state[c] as `state[c] + state[d]` - let (state_c, extra_opcodes, num_witness) = state[c].add(&state[d], num_witness); - new_opcodes.extend(extra_opcodes); - state[c] = state_c; - - // caclulate state[b] as `(state[b] ^ state[c]).ror(7)` - let (state_b_1, extra_opcodes, num_witness) = state[b].xor(&state[c], num_witness); - new_opcodes.extend(extra_opcodes); - let (state_b, extra_opcodes, num_witness) = state_b_1.ror(7, num_witness); - new_opcodes.extend(extra_opcodes); - state[b] = state_b; - - (new_opcodes, num_witness) -} - -/// Blake2s state `h` `t` and `f` -#[derive(Debug)] -struct Blake2sState { - h: Vec, - t: Vec, - f: Vec, -} - -impl Blake2sState { - fn new(h: Vec, t: Vec, f: Vec) -> Self { - Blake2sState { h, t, f } - } - - /// Initialize internal state of Blake2s - fn init(mut num_witness: u32) -> (Blake2sState, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut h = Vec::new(); - let mut t = Vec::new(); - let mut f = Vec::new(); - - for init_h in INITIAL_H { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(init_h, num_witness); - new_opcodes.extend(extra_opcodes); - h.push(new_witness); - num_witness = updated_witness_counter; - } - - for _ in 0..2 { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(0_u32, num_witness); - new_opcodes.extend(extra_opcodes); - t.push(new_witness); - num_witness = updated_witness_counter; - } - - for _ in 0..2 { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(0_u32, num_witness); - new_opcodes.extend(extra_opcodes); - f.push(new_witness); - num_witness = updated_witness_counter; - } - - let blake2s_state = Blake2sState::new(h, t, f); - - (blake2s_state, new_opcodes, num_witness) - } -} - -/// Blake2s IV (Initialization Vector) -struct Blake2sIV { - iv: Vec, -} - -impl Blake2sIV { - fn new(iv: Vec) -> Self { - Blake2sIV { iv } - } - - /// Initialize IV of Blake2s - fn init(mut num_witness: u32) -> (Blake2sIV, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut iv = Vec::new(); - - for iv_v in IV_VALUE { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(iv_v, num_witness); - new_opcodes.extend(extra_opcodes); - iv.push(new_witness); - num_witness = updated_witness_counter; - } - - let blake2s_iv = Blake2sIV::new(iv); - - (blake2s_iv, new_opcodes, num_witness) - } -} - -struct Blake2sConstantsInCircuit { - blake2s_blockbytes_uint32: UInt32, -} - -impl Blake2sConstantsInCircuit { - fn new(blake2s_blockbytes_uint32: UInt32) -> Self { - Blake2sConstantsInCircuit { blake2s_blockbytes_uint32 } - } - - fn init(num_witness: u32) -> (Blake2sConstantsInCircuit, Vec, u32) { - let mut new_opcodes = Vec::new(); - let (blake2s_blockbytes_uint32, extra_opcodes, num_witness) = - UInt32::load_constant(64_u32, num_witness); - new_opcodes.extend(extra_opcodes); - - (Blake2sConstantsInCircuit::new(blake2s_blockbytes_uint32), new_opcodes, num_witness) - } -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/hash_to_field.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/hash_to_field.rs deleted file mode 100644 index 91a7cdd09e4..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/hash_to_field.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! HashToField128Security fallback function. -use super::{ - blake2s::create_blake2s_constraint, - utils::{byte_decomposition, round_to_nearest_byte}, - UInt32, -}; -use crate::helpers::VariableStore; -use acir::{ - brillig::{self, RegisterIndex}, - circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; - -pub fn hash_to_field( - inputs: Vec<(Expression, u32)>, - outputs: Witness, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = create_blake2s_constraint(new_inputs, num_witness); - new_opcodes.extend(extra_opcodes); - - // transform bytes to a single field - let (result, extra_opcodes, num_witness) = field_from_be_bytes(&result, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - let mut expr = Expression::from(outputs); - expr.push_addition_term(-FieldElement::one(), result); - new_opcodes.push(Opcode::Arithmetic(expr)); - (num_witness, new_opcodes) -} - -/// Convert bytes represented by [Witness]es to a single [FieldElement] -fn field_from_be_bytes(result: &[Witness], num_witness: u32) -> (Witness, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // Load `0` and `256` using the load constant function from UInt32 - let (new_witness, extra_opcodes, num_witness) = UInt32::load_constant(0, num_witness); - let mut new_witness = new_witness.inner; - new_opcodes.extend(extra_opcodes); - let (const_256, extra_opcodes, mut num_witness) = UInt32::load_constant(256, num_witness); - let const_256 = const_256.inner; - new_opcodes.extend(extra_opcodes); - - // add byte and multiply 256 each round - for r in result.iter().take(result.len() - 1) { - let (updated_witness, extra_opcodes, updated_witness_counter) = - field_addition(&new_witness, r, num_witness); - new_opcodes.extend(extra_opcodes); - let (updated_witness, extra_opcodes, updated_witness_counter) = - field_mul(&updated_witness, &const_256, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - new_witness = updated_witness; - num_witness = updated_witness_counter; - } - - let (new_witness, extra_opcodes, num_witness) = - field_addition(&new_witness, &result[result.len() - 1], num_witness); - new_opcodes.extend(extra_opcodes); - - (new_witness, new_opcodes, num_witness) -} - -/// Caculate and constrain `self` + `rhs` as field -fn field_addition( - lhs: &Witness, - rhs: &Witness, - mut num_witness: u32, -) -> (Witness, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate `self` + `rhs` as field - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *lhs)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *rhs)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryFieldOp { - op: brillig::BinaryFieldOp::Add, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain addition - let mut add_expr = Expression::from(new_witness); - add_expr.push_addition_term(-FieldElement::one(), *lhs); - add_expr.push_addition_term(-FieldElement::one(), *rhs); - new_opcodes.push(Opcode::Arithmetic(add_expr)); - - (new_witness, new_opcodes, num_witness) -} - -/// Calculate and constrain `self` * `rhs` as field -pub(crate) fn field_mul( - lhs: &Witness, - rhs: &Witness, - mut num_witness: u32, -) -> (Witness, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calulate `self` * `rhs` with overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *lhs)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), *rhs)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryFieldOp { - op: brillig::BinaryFieldOp::Mul, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain mul - let mut mul_constraint = Expression::from(new_witness); - mul_constraint.push_multiplication_term(-FieldElement::one(), *lhs, *rhs); - new_opcodes.push(Opcode::Arithmetic(mul_constraint)); - - (new_witness, new_opcodes, num_witness) -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/keccak256.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/keccak256.rs deleted file mode 100644 index d91db3dc2c6..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/keccak256.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! Keccak256 fallback function. -use super::{ - sha256::pad, - uint8::UInt8, - utils::{byte_decomposition, round_to_nearest_byte}, - UInt64, -}; -use acir::{ - circuit::Opcode, - native_types::{Expression, Witness}, - FieldElement, -}; - -const STATE_NUM_BYTES: usize = 200; -const BITS: usize = 256; -const WORD_SIZE: usize = 8; -const BLOCK_SIZE: usize = (1600 - BITS * 2) / WORD_SIZE; -const ROUND_CONSTANTS: [u64; 24] = [ - 1, - 0x8082, - 0x800000000000808a, - 0x8000000080008000, - 0x808b, - 0x80000001, - 0x8000000080008081, - 0x8000000000008009, - 0x8a, - 0x88, - 0x80008009, - 0x8000000a, - 0x8000808b, - 0x800000000000008b, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x800a, - 0x800000008000000a, - 0x8000000080008081, - 0x8000000000008080, - 0x80000001, - 0x8000000080008008, -]; -const RHO: [u32; 24] = - [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]; -const PI: [usize; 24] = - [10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1]; - -pub fn keccak256( - inputs: Vec<(Expression, u32)>, - outputs: Vec, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = create_keccak_constraint(new_inputs, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - for i in 0..outputs.len() { - let mut expr = Expression::from(outputs[i]); - expr.push_addition_term(-FieldElement::one(), result[i]); - new_opcodes.push(Opcode::Arithmetic(expr)); - } - (num_witness, new_opcodes) -} - -fn create_keccak_constraint( - input: Vec, - num_witness: u32, -) -> (Vec, u32, Vec) { - let mut new_opcodes = Vec::new(); - let num_blocks = input.len() / BLOCK_SIZE + 1; - - // pad keccak - let (input, extra_opcodes, mut num_witness) = pad_keccak(input, num_blocks, num_witness); - new_opcodes.extend(extra_opcodes); - - // prepare state - let mut state = Vec::with_capacity(200); - for _ in 0..STATE_NUM_BYTES { - let (zero, extra_opcodes, updated_witness_counter) = UInt8::load_constant(0, num_witness); - new_opcodes.extend(extra_opcodes); - state.push(zero); - num_witness = updated_witness_counter; - } - - // process block - for i in 0..num_blocks { - for j in 0..BLOCK_SIZE { - let (new_state, extra_opcodes, updated_witness_counter) = - state[j].xor(&UInt8::new(input[i * BLOCK_SIZE + j]), num_witness); - new_opcodes.extend(extra_opcodes); - state[j] = new_state; - num_witness = updated_witness_counter; - } - let (new_state, extra_opcodes, updated_witness_counter) = keccakf(state, num_witness); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - state = new_state; - } - - let result: Vec = state[..32].iter().map(|x| x.inner).collect(); - (result, num_witness, new_opcodes) -} - -fn keccakf(state: Vec, num_witness: u32) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // turn state into UInt64 - let mut state_witnesses: Vec = Vec::new(); - for i in 0..state.len() / 8 { - for j in 0..8 { - state_witnesses.push(state[i * 8 + (7 - j)].inner); - } - } - let (mut state_u64, extra_opcodes, mut num_witness) = - UInt64::from_witnesses(&state_witnesses, num_witness); - new_opcodes.extend(extra_opcodes); - - // process round - for round_constant in ROUND_CONSTANTS { - let (new_state_u64, extra_opcodes, updated_witness_counter) = - keccak_round(state_u64, round_constant, num_witness); - state_u64 = new_state_u64; - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - } - - // turn state back to UInt8 - let state_u64_witnesses: Vec = state_u64.into_iter().map(|x| x.inner).collect(); - let mut state_u8 = Vec::with_capacity(state_u64_witnesses.len()); - for state_u64_witness in state_u64_witnesses { - let (extra_opcodes, mut u8s, updated_witness_counter) = - byte_decomposition(Expression::from(state_u64_witness), 8, num_witness); - new_opcodes.extend(extra_opcodes); - u8s.reverse(); - state_u8.push(u8s); - num_witness = updated_witness_counter; - } - - let state_u8: Vec = state_u8.into_iter().flatten().map(UInt8::new).collect(); - (state_u8, new_opcodes, num_witness) -} - -fn keccak_round( - mut a: Vec, - round_const: u64, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // theta - let mut array = Vec::with_capacity(5); - for _ in 0..5 { - let (zero, extra_opcodes, updated_witness_counter) = UInt64::load_constant(0, num_witness); - array.push(zero); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - } - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - let (new_array_ele, extra_opcodes, updated_witness_counter) = - array[x].xor(&a[x + y], num_witness); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - array[x] = new_array_ele; - } - } - for x in 0..5 { - for y_count in 0..5 { - let y = y_count * 5; - let (a_ele, extra_opcodes, updated_witness_counter) = - array[(x + 1) % 5].rol(1, num_witness); - new_opcodes.extend(extra_opcodes); - let (b_ele, extra_opcodes, updated_witness_counter) = - array[(x + 4) % 5].xor(&a_ele, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (new_array_ele, extra_opcodes, updated_witness_counter) = - a[x + y].xor(&b_ele, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - a[x + y] = new_array_ele; - } - } - - // rho and pi - let mut last = a[1]; - for x in 0..24 { - array[0] = a[PI[x]]; - let (a_ele, extra_opcodes, updated_witness_counter) = last.rol(RHO[x], num_witness); - new_opcodes.extend(extra_opcodes); - a[PI[x]] = a_ele; - num_witness = updated_witness_counter; - last = array[0]; - } - - // chi - for y_step in 0..5 { - let y = y_step * 5; - - array[..5].copy_from_slice(&a[y..(5 + y)]); - - for x in 0..5 { - let (a_ele, extra_opcodes, updated_witness_counter) = - array[(x + 1) % 5].not(num_witness); - new_opcodes.extend(extra_opcodes); - let (b_ele, extra_opcodes, updated_witness_counter) = - a_ele.and(&array[(x + 2) % 5], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c_ele, extra_opcodes, updated_witness_counter) = - array[x].xor(&b_ele, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - a[y + x] = c_ele; - num_witness = updated_witness_counter; - } - } - - // iota - let (rc, extra_opcodes, num_witness) = UInt64::load_constant(round_const, num_witness); - new_opcodes.extend(extra_opcodes); - let (a_ele, extra_opcodes, num_witness) = a[0].xor(&rc, num_witness); - new_opcodes.extend(extra_opcodes); - a[0] = a_ele; - - (a, new_opcodes, num_witness) -} - -fn pad_keccak( - mut input: Vec, - num_blocks: usize, - num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let total_len = BLOCK_SIZE * num_blocks; - - let (mut num_witness, pad_witness, extra_opcodes) = pad(0x01, 8, num_witness); - - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - for _ in 0..total_len - input.len() { - let (updated_witness_counter, pad_witness, extra_opcodes) = pad(0x00, 8, num_witness); - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - num_witness = updated_witness_counter; - } - - let (zero_x_80, extra_opcodes, num_witness) = UInt8::load_constant(0x80, num_witness); - new_opcodes.extend(extra_opcodes); - let (final_pad, extra_opcodes, num_witness) = - UInt8::new(input[total_len - 1]).xor(&zero_x_80, num_witness); - new_opcodes.extend(extra_opcodes); - input[total_len - 1] = final_pad.inner; - - (input, new_opcodes, num_witness) -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/logic_fallbacks.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/logic_fallbacks.rs deleted file mode 100644 index fa8c1060a26..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/logic_fallbacks.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::{blackbox_fallbacks::utils::mul_with_witness, helpers::VariableStore}; - -use super::utils::{bit_decomposition, boolean_expr}; -use acir::{ - acir_field::FieldElement, - circuit::Opcode, - native_types::{Expression, Witness}, -}; - -// Range constraint -pub fn range(opcode: Expression, bit_size: u32, mut num_witness: u32) -> (u32, Vec) { - if bit_size == 1 { - let mut variables = VariableStore::new(&mut num_witness); - let bit_constraint = Opcode::Arithmetic(boolean_expr(&opcode, &mut variables)); - return (variables.finalize(), vec![bit_constraint]); - } - - let (new_opcodes, _, updated_witness_counter) = - bit_decomposition(opcode, bit_size, num_witness); - (updated_witness_counter, new_opcodes) -} - -/// Returns a set of opcodes which constrain `a & b == result` -/// -/// `a` and `b` are assumed to be constrained to fit within `bit_size` externally. -pub fn and( - a: Expression, - b: Expression, - result: Witness, - bit_size: u32, - mut num_witness: u32, -) -> (u32, Vec) { - if bit_size == 1 { - let mut variables = VariableStore::new(&mut num_witness); - - let mut and_expr = mul_with_witness(&a, &b, &mut variables); - and_expr.push_addition_term(-FieldElement::one(), result); - - return (variables.finalize(), vec![Opcode::Arithmetic(and_expr)]); - } - // Decompose the operands into bits - // - let (extra_opcodes_a, a_bits, updated_witness_counter) = - bit_decomposition(a, bit_size, num_witness); - - let (extra_opcodes_b, b_bits, updated_witness_counter) = - bit_decomposition(b, bit_size, updated_witness_counter); - - assert_eq!(a_bits.len(), b_bits.len()); - assert_eq!(a_bits.len(), bit_size as usize); - - let mut two_pow = FieldElement::one(); - let two = FieldElement::from(2_i128); - - // Build an expression that Multiplies each bit element-wise - // This gives the same truth table as the AND operation - // Additionally, we multiply by a power of 2 to build up the - // expected output; ie result = \sum 2^i x_i * y_i - let mut and_expr = Expression::default(); - for (a_bit, b_bit) in a_bits.into_iter().zip(b_bits) { - and_expr.push_multiplication_term(two_pow, a_bit, b_bit); - two_pow = two * two_pow; - } - and_expr.push_addition_term(-FieldElement::one(), result); - - and_expr.sort(); - - let mut new_opcodes = Vec::new(); - new_opcodes.extend(extra_opcodes_a); - new_opcodes.extend(extra_opcodes_b); - new_opcodes.push(Opcode::Arithmetic(and_expr)); - - (updated_witness_counter, new_opcodes) -} - -/// Returns a set of opcodes which constrain `a ^ b == result` -/// -/// `a` and `b` are assumed to be constrained to fit within `bit_size` externally. -pub fn xor( - a: Expression, - b: Expression, - result: Witness, - bit_size: u32, - mut num_witness: u32, -) -> (u32, Vec) { - if bit_size == 1 { - let mut variables = VariableStore::new(&mut num_witness); - - let product = mul_with_witness(&a, &b, &mut variables); - let mut xor_expr = &(&a + &b) - &product; - xor_expr.push_addition_term(-FieldElement::one(), result); - - return (variables.finalize(), vec![Opcode::Arithmetic(xor_expr)]); - } - - // Decompose the operands into bits - // - let (extra_opcodes_a, a_bits, updated_witness_counter) = - bit_decomposition(a, bit_size, num_witness); - let (extra_opcodes_b, b_bits, updated_witness_counter) = - bit_decomposition(b, bit_size, updated_witness_counter); - - assert_eq!(a_bits.len(), b_bits.len()); - assert_eq!(a_bits.len(), bit_size as usize); - - let mut two_pow = FieldElement::one(); - let two = FieldElement::from(2_i128); - - // Build an xor expression - // TODO: check this is the correct arithmetization - let mut xor_expr = Expression::default(); - for (a_bit, b_bit) in a_bits.into_iter().zip(b_bits) { - xor_expr.push_addition_term(two_pow, a_bit); - xor_expr.push_addition_term(two_pow, b_bit); - two_pow = two * two_pow; - xor_expr.push_multiplication_term(-two_pow, a_bit, b_bit); - } - xor_expr.push_addition_term(-FieldElement::one(), result); - - xor_expr.sort(); - let mut new_opcodes = Vec::new(); - new_opcodes.extend(extra_opcodes_a); - new_opcodes.extend(extra_opcodes_b); - new_opcodes.push(Opcode::Arithmetic(xor_expr)); - - (updated_witness_counter, new_opcodes) -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/mod.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/mod.rs deleted file mode 100644 index d2ca3c50fa7..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod blake2s; -mod hash_to_field; -mod keccak256; -mod logic_fallbacks; -mod sha256; -#[macro_use] -mod uint; -mod uint32; -mod uint64; -mod uint8; -mod utils; -pub use blake2s::blake2s; -pub use hash_to_field::hash_to_field; -pub use keccak256::keccak256; -pub use logic_fallbacks::{and, range, xor}; -pub use sha256::sha256; -pub use uint32::UInt32; -pub use uint64::UInt64; -pub use uint8::UInt8; diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/sha256.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/sha256.rs deleted file mode 100644 index 1661b030bcc..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/sha256.rs +++ /dev/null @@ -1,377 +0,0 @@ -//! Sha256 fallback function. -use super::uint32::UInt32; -use super::utils::{byte_decomposition, round_to_nearest_byte}; -use crate::helpers::VariableStore; -use acir::{ - brillig, - circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, - opcodes::{BlackBoxFuncCall, FunctionInput}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; - -const INIT_CONSTANTS: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; - -const ROUND_CONSTANTS: [u32; 64] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - -pub fn sha256( - inputs: Vec<(Expression, u32)>, - outputs: Vec, - mut num_witness: u32, -) -> (u32, Vec) { - let mut new_opcodes = Vec::new(); - let mut new_inputs = Vec::new(); - let mut total_num_bytes = 0; - - // Decompose the input field elements into bytes and collect the resulting witnesses. - for (witness, num_bits) in inputs { - let num_bytes = round_to_nearest_byte(num_bits); - total_num_bytes += num_bytes; - let (extra_opcodes, extra_inputs, updated_witness_counter) = - byte_decomposition(witness, num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - new_inputs.extend(extra_inputs); - num_witness = updated_witness_counter; - } - - let (result, num_witness, extra_opcodes) = - create_sha256_constraint(new_inputs, total_num_bytes, num_witness); - new_opcodes.extend(extra_opcodes); - - // constrain the outputs to be the same as the result of the circuit - for i in 0..outputs.len() { - let mut expr = Expression::from(outputs[i]); - expr.push_addition_term(-FieldElement::one(), result[i]); - new_opcodes.push(Opcode::Arithmetic(expr)); - } - (num_witness, new_opcodes) -} - -fn create_sha256_constraint( - mut input: Vec, - total_num_bytes: u32, - num_witness: u32, -) -> (Vec, u32, Vec) { - let mut new_opcodes = Vec::new(); - - // pad the bytes according to sha256 padding rules - let message_bits = total_num_bytes * 8; - let (mut num_witness, pad_witness, extra_opcodes) = pad(128, 8, num_witness); - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - let bytes_per_block = 64; - let num_bytes = (input.len() + 8) as u32; - let num_blocks = num_bytes / bytes_per_block + ((num_bytes % bytes_per_block != 0) as u32); - let num_total_bytes = num_blocks * bytes_per_block; - for _ in num_bytes..num_total_bytes { - let (updated_witness_counter, pad_witness, extra_opcodes) = pad(0, 8, num_witness); - num_witness = updated_witness_counter; - new_opcodes.extend(extra_opcodes); - input.push(pad_witness); - } - let (num_witness, pad_witness, extra_opcodes) = pad(message_bits, 64, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, pad_witness, num_witness) = - byte_decomposition(pad_witness.into(), 8, num_witness); - new_opcodes.extend(extra_opcodes); - input.extend(pad_witness); - - // turn witness into u32 and load sha256 state - let (input, extra_opcodes, num_witness) = UInt32::from_witnesses(&input, num_witness); - new_opcodes.extend(extra_opcodes); - let (mut rolling_hash, extra_opcodes, num_witness) = prepare_state_constants(num_witness); - new_opcodes.extend(extra_opcodes); - let (round_constants, extra_opcodes, mut num_witness) = prepare_round_constants(num_witness); - new_opcodes.extend(extra_opcodes); - // split the input into blocks of size 16 - let input: Vec> = input.chunks(16).map(|block| block.to_vec()).collect(); - - // process sha256 blocks - for i in &input { - let (new_rolling_hash, extra_opcodes, updated_witness_counter) = - sha256_block(i, rolling_hash.clone(), round_constants.clone(), num_witness); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - rolling_hash = new_rolling_hash; - } - - // decompose the result bytes in u32 to u8 - let (extra_opcodes, byte1, num_witness) = - byte_decomposition(Expression::from(rolling_hash[0].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte2, num_witness) = - byte_decomposition(Expression::from(rolling_hash[1].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte3, num_witness) = - byte_decomposition(Expression::from(rolling_hash[2].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte4, num_witness) = - byte_decomposition(Expression::from(rolling_hash[3].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte5, num_witness) = - byte_decomposition(Expression::from(rolling_hash[4].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte6, num_witness) = - byte_decomposition(Expression::from(rolling_hash[5].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte7, num_witness) = - byte_decomposition(Expression::from(rolling_hash[6].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - let (extra_opcodes, byte8, num_witness) = - byte_decomposition(Expression::from(rolling_hash[7].inner), 4, num_witness); - new_opcodes.extend(extra_opcodes); - - let result = vec![byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8] - .into_iter() - .flatten() - .collect(); - - (result, num_witness, new_opcodes) -} - -pub(crate) fn pad(number: u32, bit_size: u32, mut num_witness: u32) -> (u32, Witness, Vec) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let pad = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(number as u128), - })], - outputs: vec![BrilligOutputs::Simple(pad)], - bytecode: vec![brillig::Opcode::Stop], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - - let range = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: pad, num_bits: bit_size }, - }); - new_opcodes.push(range); - - (num_witness, pad, new_opcodes) -} - -fn sha256_block( - input: &[UInt32], - rolling_hash: Vec, - round_constants: Vec, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut w = Vec::new(); - w.extend(input.to_owned()); - - for i in 16..64 { - // calculate s0 `w[i - 15].ror(7) ^ w[i - 15].ror(18) ^ (w[i - 15] >> 3)` - let (a1, extra_opcodes, updated_witness_counter) = w[i - 15].ror(7, num_witness); - new_opcodes.extend(extra_opcodes); - let (a2, extra_opcodes, updated_witness_counter) = - w[i - 15].ror(18, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a3, extra_opcodes, updated_witness_counter) = - w[i - 15].rightshift(3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a4, extra_opcodes, updated_witness_counter) = a1.xor(&a2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (s0, extra_opcodes, updated_witness_counter) = a4.xor(&a3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate s1 `w[i - 2].ror(17) ^ w[i - 2].ror(19) ^ (w[i - 2] >> 10)` - let (b1, extra_opcodes, updated_witness_counter) = - w[i - 2].ror(17, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b2, extra_opcodes, updated_witness_counter) = - w[i - 2].ror(19, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b3, extra_opcodes, updated_witness_counter) = - w[i - 2].rightshift(10, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b4, extra_opcodes, updated_witness_counter) = b1.xor(&b2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (s1, extra_opcodes, updated_witness_counter) = b4.xor(&b3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate w[i] `w[i - 16] + w[i - 7] + s0 + s1` - let (c1, extra_opcodes, updated_witness_counter) = - w[i - 16].add(&w[i - 7], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c2, extra_opcodes, updated_witness_counter) = c1.add(&s0, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c3, extra_opcodes, updated_witness_counter) = c2.add(&s1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - w.push(c3); - num_witness = updated_witness_counter; - } - - let mut a = rolling_hash[0]; - let mut b = rolling_hash[1]; - let mut c = rolling_hash[2]; - let mut d = rolling_hash[3]; - let mut e = rolling_hash[4]; - let mut f = rolling_hash[5]; - let mut g = rolling_hash[6]; - let mut h = rolling_hash[7]; - - #[allow(non_snake_case)] - for i in 0..64 { - // calculate S1 `e.ror(6) ^ e.ror(11) ^ e.ror(25)` - let (a1, extra_opcodes, updated_witness_counter) = e.ror(6, num_witness); - new_opcodes.extend(extra_opcodes); - let (a2, extra_opcodes, updated_witness_counter) = e.ror(11, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a3, extra_opcodes, updated_witness_counter) = e.ror(25, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (a4, extra_opcodes, updated_witness_counter) = a1.xor(&a2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (S1, extra_opcodes, updated_witness_counter) = a4.xor(&a3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate ch `(e & f) + (~e & g)` - let (b1, extra_opcodes, updated_witness_counter) = e.and(&f, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b2, extra_opcodes, updated_witness_counter) = e.not(updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (b3, extra_opcodes, updated_witness_counter) = b2.and(&g, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (ch, extra_opcodes, updated_witness_counter) = b1.add(&b3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // caculate temp1 `h + S1 + ch + round_constants[i] + w[i]` - let (c1, extra_opcodes, updated_witness_counter) = h.add(&S1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c2, extra_opcodes, updated_witness_counter) = c1.add(&ch, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (c3, extra_opcodes, updated_witness_counter) = - c2.add(&round_constants[i], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (temp1, extra_opcodes, updated_witness_counter) = - c3.add(&w[i], updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate S0 `a.ror(2) ^ a.ror(13) ^ a.ror(22)` - let (d1, extra_opcodes, updated_witness_counter) = a.ror(2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (d2, extra_opcodes, updated_witness_counter) = a.ror(13, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (d3, extra_opcodes, updated_witness_counter) = a.ror(22, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (d4, extra_opcodes, updated_witness_counter) = d1.xor(&d2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (S0, extra_opcodes, updated_witness_counter) = d4.xor(&d3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate T0 `b & c` - let (T0, extra_opcodes, updated_witness_counter) = b.and(&c, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate maj `(a & (b + c - (T0 + T0))) + T0` which is the same as `(a & b) ^ (a & c) ^ (b & c)` - let (e1, extra_opcodes, updated_witness_counter) = T0.add(&T0, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (e2, extra_opcodes, updated_witness_counter) = c.sub(&e1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (e3, extra_opcodes, updated_witness_counter) = b.add(&e2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (e4, extra_opcodes, updated_witness_counter) = a.and(&e3, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - let (maj, extra_opcodes, updated_witness_counter) = e4.add(&T0, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - // calculate temp2 `S0 + maj` - let (temp2, extra_opcodes, updated_witness_counter) = S0.add(&maj, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - - h = g; - g = f; - f = e; - let (new_e, extra_opcodes, updated_witness_counter) = - d.add(&temp1, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - d = c; - c = b; - b = a; - let (new_a, extra_opcodes, updated_witness_counter) = - temp1.add(&temp2, updated_witness_counter); - new_opcodes.extend(extra_opcodes); - num_witness = updated_witness_counter; - a = new_a; - e = new_e; - } - - let mut output = Vec::new(); - let (output0, extra_opcodes, num_witness) = a.add(&rolling_hash[0], num_witness); - new_opcodes.extend(extra_opcodes); - let (output1, extra_opcodes, num_witness) = b.add(&rolling_hash[1], num_witness); - new_opcodes.extend(extra_opcodes); - let (output2, extra_opcodes, num_witness) = c.add(&rolling_hash[2], num_witness); - new_opcodes.extend(extra_opcodes); - let (output3, extra_opcodes, num_witness) = d.add(&rolling_hash[3], num_witness); - new_opcodes.extend(extra_opcodes); - let (output4, extra_opcodes, num_witness) = e.add(&rolling_hash[4], num_witness); - new_opcodes.extend(extra_opcodes); - let (output5, extra_opcodes, num_witness) = f.add(&rolling_hash[5], num_witness); - new_opcodes.extend(extra_opcodes); - let (output6, extra_opcodes, num_witness) = g.add(&rolling_hash[6], num_witness); - new_opcodes.extend(extra_opcodes); - let (output7, extra_opcodes, num_witness) = h.add(&rolling_hash[7], num_witness); - new_opcodes.extend(extra_opcodes); - - output.push(output0); - output.push(output1); - output.push(output2); - output.push(output3); - output.push(output4); - output.push(output5); - output.push(output6); - output.push(output7); - - (output, new_opcodes, num_witness) -} - -/// Load initial state constants of Sha256 -pub(crate) fn prepare_state_constants(mut num_witness: u32) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut new_witnesses = Vec::new(); - - for i in INIT_CONSTANTS { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(i, num_witness); - new_opcodes.extend(extra_opcodes); - new_witnesses.push(new_witness); - num_witness = updated_witness_counter; - } - - (new_witnesses, new_opcodes, num_witness) -} - -/// Load round constants of Sha256 -pub(crate) fn prepare_round_constants(mut num_witness: u32) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut new_witnesses = Vec::new(); - - for i in ROUND_CONSTANTS { - let (new_witness, extra_opcodes, updated_witness_counter) = - UInt32::load_constant(i, num_witness); - new_opcodes.extend(extra_opcodes); - new_witnesses.push(new_witness); - num_witness = updated_witness_counter; - } - - (new_witnesses, new_opcodes, num_witness) -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint.rs deleted file mode 100644 index 6f4039835f7..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint.rs +++ /dev/null @@ -1,648 +0,0 @@ -#[macro_export] -macro_rules! impl_uint { - ( - $name:ident, - $type:ty, - $size:expr - ) => { - use acir::{ - brillig::{self, RegisterIndex}, - circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, - directives::QuotientDirective, - opcodes::{BlackBoxFuncCall, FunctionInput}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, - }; - use $crate::helpers::VariableStore; - - /// UInt contains a witness that points to a field element that represents a u32 integer - /// It has a inner field of type [Witness] that points to the field element and width = 32 - #[derive(Copy, Clone, Debug)] - pub struct $name { - pub(crate) inner: Witness, - width: u32, - } - - impl $name { - #[cfg(any(test, feature = "testing"))] - pub fn get_inner(&self) -> Witness { - self.inner - } - } - - impl $name { - /// Initialize A new [UInt] type with a [Witness] - pub fn new(witness: Witness) -> Self { - $name { inner: witness, width: $size } - } - - /// Get u(n) + 1 - pub(crate) fn get_max_plus_one( - &self, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(2_u128.pow(self.width)), - })], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::Stop], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Load a constant into the circuit - pub(crate) fn load_constant( - constant: $type, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(constant as u128), - })], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::Stop], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Returns the quotient and remainder such that lhs = rhs * quotient + remainder - // This should be the same as its equivalent in the Noir repo - pub fn euclidean_division( - lhs: &$name, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, $name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let q_witness = variables.new_variable(); - let r_witness = variables.new_variable(); - - // compute quotient using directive function - let quotient_opcode = Opcode::Directive( - acir::circuit::directives::Directive::Quotient(QuotientDirective { - a: lhs.inner.into(), - b: rhs.inner.into(), - q: q_witness, - r: r_witness, - predicate: None, - }), - ); - new_opcodes.push(quotient_opcode); - - // make sure r and q are in 32 bit range - let r_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: r_witness, num_bits: lhs.width }, - }); - let q_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: q_witness, num_bits: lhs.width }, - }); - new_opcodes.push(r_range_opcode); - new_opcodes.push(q_range_opcode); - let num_witness = variables.finalize(); - - // constrain r < rhs - let (rhs_sub_r, extra_opcodes, num_witness) = - rhs.sub_no_overflow(&$name::new(r_witness), num_witness); - new_opcodes.extend(extra_opcodes); - let rhs_sub_r_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: rhs_sub_r.inner, num_bits: lhs.width }, - }); - new_opcodes.push(rhs_sub_r_range_opcode); - - // constrain lhs = rhs * quotient + remainder - let rhs_expr = Expression::from(rhs.inner); - let lhs_constraint = Expression::from(lhs.inner); - let rhs_constraint = &rhs_expr * &Expression::from(q_witness); - let rhs_constraint = &rhs_constraint.unwrap() + &Expression::from(r_witness); - let div_euclidean = &lhs_constraint - &rhs_constraint; - new_opcodes.push(Opcode::Arithmetic(div_euclidean)); - - ($name::new(q_witness), $name::new(r_witness), new_opcodes, num_witness) - } - - /// Rotate left `rotation` bits. `(x << rotation) | (x >> (width - rotation))` - // This should be the same as `u32.rotate_left(rotation)` in rust stdlib - pub fn rol(&self, rotation: u32, num_witness: u32) -> ($name, Vec, u32) { - let rotation = rotation % self.width; - let mut new_opcodes = Vec::new(); - let (right_shift, extra_opcodes, num_witness) = - self.rightshift(self.width - rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (left_shift, extra_opcodes, num_witness) = - self.leftshift(rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (result, extra_opcodes, num_witness) = left_shift.or(&right_shift, num_witness); - new_opcodes.extend(extra_opcodes); - - (result, new_opcodes, num_witness) - } - - /// Rotate right `rotation` bits. `(x >> rotation) | (x << (width - rotation))` - // This should be the same as `u32.rotate_right(rotation)` in rust stdlib - pub fn ror(&self, rotation: u32, num_witness: u32) -> ($name, Vec, u32) { - let rotation = rotation % self.width; - let mut new_opcodes = Vec::new(); - let (left_shift, extra_opcodes, num_witness) = - self.leftshift(self.width - rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (right_shift, extra_opcodes, num_witness) = - self.rightshift(rotation, num_witness); - new_opcodes.extend(extra_opcodes); - let (result, extra_opcodes, num_witness) = left_shift.or(&right_shift, num_witness); - new_opcodes.extend(extra_opcodes); - - (result, new_opcodes, num_witness) - } - - /// left shift by `bits` - pub fn leftshift(&self, bits: u32, num_witness: u32) -> ($name, Vec, u32) { - let bits = bits % self.width; - let mut new_opcodes = Vec::new(); - let two: $type = 2; - let (two_pow_rhs, extra_opcodes, num_witness) = - $name::load_constant(two.pow(bits), num_witness); - new_opcodes.extend(extra_opcodes); - let (left_shift, extra_opcodes, num_witness) = self.mul(&two_pow_rhs, num_witness); - new_opcodes.extend(extra_opcodes); - - (left_shift, new_opcodes, num_witness) - } - - /// right shift by `bits` - pub fn rightshift(&self, bits: u32, num_witness: u32) -> ($name, Vec, u32) { - let bits = bits % self.width; - let mut new_opcodes = Vec::new(); - let two: $type = 2; - let (two_pow_rhs, extra_opcodes, num_witness) = - $name::load_constant(two.pow(bits), num_witness); - new_opcodes.extend(extra_opcodes); - let (right_shift, _, extra_opcodes, num_witness) = - $name::euclidean_division(self, &two_pow_rhs, num_witness); - new_opcodes.extend(extra_opcodes); - - (right_shift, new_opcodes, num_witness) - } - - /// Caculate and constrain `self` + `rhs` - pub fn add(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate `self` + `rhs` with overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Add, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain addition - let mut add_expr = Expression::from(new_witness); - add_expr.push_addition_term(-FieldElement::one(), self.inner); - add_expr.push_addition_term(-FieldElement::one(), rhs.inner); - new_opcodes.push(Opcode::Arithmetic(add_expr)); - - // mod 2^width to get final result as the remainder - let (two_pow_width, extra_opcodes, num_witness) = - self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - let (_, add_mod, extra_opcodes, num_witness) = $name::euclidean_division( - &$name::new(new_witness), - &two_pow_width, - num_witness, - ); - new_opcodes.extend(extra_opcodes); - - (add_mod, new_opcodes, num_witness) - } - - /// Caculate and constrain `self` - `rhs` - pub fn sub(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate 2^32 + self - rhs to avoid overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(1_u128 << self.width), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![ - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Add, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(2), - destination: RegisterIndex::from(0), - }, - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }, - ], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain subtraction - let mut sub_constraint = Expression::from(self.inner); - sub_constraint.push_addition_term(-FieldElement::one(), new_witness); - sub_constraint.push_addition_term(-FieldElement::one(), rhs.inner); - sub_constraint.q_c = FieldElement::from(1_u128 << self.width); - new_opcodes.push(Opcode::Arithmetic(sub_constraint)); - - // mod 2^width to get final result as the remainder - let (two_pow_width, extra_opcodes, num_witness) = - self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - let (_, sub_mod, extra_opcodes, num_witness) = $name::euclidean_division( - &$name::new(new_witness), - &two_pow_width, - num_witness, - ); - new_opcodes.extend(extra_opcodes); - - (sub_mod, new_opcodes, num_witness) - } - - /// Calculate and constrain `self` - `rhs` - 1 without allowing overflow - /// This is a helper function to `euclidean_division` - // There is a `-1` because theres a case where rhs = 2^32 and remainder = 0 - pub(crate) fn sub_no_overflow( - &self, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calculate self - rhs - 1 - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::one(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![ - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }, - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(2), - destination: RegisterIndex::from(0), - }, - ], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain subtraction - let mut sub_constraint = Expression::from(self.inner); - sub_constraint.push_addition_term(-FieldElement::one(), new_witness); - sub_constraint.push_addition_term(-FieldElement::one(), rhs.inner); - sub_constraint.q_c = -FieldElement::one(); - new_opcodes.push(Opcode::Arithmetic(sub_constraint)); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` * `rhs` - pub(crate) fn mul( - &self, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - // calulate `self` * `rhs` with overflow - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryFieldOp { - op: brillig::BinaryFieldOp::Mul, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain mul - let mut mul_constraint = Expression::from(new_witness); - mul_constraint.push_multiplication_term( - -FieldElement::one(), - self.inner, - rhs.inner, - ); - new_opcodes.push(Opcode::Arithmetic(mul_constraint)); - - // mod 2^width to get final result as the remainder - let (two_pow_rhs, extra_opcodes, num_witness) = self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - let (_, mul_mod, extra_opcodes, num_witness) = - $name::euclidean_division(&$name::new(new_witness), &two_pow_rhs, num_witness); - new_opcodes.extend(extra_opcodes); - - (mul_mod, new_opcodes, num_witness) - } - - /// Calculate and constrain `self` and `rhs` - pub fn and(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - let num_witness = variables.finalize(); - let and_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::AND { - lhs: FunctionInput { witness: self.inner, num_bits: self.width }, - rhs: FunctionInput { witness: rhs.inner, num_bits: self.width }, - output: new_witness, - }); - new_opcodes.push(and_opcode); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` xor `rhs` - pub fn xor(&self, rhs: &$name, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - let num_witness = variables.finalize(); - let xor_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::XOR { - lhs: FunctionInput { witness: self.inner, num_bits: self.width }, - rhs: FunctionInput { witness: rhs.inner, num_bits: self.width }, - output: new_witness, - }); - new_opcodes.push(xor_opcode); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` or `rhs` - pub fn or(&self, rhs: &$name, num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - - // a | b = (a & b) + (a ^ b) - let (a_and_b, extra_opcodes, num_witness) = self.and(rhs, num_witness); - new_opcodes.extend(extra_opcodes); - let (a_xor_b, extra_opcodes, num_witness) = self.xor(rhs, num_witness); - new_opcodes.extend(extra_opcodes); - let (or, extra_opcodes, num_witness) = a_and_b.add(&a_xor_b, num_witness); - new_opcodes.extend(extra_opcodes); - - (or, new_opcodes, num_witness) - } - - /// Calculate and constrain not `self` - pub(crate) fn not(&self, mut num_witness: u32) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from((1_u128 << self.width) - 1), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: self.width, - lhs: RegisterIndex::from(1), - rhs: RegisterIndex::from(0), - destination: RegisterIndex::from(0), - }], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - let mut not_constraint = Expression::from(new_witness); - not_constraint.push_addition_term(FieldElement::one(), self.inner); - not_constraint.q_c = -FieldElement::from((1_u128 << self.width) - 1); - new_opcodes.push(Opcode::Arithmetic(not_constraint)); - - ($name::new(new_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` >= `rhs` - // This should be similar to its equivalent in the Noir repo - pub(crate) fn more_than_eq_comparison( - &self, - rhs: &$name, - mut num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let new_witness = variables.new_variable(); - let q_witness = variables.new_variable(); - let r_witness = variables.new_variable(); - - // calculate 2^32 + self - rhs - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), self.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), rhs.inner)], - q_c: FieldElement::zero(), - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![], - q_c: FieldElement::from(1_u128 << self.width), - }), - ], - outputs: vec![BrilligOutputs::Simple(new_witness)], - bytecode: vec![ - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Add, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(2), - destination: RegisterIndex::from(0), - }, - brillig::Opcode::BinaryIntOp { - op: brillig::BinaryIntOp::Sub, - bit_size: 127, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - destination: RegisterIndex::from(0), - }, - ], - predicate: None, - }); - new_opcodes.push(brillig_opcode); - let num_witness = variables.finalize(); - - // constrain subtraction - let mut sub_constraint = Expression::from(self.inner); - sub_constraint.push_addition_term(-FieldElement::one(), new_witness); - sub_constraint.push_addition_term(-FieldElement::one(), rhs.inner); - sub_constraint.q_c = FieldElement::from(1_u128 << self.width); - new_opcodes.push(Opcode::Arithmetic(sub_constraint)); - - let (two_pow_rhs, extra_opcodes, num_witness) = self.get_max_plus_one(num_witness); - new_opcodes.extend(extra_opcodes); - - // constraint 2^{max_bits} + a - b = q * 2^{max_bits} + r - // q = 1 if a == b - // q = 1 if a > b - // q = 0 if a < b - let quotient_opcode = Opcode::Directive( - acir::circuit::directives::Directive::Quotient(QuotientDirective { - a: new_witness.into(), - b: two_pow_rhs.inner.into(), - q: q_witness, - r: r_witness, - predicate: None, - }), - ); - new_opcodes.push(quotient_opcode); - - // make sure r in 32 bit range and q is 1 bit - let r_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: r_witness, num_bits: self.width }, - }); - let q_range_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: q_witness, num_bits: 1 }, - }); - new_opcodes.push(r_range_opcode); - new_opcodes.push(q_range_opcode); - - ($name::new(q_witness), new_opcodes, num_witness) - } - - /// Calculate and constrain `self` < `rhs` - pub fn less_than_comparison( - &self, - rhs: &$name, - num_witness: u32, - ) -> ($name, Vec, u32) { - let mut new_opcodes = Vec::new(); - let (mut comparison, extra_opcodes, num_witness) = - self.more_than_eq_comparison(rhs, num_witness); - new_opcodes.extend(extra_opcodes); - comparison.width = 1; - - // `self` < `rhs` == not `self` >= `rhs` - let (less_than, extra_opcodes, num_witness) = comparison.not(num_witness); - new_opcodes.extend(extra_opcodes); - - (less_than, new_opcodes, num_witness) - } - } - }; -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint32.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint32.rs deleted file mode 100644 index 58314d6ba4c..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint32.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::impl_uint; - -impl_uint!(UInt32, u32, 32); -impl UInt32 { - /// Load a [UInt32] from four [Witness]es each representing a [u8] - pub(crate) fn from_witnesses( - witnesses: &[Witness], - mut num_witness: u32, - ) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let mut uint = Vec::new(); - - for i in 0..witnesses.len() / 4 { - let new_witness = variables.new_variable(); - uint.push(UInt32::new(new_witness)); - let mut expr = Expression::from(new_witness); - for j in 0..4 { - let scaling_factor_value = 1 << (8 * (3 - j) as u32); - let scaling_factor = FieldElement::from(scaling_factor_value as u128); - expr.push_addition_term(-scaling_factor, witnesses[i * 4 + j]); - } - - new_opcodes.push(Opcode::Arithmetic(expr)); - } - let num_witness = variables.finalize(); - - (uint, new_opcodes, num_witness) - } -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint64.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint64.rs deleted file mode 100644 index cddb23275cb..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint64.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::impl_uint; - -impl_uint!(UInt64, u64, 64); -impl UInt64 { - /// Load a [UInt64] from eight [Witness]es each representing a [u8] - pub(crate) fn from_witnesses( - witnesses: &[Witness], - mut num_witness: u32, - ) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - let mut uint = Vec::new(); - - for i in 0..witnesses.len() / 8 { - let new_witness = variables.new_variable(); - uint.push(UInt64::new(new_witness)); - let mut expr = Expression::from(new_witness); - for j in 0..8 { - let scaling_factor_value: u128 = 1 << (8 * (7 - j) as u32); - let scaling_factor = FieldElement::from(scaling_factor_value); - expr.push_addition_term(-scaling_factor, witnesses[i * 8 + j]); - } - - new_opcodes.push(Opcode::Arithmetic(expr)); - } - let num_witness = variables.finalize(); - - (uint, new_opcodes, num_witness) - } -} diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint8.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint8.rs deleted file mode 100644 index 2ffc2cae1be..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/uint8.rs +++ /dev/null @@ -1,2 +0,0 @@ -use crate::impl_uint; -impl_uint!(UInt8, u8, 8); diff --git a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/utils.rs b/noir/acvm-repo/stdlib/src/blackbox_fallbacks/utils.rs deleted file mode 100644 index 4921c71c9fe..00000000000 --- a/noir/acvm-repo/stdlib/src/blackbox_fallbacks/utils.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::helpers::VariableStore; -use acir::{ - circuit::{ - directives::Directive, - opcodes::{BlackBoxFuncCall, FunctionInput}, - Opcode, - }, - native_types::{Expression, Witness}, - FieldElement, -}; - -fn round_to_nearest_mul_8(num_bits: u32) -> u32 { - let remainder = num_bits % 8; - - if remainder == 0 { - return num_bits; - } - - num_bits + 8 - remainder -} - -pub(crate) fn round_to_nearest_byte(num_bits: u32) -> u32 { - round_to_nearest_mul_8(num_bits) / 8 -} - -pub(crate) fn boolean_expr(expr: &Expression, variables: &mut VariableStore) -> Expression { - &mul_with_witness(expr, expr, variables) - expr -} - -/// Returns an expression which represents `lhs * rhs` -/// -/// If one has multiplicative term and the other is of degree one or more, -/// the function creates [intermediate variables][`Witness`] accordingly. -/// There are two cases where we can optimize the multiplication between two expressions: -/// 1. If both expressions have at most a total degree of 1 in each term, then we can just multiply them -/// as each term in the result will be degree-2. -/// 2. If one expression is a constant, then we can just multiply the constant with the other expression -/// -/// (1) is because an [`Expression`] can hold at most a degree-2 univariate polynomial -/// which is what you get when you multiply two degree-1 univariate polynomials. -pub(crate) fn mul_with_witness( - lhs: &Expression, - rhs: &Expression, - variables: &mut VariableStore, -) -> Expression { - use std::borrow::Cow; - let lhs_is_linear = lhs.is_linear(); - let rhs_is_linear = rhs.is_linear(); - - // Case 1: Both expressions have at most a total degree of 1 in each term - if lhs_is_linear && rhs_is_linear { - return (lhs * rhs) - .expect("one of the expressions is a constant and so this should not fail"); - } - - // Case 2: One or both of the sides needs to be reduced to a degree-1 univariate polynomial - let lhs_reduced = if lhs_is_linear { - Cow::Borrowed(lhs) - } else { - Cow::Owned(variables.new_variable().into()) - }; - - // If the lhs and rhs are the same, then we do not need to reduce - // rhs, we only need to square the lhs. - if lhs == rhs { - return (&*lhs_reduced * &*lhs_reduced) - .expect("Both expressions are reduced to be degree<=1"); - }; - - let rhs_reduced = if rhs_is_linear { - Cow::Borrowed(rhs) - } else { - Cow::Owned(variables.new_variable().into()) - }; - - (&*lhs_reduced * &*rhs_reduced).expect("Both expressions are reduced to be degree<=1") -} - -// Generates opcodes and directives to bit decompose the input `opcode` -// Returns the bits and the updated witness counter -// TODO:Ideally, we return the updated witness counter, or we require the input -// TODO to be a VariableStore. We are not doing this because we want migration to -// TODO be less painful -pub(crate) fn bit_decomposition( - opcode: Expression, - bit_size: u32, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - - // First create a witness for each bit - let mut bit_vector = Vec::with_capacity(bit_size as usize); - for _ in 0..bit_size { - bit_vector.push(variables.new_variable()); - } - - // Next create a directive which computes those bits. - new_opcodes.push(Opcode::Directive(Directive::ToLeRadix { - a: opcode.clone(), - b: bit_vector.clone(), - radix: 2, - })); - - // Now apply constraints to the bits such that they are the bit decomposition - // of the input and each bit is actually a bit - let mut binary_exprs = Vec::new(); - let mut bit_decomp_constraint = opcode; - let mut two_pow: FieldElement = FieldElement::one(); - let two = FieldElement::from(2_i128); - for &bit in &bit_vector { - // Bit constraint to ensure each bit is a zero or one; bit^2 - bit = 0 - let expr = boolean_expr(&bit.into(), &mut variables); - binary_exprs.push(Opcode::Arithmetic(expr)); - - // Constraint to ensure that the bits are constrained to be a bit decomposition - // of the input - // ie \sum 2^i * x_i = input - bit_decomp_constraint.push_addition_term(-two_pow, bit); - two_pow = two * two_pow; - } - - new_opcodes.extend(binary_exprs); - bit_decomp_constraint.sort(); // TODO: we have an issue open to check if this is needed. Ideally, we remove it. - new_opcodes.push(Opcode::Arithmetic(bit_decomp_constraint)); - - (new_opcodes, bit_vector, variables.finalize()) -} - -// TODO: Maybe this can be merged with `bit_decomposition` -pub(crate) fn byte_decomposition( - opcode: Expression, - num_bytes: u32, - mut num_witness: u32, -) -> (Vec, Vec, u32) { - let mut new_opcodes = Vec::new(); - let mut variables = VariableStore::new(&mut num_witness); - - // First create a witness for each byte - let mut vector = Vec::with_capacity(num_bytes as usize); - for _ in 0..num_bytes { - vector.push(variables.new_variable()); - } - - // Next create a directive which computes those byte. - new_opcodes.push(Opcode::Directive(Directive::ToLeRadix { - a: opcode.clone(), - b: vector.clone(), - radix: 256, - })); - vector.reverse(); - - // Now apply constraints to the bytes such that they are the byte decomposition - // of the input and each byte is actually a byte - let mut byte_exprs = Vec::new(); - let mut decomp_constraint = opcode; - let byte_shift: u128 = 256; - for (i, v) in vector.iter().enumerate() { - let range = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { - input: FunctionInput { witness: *v, num_bits: 8 }, - }); - let scaling_factor_value = byte_shift.pow(num_bytes - 1 - i as u32); - let scaling_factor = FieldElement::from(scaling_factor_value); - - decomp_constraint.push_addition_term(-scaling_factor, *v); - - byte_exprs.push(range); - } - - new_opcodes.extend(byte_exprs); - decomp_constraint.sort(); - new_opcodes.push(Opcode::Arithmetic(decomp_constraint)); - - (new_opcodes, vector, variables.finalize()) -} diff --git a/noir/acvm-repo/stdlib/src/helpers.rs b/noir/acvm-repo/stdlib/src/helpers.rs deleted file mode 100644 index 5ab258368f4..00000000000 --- a/noir/acvm-repo/stdlib/src/helpers.rs +++ /dev/null @@ -1,23 +0,0 @@ -use acir::native_types::Witness; - -// Simple helper struct to keep track of the current witness index -// and create variables -pub struct VariableStore<'a> { - witness_index: &'a mut u32, -} - -impl<'a> VariableStore<'a> { - pub fn new(witness_index: &'a mut u32) -> Self { - Self { witness_index } - } - - pub fn new_variable(&mut self) -> Witness { - let witness = Witness(*self.witness_index); - *self.witness_index += 1; - witness - } - - pub fn finalize(self) -> u32 { - *self.witness_index - } -} diff --git a/noir/acvm-repo/stdlib/src/lib.rs b/noir/acvm-repo/stdlib/src/lib.rs deleted file mode 100644 index 9aecde631fb..00000000000 --- a/noir/acvm-repo/stdlib/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![forbid(unsafe_code)] -#![warn(unreachable_pub)] -#![warn(clippy::semicolon_if_nothing_returned)] -#![cfg_attr(not(test), warn(unused_crate_dependencies, unused_extern_crates))] - -pub mod blackbox_fallbacks; -pub mod helpers; diff --git a/noir/aztec_macros/src/lib.rs b/noir/aztec_macros/src/lib.rs index 6d3aa0d8b01..1b433c33df3 100644 --- a/noir/aztec_macros/src/lib.rs +++ b/noir/aztec_macros/src/lib.rs @@ -914,9 +914,10 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { // `for i in 0..{ident}.len()` make_statement(StatementKind::For(ForLoopStatement { range: ForRange::Range( - expression(ExpressionKind::Literal(Literal::Integer(FieldElement::from(i128::from( - 0, - ))))), + expression(ExpressionKind::Literal(Literal::Integer( + FieldElement::from(i128::from(0)), + false, + ))), end_range_expression, ), identifier: ident("i"), diff --git a/noir/compiler/fm/Cargo.toml b/noir/compiler/fm/Cargo.toml index 9e4309693ed..42e4b0c25d7 100644 --- a/noir/compiler/fm/Cargo.toml +++ b/noir/compiler/fm/Cargo.toml @@ -9,9 +9,8 @@ license.workspace = true [dependencies] codespan-reporting.workspace = true -rust-embed = "6.6.0" serde.workspace = true [dev-dependencies] -tempfile = "3.2.0" +tempfile.workspace = true iter-extended.workspace = true diff --git a/noir/compiler/fm/build.rs b/noir/compiler/fm/build.rs deleted file mode 100644 index 747ab4fe1a2..00000000000 --- a/noir/compiler/fm/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::path::Path; - -/// Expects that the given directory is an existing path -fn rerun_if_stdlib_changes(directory: &Path) { - for entry in std::fs::read_dir(directory).unwrap() { - let path = entry.unwrap().path(); - - if path.is_dir() { - rerun_if_stdlib_changes(&path); - } else { - // Tell Cargo that if the given file changes, to rerun this build script. - println!("cargo:rerun-if-changed={}", path.to_string_lossy()); - } - } -} - -fn main() { - let stdlib_src_dir = Path::new("../../noir_stdlib/"); - rerun_if_stdlib_changes(stdlib_src_dir); -} diff --git a/noir/compiler/fm/src/file_map.rs b/noir/compiler/fm/src/file_map.rs index 199723a28b5..0cbdc535e40 100644 --- a/noir/compiler/fm/src/file_map.rs +++ b/noir/compiler/fm/src/file_map.rs @@ -1,11 +1,12 @@ use codespan_reporting::files::{Error, Files, SimpleFile, SimpleFiles}; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::{ops::Range, path::PathBuf}; // XXX: File and FileMap serve as opaque types, so that the rest of the library does not need to import the dependency // or worry about when we change the dep -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct PathString(PathBuf); impl std::fmt::Display for PathString { @@ -30,7 +31,10 @@ impl From<&PathBuf> for PathString { } } #[derive(Debug)] -pub struct FileMap(SimpleFiles); +pub struct FileMap { + files: SimpleFiles, + name_to_id: HashMap, +} // XXX: Note that we derive Default here due to ModuleOrigin requiring us to set a FileId #[derive( @@ -59,17 +63,22 @@ impl<'input> File<'input> { impl FileMap { pub fn add_file(&mut self, file_name: PathString, code: String) -> FileId { - let file_id = self.0.add(file_name, code); - FileId(file_id) + let file_id = FileId(self.files.add(file_name.clone(), code)); + self.name_to_id.insert(file_name, file_id); + file_id } + pub fn get_file(&self, file_id: FileId) -> Option { - self.0.get(file_id.0).map(File).ok() + self.files.get(file_id.0).map(File).ok() } -} + pub fn get_file_id(&self, file_name: &PathString) -> Option { + self.name_to_id.get(file_name).cloned() + } +} impl Default for FileMap { fn default() -> Self { - FileMap(SimpleFiles::new()) + FileMap { files: SimpleFiles::new(), name_to_id: HashMap::new() } } } @@ -79,18 +88,18 @@ impl<'a> Files<'a> for FileMap { type Source = &'a str; fn name(&self, file_id: Self::FileId) -> Result { - Ok(self.0.get(file_id.as_usize())?.name().clone()) + Ok(self.files.get(file_id.as_usize())?.name().clone()) } fn source(&'a self, file_id: Self::FileId) -> Result { - Ok(self.0.get(file_id.as_usize())?.source().as_ref()) + Ok(self.files.get(file_id.as_usize())?.source().as_ref()) } fn line_index(&self, file_id: Self::FileId, byte_index: usize) -> Result { - self.0.get(file_id.as_usize())?.line_index((), byte_index) + self.files.get(file_id.as_usize())?.line_index((), byte_index) } fn line_range(&self, file_id: Self::FileId, line_index: usize) -> Result, Error> { - self.0.get(file_id.as_usize())?.line_range((), line_index) + self.files.get(file_id.as_usize())?.line_range((), line_index) } } diff --git a/noir/compiler/fm/src/file_reader.rs b/noir/compiler/fm/src/file_reader.rs deleted file mode 100644 index d17aefeda7e..00000000000 --- a/noir/compiler/fm/src/file_reader.rs +++ /dev/null @@ -1,49 +0,0 @@ -use rust_embed::RustEmbed; -use std::io::{Error, ErrorKind}; -use std::path::Path; - -// Based on the environment, we either read files using the rust standard library or we -// read files using the javascript host function - -pub type FileReader = dyn Fn(&Path) -> std::io::Result + Send; - -#[derive(RustEmbed)] -#[folder = "../../noir_stdlib/src"] -#[cfg_attr(not(target_os = "windows"), prefix = "std/")] -#[cfg_attr(target_os = "windows", prefix = r"std\")] // Note reversed slash direction -struct StdLibAssets; - -#[cfg(target_os = "windows")] -pub(super) fn is_stdlib_asset(path: &Path) -> bool { - path.starts_with("std\\") -} - -#[cfg(not(target_os = "windows"))] -pub(super) fn is_stdlib_asset(path: &Path) -> bool { - path.starts_with("std/") -} - -fn get_stdlib_asset(path: &Path) -> std::io::Result { - if !is_stdlib_asset(path) { - return Err(Error::new(ErrorKind::InvalidInput, "requested a non-stdlib asset")); - } - - match StdLibAssets::get(path.to_str().unwrap()) { - Some(std_lib_asset) => { - Ok(std::str::from_utf8(std_lib_asset.data.as_ref()).unwrap().to_string()) - } - - None => Err(Error::new(ErrorKind::NotFound, "invalid stdlib path")), - } -} - -pub(crate) fn read_file_to_string( - path_to_file: &Path, - get_non_stdlib_asset: &impl Fn(&Path) -> std::io::Result, -) -> std::io::Result { - if is_stdlib_asset(path_to_file) { - get_stdlib_asset(path_to_file) - } else { - get_non_stdlib_asset(path_to_file) - } -} diff --git a/noir/compiler/fm/src/lib.rs b/noir/compiler/fm/src/lib.rs index 6e11489f7f2..4870a6c283b 100644 --- a/noir/compiler/fm/src/lib.rs +++ b/noir/compiler/fm/src/lib.rs @@ -4,11 +4,11 @@ #![warn(clippy::semicolon_if_nothing_returned)] mod file_map; -mod file_reader; pub use file_map::{File, FileId, FileMap, PathString}; -use file_reader::is_stdlib_asset; -pub use file_reader::FileReader; + +// Re-export for the lsp +pub use codespan_reporting::files as codespan_files; use std::{ collections::HashMap, @@ -19,10 +19,9 @@ pub const FILE_EXTENSION: &str = "nr"; pub struct FileManager { root: PathBuf, - file_map: file_map::FileMap, + file_map: FileMap, id_to_path: HashMap, path_to_id: HashMap, - file_reader: Box, } impl std::fmt::Debug for FileManager { @@ -37,13 +36,12 @@ impl std::fmt::Debug for FileManager { } impl FileManager { - pub fn new(root: &Path, file_reader: Box) -> Self { + pub fn new(root: &Path) -> Self { Self { root: root.normalize(), file_map: Default::default(), id_to_path: Default::default(), path_to_id: Default::default(), - file_reader, } } @@ -51,25 +49,32 @@ impl FileManager { &self.file_map } - pub fn add_file(&mut self, file_name: &Path) -> Option { - // Handle both relative file paths and std/lib virtual paths. - let resolved_path: PathBuf = if is_stdlib_asset(file_name) { - // Special case for stdlib where we want to read specifically the `std/` relative path - // TODO: The stdlib path should probably be an absolute path rooted in something people would never create - file_name.to_path_buf() - } else { - self.root.join(file_name).normalize() - }; - - // Check that the resolved path already exists in the file map, if it is, we return it. - if let Some(file_id) = self.path_to_id.get(&resolved_path) { + /// Adds a source file to the [`FileManager`]. + /// + /// The `file_name` is expected to be relative to the [`FileManager`]'s root directory. + pub fn add_file_with_source(&mut self, file_name: &Path, source: String) -> Option { + let file_name = self.root.join(file_name); + self.add_file_with_source_canonical_path(&file_name, source) + } + + /// Adds a source file to the [`FileManager`] using a path which is not appended to the root path. + /// + /// This should only be used for the stdlib as these files do not exist on the user's filesystem. + pub fn add_file_with_source_canonical_path( + &mut self, + file_name: &Path, + source: String, + ) -> Option { + let file_name = file_name.normalize(); + // Check that the file name already exists in the file map, if it is, we return it. + if let Some(file_id) = self.path_to_id.get(&file_name) { return Some(*file_id); } + let file_name_path_buf = file_name.to_path_buf(); // Otherwise we add the file - let source = file_reader::read_file_to_string(&resolved_path, &self.file_reader).ok()?; - let file_id = self.file_map.add_file(resolved_path.clone().into(), source); - self.register_path(file_id, resolved_path); + let file_id = self.file_map.add_file(file_name_path_buf.clone().into(), source); + self.register_path(file_id, file_name_path_buf); Some(file_id) } @@ -83,9 +88,9 @@ impl FileManager { assert!(old_value.is_none(), "ice: the same path was inserted into the file manager twice"); } - pub fn fetch_file(&self, file_id: FileId) -> File { + pub fn fetch_file(&self, file_id: FileId) -> &str { // Unwrap as we ensure that all file_id's map to a corresponding file in the file map - self.file_map.get_file(file_id).unwrap() + self.file_map.get_file(file_id).unwrap().source() } pub fn path(&self, file_id: FileId) -> &Path { @@ -94,39 +99,9 @@ impl FileManager { self.id_to_path.get(&file_id).unwrap().as_path() } - pub fn find_module(&mut self, anchor: FileId, mod_name: &str) -> Result { - let anchor_path = self.path(anchor).with_extension(""); - let anchor_dir = anchor_path.parent().unwrap(); - - // if `anchor` is a `main.nr`, `lib.nr`, `mod.nr` or `{mod_name}.nr`, we check siblings of - // the anchor at `base/mod_name.nr`. - let candidate = if should_check_siblings_for_module(&anchor_path, anchor_dir) { - anchor_dir.join(format!("{mod_name}.{FILE_EXTENSION}")) - } else { - // Otherwise, we check for children of the anchor at `base/anchor/mod_name.nr` - anchor_path.join(format!("{mod_name}.{FILE_EXTENSION}")) - }; - - self.add_file(&candidate).ok_or_else(|| candidate.as_os_str().to_string_lossy().to_string()) - } -} - -/// Returns true if a module's child module's are expected to be in the same directory. -/// Returns false if they are expected to be in a subdirectory matching the name of the module. -fn should_check_siblings_for_module(module_path: &Path, parent_path: &Path) -> bool { - if let Some(filename) = module_path.file_stem() { - // This check also means a `main.nr` or `lib.nr` file outside of the crate root would - // check its same directory for child modules instead of a subdirectory. Should we prohibit - // `main.nr` and `lib.nr` files outside of the crate root? - filename == "main" - || filename == "lib" - || filename == "mod" - || Some(filename) == parent_path.file_stem() - } else { - // If there's no filename, we arbitrarily return true. - // Alternatively, we could panic, but this is left to a different step where we - // ideally have some source location to issue an error. - true + // TODO: This should accept a &Path instead of a PathBuf + pub fn name_to_id(&self, file_name: PathBuf) -> Option { + self.file_map.get_file_id(&PathString::from_path(file_name)) } } @@ -212,25 +187,11 @@ mod tests { use super::*; use tempfile::{tempdir, TempDir}; - fn create_dummy_file(dir: &TempDir, file_name: &Path) { + // Returns the absolute path to the file + fn create_dummy_file(dir: &TempDir, file_name: &Path) -> PathBuf { let file_path = dir.path().join(file_name); - let _file = std::fs::File::create(file_path).unwrap(); - } - - #[test] - fn path_resolve_file_module() { - let dir = tempdir().unwrap(); - - let entry_file_name = Path::new("my_dummy_file.nr"); - create_dummy_file(&dir, entry_file_name); - - let mut fm = FileManager::new(dir.path(), Box::new(|path| std::fs::read_to_string(path))); - - let file_id = fm.add_file(entry_file_name).unwrap(); - - let dep_file_name = Path::new("foo.nr"); - create_dummy_file(&dir, dep_file_name); - fm.find_module(file_id, "foo").unwrap_err(); + let _file = std::fs::File::create(&file_path).unwrap(); + file_path } #[test] @@ -239,52 +200,13 @@ mod tests { let file_name = Path::new("foo.nr"); create_dummy_file(&dir, file_name); - let mut fm = FileManager::new(dir.path(), Box::new(|path| std::fs::read_to_string(path))); + let mut fm = FileManager::new(dir.path()); - let file_id = fm.add_file(file_name).unwrap(); + let file_id = fm.add_file_with_source(file_name, "fn foo() {}".to_string()).unwrap(); assert!(fm.path(file_id).ends_with("foo.nr")); } - #[test] - fn path_resolve_sub_module() { - let dir = tempdir().unwrap(); - let mut fm = FileManager::new(dir.path(), Box::new(|path| std::fs::read_to_string(path))); - - // Create a lib.nr file at the root. - // we now have dir/lib.nr - let file_name = Path::new("lib.nr"); - create_dummy_file(&dir, file_name); - - let file_id = fm.add_file(file_name).unwrap(); - - // Create a sub directory - // we now have: - // - dir/lib.nr - // - dir/sub_dir - let sub_dir = TempDir::new_in(&dir).unwrap(); - let sub_dir_name = sub_dir.path().file_name().unwrap().to_str().unwrap(); - - // Add foo.nr to the subdirectory - // we no have: - // - dir/lib.nr - // - dir/sub_dir/foo.nr - create_dummy_file(&sub_dir, Path::new("foo.nr")); - - // Add a parent module for the sub_dir - // we no have: - // - dir/lib.nr - // - dir/sub_dir.nr - // - dir/sub_dir/foo.nr - create_dummy_file(&dir, Path::new(&format!("{sub_dir_name}.nr"))); - - // First check for the sub_dir.nr file and add it to the FileManager - let sub_dir_file_id = fm.find_module(file_id, sub_dir_name).unwrap(); - - // Now check for files in it's subdirectory - fm.find_module(sub_dir_file_id, "foo").unwrap(); - } - /// Tests that two identical files that have different paths are treated as the same file /// e.g. if we start in the dir ./src and have a file ../../foo.nr /// that should be treated as the same file as ../ starting in ./ @@ -295,7 +217,7 @@ mod tests { let sub_dir = TempDir::new_in(&dir).unwrap(); let sub_sub_dir = TempDir::new_in(&sub_dir).unwrap(); - let mut fm = FileManager::new(dir.path(), Box::new(|path| std::fs::read_to_string(path))); + let mut fm = FileManager::new(dir.path()); // Create a lib.nr file at the root. let file_name = Path::new("lib.nr"); @@ -305,8 +227,9 @@ mod tests { let second_file_name = PathBuf::from(sub_sub_dir.path()).join("./../../lib.nr"); // Add both files to the file manager - let file_id = fm.add_file(file_name).unwrap(); - let second_file_id = fm.add_file(&second_file_name).unwrap(); + let file_id = fm.add_file_with_source(file_name, "fn foo() {}".to_string()).unwrap(); + let second_file_id = + fm.add_file_with_source(&second_file_name, "fn foo() {}".to_string()).unwrap(); assert_eq!(file_id, second_file_id); } diff --git a/noir/compiler/integration-tests/circuits/recursion/src/main.nr b/noir/compiler/integration-tests/circuits/recursion/src/main.nr index 7cf956d1950..e60e4e0b61a 100644 --- a/noir/compiler/integration-tests/circuits/recursion/src/main.nr +++ b/noir/compiler/integration-tests/circuits/recursion/src/main.nr @@ -1,14 +1,17 @@ use dep::std; fn main( - verification_key: [Field; 114], - proof: [Field; 94], - public_inputs: [Field; 1], - key_hash: Field, - input_aggregation_object: [Field; 16] -) -> pub [Field; 16] { - let vk : [Field] = verification_key; - let p : [Field] = proof; - let pi : [Field] = public_inputs; - std::verify_proof(vk, p, pi, key_hash, input_aggregation_object) + verification_key : [Field; 114], + proof : [Field; 94], + public_inputs : [Field; 1], + key_hash : Field, +) -> pub [Field;16]{ + let input_aggregation_object = [0; 16]; + std::verify_proof( + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), + key_hash, + input_aggregation_object + ) } diff --git a/noir/compiler/integration-tests/hardhat.config.ts b/noir/compiler/integration-tests/hardhat.config.ts index 2c68b3fae0f..af4728c68ec 100644 --- a/noir/compiler/integration-tests/hardhat.config.ts +++ b/noir/compiler/integration-tests/hardhat.config.ts @@ -12,6 +12,9 @@ const config: HardhatUserConfig = { }, }, }, + mocha: { + timeout: 5 * 60 * 1000, + }, }; export default config; diff --git a/noir/compiler/integration-tests/package.json b/noir/compiler/integration-tests/package.json index 344d1361263..c4e424df480 100644 --- a/noir/compiler/integration-tests/package.json +++ b/noir/compiler/integration-tests/package.json @@ -16,7 +16,6 @@ "@noir-lang/backend_barretenberg": "workspace:*", "@noir-lang/noir_js": "workspace:*", "@noir-lang/noir_wasm": "workspace:*", - "@noir-lang/source-resolver": "workspace:*", "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", "@nomicfoundation/hardhat-ethers": "^3.0.0", "@web/dev-server-esbuild": "^0.3.6", diff --git a/noir/compiler/integration-tests/scripts/codegen-verifiers.sh b/noir/compiler/integration-tests/scripts/codegen-verifiers.sh index 4518141fc13..e377a3ee3f8 100644 --- a/noir/compiler/integration-tests/scripts/codegen-verifiers.sh +++ b/noir/compiler/integration-tests/scripts/codegen-verifiers.sh @@ -12,9 +12,15 @@ nargo --program-dir $mul_dir codegen-verifier assert_statement_dir=$repo_root/test_programs/execution_success/assert_statement nargo --program-dir $assert_statement_dir codegen-verifier +# Run codegen-verifier for recursion +recursion_dir=$repo_root/compiler/integration-tests/circuits/recursion +nargo --program-dir $recursion_dir codegen-verifier + # Copy compiled contracts from the root of compiler/integration-tests contracts_dir=$self_path/../contracts +rm -rf $contracts_dir mkdir $contracts_dir cp $mul_dir/contract/1_mul/plonk_vk.sol $contracts_dir/1_mul.sol cp $assert_statement_dir/contract/assert_statement/plonk_vk.sol $contracts_dir/assert_statement.sol +cp $recursion_dir/contract/recursion/plonk_vk.sol $contracts_dir/recursion.sol diff --git a/noir/compiler/integration-tests/test/browser/compile_prove_verify.test.ts b/noir/compiler/integration-tests/test/browser/compile_prove_verify.test.ts index 2aef56c23f9..29e2fbc55b8 100644 --- a/noir/compiler/integration-tests/test/browser/compile_prove_verify.test.ts +++ b/noir/compiler/integration-tests/test/browser/compile_prove_verify.test.ts @@ -1,17 +1,17 @@ import { expect } from '@esm-bundle/chai'; -import { Logger } from 'tslog'; import * as TOML from 'smol-toml'; -import { initializeResolver } from '@noir-lang/source-resolver'; -import newCompiler, { CompiledProgram, compile, init_log_level as compilerLogLevel } from '@noir-lang/noir_wasm'; +import newCompiler, { + CompiledProgram, + PathToFileSourceMap, + compile, + init_log_level as compilerLogLevel, +} from '@noir-lang/noir_wasm'; import { Noir } from '@noir-lang/noir_js'; import { InputMap } from '@noir-lang/noirc_abi'; import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; import { getFile } from './utils.js'; -import { TEST_LOG_LEVEL } from '../environment.js'; - -const logger = new Logger({ name: 'test', minLevel: TEST_LOG_LEVEL }); await newCompiler(); @@ -33,14 +33,11 @@ const suite = Mocha.Suite.create(mocha.suite, 'Noir end to end test'); suite.timeout(60 * 20e3); //20mins function getCircuit(noirSource: string): CompiledProgram { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - initializeResolver((id: string) => { - logger.debug('source-resolver: resolving:', id); - return noirSource; - }); + const sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code('main.nr', noirSource); // We're ignoring this in the resolver but pass in something sensible. - const result = compile('/main.nr'); + const result = compile('main.nr', undefined, undefined, sourceMap); if (!('program' in result)) { throw new Error('Compilation failed'); } diff --git a/noir/compiler/integration-tests/test/browser/recursion.test.ts b/noir/compiler/integration-tests/test/browser/recursion.test.ts index 308be81417f..faa317b2c3c 100644 --- a/noir/compiler/integration-tests/test/browser/recursion.test.ts +++ b/noir/compiler/integration-tests/test/browser/recursion.test.ts @@ -2,8 +2,12 @@ import { expect } from '@esm-bundle/chai'; import { TEST_LOG_LEVEL } from '../environment.js'; import { Logger } from 'tslog'; -import { initializeResolver } from '@noir-lang/source-resolver'; -import newCompiler, { CompiledProgram, compile, init_log_level as compilerLogLevel } from '@noir-lang/noir_wasm'; +import newCompiler, { + CompiledProgram, + PathToFileSourceMap, + compile, + init_log_level as compilerLogLevel, +} from '@noir-lang/noir_wasm'; import { acvm, abi, Noir } from '@noir-lang/noir_js'; import * as TOML from 'smol-toml'; @@ -27,14 +31,9 @@ const circuit_main = 'test_programs/execution_success/assert_statement'; const circuit_recursion = 'compiler/integration-tests/circuits/recursion'; function getCircuit(noirSource: string): CompiledProgram { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - initializeResolver((id: string) => { - logger.debug('source-resolver: resolving:', id); - return noirSource; - }); - - // We're ignoring this in the resolver but pass in something sensible. - const result = compile('/main.nr'); + const sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code('main.nr', noirSource); + const result = compile('main.nr', undefined, undefined, sourceMap); if (!('program' in result)) { throw new Error('Compilation failed'); } diff --git a/noir/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts b/noir/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts new file mode 100644 index 00000000000..6c20d44882b --- /dev/null +++ b/noir/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts @@ -0,0 +1,80 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { readFileSync } from 'node:fs'; +import { resolve } from 'path'; +import toml from 'toml'; + +import { + compile, + CompiledProgram, + init_log_level as compilerLogLevel, + PathToFileSourceMap, +} from '@noir-lang/noir_wasm'; +import { Noir } from '@noir-lang/noir_js'; +import { BarretenbergBackend, flattenPublicInputs } from '@noir-lang/backend_barretenberg'; +import { Field, InputMap } from '@noir-lang/noirc_abi'; + +compilerLogLevel('INFO'); + +it(`smart contract can verify a recursive proof`, async () => { + const innerSourcePath = resolve(`../../test_programs/execution_success/assert_statement/src/main.nr`); + const sourceMapInnerProgram = new PathToFileSourceMap(); + sourceMapInnerProgram.add_source_code(innerSourcePath, readFileSync(innerSourcePath, 'utf-8')); + const innerProgram = ( + compile(innerSourcePath, undefined, undefined, sourceMapInnerProgram) as { program: CompiledProgram } + ).program; + + const recursionSourcePath = resolve(`./circuits/recursion/src/main.nr`); + const sourceMapRecursionProgram = new PathToFileSourceMap(); + sourceMapRecursionProgram.add_source_code(recursionSourcePath, readFileSync(recursionSourcePath, 'utf-8')); + const recursionProgram = ( + compile(recursionSourcePath, undefined, undefined, sourceMapRecursionProgram) as { program: CompiledProgram } + ).program; + + // Intermediate proof + + const inner_backend = new BarretenbergBackend(innerProgram); + const inner = new Noir(innerProgram); + + const inner_prover_toml = readFileSync( + resolve(`../../test_programs/execution_success/assert_statement/Prover.toml`), + ).toString(); + const inner_inputs = toml.parse(inner_prover_toml); + + const { witness: main_witness } = await inner.execute(inner_inputs); + const intermediate_proof = await inner_backend.generateIntermediateProof(main_witness); + + expect(await inner_backend.verifyIntermediateProof(intermediate_proof)).to.be.true; + + const { proofAsFields, vkAsFields, vkHash } = await inner_backend.generateIntermediateProofArtifacts( + intermediate_proof, + 1, // 1 public input + ); + + // Final proof + + const recursion_backend = new BarretenbergBackend(recursionProgram); + const recursion = new Noir(recursionProgram, recursion_backend); + + const recursion_inputs: InputMap = { + verification_key: vkAsFields, + proof: proofAsFields, + public_inputs: [inner_inputs.y as Field], + key_hash: vkHash, + }; + + const recursion_proof = await recursion.generateFinalProof(recursion_inputs); + expect(await recursion.verifyFinalProof(recursion_proof)).to.be.true; + + // Smart contract verification + + const contract = await ethers.deployContract('contracts/recursion.sol:UltraVerifier', []); + + const result = await contract.verify.staticCall( + recursion_proof.proof, + flattenPublicInputs(recursion_proof.publicInputs), + ); + + expect(result).to.be.true; +}); diff --git a/noir/compiler/integration-tests/test/node/smart_contract_verifier.test.ts b/noir/compiler/integration-tests/test/node/smart_contract_verifier.test.ts index 57199fc8667..5b3d0e2d337 100644 --- a/noir/compiler/integration-tests/test/node/smart_contract_verifier.test.ts +++ b/noir/compiler/integration-tests/test/node/smart_contract_verifier.test.ts @@ -5,7 +5,7 @@ import { readFileSync } from 'node:fs'; import { resolve } from 'path'; import toml from 'toml'; -import { compile, init_log_level as compilerLogLevel } from '@noir-lang/noir_wasm'; +import { PathToFileSourceMap, compile, init_log_level as compilerLogLevel } from '@noir-lang/noir_wasm'; import { Noir } from '@noir-lang/noir_js'; import { BarretenbergBackend, flattenPublicInputs } from '@noir-lang/backend_barretenberg'; @@ -31,9 +31,11 @@ test_cases.forEach((testInfo) => { const base_relative_path = '../..'; const test_case = testInfo.case; - const noir_source_path = resolve(`${base_relative_path}/${test_case}/src/main.nr`); + const noirSourcePath = resolve(`${base_relative_path}/${test_case}/src/main.nr`); + const sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code(noirSourcePath, readFileSync(noirSourcePath, 'utf-8')); - const compileResult = compile(noir_source_path); + const compileResult = compile(noirSourcePath, undefined, undefined, sourceMap); if (!('program' in compileResult)) { throw new Error('Compilation failed'); } @@ -57,7 +59,7 @@ test_cases.forEach((testInfo) => { // Smart contract verification - const contract = await ethers.deployContract(testInfo.compiled, [], {}); + const contract = await ethers.deployContract(testInfo.compiled, []); const result = await contract.verify(proofData.proof, flattenPublicInputs(proofData.publicInputs)); diff --git a/noir/compiler/noirc_driver/Cargo.toml b/noir/compiler/noirc_driver/Cargo.toml index c717efed6f5..7f431db4398 100644 --- a/noir/compiler/noirc_driver/Cargo.toml +++ b/noir/compiler/noirc_driver/Cargo.toml @@ -21,8 +21,7 @@ iter-extended.workspace = true fm.workspace = true serde.workspace = true fxhash.workspace = true +rust-embed = "6.6.0" +log.workspace = true -aztec_macros ={path = "../../aztec_macros", optional = true} - -[features] -aztec = ["aztec_macros"] \ No newline at end of file +aztec_macros = { path = "../../aztec_macros" } diff --git a/noir/compiler/noirc_driver/build.rs b/noir/compiler/noirc_driver/build.rs index 6bef7f1fda7..73a56142075 100644 --- a/noir/compiler/noirc_driver/build.rs +++ b/noir/compiler/noirc_driver/build.rs @@ -1,4 +1,5 @@ const GIT_COMMIT: &&str = &"GIT_COMMIT"; +use std::path::Path; fn main() { // Only use build_data if the environment variable isn't set @@ -8,4 +9,21 @@ fn main() { build_data::set_GIT_DIRTY(); build_data::no_debug_rebuilds(); } + + let stdlib_src_dir = Path::new("../../noir_stdlib/"); + rerun_if_stdlib_changes(stdlib_src_dir); +} + +/// Expects that the given directory is an existing path +fn rerun_if_stdlib_changes(directory: &Path) { + for entry in std::fs::read_dir(directory).unwrap() { + let path = entry.unwrap().path(); + + if path.is_dir() { + rerun_if_stdlib_changes(&path); + } else { + // Tell Cargo that if the given file changes, to rerun this build script. + println!("cargo:rerun-if-changed={}", path.to_string_lossy()); + } + } } diff --git a/noir/compiler/noirc_driver/src/abi_gen.rs b/noir/compiler/noirc_driver/src/abi_gen.rs index 1cad67ba5b7..9d0d64b6300 100644 --- a/noir/compiler/noirc_driver/src/abi_gen.rs +++ b/noir/compiler/noirc_driver/src/abi_gen.rs @@ -2,11 +2,12 @@ use std::collections::BTreeMap; use acvm::acir::native_types::Witness; use iter_extended::{btree_map, vecmap}; -use noirc_abi::{Abi, AbiParameter, AbiType}; +use noirc_abi::{Abi, AbiParameter, AbiReturnType, AbiType}; use noirc_frontend::{ hir::Context, hir_def::{function::Param, stmt::HirPattern}, node_interner::{FuncId, NodeInterner}, + Visibility, }; use std::ops::Range; @@ -17,9 +18,12 @@ pub(super) fn gen_abi( func_id: &FuncId, input_witnesses: Vec, return_witnesses: Vec, + return_visibility: Visibility, ) -> Abi { let (parameters, return_type) = compute_function_abi(context, func_id); let param_witnesses = param_witnesses_from_abi_param(¶meters, input_witnesses); + let return_type = return_type + .map(|typ| AbiReturnType { abi_type: typ, visibility: return_visibility.into() }); Abi { parameters, return_type, param_witnesses, return_witnesses } } diff --git a/noir/compiler/noirc_driver/src/debug.rs b/noir/compiler/noirc_driver/src/debug.rs index 144e636b534..84a3e143357 100644 --- a/noir/compiler/noirc_driver/src/debug.rs +++ b/noir/compiler/noirc_driver/src/debug.rs @@ -31,7 +31,7 @@ pub(crate) fn filter_relevant_files( let mut file_map = BTreeMap::new(); for file_id in files_with_debug_symbols { - let file_source = file_manager.fetch_file(file_id).source(); + let file_source = file_manager.fetch_file(file_id); file_map.insert( file_id, diff --git a/noir/compiler/noirc_driver/src/lib.rs b/noir/compiler/noirc_driver/src/lib.rs index 93ed26fb91a..24b159568f2 100644 --- a/noir/compiler/noirc_driver/src/lib.rs +++ b/noir/compiler/noirc_driver/src/lib.rs @@ -23,6 +23,7 @@ mod abi_gen; mod contract; mod debug; mod program; +mod stdlib; use debug::filter_relevant_files; @@ -61,6 +62,14 @@ pub struct CompileOptions { /// Suppress warnings #[arg(long, conflicts_with = "deny_warnings")] pub silence_warnings: bool, + + /// Output ACIR gzipped bytecode instead of the JSON artefact + #[arg(long, hide = true)] + pub only_acir: bool, + + /// Disables the builtin macros being used in the compiler + #[arg(long, hide = true)] + pub disable_macros: bool, } /// Helper type used to signify where only warnings are expected in file diagnostics @@ -74,11 +83,23 @@ pub type CompilationResult = Result<(T, Warnings), ErrorsAndWarnings>; /// Adds the file from the file system at `Path` to the crate graph as a root file pub fn prepare_crate(context: &mut Context, file_name: &Path) -> CrateId { + // Add the stdlib contents to the file manager, since every package automatically has a dependency + // on the stdlib. For other dependencies, we read the package.Dependencies file to add their file + // contents to the file manager. However since the dependency on the stdlib is implicit, we need + // to manually add it here. + let stdlib_paths_with_source = stdlib::stdlib_paths_with_source(); + for (path, source) in stdlib_paths_with_source { + context.file_manager.add_file_with_source_canonical_path(Path::new(&path), source); + } + let path_to_std_lib_file = Path::new(STD_CRATE_NAME).join("lib.nr"); - let std_file_id = context.file_manager.add_file(&path_to_std_lib_file).unwrap(); + let std_file_id = context + .file_manager + .name_to_id(path_to_std_lib_file) + .expect("stdlib file id is expected to be present"); let std_crate_id = context.crate_graph.add_stdlib(std_file_id); - let root_file_id = context.file_manager.add_file(file_name).unwrap(); + let root_file_id = context.file_manager.name_to_id(file_name.to_path_buf()).unwrap_or_else(|| panic!("files are expected to be added to the FileManager before reaching the compiler file_path: {file_name:?}")); let root_crate_id = context.crate_graph.add_crate_root(root_file_id); @@ -89,7 +110,10 @@ pub fn prepare_crate(context: &mut Context, file_name: &Path) -> CrateId { // Adds the file from the file system at `Path` to the crate graph pub fn prepare_dependency(context: &mut Context, file_name: &Path) -> CrateId { - let root_file_id = context.file_manager.add_file(file_name).unwrap(); + let root_file_id = context + .file_manager + .name_to_id(file_name.to_path_buf()) + .unwrap_or_else(|| panic!("files are expected to be added to the FileManager before reaching the compiler file_path: {file_name:?}")); let crate_id = context.crate_graph.add_crate(root_file_id); @@ -121,11 +145,15 @@ pub fn check_crate( context: &mut Context, crate_id: CrateId, deny_warnings: bool, + disable_macros: bool, ) -> CompilationResult<()> { - #[cfg(not(feature = "aztec"))] - let macros: Vec<&dyn MacroProcessor> = Vec::new(); - #[cfg(feature = "aztec")] - let macros = vec![&aztec_macros::AztecMacro as &dyn MacroProcessor]; + log::trace!("Start checking crate"); + + let macros: Vec<&dyn MacroProcessor> = if disable_macros { + vec![] + } else { + vec![&aztec_macros::AztecMacro as &dyn MacroProcessor] + }; let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); @@ -134,6 +162,8 @@ pub fn check_crate( diagnostic.in_file(file_id) })); + log::trace!("Finish checking crate"); + if has_errors(&errors, deny_warnings) { Err(errors) } else { @@ -161,7 +191,8 @@ pub fn compile_main( cached_program: Option, force_compile: bool, ) -> CompilationResult { - let (_, mut warnings) = check_crate(context, crate_id, options.deny_warnings)?; + let (_, mut warnings) = + check_crate(context, crate_id, options.deny_warnings, options.disable_macros)?; let main = context.get_main_function(&crate_id).ok_or_else(|| { // TODO(#2155): This error might be a better to exist in Nargo @@ -194,7 +225,8 @@ pub fn compile_contract( crate_id: CrateId, options: &CompileOptions, ) -> CompilationResult { - let (_, warnings) = check_crate(context, crate_id, options.deny_warnings)?; + let (_, warnings) = + check_crate(context, crate_id, options.deny_warnings, options.disable_macros)?; // TODO: We probably want to error if contracts is empty let contracts = context.get_all_contracts(&crate_id); @@ -344,13 +376,15 @@ pub fn compile_no_check( force_compile || options.print_acir || options.show_brillig || options.show_ssa; if !force_compile && hashes_match { + log::info!("Program matches existing artifact, returning early"); return Ok(cached_program.expect("cache must exist for hashes to match")); } - + let visibility = program.return_visibility; let (circuit, debug, input_witnesses, return_witnesses, warnings) = create_circuit(program, options.show_ssa, options.show_brillig)?; - let abi = abi_gen::gen_abi(context, &main_function, input_witnesses, return_witnesses); + let abi = + abi_gen::gen_abi(context, &main_function, input_witnesses, return_witnesses, visibility); let file_map = filter_relevant_files(&[debug.clone()], &context.file_manager); Ok(CompiledProgram { diff --git a/noir/compiler/noirc_driver/src/stdlib.rs b/noir/compiler/noirc_driver/src/stdlib.rs new file mode 100644 index 00000000000..5a91e3f45b5 --- /dev/null +++ b/noir/compiler/noirc_driver/src/stdlib.rs @@ -0,0 +1,24 @@ +use rust_embed::RustEmbed; + +#[derive(RustEmbed)] +#[folder = "../../noir_stdlib/src"] +#[cfg_attr(not(target_os = "windows"), prefix = "std/")] +#[cfg_attr(target_os = "windows", prefix = r"std\")] // Note reversed slash direction +struct StdLibAssets; + +// Returns a vector of tuples containing the path to a stdlib file in the std lib crate +// along with the source code of that file. +// +// This is needed because when we preload the file manager, it needs to know where +// the source code for the stdlib is. The stdlib is treated special because it comes with +// the compiler and is never included as a dependency like other user defined crates. +pub(crate) fn stdlib_paths_with_source() -> Vec<(String, String)> { + StdLibAssets::iter() + .map(|path| { + let source = std::str::from_utf8(StdLibAssets::get(&path).unwrap().data.as_ref()) + .unwrap() + .to_string(); + (path.to_string(), source) + }) + .collect() +} diff --git a/noir/compiler/noirc_errors/Cargo.toml b/noir/compiler/noirc_errors/Cargo.toml index 0cb6afc73bd..812a507550c 100644 --- a/noir/compiler/noirc_errors/Cargo.toml +++ b/noir/compiler/noirc_errors/Cargo.toml @@ -15,3 +15,4 @@ fm.workspace = true chumsky.workspace = true serde.workspace = true serde_with = "3.2.0" +log.workspace = true diff --git a/noir/compiler/noirc_errors/src/debug_info.rs b/noir/compiler/noirc_errors/src/debug_info.rs index 888c24adc1a..3ae5c193e39 100644 --- a/noir/compiler/noirc_errors/src/debug_info.rs +++ b/noir/compiler/noirc_errors/src/debug_info.rs @@ -39,6 +39,7 @@ impl DebugInfo { /// renders the old `OpcodeLocation`s invalid. The AcirTransformationMap is able to map the old `OpcodeLocation` to the new ones. /// Note: One old `OpcodeLocation` might have transformed into more than one new `OpcodeLocation`. pub fn update_acir(&mut self, update_map: AcirTransformationMap) { + log::trace!("Start debug info update"); let old_locations = mem::take(&mut self.locations); for (old_opcode_location, source_locations) in old_locations { @@ -46,6 +47,7 @@ impl DebugInfo { self.locations.insert(new_opcode_location, source_locations.clone()); }); } + log::trace!("Finish debug info update"); } pub fn opcode_location(&self, loc: &OpcodeLocation) -> Option> { diff --git a/noir/compiler/noirc_errors/src/position.rs b/noir/compiler/noirc_errors/src/position.rs index e308eb9a2c7..007ec58ca27 100644 --- a/noir/compiler/noirc_errors/src/position.rs +++ b/noir/compiler/noirc_errors/src/position.rs @@ -65,6 +65,10 @@ impl Span { Span::inclusive(start, start) } + pub fn empty(position: u32) -> Span { + Span::from(position..position) + } + #[must_use] pub fn merge(self, other: Span) -> Span { Span(self.0.merge(other.0)) @@ -81,6 +85,16 @@ impl Span { pub fn end(&self) -> u32 { self.0.end().into() } + + pub fn contains(&self, other: &Span) -> bool { + self.start() <= other.start() && self.end() >= other.end() + } + + pub fn is_smaller(&self, other: &Span) -> bool { + let self_distance = self.end() - self.start(); + let other_distance = other.end() - other.start(); + self_distance < other_distance + } } impl From for Range { @@ -129,4 +143,8 @@ impl Location { pub fn dummy() -> Self { Self { span: Span::single_char(0), file: FileId::dummy() } } + + pub fn contains(&self, other: &Location) -> bool { + self.file == other.file && self.span.contains(&other.span) + } } diff --git a/noir/compiler/noirc_evaluator/Cargo.toml b/noir/compiler/noirc_evaluator/Cargo.toml index 933ec2b300c..6e7152c6d71 100644 --- a/noir/compiler/noirc_evaluator/Cargo.toml +++ b/noir/compiler/noirc_evaluator/Cargo.toml @@ -17,3 +17,4 @@ thiserror.workspace = true num-bigint = "0.4" im = { version = "15.1", features = ["serde"] } serde.workspace = true +log.workspace = true diff --git a/noir/compiler/noirc_evaluator/src/errors.rs b/noir/compiler/noirc_evaluator/src/errors.rs index 42672d4d0ad..42818e8b19d 100644 --- a/noir/compiler/noirc_evaluator/src/errors.rs +++ b/noir/compiler/noirc_evaluator/src/errors.rs @@ -26,7 +26,7 @@ pub enum RuntimeError { }, #[error(transparent)] InternalError(#[from] InternalError), - #[error("Index out of bounds, array has size {index:?}, but index was {array_size:?}")] + #[error("Index out of bounds, array has size {array_size}, but index was {index}")] IndexOutOfBounds { index: usize, array_size: usize, call_stack: CallStack }, #[error("Range constraint of {num_bits} bits is too large for the Field size")] InvalidRangeConstraint { num_bits: u32, call_stack: CallStack }, diff --git a/noir/compiler/noirc_evaluator/src/ssa.rs b/noir/compiler/noirc_evaluator/src/ssa.rs index 8e1c62edc69..6a02a5f6edc 100644 --- a/noir/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/compiler/noirc_evaluator/src/ssa.rs @@ -42,6 +42,7 @@ pub(crate) fn optimize_into_acir( ) -> Result { let abi_distinctness = program.return_distinctness; + log::trace!("Start SSA generation"); let ssa_builder = SsaBuilder::new(program, print_ssa_passes)? .run_pass(Ssa::defunctionalize, "After Defunctionalization:") .run_pass(Ssa::inline_functions, "After Inlining:") @@ -69,9 +70,15 @@ pub(crate) fn optimize_into_acir( let ssa = ssa_builder .run_pass(Ssa::fill_internal_slices, "After Fill Internal Slice Dummy Data:") .finish(); + log::trace!("Finish SSA generation"); let last_array_uses = ssa.find_last_array_uses(); - ssa.into_acir(brillig, abi_distinctness, &last_array_uses) + + log::trace!("Start ACIR generation"); + let acir = ssa.into_acir(brillig, abi_distinctness, &last_array_uses); + log::trace!("Finish ACIR generation"); + + acir } /// Compiles the [`Program`] into [`ACIR`][acvm::acir::circuit::Circuit]. @@ -83,6 +90,8 @@ pub fn create_circuit( enable_ssa_logging: bool, enable_brillig_logging: bool, ) -> Result<(Circuit, DebugInfo, Vec, Vec, Vec), RuntimeError> { + log::trace!("Start circuit generation"); + let func_sig = program.main_function_signature.clone(); let mut generated_acir = optimize_into_acir(program, enable_ssa_logging, enable_brillig_logging)?; @@ -124,6 +133,8 @@ pub fn create_circuit( let (optimized_circuit, transformation_map) = acvm::compiler::optimize(circuit); debug_info.update_acir(transformation_map); + log::trace!("Finish circuit generation"); + Ok((optimized_circuit, debug_info, input_witnesses, return_witnesses, warnings)) } diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 09a3bd4e44b..e039a7793c0 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -130,8 +130,8 @@ impl AcirContext { } /// Adds a constant to the context and assigns a Variable to represent it - pub(crate) fn add_constant(&mut self, constant: FieldElement) -> AcirVar { - let constant_data = AcirVarData::Const(constant); + pub(crate) fn add_constant(&mut self, constant: impl Into) -> AcirVar { + let constant_data = AcirVarData::Const(constant.into()); self.add_data(constant_data) } @@ -353,7 +353,7 @@ impl AcirContext { // Check to see if equality can be determined at compile-time. if diff_expr.is_const() { - return Ok(self.add_constant(diff_expr.is_zero().into())); + return Ok(self.add_constant(diff_expr.is_zero())); } let is_equal_witness = self.acir_ir.is_equal(&lhs_expr, &rhs_expr); @@ -410,7 +410,7 @@ impl AcirContext { // max - ((max - a) AND (max -b)) // Subtracting from max flips the bits, so this is effectively: // (NOT a) NAND (NOT b) - let max = self.add_constant(FieldElement::from((1_u128 << bit_size) - 1)); + let max = self.add_constant((1_u128 << bit_size) - 1); let a = self.sub_var(max, lhs)?; let b = self.sub_var(max, rhs)?; let inputs = vec![AcirValue::Var(a, typ.clone()), AcirValue::Var(b, typ)]; @@ -553,7 +553,7 @@ impl AcirContext { pub(crate) fn not_var(&mut self, x: AcirVar, typ: AcirType) -> Result { let bit_size = typ.bit_size(); // Subtracting from max flips the bits - let max = self.add_constant(FieldElement::from((1_u128 << bit_size) - 1)); + let max = self.add_constant((1_u128 << bit_size) - 1); self.sub_var(max, x) } @@ -580,8 +580,8 @@ impl AcirContext { let quotient = lhs_const.to_u128() / rhs_const.to_u128(); let remainder = lhs_const.to_u128() - quotient * rhs_const.to_u128(); - let quotient_var = self.add_constant(FieldElement::from(quotient)); - let remainder_var = self.add_constant(FieldElement::from(remainder)); + let quotient_var = self.add_constant(quotient); + let remainder_var = self.add_constant(remainder); return Ok((quotient_var, remainder_var)); } @@ -778,7 +778,7 @@ impl AcirContext { // witness = lhs_offset + r assert!(bits + r_bit_size < FieldElement::max_num_bits()); //we need to ensure lhs_offset + r does not overflow - let r_var = self.add_constant(r.into()); + let r_var = self.add_constant(r); let aor = self.add_var(lhs_offset, r_var)?; // lhs_offset<=rhs_offset <=> lhs_offset + r < rhs_offset + r = 2^bit_size <=> witness < 2^bit_size self.range_constrain_var(aor, &NumericType::Unsigned { bit_size }, None)?; @@ -877,7 +877,8 @@ impl AcirContext { /// Converts the `AcirVar` to a `Witness` if it hasn't been already, and appends it to the /// `GeneratedAcir`'s return witnesses. pub(crate) fn return_var(&mut self, acir_var: AcirVar) -> Result<(), InternalError> { - let witness = self.var_to_witness(acir_var)?; + let return_var = self.get_or_create_witness_var(acir_var)?; + let witness = self.var_to_witness(return_var)?; self.acir_ir.push_return_witness(witness); Ok(()) } @@ -926,7 +927,7 @@ impl AcirContext { ) -> Result { // 2^{rhs} let divisor = - self.add_constant(FieldElement::from(2_i128).pow(&FieldElement::from(rhs as i128))); + self.add_constant(FieldElement::from(2_u128).pow(&FieldElement::from(rhs as u128))); let one = self.add_constant(FieldElement::one()); // Computes lhs = 2^{rhs} * q + r @@ -937,7 +938,7 @@ impl AcirContext { /// Returns an `AcirVar` which will be `1` if lhs >= rhs /// and `0` otherwise. - fn more_than_eq_var( + pub(crate) fn more_than_eq_var( &mut self, lhs: AcirVar, rhs: AcirVar, @@ -1150,10 +1151,7 @@ impl AcirContext { // `Intrinsic::ToRadix` returns slices which are represented // by tuples with the structure (length, slice contents) Ok(vec![ - AcirValue::Var( - self.add_constant(FieldElement::from(limb_vars.len() as u128)), - AcirType::field(), - ), + AcirValue::Var(self.add_constant(limb_vars.len()), AcirType::field()), AcirValue::Array(limb_vars.into()), ]) } @@ -1166,7 +1164,7 @@ impl AcirContext { limb_count_var: AcirVar, result_element_type: AcirType, ) -> Result, RuntimeError> { - let two_var = self.add_constant(FieldElement::from(2_u128)); + let two_var = self.add_constant(2_u128); self.radix_decompose(endian, input_var, two_var, limb_count_var, result_element_type) } @@ -1274,7 +1272,7 @@ impl AcirContext { AcirValue::DynamicArray(AcirDynamicArray { block_id, len, .. }) => { for i in 0..len { // We generate witnesses corresponding to the array values - let index_var = self.add_constant(FieldElement::from(i as u128)); + let index_var = self.add_constant(i); let value_read_var = self.read_from_memory(block_id, &index_var)?; let value_read = AcirValue::Var(value_read_var, AcirType::field()); @@ -1428,7 +1426,8 @@ impl AcirContext { index: &AcirVar, ) -> Result { // Fetch the witness corresponding to the index - let index_witness = self.var_to_witness(*index)?; + let index_var = self.get_or_create_witness_var(*index)?; + let index_witness = self.var_to_witness(index_var)?; // Create a Variable to hold the result of the read and extract the corresponding Witness let value_read_var = self.add_variable(); @@ -1449,11 +1448,12 @@ impl AcirContext { value: &AcirVar, ) -> Result<(), InternalError> { // Fetch the witness corresponding to the index - // - let index_witness = self.var_to_witness(*index)?; + let index_var = self.get_or_create_witness_var(*index)?; + let index_witness = self.var_to_witness(index_var)?; // Fetch the witness corresponding to the value to be written - let value_write_witness = self.var_to_witness(*value)?; + let value_write_var = self.get_or_create_witness_var(*value)?; + let value_write_witness = self.var_to_witness(value_write_var)?; // Add the memory write operation to the list of opcodes let op = MemOp::write_to_mem_index(index_witness.into(), value_write_witness.into()); @@ -1495,6 +1495,7 @@ impl AcirContext { ) -> Result<(), InternalError> { match input { AcirValue::Var(var, _) => { + let var = self.get_or_create_witness_var(var)?; witnesses.push(self.var_to_witness(var)?); } AcirValue::Array(values) => { @@ -1604,28 +1605,40 @@ fn execute_brillig( _signature: &[u8], _message: &[u8], ) -> Result { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::SchnorrVerify)) + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::SchnorrVerify, + "SchnorrVerify is not supported".to_string(), + )) } fn pedersen_commitment( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::PedersenCommitment)) + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::PedersenCommitment, + "PedersenCommitment is not supported".to_string(), + )) } fn pedersen_hash( &self, _inputs: &[FieldElement], _domain_separator: u32, ) -> Result { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::PedersenHash)) + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::PedersenHash, + "PedersenHash is not supported".to_string(), + )) } fn fixed_base_scalar_mul( &self, _low: &FieldElement, _high: &FieldElement, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Err(BlackBoxResolutionError::Unsupported(BlackBoxFunc::FixedBaseScalarMul)) + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::FixedBaseScalarMul, + "FixedBaseScalarMul is not supported".to_string(), + )) } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 331c837a521..d73bb514e02 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -5,6 +5,7 @@ use std::collections::HashSet; use std::fmt::Debug; use self::acir_ir::acir_variable::{AcirContext, AcirType, AcirVar}; +use super::function_builder::data_bus::DataBus; use super::ir::dfg::CallStack; use super::{ ir::{ @@ -90,6 +91,8 @@ struct Context { /// Maps SSA array values to their slice size and any nested slices internal to the parent slice. /// This enables us to maintain the slice structure of a slice when performing an array get. slice_sizes: HashMap, Vec>, + + data_bus: DataBus, } #[derive(Clone)] @@ -133,6 +136,16 @@ impl AcirValue { } } + fn borrow_var(&self) -> Result { + match self { + AcirValue::Var(var, _) => Ok(*var), + AcirValue::DynamicArray(_) | AcirValue::Array(_) => Err(InternalError::General { + message: "Called AcirValue::borrow_var on an array".to_string(), + call_stack: CallStack::new(), + }), + } + } + fn flatten(self) -> Vec<(AcirVar, AcirType)> { match self { AcirValue::Var(var, typ) => vec![(var, typ)], @@ -189,6 +202,7 @@ impl Context { internal_mem_block_lengths: HashMap::default(), max_block_id: 0, slice_sizes: HashMap::default(), + data_bus: DataBus::default(), } } @@ -216,6 +230,8 @@ impl Context { let dfg = &main_func.dfg; let entry_block = &dfg[main_func.entry_block()]; let input_witness = self.convert_ssa_block_params(entry_block.parameters(), dfg)?; + + self.data_bus = dfg.data_bus.to_owned(); let mut warnings = Vec::new(); for instruction_id in entry_block.instructions() { warnings.extend(self.convert_ssa_instruction( @@ -441,8 +457,7 @@ impl Context { let mut read_dynamic_array_index = |block_id: BlockId, array_index: usize| -> Result { - let index_var = - self.acir_context.add_constant(FieldElement::from(array_index as u128)); + let index_var = self.acir_context.add_constant(array_index); self.acir_context.read_from_memory(block_id, &index_var) }; @@ -852,7 +867,7 @@ impl Context { ); let values = try_vecmap(0..*len, |i| { - let index_var = self.acir_context.add_constant(FieldElement::from(i as u128)); + let index_var = self.acir_context.add_constant(i); let read = self.acir_context.read_from_memory(*block_id, &index_var)?; Ok::(AcirValue::Var(read, AcirType::field())) @@ -883,10 +898,26 @@ impl Context { dfg: &DataFlowGraph, ) -> Result { let (array_id, _, block_id) = self.check_array_is_initialized(array, dfg)?; - let results = dfg.instruction_results(instruction); let res_typ = dfg.type_of_value(results[0]); + // Get operations to call-data parameters are replaced by a get to the call-data-bus array + if let Some(call_data) = self.data_bus.call_data { + if self.data_bus.call_data_map.contains_key(&array_id) { + // TODO: the block_id of call-data must be notified to the backend + // TODO: should we do the same for return-data? + let type_size = res_typ.flattened_size(); + let type_size = + self.acir_context.add_constant(FieldElement::from(type_size as i128)); + let offset = self.acir_context.mul_var(var_index, type_size)?; + let bus_index = self.acir_context.add_constant(FieldElement::from( + self.data_bus.call_data_map[&array_id] as i128, + )); + let new_index = self.acir_context.add_var(offset, bus_index)?; + return self.array_get(instruction, call_data, new_index, dfg); + } + } + let value = if !res_typ.contains_slice_element() { self.array_get_value(&res_typ, block_id, &mut var_index, &[])? } else { @@ -897,7 +928,7 @@ impl Context { // The first max size is going to be the length of the parent slice // As we are fetching from the parent slice we just want its internal - // slize sizes. + // slice sizes. let slice_sizes = slice_sizes[1..].to_vec(); let value = self.array_get_value(&res_typ, block_id, &mut var_index, &slice_sizes)?; @@ -1022,7 +1053,7 @@ impl Context { self.copy_dynamic_array(block_id, result_block_id, array_len)?; } - self.array_set_value(store_value, result_block_id, &mut var_index)?; + self.array_set_value(&store_value, result_block_id, &mut var_index)?; // Set new resulting array to have the same slice sizes as the instruction input if let Type::Slice(element_types) = &array_typ { @@ -1057,7 +1088,7 @@ impl Context { fn array_set_value( &mut self, - value: AcirValue, + value: &AcirValue, block_id: BlockId, var_index: &mut AcirVar, ) -> Result<(), RuntimeError> { @@ -1065,8 +1096,8 @@ impl Context { match value { AcirValue::Var(store_var, _) => { // Write the new value into the new array at the specified index - self.acir_context.write_to_memory(block_id, var_index, &store_var)?; - // Incremement the var_index in case of a nested array + self.acir_context.write_to_memory(block_id, var_index, store_var)?; + // Increment the var_index in case of a nested array *var_index = self.acir_context.add_var(*var_index, one)?; } AcirValue::Array(values) => { @@ -1075,13 +1106,13 @@ impl Context { } } AcirValue::DynamicArray(AcirDynamicArray { block_id: inner_block_id, len, .. }) => { - let values = try_vecmap(0..len, |i| { - let index_var = self.acir_context.add_constant(FieldElement::from(i as u128)); + let values = try_vecmap(0..*len, |i| { + let index_var = self.acir_context.add_constant(i); - let read = self.acir_context.read_from_memory(inner_block_id, &index_var)?; + let read = self.acir_context.read_from_memory(*inner_block_id, &index_var)?; Ok::(AcirValue::Var(read, AcirType::field())) })?; - self.array_set_value(AcirValue::Array(values.into()), block_id, var_index)?; + self.array_set_value(&AcirValue::Array(values.into()), block_id, var_index)?; } } Ok(()) @@ -1235,7 +1266,7 @@ impl Context { // The final array should will the flattened index at each outer array index let init_values = vecmap(flat_elem_type_sizes, |type_size| { - let var = self.acir_context.add_constant(FieldElement::from(type_size as u128)); + let var = self.acir_context.add_constant(type_size); AcirValue::Var(var, AcirType::field()) }); let element_type_sizes_len = init_values.len(); @@ -1292,7 +1323,7 @@ impl Context { array_len: usize, ) -> Result<(), RuntimeError> { let init_values = try_vecmap(0..array_len, |i| { - let index_var = self.acir_context.add_constant(FieldElement::from(i as u128)); + let index_var = self.acir_context.add_constant(i); let read = self.acir_context.read_from_memory(source, &index_var)?; Ok::(AcirValue::Var(read, AcirType::field())) @@ -1653,8 +1684,7 @@ impl Context { ) { // Subtractions must first have the integer modulus added before truncation can be // applied. This is done in order to prevent underflow. - let integer_modulus = - self.acir_context.add_constant(FieldElement::from(2_u128.pow(bit_size))); + let integer_modulus = self.acir_context.add_constant(2_u128.pow(bit_size)); var = self.acir_context.add_var(var, integer_modulus)?; } } @@ -1760,45 +1790,72 @@ impl Context { Intrinsic::ArrayLen => { let len = match self.convert_value(arguments[0], dfg) { AcirValue::Var(_, _) => unreachable!("Non-array passed to array.len() method"), - AcirValue::Array(values) => (values.len() as u128).into(), - AcirValue::DynamicArray(array) => (array.len as u128).into(), + AcirValue::Array(values) => values.len(), + AcirValue::DynamicArray(array) => array.len, }; Ok(vec![AcirValue::Var(self.acir_context.add_constant(len), AcirType::field())]) } Intrinsic::SlicePushBack => { + // arguments = [slice_length, slice_contents, ...elements_to_push] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; - let (array_id, array_typ, _) = + let (slice_contents, slice_typ, _) = self.check_array_is_initialized(arguments[1], dfg)?; - let slice = self.convert_value(arguments[1], dfg); + let slice = self.convert_value(slice_contents, dfg); - // TODO(#3364): make sure that we have handled nested struct inputs - let element = self.convert_value(arguments[2], dfg); - let one = self.acir_context.add_constant(FieldElement::one()); - let new_slice_length = self.acir_context.add_var(slice_length, one)?; + let mut new_elem_size = Self::flattened_value_size(&slice); - // We attach the element no matter what in case len == capacity, as otherwise we - // may get an out of bounds error. let mut new_slice = Vector::new(); - self.slice_intrinsic_input(&mut new_slice, slice.clone())?; - new_slice.push_back(element.clone()); + self.slice_intrinsic_input(&mut new_slice, slice)?; + + let elements_to_push = &arguments[2..]; + // We only fill internal slices for nested slices (a slice inside of a slice). + // So we must directly push back elements for slices which are not a nested slice. + if !slice_typ.is_nested_slice() { + for elem in elements_to_push { + let element = self.convert_value(*elem, dfg); + + new_elem_size += Self::flattened_value_size(&element); + new_slice.push_back(element); + } + } + + // Increase the slice length by one to enable accessing more elements in the slice. + let one = self.acir_context.add_constant(FieldElement::one()); + let new_slice_length = self.acir_context.add_var(slice_length, one)?; - // TODO(#3364): This works for non-nested outputs - let len = Self::flattened_value_size(&slice); - let new_elem_size = Self::flattened_value_size(&element); let new_slice_val = AcirValue::Array(new_slice); let result_block_id = self.block_id(&result_ids[1]); - self.initialize_array( - result_block_id, - len + new_elem_size, - Some(new_slice_val.clone()), - )?; + self.initialize_array(result_block_id, new_elem_size, Some(new_slice_val.clone()))?; + // The previous slice length represents the index we want to write into. let mut var_index = slice_length; - self.array_set_value(element, result_block_id, &mut var_index)?; + // Dynamic arrays are represented as flat memory. We must flatten the user facing index + // to a flattened index that matches the complex slice structure. + if slice_typ.is_nested_slice() { + let element_size = slice_typ.element_size(); + + // Multiply the element size against the var index before fetching the flattened index + // This operation makes sure our user-facing slice index matches the strategy for indexing in SSA, + // which is how `get_flattened_index` expects its index input. + let element_size_var = self.acir_context.add_constant(element_size); + var_index = self.acir_context.mul_var(slice_length, element_size_var)?; + var_index = + self.get_flattened_index(&slice_typ, slice_contents, var_index, dfg)?; + } - let element_type_sizes = if !can_omit_element_sizes_array(&array_typ) { + // Write the elements we wish to push back directly. + // The slice's underlying array value should already be filled with dummy data + // to enable this write to be within bounds. + // The dummy data is either attached during SSA gen or in this match case for non-nested slices. + // These values can then be accessed due to the increased dynamic slice length. + for elem in elements_to_push { + let element = self.convert_value(*elem, dfg); + self.array_set_value(&element, result_block_id, &mut var_index)?; + } + + let element_type_sizes = if !can_omit_element_sizes_array(&slice_typ) { Some(self.init_element_type_sizes_array( - &array_typ, - array_id, + &slice_typ, + slice_contents, Some(new_slice_val), dfg, )?) @@ -1807,155 +1864,505 @@ impl Context { }; let result = AcirValue::DynamicArray(AcirDynamicArray { block_id: result_block_id, - len: len + new_elem_size, + len: new_elem_size, element_type_sizes, }); Ok(vec![AcirValue::Var(new_slice_length, AcirType::field()), result]) } Intrinsic::SlicePushFront => { + // arguments = [slice_length, slice_contents, ...elements_to_push] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; - let slice: AcirValue = self.convert_value(arguments[1], dfg); - // TODO(#3364): make sure that we have handled nested struct inputs - let element = self.convert_value(arguments[2], dfg); + let (slice_contents, slice_typ, _) = + self.check_array_is_initialized(arguments[1], dfg)?; + let slice: AcirValue = self.convert_value(slice_contents, dfg); + + let mut new_slice_size = Self::flattened_value_size(&slice); + + // Increase the slice length by one to enable accessing more elements in the slice. let one = self.acir_context.add_constant(FieldElement::one()); let new_slice_length = self.acir_context.add_var(slice_length, one)?; let mut new_slice = Vector::new(); self.slice_intrinsic_input(&mut new_slice, slice)?; - new_slice.push_front(element); - Ok(vec![ - AcirValue::Var(new_slice_length, AcirType::field()), - AcirValue::Array(new_slice), - ]) + let elements_to_push = &arguments[2..]; + let mut elem_size = 0; + // We only fill internal slices for nested slices (a slice inside of a slice). + // So we must directly push front elements for slices which are not a nested slice. + if !slice_typ.is_nested_slice() { + for elem in elements_to_push.iter().rev() { + let element = self.convert_value(*elem, dfg); + + elem_size += Self::flattened_value_size(&element); + new_slice.push_front(element); + } + new_slice_size += elem_size; + } else { + // We have already filled the appropriate dummy values for nested slice during SSA gen. + // We need to account for that we do not go out of bounds by removing dummy data as we + // push elements to the front of our slice. + // Using this strategy we are able to avoid dynamic writes like we do for a SlicePushBack. + for elem in elements_to_push.iter().rev() { + let element = self.convert_value(*elem, dfg); + + let elem_size = Self::flattened_value_size(&element); + // Have to pop based off of the flattened value size as we read the + // slice intrinsic as a flat list of AcirValue::Var + for _ in 0..elem_size { + new_slice.pop_back(); + } + new_slice.push_front(element); + } + } + + let new_slice_val = AcirValue::Array(new_slice.clone()); + + let result_block_id = self.block_id(&result_ids[1]); + self.initialize_array( + result_block_id, + new_slice_size, + Some(new_slice_val.clone()), + )?; + + let element_type_sizes = if !can_omit_element_sizes_array(&slice_typ) { + Some(self.init_element_type_sizes_array( + &slice_typ, + slice_contents, + Some(new_slice_val), + dfg, + )?) + } else { + None + }; + let result = AcirValue::DynamicArray(AcirDynamicArray { + block_id: result_block_id, + len: new_slice_size, + element_type_sizes, + }); + + Ok(vec![AcirValue::Var(new_slice_length, AcirType::field()), result]) } Intrinsic::SlicePopBack => { + // arguments = [slice_length, slice_contents] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; - let slice = self.convert_value(arguments[1], dfg); let one = self.acir_context.add_constant(FieldElement::one()); let new_slice_length = self.acir_context.sub_var(slice_length, one)?; - - let (_, _, block_id) = self.check_array_is_initialized(arguments[1], dfg)?; + // For a pop back operation we want to fetch from the `length - 1` as this is the + // last valid index that can be accessed in a slice. After the pop back operation + // the elements stored at that index will no longer be able to be accessed. let mut var_index = new_slice_length; - let elem = self.array_get_value( - &dfg.type_of_value(result_ids[2]), - block_id, - &mut var_index, - &[], - )?; - // TODO(#3364): make sure that we have handled nested struct inputs + let (slice_contents, slice_typ, block_id) = + self.check_array_is_initialized(arguments[1], dfg)?; + let slice = self.convert_value(slice_contents, dfg); + + let element_size = slice_typ.element_size(); + + let mut popped_elements = Vec::new(); + // Fetch the values we are popping off of the slice. + // In the case of non-nested slice the logic is simple as we do not + // need to account for the internal slice sizes or flattening the index. + // + // The pop back operation results are of the format [slice length, slice contents, popped elements]. + // Thus, we look at the result ids at index 2 and onwards to determine the type of each popped element. + if !slice_typ.is_nested_slice() { + for res in &result_ids[2..] { + let elem = self.array_get_value( + &dfg.type_of_value(*res), + block_id, + &mut var_index, + &[], + )?; + popped_elements.push(elem); + } + } else { + // Fetch the slice sizes of the nested slice. + let slice_sizes = self.slice_sizes.get(&slice_contents); + let mut slice_sizes = + slice_sizes.expect("ICE: should have slice sizes").clone(); + // We want to remove the parent size as we are fetching the child + slice_sizes.remove(0); + + // Multiply the element size against the var index before fetching the flattened index + // This operation makes sure our user-facing slice index matches the strategy for indexing in SSA, + // which is how `get_flattened_index` expects its index input. + let element_size_var = self.acir_context.add_constant(element_size); + // We want to use an index one less than the slice length + var_index = self.acir_context.mul_var(var_index, element_size_var)?; + var_index = + self.get_flattened_index(&slice_typ, slice_contents, var_index, dfg)?; + + for res in &result_ids[2..] { + let elem = self.array_get_value( + &dfg.type_of_value(*res), + block_id, + &mut var_index, + &slice_sizes, + )?; + popped_elements.push(elem); + } + } + let mut new_slice = Vector::new(); self.slice_intrinsic_input(&mut new_slice, slice)?; - Ok(vec![ + let mut results = vec![ AcirValue::Var(new_slice_length, AcirType::field()), AcirValue::Array(new_slice), - elem, - ]) + ]; + results.append(&mut popped_elements); + + Ok(results) } Intrinsic::SlicePopFront => { + // arguments = [slice_length, slice_contents] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; - let slice = self.convert_value(arguments[1], dfg); + + let (slice_contents, slice_typ, block_id) = + self.check_array_is_initialized(arguments[1], dfg)?; + let slice = self.convert_value(slice_contents, dfg); let one = self.acir_context.add_constant(FieldElement::one()); let new_slice_length = self.acir_context.sub_var(slice_length, one)?; let mut new_slice = Vector::new(); self.slice_intrinsic_input(&mut new_slice, slice)?; - // TODO(#3364): make sure that we have handled nested struct inputs - let elem = new_slice - .pop_front() - .expect("There are no elements in this slice to be removed"); - Ok(vec![ - elem, - AcirValue::Var(new_slice_length, AcirType::field()), - AcirValue::Array(new_slice), - ]) + let element_size = slice_typ.element_size(); + + let mut popped_elements: Vec = Vec::new(); + let mut popped_elements_size = 0; + let mut var_index = self.acir_context.add_constant(FieldElement::zero()); + // Fetch the values we are popping off of the slice. + // In the case of non-nested slice the logic is simple as we do not + // need to account for the internal slice sizes or flattening the index. + // + // The pop front operation results are of the format [popped elements, slice length, slice contents]. + // Thus, we look at the result ids up to the element size to determine the type of each popped element. + if !slice_typ.is_nested_slice() { + for res in &result_ids[..element_size] { + let element = self.array_get_value( + &dfg.type_of_value(*res), + block_id, + &mut var_index, + &[], + )?; + let elem_size = Self::flattened_value_size(&element); + popped_elements_size += elem_size; + popped_elements.push(element); + } + } else { + let slice_sizes = self.slice_sizes.get(&slice_contents); + let mut slice_sizes = + slice_sizes.expect("ICE: should have slice sizes").clone(); + // We want to remove the parent size as we are fetching the child + slice_sizes.remove(0); + + for res in &result_ids[..element_size] { + let element = self.array_get_value( + &dfg.type_of_value(*res), + block_id, + &mut var_index, + &slice_sizes, + )?; + let elem_size = Self::flattened_value_size(&element); + popped_elements_size += elem_size; + popped_elements.push(element); + } + } + // It is expected that the `popped_elements_size` is the flattened size of the elements, + // as the input slice should be a dynamic array which is represented by flat memory. + new_slice = new_slice.slice(popped_elements_size..); + + popped_elements.push(AcirValue::Var(new_slice_length, AcirType::field())); + popped_elements.push(AcirValue::Array(new_slice)); + + Ok(popped_elements) } Intrinsic::SliceInsert => { - // Slice insert with a constant index + // arguments = [slice_length, slice_contents, insert_index, ...elements_to_insert] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; - let slice = self.convert_value(arguments[1], dfg); - let index = self.convert_value(arguments[2], dfg).into_var()?; - let element = self.convert_value(arguments[3], dfg); + + let (slice_contents, slice_typ, block_id) = + self.check_array_is_initialized(arguments[1], dfg)?; + + let slice = self.convert_value(slice_contents, dfg); + let insert_index = self.convert_value(arguments[2], dfg).into_var()?; let one = self.acir_context.add_constant(FieldElement::one()); let new_slice_length = self.acir_context.add_var(slice_length, one)?; - // TODO(#2462): Slice insert is a little less obvious on how to implement due to the case - // of having a dynamic index - // The slice insert logic will need a more involved codegen - let index = self.acir_context.var_to_expression(index)?.to_const(); - let index = index - .expect("ICE: slice length should be fully tracked and constant by ACIR gen"); - let index = index.to_u128() as usize; + let slice_size = Self::flattened_value_size(&slice); + + // Fetch the flattened index from the user provided index argument. + let element_size = slice_typ.element_size(); + let element_size_var = self.acir_context.add_constant(element_size); + let flat_insert_index = + self.acir_context.mul_var(insert_index, element_size_var)?; + let flat_user_index = + self.get_flattened_index(&slice_typ, slice_contents, flat_insert_index, dfg)?; + + let elements_to_insert = &arguments[3..]; + // Determine the elements we need to write into our resulting dynamic array. + // We need to a fully flat list of AcirVar's as a dynamic array is represented with flat memory. + let mut inner_elem_size_usize = 0; + let mut flattened_elements = Vec::new(); + for elem in elements_to_insert { + let element = self.convert_value(*elem, dfg); + let elem_size = Self::flattened_value_size(&element); + inner_elem_size_usize += elem_size; + let mut flat_elem = element.flatten().into_iter().map(|(var, _)| var).collect(); + flattened_elements.append(&mut flat_elem); + } + let inner_elem_size = self.acir_context.add_constant(inner_elem_size_usize); + // Set the maximum flattened index at which a new element should be inserted. + let max_flat_user_index = + self.acir_context.add_var(flat_user_index, inner_elem_size)?; + + // Go through the entire slice argument and determine what value should be written to the new slice. + // 1. If we are below the starting insertion index we should insert the value that was already + // in the original slice. + // 2. If we are above the starting insertion index but below the max insertion index we should insert + // the flattened element arguments. + // 3. If we are above the max insertion index we should insert the previous value from the original slice, + // as during an insertion we want to shift all elements after the insertion up an index. + let result_block_id = self.block_id(&result_ids[1]); + self.initialize_array(result_block_id, slice_size, None)?; + let mut current_insert_index = 0; + for i in 0..slice_size { + let current_index = self.acir_context.add_constant(i); + + // Check that we are above the lower bound of the insertion index + let greater_eq_than_idx = self.acir_context.more_than_eq_var( + current_index, + flat_user_index, + 64, + self.current_side_effects_enabled_var, + )?; + // Check that we are below the upper bound of the insertion index + let less_than_idx = self.acir_context.less_than_var( + current_index, + max_flat_user_index, + 64, + self.current_side_effects_enabled_var, + )?; + + // Read from the original slice the value we want to insert into our new slice. + // We need to make sure that we read the previous element when our current index is greater than insertion index. + // If the index for the previous element is out of the array bounds we can avoid the check for whether + // the current index is over the insertion index. + let shifted_index = if i < inner_elem_size_usize { + current_index + } else { + let index_minus_elem_size = + self.acir_context.add_constant(i - inner_elem_size_usize); - let mut new_slice = Vector::new(); - self.slice_intrinsic_input(&mut new_slice, slice)?; + let use_shifted_index_pred = self + .acir_context + .mul_var(index_minus_elem_size, greater_eq_than_idx)?; - // We do not return an index out of bounds error directly here - // as the length of the slice is dynamic, and length of `new_slice` - // represents the capacity of the slice, not the actual length. - // - // Constraints should be generated during SSA gen to tell the user - // they are attempting to insert at too large of an index. - // This check prevents a panic inside of the im::Vector insert method. - if index <= new_slice.len() { - // TODO(#3364): make sure that we have handled nested struct inputs - new_slice.insert(index, element); + let not_pred = self.acir_context.sub_var(one, greater_eq_than_idx)?; + let use_current_index_pred = + self.acir_context.mul_var(not_pred, current_index)?; + + self.acir_context.add_var(use_shifted_index_pred, use_current_index_pred)? + }; + + let value_shifted_index = + self.acir_context.read_from_memory(block_id, &shifted_index)?; + + // Final predicate to determine whether we are within the insertion bounds + let should_insert_value_pred = + self.acir_context.mul_var(greater_eq_than_idx, less_than_idx)?; + let insert_value_pred = self.acir_context.mul_var( + flattened_elements[current_insert_index], + should_insert_value_pred, + )?; + + let not_pred = self.acir_context.sub_var(one, should_insert_value_pred)?; + let shifted_value_pred = + self.acir_context.mul_var(not_pred, value_shifted_index)?; + + let new_value = + self.acir_context.add_var(insert_value_pred, shifted_value_pred)?; + + self.acir_context.write_to_memory( + result_block_id, + ¤t_index, + &new_value, + )?; + + current_insert_index += 1; + if inner_elem_size_usize == current_insert_index { + current_insert_index = 0; + } } - Ok(vec![ - AcirValue::Var(new_slice_length, AcirType::field()), - AcirValue::Array(new_slice), - ]) + // let new_slice_val = AcirValue::Array(new_slice); + let element_type_sizes = if !can_omit_element_sizes_array(&slice_typ) { + Some(self.init_element_type_sizes_array( + &slice_typ, + slice_contents, + Some(slice), + dfg, + )?) + } else { + None + }; + let result = AcirValue::DynamicArray(AcirDynamicArray { + block_id: result_block_id, + len: slice_size, + element_type_sizes, + }); + + Ok(vec![AcirValue::Var(new_slice_length, AcirType::field()), result]) } Intrinsic::SliceRemove => { - // Slice insert with a constant index + // arguments = [slice_length, slice_contents, remove_index] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; - let slice = self.convert_value(arguments[1], dfg); - let index = self.convert_value(arguments[2], dfg).into_var()?; + + let (slice_contents, slice_typ, block_id) = + self.check_array_is_initialized(arguments[1], dfg)?; + + let slice = self.convert_value(slice_contents, dfg); + let remove_index = self.convert_value(arguments[2], dfg).into_var()?; let one = self.acir_context.add_constant(FieldElement::one()); let new_slice_length = self.acir_context.sub_var(slice_length, one)?; - // TODO(#2462): allow slice remove with a constant index - // Slice remove is a little less obvious on how to implement due to the case - // of having a dynamic index - // The slice remove logic will need a more involved codegen - let index = self.acir_context.var_to_expression(index)?.to_const(); - let index = index - .expect("ICE: slice length should be fully tracked and constant by ACIR gen"); - let index = index.to_u128() as usize; + let slice_size = Self::flattened_value_size(&slice); let mut new_slice = Vector::new(); self.slice_intrinsic_input(&mut new_slice, slice)?; - // We do not return an index out of bounds error directly here - // as the length of the slice is dynamic, and length of `new_slice` - // represents the capacity of the slice, not the actual length. - // - // Constraints should be generated during SSA gen to tell the user - // they are attempting to remove at too large of an index. - // This check prevents a panic inside of the im::Vector remove method. - let removed_elem = if index < new_slice.len() { - // TODO(#3364): make sure that we have handled nested struct inputs - new_slice.remove(index) + // Compiler sanity check + assert_eq!( + new_slice.len(), + slice_size, + "ICE: The read flattened slice should match the computed size" + ); + + // Fetch the flattened index from the user provided index argument. + let element_size = slice_typ.element_size(); + let element_size_var = self.acir_context.add_constant(element_size); + let flat_remove_index = + self.acir_context.mul_var(remove_index, element_size_var)?; + let flat_user_index = + self.get_flattened_index(&slice_typ, slice_contents, flat_remove_index, dfg)?; + + // Fetch the values we are remove from the slice. + // In the case of non-nested slice the logic is simple as we do not + // need to account for the internal slice sizes or flattening the index. + // As we fetch the values we can determine the size of the removed values + // which we will later use for writing the correct resulting slice. + let mut popped_elements = Vec::new(); + let mut popped_elements_size = 0; + // Set a temp index just for fetching from the original slice as `array_get_value` mutates + // the index internally. + let mut temp_index = flat_user_index; + if !slice_typ.is_nested_slice() { + for res in &result_ids[2..(2 + element_size)] { + let element = self.array_get_value( + &dfg.type_of_value(*res), + block_id, + &mut temp_index, + &[], + )?; + let elem_size = Self::flattened_value_size(&element); + popped_elements_size += elem_size; + popped_elements.push(element); + } + } else { + let slice_sizes = self.slice_sizes.get(&slice_contents); + let mut slice_sizes = + slice_sizes.expect("ICE: should have slice sizes").clone(); + // We want to remove the parent size as we are fetching the child + slice_sizes.remove(0); + + for res in &result_ids[2..(2 + element_size)] { + let element = self.array_get_value( + &dfg.type_of_value(*res), + block_id, + &mut temp_index, + &slice_sizes, + )?; + let elem_size = Self::flattened_value_size(&element); + popped_elements_size += elem_size; + popped_elements.push(element); + } + } + + // Go through the entire slice argument and determine what value should be written to the new slice. + // 1. If the current index is greater than the removal index we must write the next value + // from the original slice to the current index + // 2. At the end of the slice reading from the next value of the original slice + // can lead to a potential out of bounds error. In this case we just fetch from the original slice + // at the current index. As we are decreasing the slice in length, this is a safe operation. + let result_block_id = self.block_id(&result_ids[1]); + self.initialize_array( + result_block_id, + slice_size, + Some(AcirValue::Array(new_slice.clone())), + )?; + for i in 0..slice_size { + let current_index = self.acir_context.add_constant(i); + + let value_current_index = &new_slice[i].borrow_var()?; + + if slice_size > (i + popped_elements_size) { + let shifted_index = + self.acir_context.add_constant(i + popped_elements_size); + + let value_shifted_index = + self.acir_context.read_from_memory(block_id, &shifted_index)?; + + let use_shifted_value = self.acir_context.more_than_eq_var( + current_index, + flat_user_index, + 64, + self.current_side_effects_enabled_var, + )?; + + let shifted_value_pred = + self.acir_context.mul_var(value_shifted_index, use_shifted_value)?; + let not_pred = self.acir_context.sub_var(one, use_shifted_value)?; + let current_value_pred = + self.acir_context.mul_var(not_pred, *value_current_index)?; + + let new_value = + self.acir_context.add_var(shifted_value_pred, current_value_pred)?; + + self.acir_context.write_to_memory( + result_block_id, + ¤t_index, + &new_value, + )?; + }; + } + + let new_slice_val = AcirValue::Array(new_slice); + let element_type_sizes = if !can_omit_element_sizes_array(&slice_typ) { + Some(self.init_element_type_sizes_array( + &slice_typ, + slice_contents, + Some(new_slice_val), + dfg, + )?) } else { - // This is a dummy value which should never be used if the appropriate - // slice access checks are generated before this slice remove call. - AcirValue::Var(slice_length, AcirType::field()) + None }; + let result = AcirValue::DynamicArray(AcirDynamicArray { + block_id: result_block_id, + len: slice_size, + element_type_sizes, + }); - Ok(vec![ - AcirValue::Var(new_slice_length, AcirType::field()), - AcirValue::Array(new_slice), - removed_elem, - ]) + let mut result = vec![AcirValue::Var(new_slice_length, AcirType::field()), result]; + result.append(&mut popped_elements); + + Ok(result) } _ => todo!("expected a black box function"), } @@ -1978,7 +2385,7 @@ impl Context { AcirValue::DynamicArray(AcirDynamicArray { block_id, len, .. }) => { for i in 0..len { // We generate witnesses corresponding to the array values - let index_var = self.acir_context.add_constant(FieldElement::from(i as u128)); + let index_var = self.acir_context.add_constant(i); let value_read_var = self.acir_context.read_from_memory(block_id, &index_var)?; diff --git a/noir/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs b/noir/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs new file mode 100644 index 00000000000..7f337089321 --- /dev/null +++ b/noir/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs @@ -0,0 +1,144 @@ +use std::rc::Rc; + +use crate::ssa::ir::{types::Type, value::ValueId}; +use acvm::FieldElement; +use fxhash::FxHashMap as HashMap; +use noirc_frontend::hir_def::function::FunctionSignature; + +use super::FunctionBuilder; + +/// Used to create a data bus, which is an array of private inputs +/// replacing public inputs +pub(crate) struct DataBusBuilder { + pub(crate) values: im::Vector, + index: usize, + pub(crate) map: HashMap, + pub(crate) databus: Option, +} + +impl DataBusBuilder { + pub(crate) fn new() -> DataBusBuilder { + DataBusBuilder { + index: 0, + map: HashMap::default(), + databus: None, + values: im::Vector::new(), + } + } + + /// Generates a boolean vector telling which (ssa) parameter from the given function signature + /// are tagged with databus visibility + pub(crate) fn is_databus(main_signature: &FunctionSignature) -> Vec { + let mut params_is_databus = Vec::new(); + + for param in &main_signature.0 { + let is_databus = match param.2 { + noirc_frontend::Visibility::Public | noirc_frontend::Visibility::Private => false, + noirc_frontend::Visibility::DataBus => true, + }; + let len = param.1.field_count() as usize; + params_is_databus.extend(vec![is_databus; len]); + } + params_is_databus + } +} + +#[derive(Clone, Default, Debug)] +pub(crate) struct DataBus { + pub(crate) call_data: Option, + pub(crate) call_data_map: HashMap, + pub(crate) return_data: Option, +} + +impl DataBus { + /// Updates the databus values with the provided function + pub(crate) fn map_values(&self, mut f: impl FnMut(ValueId) -> ValueId) -> DataBus { + let mut call_data_map = HashMap::default(); + for (k, v) in self.call_data_map.iter() { + call_data_map.insert(f(*k), *v); + } + DataBus { + call_data: self.call_data.map(&mut f), + call_data_map, + return_data: self.return_data.map(&mut f), + } + } + + /// Construct a databus from call_data and return_data data bus builders + pub(crate) fn get_data_bus(call_data: DataBusBuilder, return_data: DataBusBuilder) -> DataBus { + DataBus { + call_data: call_data.databus, + call_data_map: call_data.map, + return_data: return_data.databus, + } + } +} + +impl FunctionBuilder { + /// Insert a value into a data bus builder + fn add_to_data_bus(&mut self, value: ValueId, databus: &mut DataBusBuilder) { + assert!(databus.databus.is_none(), "initialising finalized call data"); + let typ = self.current_function.dfg[value].get_type().clone(); + match typ { + Type::Numeric(_) => { + databus.values.push_back(value); + databus.index += 1; + } + Type::Reference(_) => unreachable!(), + Type::Array(typ, len) => { + assert!(typ.len() == 1, "unsupported composite type"); + databus.map.insert(value, databus.index); + for i in 0..len { + // load each element of the array + let index = self + .current_function + .dfg + .make_constant(FieldElement::from(i as i128), Type::field()); + let element = self.insert_array_get(value, index, typ[0].clone()); + self.add_to_data_bus(element, databus); + } + } + Type::Slice(_) => unreachable!(), + Type::Function => unreachable!(), + } + } + + /// Create a data bus builder from a list of values + pub(crate) fn initialize_data_bus( + &mut self, + values: &[ValueId], + mut databus: DataBusBuilder, + ) -> DataBusBuilder { + for value in values { + self.add_to_data_bus(*value, &mut databus); + } + let len = databus.values.len(); + + let array = if len > 0 { + let array = + self.array_constant(databus.values, Type::Array(Rc::new(vec![Type::field()]), len)); + Some(array) + } else { + None + }; + + DataBusBuilder { index: 0, map: databus.map, databus: array, values: im::Vector::new() } + } + + /// Generate the data bus for call-data, based on the parameters of the entry block + /// and a boolean vector telling which ones are call-data + pub(crate) fn call_data_bus(&mut self, is_params_databus: Vec) -> DataBusBuilder { + //filter parameters of the first block that have call-data visilibity + let first_block = self.current_function.entry_block(); + let params = self.current_function.dfg[first_block].parameters(); + let mut databus_param = Vec::new(); + for (param, is_databus) in params.iter().zip(is_params_databus) { + if is_databus { + databus_param.push(param.to_owned()); + } + } + // create the call-data-bus from the filtered list + let call_data = DataBusBuilder::new(); + self.initialize_data_bus(&databus_param, call_data) + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index e01e1fe1a1d..56a22fd4107 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -1,3 +1,5 @@ +pub(crate) mod data_bus; + use std::{borrow::Cow, rc::Rc}; use acvm::FieldElement; @@ -312,16 +314,11 @@ impl FunctionBuilder { (FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow)) }; - let instruction = Instruction::Binary(Binary { lhs, rhs: pow, operator: BinaryOp::Mul }); if max_bit <= bit_size { - self.insert_instruction(instruction, None).first() + self.insert_binary(lhs, BinaryOp::Mul, pow) } else { - let result = self.insert_instruction(instruction, None).first(); - self.insert_instruction( - Instruction::Truncate { value: result, bit_size, max_bit_size: max_bit }, - None, - ) - .first() + let result = self.insert_binary(lhs, BinaryOp::Mul, pow); + self.insert_truncate(result, bit_size, max_bit) } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 75b2cf962f7..abddbfb74c7 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use crate::ssa::ir::instruction::SimplifyResult; +use crate::ssa::{function_builder::data_bus::DataBus, ir::instruction::SimplifyResult}; use super::{ basic_block::{BasicBlock, BasicBlockId}, @@ -80,6 +80,8 @@ pub(crate) struct DataFlowGraph { /// Instructions inserted by internal SSA passes that don't correspond to user code /// may not have a corresponding location. locations: HashMap, + + pub(crate) data_bus: DataBus, } pub(crate) type CallStack = im::Vector; diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 63b32766f62..628ad638e64 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -232,7 +232,11 @@ impl Instruction { use Instruction::*; match self { - Binary(_) | Cast(_, _) | Not(_) | ArrayGet { .. } | ArraySet { .. } => true, + Binary(bin) => { + // In ACIR, a division with a false predicate outputs (0,0), so it cannot replace another instruction unless they have the same predicate + bin.operator != BinaryOp::Div + } + Cast(_, _) | Not(_) | ArrayGet { .. } | ArraySet { .. } => true, // Unclear why this instruction causes problems. Truncate { .. } => false, @@ -429,12 +433,74 @@ impl Instruction { _ => None, } } - Instruction::Constrain(lhs, rhs, ..) => { + Instruction::Constrain(lhs, rhs, msg) => { if dfg.resolve(*lhs) == dfg.resolve(*rhs) { // Remove trivial case `assert_eq(x, x)` SimplifyResult::Remove } else { - SimplifyResult::None + match (&dfg[dfg.resolve(*lhs)], &dfg[dfg.resolve(*rhs)]) { + ( + Value::NumericConstant { constant, typ }, + Value::Instruction { instruction, .. }, + ) + | ( + Value::Instruction { instruction, .. }, + Value::NumericConstant { constant, typ }, + ) if *typ == Type::bool() => { + match dfg[*instruction] { + Instruction::Binary(Binary { + lhs, + rhs, + operator: BinaryOp::Eq, + }) if constant.is_one() => { + // Replace an explicit two step equality assertion + // + // v2 = eq v0, u32 v1 + // constrain v2 == u1 1 + // + // with a direct assertion of equality between the two values + // + // v2 = eq v0, u32 v1 + // constrain v0 == v1 + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + + SimplifiedToInstruction(Instruction::Constrain( + lhs, + rhs, + msg.clone(), + )) + } + Instruction::Not(value) => { + // Replace an assertion that a not instruction is truthy + // + // v1 = not v0 + // constrain v1 == u1 1 + // + // with an assertion that the not instruction input is falsy + // + // v1 = not v0 + // constrain v0 == u1 0 + // + // Note that this doesn't remove the value `v1` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let reversed_constant = FieldElement::from(!constant.is_one()); + let reversed_constant = + dfg.make_constant(reversed_constant, Type::bool()); + SimplifiedToInstruction(Instruction::Constrain( + value, + reversed_constant, + msg.clone(), + )) + } + + _ => None, + } + } + + _ => None, + } } } Instruction::ArrayGet { array, index } => { @@ -463,11 +529,23 @@ impl Instruction { } None } - Instruction::Truncate { value, bit_size, .. } => { + Instruction::Truncate { value, bit_size, max_bit_size } => { if let Some((numeric_constant, typ)) = dfg.get_numeric_constant_with_type(*value) { let integer_modulus = 2_u128.pow(*bit_size); let truncated = numeric_constant.to_u128() % integer_modulus; SimplifiedTo(dfg.make_constant(truncated.into(), typ)) + } else if let Value::Instruction { instruction, .. } = &dfg[dfg.resolve(*value)] { + if let Instruction::Truncate { bit_size: src_bit_size, .. } = &dfg[*instruction] + { + // If we're truncating the value to fit into the same or larger bit size then this is a noop. + if src_bit_size <= bit_size && src_bit_size <= max_bit_size { + SimplifiedTo(*value) + } else { + None + } + } else { + None + } } else { None } @@ -779,10 +857,19 @@ impl Binary { let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); return SimplifyResult::SimplifiedTo(zero); } - if operand_type.is_unsigned() && rhs_is_zero { - // Unsigned values cannot be less than zero. - let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); - return SimplifyResult::SimplifiedTo(zero); + if operand_type.is_unsigned() { + if rhs_is_zero { + // Unsigned values cannot be less than zero. + let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); + return SimplifyResult::SimplifiedTo(zero); + } else if rhs_is_one { + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedToInstruction(Instruction::binary( + BinaryOp::Eq, + self.lhs, + zero, + )); + } } } BinaryOp::And => { diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs index 8f2fe2d236b..bae06a805d0 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -104,6 +104,14 @@ impl Type { } } + pub(crate) fn is_nested_slice(&self) -> bool { + if let Type::Slice(element_types) = self { + element_types.as_ref().iter().any(|typ| typ.contains_slice_element()) + } else { + false + } + } + /// True if this type is an array (or slice) or internally contains an array (or slice) pub(crate) fn contains_an_array(&self) -> bool { match self { @@ -119,13 +127,7 @@ impl NumericType { /// for the current NumericType. pub(crate) fn value_is_within_limits(self, field: FieldElement) -> bool { match self { - NumericType::Signed { bit_size } => { - let min = -(2i128.pow(bit_size - 1)); - let max = 2u128.pow(bit_size - 1) - 1; - // Signed integers are odd since they will overflow the field value - field <= max.into() || field >= min.into() - } - NumericType::Unsigned { bit_size } => { + NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => { let max = 2u128.pow(bit_size) - 1; field <= max.into() } diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/die.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/die.rs index 53cdf72bbbf..492e96dc08c 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -33,6 +33,10 @@ impl Ssa { /// of its instructions are needed elsewhere. fn dead_instruction_elimination(function: &mut Function) { let mut context = Context::default(); + if let Some(call_data) = function.dfg.data_bus.call_data { + context.mark_used_instruction_results(&function.dfg, call_data); + } + let blocks = PostOrder::with_function(function); for block in blocks.as_slice() { diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs index 57e85f076da..f5e9598114c 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/fill_internal_slices.rs @@ -46,7 +46,7 @@ use crate::ssa::{ ir::{ basic_block::BasicBlockId, dfg::CallStack, - function::Function, + function::{Function, RuntimeType}, function_inserter::FunctionInserter, instruction::{Instruction, InstructionId, Intrinsic}, post_order::PostOrder, @@ -62,8 +62,17 @@ use fxhash::FxHashMap as HashMap; impl Ssa { pub(crate) fn fill_internal_slices(mut self) -> Ssa { for function in self.functions.values_mut() { - let mut context = Context::new(function); - context.process_blocks(); + // This pass is only necessary for generating ACIR and thus we should not + // process Brillig functions. + // The pass is also currently only setup to handle a function with a single flattened block. + // For complex Brillig functions we can expect this pass to panic. + if function.runtime() == RuntimeType::Acir { + let databus = function.dfg.data_bus.clone(); + let mut context = Context::new(function); + context.process_blocks(); + // update the databus with the new array instructions + function.dfg.data_bus = databus.map_values(|t| context.inserter.resolve(t)); + } } self } @@ -168,6 +177,9 @@ impl<'f> Context<'f> { panic!("ICE: should have inner slice set for {slice_value}") }); slice_sizes.insert(results[0], inner_slice.clone()); + if slice_value != results[0] { + self.mapped_slice_values.insert(slice_value, results[0]); + } } } } @@ -192,17 +204,11 @@ impl<'f> Context<'f> { let inner_sizes = slice_sizes.get_mut(array).expect("ICE expected slice sizes"); inner_sizes.1.push(*value); - - let value_parent = self.resolve_slice_parent(*value); - if slice_values.contains(&value_parent) { - // Map the value parent to the current array in case nested slices - // from the current array are set to larger values later in the program - self.mapped_slice_values.insert(value_parent, *array); - } } if let Some(inner_sizes) = slice_sizes.get_mut(array) { let inner_sizes = inner_sizes.clone(); + slice_sizes.insert(results[0], inner_sizes); self.mapped_slice_values.insert(*array, results[0]); @@ -218,14 +224,27 @@ impl<'f> Context<'f> { | Intrinsic::SlicePopBack | Intrinsic::SliceInsert | Intrinsic::SliceRemove => (1, 1), - Intrinsic::SlicePopFront => (1, 2), + // `pop_front` returns the popped element, and then the respective slice. + // This means in the case of a slice with structs, the result index of the popped slice + // will change depending on the number of elements in the struct. + // For example, a slice with four elements will look as such in SSA: + // v3, v4, v5, v6, v7, v8 = call slice_pop_front(v1, v2) + // where v7 is the slice length and v8 is the popped slice itself. + Intrinsic::SlicePopFront => (1, results.len() - 1), _ => return, }; + let slice_contents = arguments[argument_index]; match intrinsic { Intrinsic::SlicePushBack | Intrinsic::SlicePushFront | Intrinsic::SliceInsert => { - let slice_contents = arguments[argument_index]; + for arg in &arguments[(argument_index + 1)..] { + let element_typ = self.inserter.function.dfg.type_of_value(*arg); + if element_typ.contains_slice_element() { + slice_values.push(*arg); + self.compute_slice_sizes(*arg, slice_sizes); + } + } if let Some(inner_sizes) = slice_sizes.get_mut(&slice_contents) { inner_sizes.0 += 1; @@ -234,12 +253,12 @@ impl<'f> Context<'f> { self.mapped_slice_values .insert(slice_contents, results[result_index]); + self.slice_parents.insert(results[result_index], slice_contents); } } Intrinsic::SlicePopBack - | Intrinsic::SlicePopFront - | Intrinsic::SliceRemove => { - let slice_contents = arguments[argument_index]; + | Intrinsic::SliceRemove + | Intrinsic::SlicePopFront => { // We do not decrement the size on intrinsics that could remove values from a slice. // This is because we could potentially go back to the smaller slice and not fill in dummies. // This pass should be tracking the potential max that a slice ***could be*** @@ -249,6 +268,7 @@ impl<'f> Context<'f> { self.mapped_slice_values .insert(slice_contents, results[result_index]); + self.slice_parents.insert(results[result_index], slice_contents); } } _ => {} @@ -271,7 +291,6 @@ impl<'f> Context<'f> { if slice_values.contains(array) { let (new_array_op_instr, call_stack) = self.get_updated_array_op_instr(*array, slice_sizes, instruction); - self.inserter.push_instruction_value( new_array_op_instr, instruction, @@ -282,6 +301,55 @@ impl<'f> Context<'f> { self.inserter.push_instruction(instruction, block); } } + Instruction::Call { func: _, arguments } => { + let mut args_to_replace = Vec::new(); + for (i, arg) in arguments.iter().enumerate() { + let element_typ = self.inserter.function.dfg.type_of_value(*arg); + if slice_values.contains(arg) && element_typ.contains_slice_element() { + args_to_replace.push((i, *arg)); + } + } + if args_to_replace.is_empty() { + self.inserter.push_instruction(instruction, block); + } else { + // Using the original slice is ok to do as during collection of slice information + // we guarantee that only the arguments to slice intrinsic calls can be replaced. + let slice_contents = arguments[1]; + + let element_typ = self.inserter.function.dfg.type_of_value(arguments[1]); + let elem_depth = Self::compute_nested_slice_depth(&element_typ); + + let mut max_sizes = Vec::new(); + max_sizes.resize(elem_depth, 0); + // We want the max for the parent of the argument + let parent = self.resolve_slice_parent(slice_contents); + self.compute_slice_max_sizes(parent, slice_sizes, &mut max_sizes, 0); + + for (index, arg) in args_to_replace { + let element_typ = self.inserter.function.dfg.type_of_value(arg); + max_sizes.remove(0); + let new_array = + self.attach_slice_dummies(&element_typ, Some(arg), false, &max_sizes); + + let instruction_id = instruction; + let (instruction, call_stack) = + self.inserter.map_instruction(instruction_id); + let new_call_instr = match instruction { + Instruction::Call { func, mut arguments } => { + arguments[index] = new_array; + Instruction::Call { func, arguments } + } + _ => panic!("Expected call instruction"), + }; + self.inserter.push_instruction_value( + new_call_instr, + instruction_id, + block, + call_stack, + ); + } + } + } _ => { self.inserter.push_instruction(instruction, block); } @@ -308,6 +376,7 @@ impl<'f> Context<'f> { let typ = self.inserter.function.dfg.type_of_value(array_id); let depth = Self::compute_nested_slice_depth(&typ); max_sizes.resize(depth, 0); + max_sizes[0] = *current_size; self.compute_slice_max_sizes(array_id, slice_sizes, &mut max_sizes, 1); @@ -364,9 +433,12 @@ impl<'f> Context<'f> { if let Some(value) = value { let mut slice = im::Vector::new(); - let array = match self.inserter.function.dfg[value].clone() { + let value = self.inserter.function.dfg[value].clone(); + let array = match value { Value::Array { array, .. } => array, - _ => panic!("Expected an array value"), + _ => { + panic!("Expected an array value"); + } }; if is_parent_slice { @@ -481,7 +553,6 @@ impl<'f> Context<'f> { self.compute_slice_max_sizes(*inner_slice, slice_sizes, max_sizes, depth + 1); } - max_sizes[depth] = max; if max > max_sizes[depth] { max_sizes[depth] = max; } diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 29df9d3c76d..f0ad610948c 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -640,22 +640,9 @@ impl<'f> Context<'f> { match instruction { Instruction::Constrain(lhs, rhs, message) => { // Replace constraint `lhs == rhs` with `condition * lhs == condition * rhs`. + let lhs = self.handle_constrain_arg_side_effects(lhs, condition, &call_stack); + let rhs = self.handle_constrain_arg_side_effects(rhs, condition, &call_stack); - // Condition needs to be cast to argument type in order to multiply them together. - let argument_type = self.inserter.function.dfg.type_of_value(lhs); - let casted_condition = self.insert_instruction( - Instruction::Cast(condition, argument_type), - call_stack.clone(), - ); - - let lhs = self.insert_instruction( - Instruction::binary(BinaryOp::Mul, lhs, casted_condition), - call_stack.clone(), - ); - let rhs = self.insert_instruction( - Instruction::binary(BinaryOp::Mul, rhs, casted_condition), - call_stack, - ); Instruction::Constrain(lhs, rhs, message) } Instruction::Store { address, value } => { @@ -685,6 +672,90 @@ impl<'f> Context<'f> { } } + /// Given the arguments of a constrain instruction, multiplying them by the branch's condition + /// requires special handling in the case of complex types. + fn handle_constrain_arg_side_effects( + &mut self, + argument: ValueId, + condition: ValueId, + call_stack: &CallStack, + ) -> ValueId { + let argument_type = self.inserter.function.dfg.type_of_value(argument); + + match &argument_type { + Type::Numeric(_) => { + // Condition needs to be cast to argument type in order to multiply them together. + let casted_condition = self.insert_instruction( + Instruction::Cast(condition, argument_type), + call_stack.clone(), + ); + + self.insert_instruction( + Instruction::binary(BinaryOp::Mul, argument, casted_condition), + call_stack.clone(), + ) + } + Type::Array(_, _) => { + self.handle_array_constrain_arg(argument_type, argument, condition, call_stack) + } + Type::Slice(_) => { + panic!("Cannot use slices directly in a constrain statement") + } + Type::Reference(_) => { + panic!("Cannot use references directly in a constrain statement") + } + Type::Function => { + panic!("Cannot use functions directly in a constrain statement") + } + } + } + + fn handle_array_constrain_arg( + &mut self, + typ: Type, + argument: ValueId, + condition: ValueId, + call_stack: &CallStack, + ) -> ValueId { + let mut new_array = im::Vector::new(); + + let (element_types, len) = match &typ { + Type::Array(elements, len) => (elements, *len), + _ => panic!("Expected array type"), + }; + + for i in 0..len { + for (element_index, element_type) in element_types.iter().enumerate() { + let index = ((i * element_types.len() + element_index) as u128).into(); + let index = self.inserter.function.dfg.make_constant(index, Type::field()); + + let typevars = Some(vec![element_type.clone()]); + + let mut get_element = |array, typevars| { + let get = Instruction::ArrayGet { array, index }; + self.inserter + .function + .dfg + .insert_instruction_and_results( + get, + self.inserter.function.entry_block(), + typevars, + CallStack::new(), + ) + .first() + }; + + let element = get_element(argument, typevars); + + new_array.push_back( + self.handle_constrain_arg_side_effects(element, condition, call_stack), + ); + } + } + + self.inserter.function.dfg.make_array(new_array, typ) + } + fn undo_stores_in_then_branch(&mut self, then_branch: &Branch) { for (address, store) in &then_branch.store_values { let address = *address; @@ -935,7 +1006,6 @@ mod test { // } let ssa = ssa.flatten_cfg(); let main = ssa.main(); - println!("{ssa}"); assert_eq!(main.reachable_blocks().len(), 1); let store_count = count_instruction(main, |ins| matches!(ins, Instruction::Store { .. })); diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index ed2484febac..b4f12b2f897 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -139,11 +139,15 @@ impl InlineContext { context.blocks.insert(context.source_function.entry_block(), entry_block); context.inline_blocks(ssa); + // translate databus values + let databus = entry_point.dfg.data_bus.map_values(|t| context.translate_value(t)); // Finally, we should have 1 function left representing the inlined version of the target function. let mut new_ssa = self.builder.finish(); assert_eq!(new_ssa.functions.len(), 1); - new_ssa.functions.pop_first().unwrap().1 + let mut new_func = new_ssa.functions.pop_first().unwrap().1; + new_func.dfg.data_bus = databus; + new_func } /// Inlines a function into the current function and returns the translated return values diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs index fba6e6ab989..ce205c8d883 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs @@ -91,6 +91,7 @@ impl Ssa { let mut context = PerFunctionContext::new(function); context.mem2reg(); context.remove_instructions(); + context.update_data_bus(); } self } @@ -362,6 +363,11 @@ impl<'f> PerFunctionContext<'f> { } } + fn update_data_bus(&mut self) { + let databus = self.inserter.function.dfg.data_bus.clone(); + self.inserter.function.dfg.data_bus = databus.map_values(|t| self.inserter.resolve(t)); + } + fn handle_terminator(&mut self, block: BasicBlockId, references: &mut Block) { self.inserter.map_terminator_in_place(block); diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 9d27ffc60d8..501a03bcb5c 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -275,16 +275,11 @@ impl<'a> FunctionContext<'a> { let bit_width = self.builder.numeric_constant(FieldElement::from(2_i128.pow(bit_size)), Type::field()); let sign_not = self.builder.insert_binary(one, BinaryOp::Sub, sign); - let as_field = - self.builder.insert_instruction(Instruction::Cast(input, Type::field()), None).first(); - let sign_field = - self.builder.insert_instruction(Instruction::Cast(sign, Type::field()), None).first(); + let as_field = self.builder.insert_cast(input, Type::field()); + let sign_field = self.builder.insert_cast(sign, Type::field()); let positive_predicate = self.builder.insert_binary(sign_field, BinaryOp::Mul, as_field); let two_complement = self.builder.insert_binary(bit_width, BinaryOp::Sub, as_field); - let sign_not_field = self - .builder - .insert_instruction(Instruction::Cast(sign_not, Type::field()), None) - .first(); + let sign_not_field = self.builder.insert_cast(sign_not, Type::field()); let negative_predicate = self.builder.insert_binary(sign_not_field, BinaryOp::Mul, two_complement); self.builder.insert_binary(positive_predicate, BinaryOp::Add, negative_predicate) @@ -315,17 +310,8 @@ impl<'a> FunctionContext<'a> { match operator { BinaryOpKind::Add | BinaryOpKind::Subtract => { // Result is computed modulo the bit size - let mut result = self - .builder - .insert_instruction( - Instruction::Truncate { - value: result, - bit_size, - max_bit_size: bit_size + 1, - }, - None, - ) - .first(); + let mut result = + self.builder.insert_truncate(result, bit_size, bit_size + 1); result = self.builder.insert_cast(result, Type::unsigned(bit_size)); self.check_signed_overflow(result, lhs, rhs, operator, bit_size, location); @@ -335,17 +321,7 @@ impl<'a> FunctionContext<'a> { // Result is computed modulo the bit size let mut result = self.builder.insert_cast(result, Type::unsigned(2 * bit_size)); - result = self - .builder - .insert_instruction( - Instruction::Truncate { - value: result, - bit_size, - max_bit_size: 2 * bit_size, - }, - None, - ) - .first(); + result = self.builder.insert_truncate(result, bit_size, 2 * bit_size); self.check_signed_overflow(result, lhs, rhs, operator, bit_size, location); self.builder.insert_cast(result, result_type) @@ -365,7 +341,9 @@ impl<'a> FunctionContext<'a> { _ => unreachable!("operator {} should not overflow", operator), }; - if operator == BinaryOpKind::ShiftLeft { + if operator == BinaryOpKind::Multiply && bit_size == 1 { + result + } else if operator == BinaryOpKind::ShiftLeft { self.check_left_shift_overflow(result, rhs, bit_size, location) } else { let message = format!("attempt to {} with overflow", op_name); @@ -476,17 +454,16 @@ impl<'a> FunctionContext<'a> { // Then we check the signed product fits in a signed integer of bit_size-bits let not_same = self.builder.insert_binary(one, BinaryOp::Sub, same_sign); - let not_same_sign_field = self - .builder - .insert_instruction(Instruction::Cast(not_same, Type::unsigned(bit_size)), None) - .first(); + let not_same_sign_field = + self.builder.insert_cast(not_same, Type::unsigned(bit_size)); let positive_maximum_with_offset = self.builder.insert_binary(half_width, BinaryOp::Add, not_same_sign_field); let product_overflow_check = self.builder.insert_binary(product, BinaryOp::Lt, positive_maximum_with_offset); - self.builder.set_location(location).insert_instruction( - Instruction::Constrain(product_overflow_check, one, Some(message)), - None, + self.builder.set_location(location).insert_constrain( + product_overflow_check, + one, + Some(message), ); } BinaryOpKind::ShiftLeft => unreachable!("shift is not supported for signed integer"), diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 53f1bc863be..d7e6b8b0a3d 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -1,4 +1,4 @@ -mod context; +pub(crate) mod context; mod program; mod value; @@ -9,12 +9,15 @@ use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use noirc_frontend::{ monomorphization::ast::{self, Binary, Expression, Program}, - BinaryOpKind, + BinaryOpKind, Visibility, }; use crate::{ errors::RuntimeError, - ssa::ir::{instruction::Intrinsic, types::NumericType}, + ssa::{ + function_builder::data_bus::DataBusBuilder, + ir::{instruction::Intrinsic, types::NumericType}, + }, }; use self::{ @@ -22,17 +25,25 @@ use self::{ value::{Tree, Values}, }; -use super::ir::{ - function::RuntimeType, - instruction::{BinaryOp, TerminatorInstruction}, - types::Type, - value::ValueId, +use super::{ + function_builder::data_bus::DataBus, + ir::{ + function::RuntimeType, + instruction::{BinaryOp, TerminatorInstruction}, + types::Type, + value::ValueId, + }, }; /// Generates SSA for the given monomorphized program. /// /// This function will generate the SSA but does not perform any optimizations on it. pub(crate) fn generate_ssa(program: Program) -> Result { + // see which parameter has call_data/return_data attribute + let is_databus = DataBusBuilder::is_databus(&program.main_function_signature); + + let is_return_data = matches!(program.return_visibility, Visibility::DataBus); + let return_location = program.return_location; let context = SharedContext::new(program); @@ -48,20 +59,41 @@ pub(crate) fn generate_ssa(program: Program) -> Result { if main.unconstrained { RuntimeType::Brillig } else { RuntimeType::Acir }, &context, ); + + // Generate the call_data bus from the relevant parameters. We create it *before* processing the function body + let call_data = function_context.builder.call_data_bus(is_databus); + function_context.codegen_function_body(&main.body)?; + let mut return_data = DataBusBuilder::new(); if let Some(return_location) = return_location { let block = function_context.builder.current_block(); - if function_context.builder.current_function.dfg[block].terminator().is_some() { - let return_instruction = - function_context.builder.current_function.dfg[block].unwrap_terminator_mut(); - match return_instruction { - TerminatorInstruction::Return { call_stack, .. } => { - call_stack.clear(); - call_stack.push_back(return_location); + if function_context.builder.current_function.dfg[block].terminator().is_some() + && is_return_data + { + // initialize the return_data bus from the return values + let return_data_values = + match function_context.builder.current_function.dfg[block].unwrap_terminator() { + TerminatorInstruction::Return { return_values, .. } => return_values.to_owned(), + _ => unreachable!("ICE - expect return on the last block"), + }; + + return_data = + function_context.builder.initialize_data_bus(&return_data_values, return_data); + } + let return_instruction = + function_context.builder.current_function.dfg[block].unwrap_terminator_mut(); + match return_instruction { + TerminatorInstruction::Return { return_values, call_stack } => { + call_stack.clear(); + call_stack.push_back(return_location); + // replace the returned values with the return data array + if let Some(return_data_bus) = return_data.databus { + return_values.clear(); + return_values.push(return_data_bus); } - _ => unreachable!("ICE - expect return on the last block"), } + _ => unreachable!("ICE - expect return on the last block"), } } @@ -74,6 +106,9 @@ pub(crate) fn generate_ssa(program: Program) -> Result { function_context.new_function(dest_id, function); function_context.codegen_function_body(&function.body)?; } + // we save the data bus inside the dfg + function_context.builder.current_function.dfg.data_bus = + DataBus::get_data_bus(call_data, return_data); Ok(function_context.builder.finish()) } @@ -189,8 +224,9 @@ impl<'a> FunctionContext<'a> { } fn codegen_string(&mut self, string: &str) -> Values { - let elements = - vecmap(string.as_bytes(), |byte| self.builder.field_constant(*byte as u128).into()); + let elements = vecmap(string.as_bytes(), |byte| { + self.builder.numeric_constant(*byte as u128, Type::unsigned(8)).into() + }); let typ = Self::convert_non_tuple_type(&ast::Type::String(elements.len() as u64)); self.codegen_array(elements, typ) } @@ -555,7 +591,6 @@ impl<'a> FunctionContext<'a> { } self.codegen_intrinsic_call_checks(function, &arguments, call.location); - Ok(self.insert_call(function, arguments, &call.return_type, call.location)) } diff --git a/noir/compiler/noirc_frontend/Cargo.toml b/noir/compiler/noirc_frontend/Cargo.toml index 6f3c35a814a..aa3a8e9f6b8 100644 --- a/noir/compiler/noirc_frontend/Cargo.toml +++ b/noir/compiler/noirc_frontend/Cargo.toml @@ -22,7 +22,9 @@ serde.workspace = true rustc-hash = "1.1.0" small-ord-set = "0.1.3" regex = "1.9.1" +log.workspace = true [dev-dependencies] strum = "0.24" strum_macros = "0.24" +tempfile.workspace = true diff --git a/noir/compiler/noirc_frontend/src/ast/expression.rs b/noir/compiler/noirc_frontend/src/ast/expression.rs index 41807d7eca7..c78deaf6dbb 100644 --- a/noir/compiler/noirc_frontend/src/ast/expression.rs +++ b/noir/compiler/noirc_frontend/src/ast/expression.rs @@ -50,7 +50,13 @@ impl ExpressionKind { } pub fn prefix(operator: UnaryOp, rhs: Expression) -> ExpressionKind { - ExpressionKind::Prefix(Box::new(PrefixExpression { operator, rhs })) + match (operator, &rhs) { + ( + UnaryOp::Minus, + Expression { kind: ExpressionKind::Literal(Literal::Integer(field, sign)), .. }, + ) => ExpressionKind::Literal(Literal::Integer(*field, !sign)), + _ => ExpressionKind::Prefix(Box::new(PrefixExpression { operator, rhs })), + } } pub fn array(contents: Vec) -> ExpressionKind { @@ -65,7 +71,7 @@ impl ExpressionKind { } pub fn integer(contents: FieldElement) -> ExpressionKind { - ExpressionKind::Literal(Literal::Integer(contents)) + ExpressionKind::Literal(Literal::Integer(contents, false)) } pub fn boolean(contents: bool) -> ExpressionKind { @@ -100,7 +106,7 @@ impl ExpressionKind { }; match literal { - Literal::Integer(integer) => Some(*integer), + Literal::Integer(integer, _) => Some(*integer), _ => None, } } @@ -314,7 +320,7 @@ impl UnaryOp { pub enum Literal { Array(ArrayLiteral), Bool(bool), - Integer(FieldElement), + Integer(FieldElement, /*sign*/ bool), // false for positive integer and true for negative Str(String), RawStr(String, u8), FmtStr(String), @@ -510,7 +516,13 @@ impl Display for Literal { write!(f, "[{repeated_element}; {length}]") } Literal::Bool(boolean) => write!(f, "{}", if *boolean { "true" } else { "false" }), - Literal::Integer(integer) => write!(f, "{}", integer.to_u128()), + Literal::Integer(integer, sign) => { + if *sign { + write!(f, "-{}", integer.to_u128()) + } else { + write!(f, "{}", integer.to_u128()) + } + } Literal::Str(string) => write!(f, "\"{string}\""), Literal::RawStr(string, num_hashes) => { let hashes: String = diff --git a/noir/compiler/noirc_frontend/src/ast/mod.rs b/noir/compiler/noirc_frontend/src/ast/mod.rs index 7ce01f461ed..5c10d3fe8f0 100644 --- a/noir/compiler/noirc_frontend/src/ast/mod.rs +++ b/noir/compiler/noirc_frontend/src/ast/mod.rs @@ -15,6 +15,7 @@ pub use expression::*; pub use function::*; use noirc_errors::Span; +use serde::{Deserialize, Serialize}; pub use statement::*; pub use structure::*; pub use traits::*; @@ -41,6 +42,8 @@ pub enum UnresolvedTypeData { FormatString(UnresolvedTypeExpression, Box), Unit, + Parenthesized(Box), + /// A Named UnresolvedType can be a struct type or a type variable Named(Path, Vec), @@ -152,6 +155,7 @@ impl std::fmt::Display for UnresolvedTypeData { Unit => write!(f, "()"), Error => write!(f, "error"), Unspecified => write!(f, "unspecified"), + Parenthesized(typ) => write!(f, "({typ})"), } } } @@ -230,10 +234,13 @@ impl UnresolvedTypeExpression { fn from_expr_helper(expr: Expression) -> Result { match expr.kind { - ExpressionKind::Literal(Literal::Integer(int)) => match int.try_to_u64() { - Some(int) => Ok(UnresolvedTypeExpression::Constant(int, expr.span)), - None => Err(expr), - }, + ExpressionKind::Literal(Literal::Integer(int, sign)) => { + assert!(!sign, "Negative literal is not allowed here"); + match int.try_to_u64() { + Some(int) => Ok(UnresolvedTypeExpression::Constant(int, expr.span)), + None => Err(expr), + } + } ExpressionKind::Variable(path) => Ok(UnresolvedTypeExpression::Variable(path)), ExpressionKind::Prefix(prefix) if prefix.operator == UnaryOp::Minus => { let lhs = Box::new(UnresolvedTypeExpression::Constant(0, expr.span)); @@ -278,13 +285,16 @@ pub enum FunctionVisibility { PublicCrate, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Represents whether the parameter is public or known only to the prover. pub enum Visibility { Public, // Constants are not allowed in the ABI for main at the moment. // Constant, Private, + /// DataBus is public input handled as private input. We use the fact that return values are properly computed by the program to avoid having them as public inputs + /// it is useful for recursion and is handled by the proving system. + DataBus, } impl std::fmt::Display for Visibility { @@ -292,6 +302,7 @@ impl std::fmt::Display for Visibility { match self { Self::Public => write!(f, "pub"), Self::Private => write!(f, "priv"), + Self::DataBus => write!(f, "databus"), } } } diff --git a/noir/compiler/noirc_frontend/src/ast/statement.rs b/noir/compiler/noirc_frontend/src/ast/statement.rs index 1ca4d3101a9..73b1f68778d 100644 --- a/noir/compiler/noirc_frontend/src/ast/statement.rs +++ b/noir/compiler/noirc_frontend/src/ast/statement.rs @@ -198,7 +198,11 @@ impl From for Expression { fn from(i: Ident) -> Expression { Expression { span: i.0.span(), - kind: ExpressionKind::Variable(Path { segments: vec![i], kind: PathKind::Plain }), + kind: ExpressionKind::Variable(Path { + span: i.span(), + segments: vec![i], + kind: PathKind::Plain, + }), } } } @@ -311,6 +315,7 @@ impl UseTree { pub struct Path { pub segments: Vec, pub kind: PathKind, + pub span: Span, } impl Path { @@ -330,18 +335,11 @@ impl Path { } pub fn from_ident(name: Ident) -> Path { - Path { segments: vec![name], kind: PathKind::Plain } + Path { span: name.span(), segments: vec![name], kind: PathKind::Plain } } pub fn span(&self) -> Span { - let mut segments = self.segments.iter(); - let first_segment = segments.next().expect("ice : cannot have an empty path"); - let mut span = first_segment.0.span(); - - for segment in segments { - span = span.merge(segment.0.span()); - } - span + self.span } pub fn last_segment(&self) -> Ident { @@ -545,8 +543,11 @@ impl ForRange { // array.len() let segments = vec![array_ident]; - let array_ident = - ExpressionKind::Variable(Path { segments, kind: PathKind::Plain }); + let array_ident = ExpressionKind::Variable(Path { + segments, + kind: PathKind::Plain, + span: array_span, + }); let end_range = ExpressionKind::MethodCall(Box::new(MethodCallExpression { object: Expression::new(array_ident.clone(), array_span), @@ -561,8 +562,11 @@ impl ForRange { // array[i] let segments = vec![Ident::new(index_name, array_span)]; - let index_ident = - ExpressionKind::Variable(Path { segments, kind: PathKind::Plain }); + let index_ident = ExpressionKind::Variable(Path { + segments, + kind: PathKind::Plain, + span: array_span, + }); let loop_element = ExpressionKind::Index(Box::new(IndexExpression { collection: Expression::new(array_ident, array_span), diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 86122530cde..ae061792125 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -7,8 +7,8 @@ use crate::hir::resolution::errors::ResolverError; use crate::hir::resolution::import::{resolve_imports, ImportDirective}; use crate::hir::resolution::resolver::Resolver; use crate::hir::resolution::{ - collect_impls, collect_trait_impls, resolve_free_functions, resolve_globals, resolve_impls, - resolve_structs, resolve_trait_by_path, resolve_trait_impls, resolve_traits, + collect_impls, collect_trait_impls, path_resolver, resolve_free_functions, resolve_globals, + resolve_impls, resolve_structs, resolve_trait_by_path, resolve_trait_impls, resolve_traits, resolve_type_aliases, }; use crate::hir::type_check::{type_check_func, TypeCheckError, TypeChecker}; @@ -19,8 +19,9 @@ use crate::node_interner::{FuncId, NodeInterner, StmtId, StructId, TraitId, Type use crate::parser::{ParserError, SortedModule}; use crate::{ - ExpressionKind, LetStatement, Literal, NoirFunction, NoirStruct, NoirTrait, NoirTypeAlias, - Path, Type, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, + ExpressionKind, Ident, LetStatement, Literal, NoirFunction, NoirStruct, NoirTrait, + NoirTypeAlias, Path, PathKind, Type, UnresolvedGenerics, UnresolvedTraitConstraint, + UnresolvedType, }; use fm::FileId; use iter_extended::vecmap; @@ -81,6 +82,7 @@ pub struct UnresolvedTrait { pub module_id: LocalModuleId, pub crate_id: CrateId, pub trait_def: NoirTrait, + pub method_ids: HashMap, pub fns_with_default_impl: UnresolvedFunctions, } @@ -243,9 +245,20 @@ impl DefCollector { context, )); + let submodules = vecmap(def_collector.def_map.modules().iter(), |(index, _)| index); // Add the current crate to the collection of DefMaps context.def_maps.insert(crate_id, def_collector.def_map); + inject_prelude(crate_id, context, crate_root, &mut def_collector.collected_imports); + for submodule in submodules { + inject_prelude( + crate_id, + context, + LocalModuleId(submodule), + &mut def_collector.collected_imports, + ); + } + // Resolve unresolved imports collected from the crate let (resolved, unresolved_imports) = resolve_imports(crate_id, def_collector.collected_imports, &context.def_maps); @@ -264,8 +277,11 @@ impl DefCollector { for resolved_import in resolved { let name = resolved_import.name; for ns in resolved_import.resolved_namespace.iter_defs() { - let result = current_def_map.modules[resolved_import.module_scope.0] - .import(name.clone(), ns); + let result = current_def_map.modules[resolved_import.module_scope.0].import( + name.clone(), + ns, + resolved_import.is_prelude, + ); if let Err((first_def, second_def)) = result { let err = DefCollectorErrorKind::Duplicate { @@ -358,6 +374,47 @@ impl DefCollector { } } +fn inject_prelude( + crate_id: CrateId, + context: &Context, + crate_root: LocalModuleId, + collected_imports: &mut Vec, +) { + let segments: Vec<_> = "std::prelude" + .split("::") + .map(|segment| crate::Ident::new(segment.into(), Span::default())) + .collect(); + + let path = + Path { segments: segments.clone(), kind: crate::PathKind::Dep, span: Span::default() }; + + if !crate_id.is_stdlib() { + if let Ok(module_def) = path_resolver::resolve_path( + &context.def_maps, + ModuleId { krate: crate_id, local_id: crate_root }, + path, + ) { + let module_id = module_def.as_module().expect("std::prelude should be a module"); + let prelude = context.module(module_id).scope().names(); + + for path in prelude { + let mut segments = segments.clone(); + segments.push(Ident::new(path.to_string(), Span::default())); + + collected_imports.insert( + 0, + ImportDirective { + module_id: crate_root, + path: Path { segments, kind: PathKind::Dep, span: Span::default() }, + alias: None, + is_prelude: true, + }, + ); + } + } + } +} + /// Separate the globals Vec into two. The first element in the tuple will be the /// literal globals, except for arrays, and the second will be all other globals. /// We exclude array literals as they can contain complex types @@ -410,12 +467,15 @@ pub(crate) fn check_methods_signatures( trait_impl_generic_count: usize, errors: &mut Vec<(CompilationError, FileId)>, ) { - let the_trait = resolver.interner.get_trait(trait_id); - - let self_type = resolver.get_self_type().expect("trait impl must have a Self type"); + let self_type = resolver.get_self_type().expect("trait impl must have a Self type").clone(); // Temporarily bind the trait's Self type to self_type so we can type check - let _ = the_trait.self_type_typevar.borrow_mut().bind_to(self_type.clone(), the_trait.span); + let the_trait = resolver.interner.get_trait_mut(trait_id); + the_trait.self_type_typevar.bind(self_type); + + // Temporarily take the trait's methods so we can use both them and a mutable reference + // to the interner within the loop. + let trait_methods = std::mem::take(&mut the_trait.methods); for (file_id, func_id) in impl_methods { let impl_method = resolver.interner.function_meta(func_id); @@ -427,19 +487,22 @@ pub(crate) fn check_methods_signatures( // If that's the case, a `MethodNotInTrait` error has already been thrown, and we can ignore // the impl method, since there's nothing in the trait to match its signature against. if let Some(trait_method) = - the_trait.methods.iter().find(|method| method.name.0.contents == func_name) + trait_methods.iter().find(|method| method.name.0.contents == func_name) { let impl_function_type = impl_method.typ.instantiate(resolver.interner); let impl_method_generic_count = impl_method.typ.generic_count() - trait_impl_generic_count; - let trait_method_generic_count = trait_method.generics.len(); + + // We subtract 1 here to account for the implicit generic `Self` type that is on all + // traits (and thus trait methods) but is not required (or allowed) for users to specify. + let trait_method_generic_count = trait_method.generics().len() - 1; if impl_method_generic_count != trait_method_generic_count { let error = DefCollectorErrorKind::MismatchTraitImplementationNumGenerics { impl_method_generic_count, trait_method_generic_count, - trait_name: the_trait.name.to_string(), + trait_name: resolver.interner.get_trait(trait_id).name.to_string(), method_name: func_name.to_string(), span: impl_method.location.span, }; @@ -447,9 +510,9 @@ pub(crate) fn check_methods_signatures( } if let Type::Function(impl_params, _, _) = impl_function_type.0 { - if trait_method.arguments.len() == impl_params.len() { + if trait_method.arguments().len() == impl_params.len() { // Check the parameters of the impl method against the parameters of the trait method - let args = trait_method.arguments.iter(); + let args = trait_method.arguments().iter(); let args_and_params = args.zip(&impl_params).zip(&impl_method.parameters.0); for (parameter_index, ((expected, actual), (hir_pattern, _, _))) in @@ -468,8 +531,8 @@ pub(crate) fn check_methods_signatures( } else { let error = DefCollectorErrorKind::MismatchTraitImplementationNumParameters { actual_num_parameters: impl_method.parameters.0.len(), - expected_num_parameters: trait_method.arguments.len(), - trait_name: the_trait.name.to_string(), + expected_num_parameters: trait_method.arguments().len(), + trait_name: resolver.interner.get_trait(trait_id).name.to_string(), method_name: func_name.to_string(), span: impl_method.location.span, }; @@ -481,11 +544,12 @@ pub(crate) fn check_methods_signatures( let resolved_return_type = resolver.resolve_type(impl_method.return_type.get_type().into_owned()); - trait_method.return_type.unify(&resolved_return_type, &mut typecheck_errors, || { + // TODO: This is not right since it may bind generic return types + trait_method.return_type().unify(&resolved_return_type, &mut typecheck_errors, || { let ret_type_span = impl_method.return_type.get_type().span; let expr_span = ret_type_span.expect("return type must always have a span"); - let expected_typ = trait_method.return_type.to_string(); + let expected_typ = trait_method.return_type().to_string(); let expr_typ = impl_method.return_type().to_string(); TypeCheckError::TypeMismatch { expr_typ, expected_typ, expr_span } }); @@ -494,5 +558,7 @@ pub(crate) fn check_methods_signatures( } } - the_trait.self_type_typevar.borrow_mut().unbind(the_trait.self_type_typevar_id); + let the_trait = resolver.interner.get_trait_mut(trait_id); + the_trait.set_methods(trait_methods); + the_trait.self_type_typevar.unbind(the_trait.self_type_typevar_id); } diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 2f79333620e..04791b11b2a 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -1,7 +1,7 @@ -use std::vec; +use std::{collections::HashMap, path::Path, vec}; use acvm::acir::acir_field::FieldOptions; -use fm::FileId; +use fm::{FileId, FileManager, FILE_EXTENSION}; use noirc_errors::Location; use crate::{ @@ -44,6 +44,7 @@ pub fn collect_defs( ) -> Vec<(CompilationError, FileId)> { let mut collector = ModCollector { def_collector, file_id, module_id }; let mut errors: Vec<(CompilationError, FileId)> = vec![]; + // First resolve the module declarations for decl in ast.module_decls { errors.extend(collector.parse_module_declaration(context, &decl, crate_id)); @@ -57,6 +58,7 @@ pub fn collect_defs( module_id: collector.module_id, path: import.path, alias: import.alias, + is_prelude: false, }); } @@ -126,7 +128,8 @@ impl<'a> ModCollector<'a> { for method in r#impl.methods { let func_id = context.def_interner.push_empty_fn(); - context.def_interner.push_function(func_id, &method.def, module_id); + let location = Location::new(method.span(), self.file_id); + context.def_interner.push_function(func_id, &method.def, module_id, location); unresolved_functions.push_fn(self.module_id, func_id, method); } @@ -152,7 +155,8 @@ impl<'a> ModCollector<'a> { for (_, func_id, noir_function) in &mut unresolved_functions.functions { noir_function.def.where_clause.append(&mut trait_impl.where_clause.clone()); - context.def_interner.push_function(*func_id, &noir_function.def, module); + let location = Location::new(noir_function.def.span, self.file_id); + context.def_interner.push_function(*func_id, &noir_function.def, module, location); } let unresolved_trait_impl = UnresolvedTraitImpl { @@ -185,7 +189,8 @@ impl<'a> ModCollector<'a> { for item in &trait_impl.items { if let TraitImplItem::Function(impl_method) = item { let func_id = context.def_interner.push_empty_fn(); - context.def_interner.push_function(func_id, &impl_method.def, module); + let location = Location::new(impl_method.span(), self.file_id); + context.def_interner.push_function(func_id, &impl_method.def, module, location); unresolved_functions.push_fn(self.module_id, func_id, impl_method.clone()); } } @@ -218,7 +223,8 @@ impl<'a> ModCollector<'a> { // First create dummy function in the DefInterner // So that we can get a FuncId - context.def_interner.push_function(func_id, &function.def, module); + let location = Location::new(function.span(), self.file_id); + context.def_interner.push_function(func_id, &function.def, module, location); // Now link this func_id to a crate level map with the noir function and the module id // Encountering a NoirFunction, we retrieve it's module_data to get the namespace @@ -266,7 +272,9 @@ impl<'a> ModCollector<'a> { // Create the corresponding module for the struct namespace let id = match self.push_child_module(&name, self.file_id, false, false) { - Ok(local_id) => context.def_interner.new_struct(&unresolved, krate, local_id), + Ok(local_id) => { + context.def_interner.new_struct(&unresolved, krate, local_id, self.file_id) + } Err(error) => { definition_errors.push((error.into(), self.file_id)); continue; @@ -343,7 +351,7 @@ impl<'a> ModCollector<'a> { let name = trait_definition.name.clone(); // Create the corresponding module for the trait namespace - let id = match self.push_child_module(&name, self.file_id, false, false) { + let trait_id = match self.push_child_module(&name, self.file_id, false, false) { Ok(local_id) => TraitId(ModuleId { krate, local_id }), Err(error) => { errors.push((error.into(), self.file_id)); @@ -353,7 +361,7 @@ impl<'a> ModCollector<'a> { // Add the trait to scope so its path can be looked up later let result = - self.def_collector.def_map.modules[self.module_id.0].declare_trait(name, id); + self.def_collector.def_map.modules[self.module_id.0].declare_trait(name, trait_id); if let Err((first_def, second_def)) = result { let error = DefCollectorErrorKind::Duplicate { @@ -370,6 +378,8 @@ impl<'a> ModCollector<'a> { functions: Vec::new(), trait_id: None, }; + + let mut method_ids = HashMap::new(); for trait_item in &trait_definition.items { match trait_item { TraitItem::Function { @@ -381,6 +391,8 @@ impl<'a> ModCollector<'a> { body, } => { let func_id = context.def_interner.push_empty_fn(); + method_ids.insert(name.to_string(), func_id); + let modifiers = FunctionModifiers { name: name.to_string(), visibility: crate::FunctionVisibility::Public, @@ -391,9 +403,12 @@ impl<'a> ModCollector<'a> { is_internal: None, }; - context.def_interner.push_function_definition(func_id, modifiers, id.0); + let location = Location::new(name.span(), self.file_id); + context + .def_interner + .push_function_definition(func_id, modifiers, trait_id.0, location); - match self.def_collector.def_map.modules[id.0.local_id.0] + match self.def_collector.def_map.modules[trait_id.0.local_id.0] .declare_function(name.clone(), func_id) { Ok(()) => { @@ -428,7 +443,7 @@ impl<'a> ModCollector<'a> { let stmt_id = context.def_interner.push_empty_global(); if let Err((first_def, second_def)) = self.def_collector.def_map.modules - [id.0.local_id.0] + [trait_id.0.local_id.0] .declare_global(name.clone(), stmt_id) { let error = DefCollectorErrorKind::Duplicate { @@ -442,7 +457,7 @@ impl<'a> ModCollector<'a> { TraitItem::Type { name } => { // TODO(nickysn or alexvitkov): implement context.def_interner.push_empty_type_alias and get an id, instead of using TypeAliasId::dummy_id() if let Err((first_def, second_def)) = self.def_collector.def_map.modules - [id.0.local_id.0] + [trait_id.0.local_id.0] .declare_type_alias(name.clone(), TypeAliasId::dummy_id()) { let error = DefCollectorErrorKind::Duplicate { @@ -462,9 +477,10 @@ impl<'a> ModCollector<'a> { module_id: self.module_id, crate_id: krate, trait_def: trait_definition, + method_ids, fns_with_default_impl: unresolved_functions, }; - self.def_collector.collected_traits.insert(id, unresolved); + self.def_collector.collected_traits.insert(trait_id, unresolved); } errors } @@ -508,7 +524,7 @@ impl<'a> ModCollector<'a> { ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; let child_file_id = - match context.file_manager.find_module(self.file_id, &mod_name.0.contents) { + match find_module(&context.file_manager, self.file_id, &mod_name.0.contents) { Ok(child_file_id) => child_file_id, Err(expected_path) => { let mod_name = mod_name.clone(); @@ -612,3 +628,116 @@ impl<'a> ModCollector<'a> { Ok(LocalModuleId(module_id)) } } + +fn find_module( + file_manager: &FileManager, + anchor: FileId, + mod_name: &str, +) -> Result { + let anchor_path = file_manager.path(anchor).with_extension(""); + let anchor_dir = anchor_path.parent().unwrap(); + + // if `anchor` is a `main.nr`, `lib.nr`, `mod.nr` or `{mod_name}.nr`, we check siblings of + // the anchor at `base/mod_name.nr`. + let candidate = if should_check_siblings_for_module(&anchor_path, anchor_dir) { + anchor_dir.join(format!("{mod_name}.{FILE_EXTENSION}")) + } else { + // Otherwise, we check for children of the anchor at `base/anchor/mod_name.nr` + anchor_path.join(format!("{mod_name}.{FILE_EXTENSION}")) + }; + + file_manager + .name_to_id(candidate.clone()) + .ok_or_else(|| candidate.as_os_str().to_string_lossy().to_string()) +} + +/// Returns true if a module's child modules are expected to be in the same directory. +/// Returns false if they are expected to be in a subdirectory matching the name of the module. +fn should_check_siblings_for_module(module_path: &Path, parent_path: &Path) -> bool { + if let Some(filename) = module_path.file_stem() { + // This check also means a `main.nr` or `lib.nr` file outside of the crate root would + // check its same directory for child modules instead of a subdirectory. Should we prohibit + // `main.nr` and `lib.nr` files outside of the crate root? + filename == "main" + || filename == "lib" + || filename == "mod" + || Some(filename) == parent_path.file_stem() + } else { + // If there's no filename, we arbitrarily return true. + // Alternatively, we could panic, but this is left to a different step where we + // ideally have some source location to issue an error. + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::path::PathBuf; + use tempfile::{tempdir, TempDir}; + + // Returns the absolute path to the file + fn create_dummy_file(dir: &TempDir, file_name: &Path) -> PathBuf { + let file_path = dir.path().join(file_name); + let _file = std::fs::File::create(&file_path).unwrap(); + file_path + } + + #[test] + fn path_resolve_file_module() { + let dir = tempdir().unwrap(); + + let entry_file_name = Path::new("my_dummy_file.nr"); + create_dummy_file(&dir, entry_file_name); + + let mut fm = FileManager::new(dir.path()); + + let file_id = fm.add_file_with_source(entry_file_name, "fn foo() {}".to_string()).unwrap(); + + let dep_file_name = Path::new("foo.nr"); + create_dummy_file(&dir, dep_file_name); + find_module(&fm, file_id, "foo").unwrap_err(); + } + + #[test] + fn path_resolve_sub_module() { + let dir = tempdir().unwrap(); + let mut fm = FileManager::new(dir.path()); + + // Create a lib.nr file at the root. + // we now have dir/lib.nr + let lib_nr_path = create_dummy_file(&dir, Path::new("lib.nr")); + let file_id = fm + .add_file_with_source(lib_nr_path.as_path(), "fn foo() {}".to_string()) + .expect("could not add file to file manager and obtain a FileId"); + + // Create a sub directory + // we now have: + // - dir/lib.nr + // - dir/sub_dir + let sub_dir = TempDir::new_in(&dir).unwrap(); + let sub_dir_name = sub_dir.path().file_name().unwrap().to_str().unwrap(); + + // Add foo.nr to the subdirectory + // we no have: + // - dir/lib.nr + // - dir/sub_dir/foo.nr + let foo_nr_path = create_dummy_file(&sub_dir, Path::new("foo.nr")); + fm.add_file_with_source(foo_nr_path.as_path(), "fn foo() {}".to_string()); + + // Add a parent module for the sub_dir + // we no have: + // - dir/lib.nr + // - dir/sub_dir.nr + // - dir/sub_dir/foo.nr + let sub_dir_nr_path = create_dummy_file(&dir, Path::new(&format!("{sub_dir_name}.nr"))); + fm.add_file_with_source(sub_dir_nr_path.as_path(), "fn foo() {}".to_string()); + + // First check for the sub_dir.nr file and add it to the FileManager + let sub_dir_file_id = find_module(&fm, file_id, sub_dir_name).unwrap(); + + // Now check for files in it's subdirectory + find_module(&fm, sub_dir_file_id, "foo").unwrap(); + } +} diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/item_scope.rs b/noir/compiler/noirc_frontend/src/hir/def_map/item_scope.rs index 42cca550651..523def89518 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/item_scope.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/item_scope.rs @@ -5,6 +5,8 @@ use crate::{ }; use std::collections::{hash_map::Entry, HashMap}; +type Scope = HashMap, (ModuleDefId, Visibility, bool /*is_prelude*/)>; + #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Visibility { Public, @@ -12,8 +14,8 @@ pub enum Visibility { #[derive(Default, Debug, PartialEq, Eq)] pub struct ItemScope { - types: HashMap, (ModuleDefId, Visibility)>>, - values: HashMap, (ModuleDefId, Visibility)>>, + types: HashMap, + values: HashMap, defs: Vec, } @@ -25,7 +27,7 @@ impl ItemScope { mod_def: ModuleDefId, trait_id: Option, ) -> Result<(), (Ident, Ident)> { - self.add_item_to_namespace(name, mod_def, trait_id)?; + self.add_item_to_namespace(name, mod_def, trait_id, false)?; self.defs.push(mod_def); Ok(()) } @@ -38,25 +40,31 @@ impl ItemScope { name: Ident, mod_def: ModuleDefId, trait_id: Option, + is_prelude: bool, ) -> Result<(), (Ident, Ident)> { - let add_item = - |map: &mut HashMap, (ModuleDefId, Visibility)>>| { - if let Entry::Occupied(mut o) = map.entry(name.clone()) { - let trait_hashmap = o.get_mut(); - if let Entry::Occupied(_) = trait_hashmap.entry(trait_id) { - let old_ident = o.key(); - Err((old_ident.clone(), name)) - } else { - trait_hashmap.insert(trait_id, (mod_def, Visibility::Public)); + let add_item = |map: &mut HashMap| { + if let Entry::Occupied(mut o) = map.entry(name.clone()) { + let trait_hashmap = o.get_mut(); + if let Entry::Occupied(mut n) = trait_hashmap.entry(trait_id) { + let is_prelude = std::mem::replace(&mut n.get_mut().2, is_prelude); + let old_ident = o.key(); + + if is_prelude { Ok(()) + } else { + Err((old_ident.clone(), name)) } } else { - let mut trait_hashmap = HashMap::new(); - trait_hashmap.insert(trait_id, (mod_def, Visibility::Public)); - map.insert(name, trait_hashmap); + trait_hashmap.insert(trait_id, (mod_def, Visibility::Public, is_prelude)); Ok(()) } - }; + } else { + let mut trait_hashmap = HashMap::new(); + trait_hashmap.insert(trait_id, (mod_def, Visibility::Public, is_prelude)); + map.insert(name, trait_hashmap); + Ok(()) + } + }; match mod_def { ModuleDefId::ModuleId(_) => add_item(&mut self.types), @@ -69,7 +77,7 @@ impl ItemScope { } pub fn find_module_with_name(&self, mod_name: &Ident) -> Option<&ModuleId> { - let (module_def, _) = self.types.get(mod_name)?.get(&None)?; + let (module_def, _, _) = self.types.get(mod_name)?.get(&None)?; match module_def { ModuleDefId::ModuleId(id) => Some(id), _ => None, @@ -81,13 +89,13 @@ impl ItemScope { // methods introduced without trait take priority and hide methods with the same name that come from a trait let a = trait_hashmap.get(&None); match a { - Some((module_def, _)) => match module_def { + Some((module_def, _, _)) => match module_def { ModuleDefId::FunctionId(id) => Some(*id), _ => None, }, None => { if trait_hashmap.len() == 1 { - let (module_def, _) = trait_hashmap.get(trait_hashmap.keys().last()?)?; + let (module_def, _, _) = trait_hashmap.get(trait_hashmap.keys().last()?)?; match module_def { ModuleDefId::FunctionId(id) => Some(*id), _ => None, @@ -105,7 +113,7 @@ impl ItemScope { func_name: &Ident, trait_id: &Option, ) -> Option { - let (module_def, _) = self.values.get(func_name)?.get(trait_id)?; + let (module_def, _, _) = self.values.get(func_name)?.get(trait_id)?; match module_def { ModuleDefId::FunctionId(id) => Some(*id), _ => None, @@ -115,20 +123,19 @@ impl ItemScope { pub fn find_name(&self, name: &Ident) -> PerNs { // Names, not associated with traits are searched first. If not found, we search for name, coming from a trait. // If we find only one name from trait, we return it. If there are multiple traits, providing the same name, we return None. - let find_name_in = - |a: &HashMap, (ModuleDefId, Visibility)>>| { - if let Some(t) = a.get(name) { - if let Some(tt) = t.get(&None) { - Some(*tt) - } else if t.len() == 1 { - t.values().last().cloned() - } else { - None - } + let find_name_in = |a: &HashMap| { + if let Some(t) = a.get(name) { + if let Some(tt) = t.get(&None) { + Some(*tt) + } else if t.len() == 1 { + t.values().last().cloned() } else { None } - }; + } else { + None + } + }; PerNs { types: find_name_in(&self.types), values: find_name_in(&self.values) } } @@ -144,15 +151,19 @@ impl ItemScope { } } + pub fn names(&self) -> impl Iterator { + self.types.keys().chain(self.values.keys()) + } + pub fn definitions(&self) -> Vec { self.defs.clone() } - pub fn types(&self) -> &HashMap, (ModuleDefId, Visibility)>> { + pub fn types(&self) -> &HashMap { &self.types } - pub fn values(&self) -> &HashMap, (ModuleDefId, Visibility)>> { + pub fn values(&self) -> &HashMap { &self.values } diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/mod.rs b/noir/compiler/noirc_frontend/src/hir/def_map/mod.rs index 5f38c80a5fe..20f05532ce4 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -173,7 +173,6 @@ impl CrateDefMap { }) }) } - /// Go through all modules in this crate, find all `contract ... { ... }` declarations, /// and collect them all into a Vec. pub fn get_all_contracts(&self, interner: &NodeInterner) -> Vec { @@ -271,8 +270,8 @@ pub struct Contract { /// Given a FileId, fetch the File, from the FileManager and parse it's content pub fn parse_file(fm: &FileManager, file_id: FileId) -> (ParsedModule, Vec) { - let file = fm.fetch_file(file_id); - parse_program(file.source()) + let file_source = fm.fetch_file(file_id); + parse_program(file_source) } impl std::ops::Index for CrateDefMap { diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs b/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs index 29b11e92c01..fbb5e5cf741 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs @@ -41,6 +41,10 @@ impl ModuleData { } } + pub(crate) fn scope(&self) -> &ItemScope { + &self.scope + } + fn declare( &mut self, name: Ident, @@ -104,8 +108,13 @@ impl ModuleData { self.scope.find_func_with_name(name) } - pub fn import(&mut self, name: Ident, id: ModuleDefId) -> Result<(), (Ident, Ident)> { - self.scope.add_item_to_namespace(name, id, None) + pub fn import( + &mut self, + name: Ident, + id: ModuleDefId, + is_prelude: bool, + ) -> Result<(), (Ident, Ident)> { + self.scope.add_item_to_namespace(name, id, None, is_prelude) } pub fn find_name(&self, name: &Ident) -> PerNs { @@ -113,12 +122,12 @@ impl ModuleData { } pub fn type_definitions(&self) -> impl Iterator + '_ { - self.definitions.types().values().flat_map(|a| a.values().map(|(id, _)| *id)) + self.definitions.types().values().flat_map(|a| a.values().map(|(id, _, _)| *id)) } /// Return an iterator over all definitions defined within this module, /// excluding any type definitions. pub fn value_definitions(&self) -> impl Iterator + '_ { - self.definitions.values().values().flat_map(|a| a.values().map(|(id, _)| *id)) + self.definitions.values().values().flat_map(|a| a.values().map(|(id, _, _)| *id)) } } diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs b/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs index 659d7712ab4..3e5629639fa 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs @@ -61,6 +61,13 @@ impl ModuleDefId { ModuleDefId::GlobalId(_) => "global", } } + + pub fn as_module(&self) -> Option { + match self { + Self::ModuleId(v) => Some(*v), + _ => None, + } + } } impl From for ModuleDefId { diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/namespace.rs b/noir/compiler/noirc_frontend/src/hir/def_map/namespace.rs index 9221b389d84..ca14d9f8617 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_map/namespace.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_map/namespace.rs @@ -3,13 +3,13 @@ use super::{item_scope::Visibility, ModuleDefId}; // This works exactly the same as in r-a, just simplified #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct PerNs { - pub types: Option<(ModuleDefId, Visibility)>, - pub values: Option<(ModuleDefId, Visibility)>, + pub types: Option<(ModuleDefId, Visibility, bool)>, + pub values: Option<(ModuleDefId, Visibility, bool)>, } impl PerNs { pub fn types(t: ModuleDefId) -> PerNs { - PerNs { types: Some((t, Visibility::Public)), values: None } + PerNs { types: Some((t, Visibility::Public, false)), values: None } } pub fn take_types(self) -> Option { @@ -24,7 +24,7 @@ impl PerNs { self.types.map(|it| it.0).into_iter().chain(self.values.map(|it| it.0)) } - pub fn iter_items(self) -> impl Iterator { + pub fn iter_items(self) -> impl Iterator { self.types.into_iter().chain(self.values) } diff --git a/noir/compiler/noirc_frontend/src/hir/mod.rs b/noir/compiler/noirc_frontend/src/hir/mod.rs index 154b695d552..adeca7cf2ba 100644 --- a/noir/compiler/noirc_frontend/src/hir/mod.rs +++ b/noir/compiler/noirc_frontend/src/hir/mod.rs @@ -36,7 +36,8 @@ pub enum FunctionNameMatch<'a> { } impl Context { - pub fn new(file_manager: FileManager, crate_graph: CrateGraph) -> Context { + pub fn new(file_manager: FileManager) -> Context { + let crate_graph = CrateGraph::default(); Context { def_interner: NodeInterner::default(), def_maps: BTreeMap::new(), @@ -180,6 +181,14 @@ impl Context { .collect() } + /// Returns the [Location] of the definition of the given Ident found at [Span] of the given [FileId]. + /// Returns [None] when definition is not found. + pub fn get_definition_location_from(&self, location: Location) -> Option { + let interner = &self.def_interner; + + interner.find_location_index(location).and_then(|index| interner.resolve_location(index)) + } + /// Return a Vec of all `contract` declarations in the source code and the functions they contain pub fn get_all_contracts(&self, crate_id: &CrateId) -> Vec { self.def_map(crate_id) diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/functions.rs b/noir/compiler/noirc_frontend/src/hir/resolution/functions.rs index 387f94e129c..e63de9b9173 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/functions.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/functions.rs @@ -11,7 +11,7 @@ use crate::{ def_map::{CrateDefMap, ModuleId}, }, node_interner::{FuncId, NodeInterner, TraitImplId}, - Shared, Type, TypeBinding, + Type, TypeVariable, }; use super::{path_resolver::StandardPathResolver, resolver::Resolver}; @@ -24,7 +24,7 @@ pub(crate) fn resolve_function_set( mut unresolved_functions: UnresolvedFunctions, self_type: Option, trait_impl_id: Option, - impl_generics: Vec<(Rc, Shared, Span)>, + impl_generics: Vec<(Rc, TypeVariable, Span)>, errors: &mut Vec<(CompilationError, FileId)>, ) -> Vec<(FileId, FuncId)> { let file_id = unresolved_functions.file_id; diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/import.rs b/noir/compiler/noirc_frontend/src/hir/resolution/import.rs index 6f3140a65d4..41fdac746bd 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -1,5 +1,5 @@ use iter_extended::partition_results; -use noirc_errors::CustomDiagnostic; +use noirc_errors::{CustomDiagnostic, Span}; use crate::graph::CrateId; use std::collections::BTreeMap; @@ -12,6 +12,7 @@ pub struct ImportDirective { pub module_id: LocalModuleId, pub path: Path, pub alias: Option, + pub is_prelude: bool, } pub type PathResolution = Result; @@ -30,6 +31,7 @@ pub struct ResolvedImport { pub resolved_namespace: PerNs, // The module which we must add the resolved namespace to pub module_scope: LocalModuleId, + pub is_prelude: bool, } impl From for CustomDiagnostic { @@ -66,7 +68,12 @@ pub fn resolve_imports( .map_err(|error| (error, module_scope))?; let name = resolve_path_name(&import_directive); - Ok(ResolvedImport { name, resolved_namespace, module_scope }) + Ok(ResolvedImport { + name, + resolved_namespace, + module_scope, + is_prelude: import_directive.is_prelude, + }) }) } @@ -202,9 +209,17 @@ fn resolve_external_dep( // Create an import directive for the dependency crate let path_without_crate_name = &path[1..]; // XXX: This will panic if the path is of the form `use dep::std` Ideal algorithm will not distinguish between crate and module - let path = Path { segments: path_without_crate_name.to_vec(), kind: PathKind::Plain }; - let dep_directive = - ImportDirective { module_id: dep_module.local_id, path, alias: directive.alias.clone() }; + let path = Path { + segments: path_without_crate_name.to_vec(), + kind: PathKind::Plain, + span: Span::default(), + }; + let dep_directive = ImportDirective { + module_id: dep_module.local_id, + path, + alias: directive.alias.clone(), + is_prelude: false, + }; let dep_def_map = def_maps.get(&dep_module.krate).unwrap(); diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs b/noir/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs index 4c16edd56f1..4c5fa3bceef 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs @@ -57,14 +57,15 @@ pub fn resolve_path( path: Path, ) -> Result { // lets package up the path into an ImportDirective and resolve it using that - let import = ImportDirective { module_id: module_id.local_id, path, alias: None }; + let import = + ImportDirective { module_id: module_id.local_id, path, alias: None, is_prelude: false }; let allow_referencing_contracts = allow_referencing_contracts(def_maps, module_id.krate, module_id.local_id); let def_map = &def_maps[&module_id.krate]; let ns = resolve_path_to_ns(&import, def_map, def_maps, allow_referencing_contracts)?; - let function = ns.values.map(|(id, _)| id); - let id = function.or_else(|| ns.types.map(|(id, _)| id)); + let function = ns.values.map(|(id, _, _)| id); + let id = function.or_else(|| ns.types.map(|(id, _, _)| id)); Ok(id.expect("Found empty namespace")) } diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 52d592404c8..9cd28d80784 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -19,7 +19,7 @@ use crate::hir_def::expr::{ }; use crate::hir_def::traits::{Trait, TraitConstraint}; -use crate::token::FunctionAttribute; +use crate::token::{Attributes, FunctionAttribute}; use regex::Regex; use std::collections::{BTreeMap, HashSet}; use std::rc::Rc; @@ -37,11 +37,11 @@ use crate::{ StatementKind, }; use crate::{ - ArrayLiteral, ContractFunctionType, Distinctness, ForRange, FunctionVisibility, Generics, - LValue, NoirStruct, NoirTypeAlias, Param, Path, PathKind, Pattern, Shared, StructType, Type, - TypeAliasType, TypeBinding, TypeVariable, UnaryOp, UnresolvedGenerics, - UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, - Visibility, ERROR_IDENT, + ArrayLiteral, ContractFunctionType, Distinctness, ForRange, FunctionDefinition, + FunctionReturnType, FunctionVisibility, Generics, LValue, NoirStruct, NoirTypeAlias, Param, + Path, PathKind, Pattern, Shared, StructType, Type, TypeAliasType, TypeBinding, TypeVariable, + UnaryOp, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, + UnresolvedTypeExpression, Visibility, ERROR_IDENT, }; use fm::FileId; use iter_extended::vecmap; @@ -200,6 +200,51 @@ impl<'a> Resolver<'a> { (hir_func, func_meta, self.errors) } + pub fn resolve_trait_function( + &mut self, + name: &Ident, + parameters: &[(Ident, UnresolvedType)], + return_type: &FunctionReturnType, + where_clause: &[UnresolvedTraitConstraint], + func_id: FuncId, + ) -> (HirFunction, FuncMeta) { + self.scopes.start_function(); + + // Check whether the function has globals in the local module and add them to the scope + self.resolve_local_globals(); + + self.trait_bounds = where_clause.to_vec(); + + let kind = FunctionKind::Normal; + let def = FunctionDefinition { + name: name.clone(), + attributes: Attributes::empty(), + is_open: false, + is_internal: false, + is_unconstrained: false, + visibility: FunctionVisibility::Public, // Trait functions are always public + generics: Vec::new(), // self.generics should already be set + parameters: vecmap(parameters, |(name, typ)| Param { + visibility: Visibility::Private, + pattern: Pattern::Identifier(name.clone()), + typ: typ.clone(), + span: name.span(), + }), + body: BlockExpression(Vec::new()), + span: name.span(), + where_clause: where_clause.to_vec(), + return_type: return_type.clone(), + return_visibility: Visibility::Private, + return_distinctness: Distinctness::DuplicationAllowed, + }; + + let (hir_func, func_meta) = self.intern_function(NoirFunction { kind, def }, func_id); + let _ = self.scopes.end_function(); + // Don't check the scope tree for unused variables, they can't be used in a declaration anyway. + self.trait_bounds.clear(); + (hir_func, func_meta) + } + fn check_for_unused_variables_in_scope_tree(&mut self, scope_decls: ScopeTree) { let mut unused_vars = Vec::new(); for scope in scope_decls.0.into_iter() { @@ -256,8 +301,9 @@ impl<'a> Resolver<'a> { return self.add_global_variable_decl(name, definition); } - let id = self.interner.push_definition(name.0.contents.clone(), mutable, definition); let location = Location::new(name.span(), self.file); + let id = + self.interner.push_definition(name.0.contents.clone(), mutable, definition, location); let ident = HirIdent { location, id }; let resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused }; @@ -300,8 +346,9 @@ impl<'a> Resolver<'a> { ident = hir_let_stmt.ident(); resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused: true }; } else { - let id = self.interner.push_definition(name.0.contents.clone(), false, definition); let location = Location::new(name.span(), self.file); + let id = + self.interner.push_definition(name.0.contents.clone(), false, definition, location); ident = HirIdent { location, id }; resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused: true }; } @@ -441,6 +488,7 @@ impl<'a> Resolver<'a> { MutableReference(element) => { Type::MutableReference(Box::new(self.resolve_type_inner(*element, new_variables))) } + Parenthesized(typ) => self.resolve_type_inner(*typ, new_variables), } } @@ -520,7 +568,7 @@ impl<'a> Resolver<'a> { _new_variables: &mut Generics, ) -> Type { if let Some(t) = self.lookup_trait_or_error(path) { - Type::TraitAsType(t) + Type::TraitAsType(t.id, Rc::new(t.name.to_string())) } else { Type::Error } @@ -571,7 +619,7 @@ impl<'a> Resolver<'a> { match length { None => { let id = self.interner.next_type_variable_id(); - let typevar = Shared::new(TypeBinding::Unbound(id)); + let typevar = TypeVariable::unbound(id); new_variables.push((id, typevar.clone())); // 'Named'Generic is a bit of a misnomer here, we want a type variable that @@ -681,7 +729,7 @@ impl<'a> Resolver<'a> { vecmap(generics, |generic| { // Map the generic to a fresh type variable let id = self.interner.next_type_variable_id(); - let typevar = Shared::new(TypeBinding::Unbound(id)); + let typevar = TypeVariable::unbound(id); let span = generic.0.span(); // Check for name collisions of this generic @@ -790,10 +838,10 @@ impl<'a> Resolver<'a> { }); } - // 'pub_allowed' also implies 'pub' is required on return types - if self.pub_allowed(func) + // 'pub' is required on return types for entry point functions + if self.is_entry_point_function(func) && return_type.as_ref() != &Type::Unit - && func.def.return_visibility != Visibility::Public + && func.def.return_visibility == Visibility::Private { self.push_err(ResolverError::NecessaryPub { ident: func.name_ident().clone() }); } @@ -846,12 +894,9 @@ impl<'a> Resolver<'a> { } /// True if the 'pub' keyword is allowed on parameters in this function + /// 'pub' on function parameters is only allowed for entry point functions fn pub_allowed(&self, func: &NoirFunction) -> bool { - if self.in_contract { - !func.def.is_unconstrained - } else { - func.name() == MAIN_FUNCTION - } + self.is_entry_point_function(func) } fn is_entry_point_function(&self, func: &NoirFunction) -> bool { @@ -927,10 +972,7 @@ impl<'a> Resolver<'a> { found.into_iter().collect() } - fn find_numeric_generics_in_type( - typ: &Type, - found: &mut BTreeMap>, - ) { + fn find_numeric_generics_in_type(typ: &Type, found: &mut BTreeMap) { match typ { Type::FieldElement | Type::Integer(_, _) @@ -941,7 +983,7 @@ impl<'a> Resolver<'a> { | Type::Constant(_) | Type::NamedGeneric(_, _) | Type::NotConstant - | Type::TraitAsType(_) + | Type::TraitAsType(..) | Type::Forall(_, _) => (), Type::Array(length, element_type) => { @@ -1201,7 +1243,7 @@ impl<'a> Resolver<'a> { HirLiteral::Array(HirArrayLiteral::Repeated { repeated_element, length }) } - Literal::Integer(integer) => HirLiteral::Integer(integer), + Literal::Integer(integer, sign) => HirLiteral::Integer(integer, sign), Literal::Str(str) => HirLiteral::Str(str), Literal::RawStr(str, _) => HirLiteral::Str(str), Literal::FmtStr(str) => self.resolve_fmt_str_literal(str, expr.span), @@ -1501,8 +1543,8 @@ impl<'a> Resolver<'a> { self.interner.get_struct(type_id) } - pub fn get_trait(&self, trait_id: TraitId) -> Trait { - self.interner.get_trait(trait_id) + pub fn get_trait_mut(&mut self, trait_id: TraitId) -> &mut Trait { + self.interner.get_trait_mut(trait_id) } fn lookup(&mut self, path: Path) -> Result { @@ -1545,9 +1587,9 @@ impl<'a> Resolver<'a> { } /// Lookup a given trait by name/path. - fn lookup_trait_or_error(&mut self, path: Path) -> Option { + fn lookup_trait_or_error(&mut self, path: Path) -> Option<&mut Trait> { match self.lookup(path) { - Ok(trait_id) => Some(self.get_trait(trait_id)), + Ok(trait_id) => Some(self.get_trait_mut(trait_id)), Err(error) => { self.push_err(error); None @@ -1587,27 +1629,39 @@ impl<'a> Resolver<'a> { &mut self, path: &Path, ) -> Option<(HirExpression, Type)> { - if let Some(trait_id) = self.trait_id { - if path.kind == PathKind::Plain && path.segments.len() == 2 { - let name = &path.segments[0].0.contents; - let method = &path.segments[1]; + let trait_id = self.trait_id?; - if name == SELF_TYPE_NAME { - let the_trait = self.interner.get_trait(trait_id); + if path.kind == PathKind::Plain && path.segments.len() == 2 { + let name = &path.segments[0].0.contents; + let method = &path.segments[1]; - if let Some(method) = the_trait.find_method(method.clone()) { - let self_type = Type::TypeVariable( - the_trait.self_type_typevar, - crate::TypeVariableKind::Normal, - ); - return Some((HirExpression::TraitMethodReference(method), self_type)); - } - } + if name == SELF_TYPE_NAME { + let the_trait = self.interner.get_trait(trait_id); + let method = the_trait.find_method(method.0.contents.as_str())?; + let self_type = self.self_type.clone()?; + return Some((HirExpression::TraitMethodReference(method), self_type)); } } None } + // this resolves TraitName::some_static_method + fn resolve_trait_static_method(&mut self, path: &Path) -> Option<(HirExpression, Type)> { + if path.kind == PathKind::Plain && path.segments.len() == 2 { + let method = &path.segments[1]; + + let mut trait_path = path.clone(); + trait_path.pop(); + let trait_id = self.lookup(trait_path).ok()?; + let the_trait = self.interner.get_trait(trait_id); + + let method = the_trait.find_method(method.0.contents.as_str())?; + let self_type = Type::type_variable(the_trait.self_type_typevar_id); + return Some((HirExpression::TraitMethodReference(method), self_type)); + } + None + } + // this resolves a static trait method T::trait_method by iterating over the where clause fn resolve_trait_method_by_named_generic( &mut self, @@ -1631,7 +1685,7 @@ impl<'a> Resolver<'a> { { let the_trait = self.interner.get_trait(trait_id); if let Some(method) = - the_trait.find_method(path.segments.last().unwrap().clone()) + the_trait.find_method(path.segments.last().unwrap().0.contents.as_str()) { let self_type = self.resolve_type(typ.clone()); return Some((HirExpression::TraitMethodReference(method), self_type)); @@ -1644,6 +1698,7 @@ impl<'a> Resolver<'a> { fn resolve_trait_generic_path(&mut self, path: &Path) -> Option<(HirExpression, Type)> { self.resolve_trait_static_method_by_self(path) + .or_else(|| self.resolve_trait_static_method(path)) .or_else(|| self.resolve_trait_method_by_named_generic(path)) } @@ -1665,10 +1720,7 @@ impl<'a> Resolver<'a> { fn eval_global_as_array_length(&mut self, global: StmtId) -> u64 { let stmt = match self.interner.statement(&global) { HirStatement::Let(let_expr) => let_expr, - other => { - dbg!(other); - return 0; - } + _ => return 0, }; let length = stmt.expression; @@ -1690,7 +1742,7 @@ impl<'a> Resolver<'a> { span: Span, ) -> Result> { match self.interner.expression(&rhs) { - HirExpression::Literal(HirLiteral::Integer(int)) => { + HirExpression::Literal(HirLiteral::Integer(int, false)) => { int.try_into_u128().ok_or(Some(ResolverError::IntegerTooLarge { span })) } _other => Err(Some(ResolverError::InvalidArrayLengthExpr { span })), @@ -1787,6 +1839,7 @@ impl<'a> Resolver<'a> { self.verify_type_valid_for_program_input(element); } } + UnresolvedTypeData::Parenthesized(typ) => self.verify_type_valid_for_program_input(typ), } } diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/traits.rs b/noir/compiler/noirc_frontend/src/hir/resolution/traits.rs index 702e96362a6..54d2630c722 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashSet}; use fm::FileId; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ graph::CrateId, @@ -16,15 +16,13 @@ use crate::{ def_map::{CrateDefMap, ModuleDefId, ModuleId}, Context, }, - hir_def::traits::{Trait, TraitConstant, TraitFunction, TraitImpl, TraitType}, + hir_def::traits::{TraitConstant, TraitFunction, TraitImpl, TraitType}, node_interner::{FuncId, NodeInterner, TraitId}, - Path, Shared, TraitItem, Type, TypeVariableKind, + Path, Shared, TraitItem, Type, TypeBinding, TypeVariableKind, }; use super::{ - errors::ResolverError, functions, get_module_mut, get_struct_type, - import::PathResolutionError, path_resolver::{PathResolver, StandardPathResolver}, resolver::Resolver, take_errors, @@ -90,15 +88,16 @@ fn resolve_trait_methods( }); let file = def_maps[&crate_id].file_id(unresolved_trait.module_id); - let mut res = vec![]; + let mut functions = vec![]; let mut resolver_errors = vec![]; + for item in &unresolved_trait.trait_def.items { if let TraitItem::Function { name, generics, parameters, return_type, - where_clause: _, + where_clause, body: _, } = item { @@ -110,39 +109,60 @@ fn resolve_trait_methods( resolver.add_generics(generics); resolver.set_self_type(Some(self_type)); + let func_id = unresolved_trait.method_ids[&name.0.contents]; + let (_, func_meta) = resolver.resolve_trait_function( + name, + parameters, + return_type, + where_clause, + func_id, + ); + resolver.interner.push_fn_meta(func_meta, func_id); + let arguments = vecmap(parameters, |param| resolver.resolve_type(param.1.clone())); - let resolved_return_type = resolver.resolve_type(return_type.get_type().into_owned()); - let generics = resolver.get_generics().to_vec(); + let return_type = resolver.resolve_type(return_type.get_type().into_owned()); + + let mut generics = vecmap(resolver.get_generics(), |(_, type_var, _)| match &*type_var + .borrow() + { + TypeBinding::Unbound(id) => (*id, type_var.clone()), + TypeBinding::Bound(binding) => unreachable!("Trait generic was bound to {binding}"), + }); + + // Ensure the trait is generic over the Self type as well + let the_trait = resolver.interner.get_trait(trait_id); + generics.push((the_trait.self_type_typevar_id, the_trait.self_type_typevar.clone())); - let name = name.clone(); - let span: Span = name.span(); let default_impl_list: Vec<_> = unresolved_trait .fns_with_default_impl .functions .iter() .filter(|(_, _, q)| q.name() == name.0.contents) .collect(); + let default_impl = if default_impl_list.len() == 1 { Some(Box::new(default_impl_list[0].2.clone())) } else { None }; - let f = TraitFunction { - name, - generics, - arguments, - return_type: resolved_return_type, - span, + let no_environment = Box::new(Type::Unit); + let function_type = Type::Function(arguments, Box::new(return_type), no_environment); + + functions.push(TraitFunction { + name: name.clone(), + typ: Type::Forall(generics, Box::new(function_type)), + span: name.span(), default_impl, default_impl_file_id: unresolved_trait.file_id, default_impl_module_id: unresolved_trait.module_id, - }; - res.push(f); - resolver_errors.extend(take_errors_filter_self_not_resolved(file, resolver)); + }); + + let errors = resolver.take_errors().into_iter(); + resolver_errors.extend(errors.map(|resolution_error| (resolution_error.into(), file))); } } - (res, resolver_errors) + (functions, resolver_errors) } fn collect_trait_impl_methods( @@ -156,15 +176,18 @@ fn collect_trait_impl_methods( // for a particular method, the default implementation will be added at that slot. let mut ordered_methods = Vec::new(); - let the_trait = interner.get_trait(trait_id); - // check whether the trait implementation is in the same crate as either the trait or the type let mut errors = - check_trait_impl_crate_coherence(interner, &the_trait, trait_impl, crate_id, def_maps); + check_trait_impl_crate_coherence(interner, trait_id, trait_impl, crate_id, def_maps); // set of function ids that have a corresponding method in the trait let mut func_ids_in_trait = HashSet::new(); - for method in &the_trait.methods { + // Temporarily take ownership of the trait's methods so we can iterate over them + // while also mutating the interner + let the_trait = interner.get_trait_mut(trait_id); + let methods = std::mem::take(&mut the_trait.methods); + + for method in &methods { let overrides: Vec<_> = trait_impl .methods .functions @@ -176,7 +199,8 @@ fn collect_trait_impl_methods( if let Some(default_impl) = &method.default_impl { let func_id = interner.push_empty_fn(); let module = ModuleId { local_id: trait_impl.module_id, krate: crate_id }; - interner.push_function(func_id, &default_impl.def, module); + let location = Location::new(default_impl.def.span, trait_impl.file_id); + interner.push_function(func_id, &default_impl.def, module, location); func_ids_in_trait.insert(func_id); ordered_methods.push(( method.default_impl_module_id, @@ -185,7 +209,7 @@ fn collect_trait_impl_methods( )); } else { let error = DefCollectorErrorKind::TraitMissingMethod { - trait_name: the_trait.name.clone(), + trait_name: interner.get_trait(trait_id).name.clone(), method_name: method.name.clone(), trait_impl_span: trait_impl.object_type.span.expect("type must have a span"), }; @@ -209,6 +233,10 @@ fn collect_trait_impl_methods( } } + // Restore the methods that were taken before the for loop + let the_trait = interner.get_trait_mut(trait_id); + the_trait.set_methods(methods); + // Emit MethodNotInTrait error for methods in the impl block that // don't have a corresponding method signature defined in the trait for (_, func_id, func) in &trait_impl.methods.functions { @@ -287,7 +315,7 @@ pub(crate) fn collect_trait_impls( fn check_trait_impl_crate_coherence( interner: &mut NodeInterner, - the_trait: &Trait, + trait_id: TraitId, trait_impl: &UnresolvedTraitImpl, current_crate: CrateId, def_maps: &BTreeMap, @@ -304,6 +332,7 @@ fn check_trait_impl_crate_coherence( _ => CrateId::Dummy, }; + let the_trait = interner.get_trait(trait_id); if current_crate != the_trait.crate_id && current_crate != object_crate { let error = DefCollectorErrorKind::TraitImplOrphaned { span: trait_impl.object_type.span.expect("object type must have a span"), @@ -430,21 +459,3 @@ pub(crate) fn resolve_trait_impls( methods } - -pub(crate) fn take_errors_filter_self_not_resolved( - file_id: FileId, - resolver: Resolver<'_>, -) -> Vec<(CompilationError, FileId)> { - resolver - .take_errors() - .iter() - .filter(|resolution_error| match resolution_error { - ResolverError::PathResolutionError(PathResolutionError::Unresolved(ident)) => { - &ident.0.contents != "Self" - } - _ => true, - }) - .cloned() - .map(|resolution_error| (resolution_error.into(), file_id)) - .collect() -} diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs b/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs index 74f076212fa..f7154895150 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -10,8 +10,8 @@ use crate::{ }, types::Type, }, - node_interner::{DefinitionKind, ExprId, FuncId, TraitId, TraitMethodId}, - BinaryOpKind, Signedness, TypeBinding, TypeVariableKind, UnaryOp, + node_interner::{DefinitionKind, ExprId, FuncId, TraitId, TraitImplKind, TraitMethodId}, + BinaryOpKind, Signedness, TypeBinding, TypeBindings, TypeVariableKind, UnaryOp, }; use super::{errors::TypeCheckError, TypeChecker}; @@ -114,7 +114,7 @@ impl<'interner> TypeChecker<'interner> { Type::Array(Box::new(length), Box::new(elem_type)) } HirLiteral::Bool(_) => Type::Bool, - HirLiteral::Integer(_) => Type::polymorphic_integer(self.interner), + HirLiteral::Integer(_, _) => Type::polymorphic_integer(self.interner), HirLiteral::Str(string) => { let len = Type::Constant(string.len() as u64); Type::String(Box::new(len)) @@ -289,15 +289,23 @@ impl<'interner> TypeChecker<'interner> { } HirExpression::TraitMethodReference(method) => { let the_trait = self.interner.get_trait(method.trait_id); - let method = &the_trait.methods[method.method_index]; - - let typ = Type::Function( - method.arguments.clone(), - Box::new(method.return_type.clone()), - Box::new(Type::Unit), - ); + let typ2 = &the_trait.methods[method.method_index].typ; + let (typ, mut bindings) = typ2.instantiate(self.interner); + + // We must also remember to apply these substitutions to the object_type + // referenced by the selected trait impl, if one has yet to be selected. + let impl_kind = self.interner.get_selected_impl_for_ident(*expr_id); + if let Some(TraitImplKind::Assumed { object_type }) = impl_kind { + let the_trait = self.interner.get_trait(method.trait_id); + let object_type = object_type.substitute(&bindings); + bindings.insert( + the_trait.self_type_typevar_id, + (the_trait.self_type_typevar.clone(), object_type.clone()), + ); + self.interner + .select_impl_for_ident(*expr_id, TraitImplKind::Assumed { object_type }); + } - let (typ, bindings) = typ.instantiate(self.interner); self.interner.store_instantiation_bindings(*expr_id, bindings); typ } @@ -546,7 +554,7 @@ impl<'interner> TypeChecker<'interner> { HirMethodReference::TraitMethodId(method) => { let the_trait = self.interner.get_trait(method.trait_id); let method = &the_trait.methods[method.method_index]; - (method.get_type(), method.arguments.len()) + (method.typ.clone(), method.arguments().len()) } }; @@ -778,7 +786,11 @@ impl<'interner> TypeChecker<'interner> { })); } - if other.try_bind_to_polymorphic_int(int).is_ok() || other == &Type::Error { + let mut bindings = TypeBindings::new(); + if other.try_bind_to_polymorphic_int(int, &mut bindings).is_ok() + || other == &Type::Error + { + Type::apply_type_bindings(bindings); Ok(Bool) } else { Err(TypeCheckError::TypeMismatchWithSource { @@ -894,7 +906,9 @@ impl<'interner> TypeChecker<'interner> { } } } - Type::TraitAsType(_trait) => { + // TODO: We should allow method calls on `impl Trait`s eventually. + // For now it is fine since they are only allowed on return types. + Type::TraitAsType(..) => { self.errors.push(TypeCheckError::UnresolvedMethodCall { method_name: method_name.to_string(), object_type: object_type.clone(), @@ -1009,7 +1023,7 @@ impl<'interner> TypeChecker<'interner> { let env_type = self.interner.next_type_variable(); let expected = Type::Function(args, Box::new(ret.clone()), Box::new(env_type)); - if let Err(error) = binding.borrow_mut().bind_to(expected, span) { + if let Err(error) = binding.try_bind(expected, span) { self.errors.push(error); } ret @@ -1077,7 +1091,11 @@ impl<'interner> TypeChecker<'interner> { })); } - if other.try_bind_to_polymorphic_int(int).is_ok() || other == &Type::Error { + let mut bindings = TypeBindings::new(); + if other.try_bind_to_polymorphic_int(int, &mut bindings).is_ok() + || other == &Type::Error + { + Type::apply_type_bindings(bindings); Ok(other.clone()) } else { Err(TypeCheckError::TypeMismatchWithSource { @@ -1167,6 +1185,10 @@ impl<'interner> TypeChecker<'interner> { match op { crate::UnaryOp::Minus => { + if rhs_type.is_unsigned() { + self.errors + .push(TypeCheckError::InvalidUnaryOp { kind: rhs_type.to_string(), span }); + } let expected = Type::polymorphic_integer(self.interner); rhs_type.unify(&expected, &mut self.errors, || TypeCheckError::InvalidUnaryOp { kind: rhs_type.to_string(), diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs b/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs index 19d9d370377..95991047091 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -101,8 +101,8 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec TypeChecker<'interner> { expr_span: range_span, }); - let fresh_id = self.interner.next_type_variable_id(); - let type_variable = Shared::new(TypeBinding::Unbound(fresh_id)); - let expected_type = Type::TypeVariable(type_variable, TypeVariableKind::IntegerOrField); + let expected_type = Type::polymorphic_integer(self.interner); self.unify(&start_range_type, &expected_type, || { TypeCheckError::TypeCannotBeUsed { @@ -350,7 +347,7 @@ impl<'interner> TypeChecker<'interner> { let expr = self.interner.expression(rhs_expr); let span = self.interner.expr_span(rhs_expr); match expr { - HirExpression::Literal(HirLiteral::Integer(value)) => { + HirExpression::Literal(HirLiteral::Integer(value, false)) => { let v = value.to_u128(); if let Type::Integer(_, bit_count) = annotated_type { let max = 1 << bit_count; diff --git a/noir/compiler/noirc_frontend/src/hir_def/expr.rs b/noir/compiler/noirc_frontend/src/hir_def/expr.rs index 755817ba1e6..ef1c3af7ac0 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/expr.rs @@ -78,7 +78,7 @@ impl HirBinaryOp { pub enum HirLiteral { Array(HirArrayLiteral), Bool(bool), - Integer(FieldElement), + Integer(FieldElement, bool), //true for negative integer and false for positive Str(String), FmtStr(String, Vec), Unit, diff --git a/noir/compiler/noirc_frontend/src/hir_def/traits.rs b/noir/compiler/noirc_frontend/src/hir_def/traits.rs index 062f505c179..ea9c2e2928c 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/traits.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/traits.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::collections::HashMap; use crate::{ graph::CrateId, @@ -11,9 +11,7 @@ use noirc_errors::Span; #[derive(Clone, Debug, PartialEq, Eq)] pub struct TraitFunction { pub name: Ident, - pub generics: Vec<(Rc, TypeVariable, Span)>, - pub arguments: Vec, - pub return_type: Type, + pub typ: Type, pub span: Span, pub default_impl: Option>, pub default_impl_file_id: fm::FileId, @@ -37,7 +35,7 @@ pub struct TraitType { /// Represents a trait in the type system. Each instance of this struct /// will be shared across all Type::Trait variants that represent /// the same trait. -#[derive(Debug, Eq, Clone)] +#[derive(Debug, Eq)] pub struct Trait { /// A unique id representing this trait type. Used to check if two /// struct traits are equal. @@ -46,6 +44,13 @@ pub struct Trait { pub crate_id: CrateId, pub methods: Vec, + + /// Maps method_name -> method id. + /// This map is separate from methods since TraitFunction ids + /// are created during collection where we don't yet have all + /// the information needed to create the full TraitFunction. + pub method_ids: HashMap, + pub constants: Vec, pub types: Vec, @@ -60,7 +65,7 @@ pub struct Trait { pub self_type_typevar_id: TypeVariableId, pub self_type_typevar: TypeVariable, } - +#[derive(Debug)] pub struct TraitImpl { pub ident: Ident, pub typ: Type, @@ -101,36 +106,13 @@ impl PartialEq for Trait { } impl Trait { - pub fn new( - id: TraitId, - name: Ident, - crate_id: CrateId, - span: Span, - generics: Generics, - self_type_typevar_id: TypeVariableId, - self_type_typevar: TypeVariable, - ) -> Trait { - Trait { - id, - name, - crate_id, - span, - methods: Vec::new(), - constants: Vec::new(), - types: Vec::new(), - generics, - self_type_typevar_id, - self_type_typevar, - } - } - pub fn set_methods(&mut self, methods: Vec) { self.methods = methods; } - pub fn find_method(&self, name: Ident) -> Option { + pub fn find_method(&self, name: &str) -> Option { for (idx, method) in self.methods.iter().enumerate() { - if method.name == name { + if &method.name == name { return Some(TraitMethodId { trait_id: self.id, method_index: idx }); } } @@ -145,12 +127,33 @@ impl std::fmt::Display for Trait { } impl TraitFunction { - pub fn get_type(&self) -> Type { - Type::Function( - self.arguments.clone(), - Box::new(self.return_type.clone()), - Box::new(Type::Unit), - ) - .generalize() + pub fn arguments(&self) -> &[Type] { + match &self.typ { + Type::Function(args, _, _) => args, + Type::Forall(_, typ) => match typ.as_ref() { + Type::Function(args, _, _) => args, + _ => unreachable!("Trait function does not have a function type"), + }, + _ => unreachable!("Trait function does not have a function type"), + } + } + + pub fn generics(&self) -> &[(TypeVariableId, TypeVariable)] { + match &self.typ { + Type::Function(..) => &[], + Type::Forall(generics, _) => generics, + _ => unreachable!("Trait function does not have a function type"), + } + } + + pub fn return_type(&self) -> &Type { + match &self.typ { + Type::Function(_, return_type, _) => return_type, + Type::Forall(_, typ) => match typ.as_ref() { + Type::Function(_, return_type, _) => return_type, + _ => unreachable!("Trait function does not have a function type"), + }, + _ => unreachable!("Trait function does not have a function type"), + } } } diff --git a/noir/compiler/noirc_frontend/src/hir_def/types.rs b/noir/compiler/noirc_frontend/src/hir_def/types.rs index 46818626a16..977293ec678 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/types.rs @@ -6,18 +6,15 @@ use std::{ use crate::{ hir::type_check::TypeCheckError, - node_interner::{ExprId, NodeInterner, TypeAliasId}, + node_interner::{ExprId, NodeInterner, TraitId, TypeAliasId}, }; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; use noirc_printable_type::PrintableType; use crate::{node_interner::StructId, Ident, Signedness}; -use super::{ - expr::{HirCallExpression, HirExpression, HirIdent}, - traits::Trait, -}; +use super::expr::{HirCallExpression, HirExpression, HirIdent}; #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum Type { @@ -65,7 +62,10 @@ pub enum Type { /// different argument types each time. TypeVariable(TypeVariable, TypeVariableKind), - TraitAsType(Trait), + /// `impl Trait` when used in a type position. + /// These are only matched based on the TraitId. The trait name paramer is only + /// used for displaying error messages using the name of the trait. + TraitAsType(TraitId, /*name:*/ Rc), /// NamedGenerics are the 'T' or 'U' in a user-defined generic function /// like `fn foo(...) {}`. Unlike TypeVariables, they cannot be bound over. @@ -75,7 +75,7 @@ pub enum Type { /// the environment should be `Unit` by default, /// for closures it should contain a `Tuple` type with the captured /// variable types. - Function(Vec, Box, Box), + Function(Vec, /*return_type:*/ Box, /*environment:*/ Box), /// &mut T MutableReference(Box), @@ -132,7 +132,7 @@ impl Type { Type::FmtString(_, _) | Type::Unit | Type::TypeVariable(_, _) - | Type::TraitAsType(_) + | Type::TraitAsType(..) | Type::NamedGeneric(_, _) | Type::Function(_, _, _) | Type::MutableReference(_) @@ -166,7 +166,7 @@ pub struct StructType { fields: Vec<(Ident, Type)>, pub generics: Generics, - pub span: Span, + pub location: Location, } /// Corresponds to generic lists such as `` in the source @@ -191,11 +191,12 @@ impl StructType { pub fn new( id: StructId, name: Ident, - span: Span, + + location: Location, fields: Vec<(Ident, Type)>, generics: Generics, ) -> StructType { - StructType { id, fields, name, span, generics } + StructType { id, fields, name, location, generics } } /// To account for cyclic references between structs, a struct's @@ -298,7 +299,7 @@ impl std::fmt::Display for TypeAliasType { write!(f, "{}", self.name)?; if !self.generics.is_empty() { - let generics = vecmap(&self.generics, |(_, binding)| binding.borrow().to_string()); + let generics = vecmap(&self.generics, |(_, binding)| binding.0.borrow().to_string()); write!(f, "{}", generics.join(", "))?; } @@ -413,7 +414,66 @@ pub enum TypeVariableKind { /// A TypeVariable is a mutable reference that is either /// bound to some type, or unbound with a given TypeVariableId. -pub type TypeVariable = Shared; +#[derive(Debug, PartialEq, Eq, Clone, Hash)] +pub struct TypeVariable(Shared); + +impl TypeVariable { + pub fn unbound(id: TypeVariableId) -> Self { + TypeVariable(Shared::new(TypeBinding::Unbound(id))) + } + + /// Bind this type variable to a value. + /// + /// Panics if this TypeVariable is already Bound. + /// Also Panics if the ID of this TypeVariable occurs within the given + /// binding, as that would cause an infinitely recursive type. + pub fn bind(&self, typ: Type) { + let id = match &*self.0.borrow() { + TypeBinding::Bound(binding) => { + unreachable!("TypeVariable::bind, cannot bind bound var {} to {}", binding, typ) + } + TypeBinding::Unbound(id) => *id, + }; + + assert!(!typ.occurs(id)); + *self.0.borrow_mut() = TypeBinding::Bound(typ); + } + + pub fn try_bind(&self, binding: Type, span: Span) -> Result<(), TypeCheckError> { + let id = match &*self.0.borrow() { + TypeBinding::Bound(binding) => { + unreachable!("Expected unbound, found bound to {binding}") + } + TypeBinding::Unbound(id) => *id, + }; + + if binding.occurs(id) { + Err(TypeCheckError::TypeAnnotationsNeeded { span }) + } else { + *self.0.borrow_mut() = TypeBinding::Bound(binding); + Ok(()) + } + } + + /// Borrows this TypeVariable to (e.g.) manually match on the inner TypeBinding. + pub fn borrow(&self) -> std::cell::Ref { + self.0.borrow() + } + + /// Unbind this type variable, setting it to Unbound(id). + /// + /// This is generally a logic error to use outside of monomorphization. + pub fn unbind(&self, id: TypeVariableId) { + *self.0.borrow_mut() = TypeBinding::Unbound(id); + } + + /// Forcibly bind a type variable to a new type - even if the type + /// variable is already bound to a different type. This generally + /// a logic error to use outside of monomorphization. + pub fn force_bind(&self, typ: Type) { + *self.0.borrow_mut() = TypeBinding::Bound(typ); + } +} /// TypeBindings are the mutable insides of a TypeVariable. /// They are either bound to some type, or are unbound. @@ -427,24 +487,6 @@ impl TypeBinding { pub fn is_unbound(&self) -> bool { matches!(self, TypeBinding::Unbound(_)) } - - pub fn bind_to(&mut self, binding: Type, span: Span) -> Result<(), TypeCheckError> { - match self { - TypeBinding::Bound(_) => panic!("Tried to bind an already bound type variable!"), - TypeBinding::Unbound(id) => { - if binding.occurs(*id) { - Err(TypeCheckError::TypeAnnotationsNeeded { span }) - } else { - *self = TypeBinding::Bound(binding); - Ok(()) - } - } - } - } - - pub fn unbind(&mut self, id: TypeVariableId) { - *self = TypeBinding::Unbound(id); - } } /// A unique ID used to differentiate different type variables @@ -461,7 +503,8 @@ impl Type { } pub fn type_variable(id: TypeVariableId) -> Type { - Type::TypeVariable(Shared::new(TypeBinding::Unbound(id)), TypeVariableKind::Normal) + let var = TypeVariable(Shared::new(TypeBinding::Unbound(id))); + Type::TypeVariable(var, TypeVariableKind::Normal) } /// Returns a TypeVariable(_, TypeVariableKind::Constant(length)) to bind to @@ -469,13 +512,15 @@ impl Type { pub fn constant_variable(length: u64, interner: &mut NodeInterner) -> Type { let id = interner.next_type_variable_id(); let kind = TypeVariableKind::Constant(length); - Type::TypeVariable(Shared::new(TypeBinding::Unbound(id)), kind) + let var = TypeVariable(Shared::new(TypeBinding::Unbound(id))); + Type::TypeVariable(var, kind) } pub fn polymorphic_integer(interner: &mut NodeInterner) -> Type { let id = interner.next_type_variable_id(); let kind = TypeVariableKind::IntegerOrField; - Type::TypeVariable(Shared::new(TypeBinding::Unbound(id)), kind) + let var = TypeVariable(Shared::new(TypeBinding::Unbound(id))); + Type::TypeVariable(var, kind) } /// A bit of an awkward name for this function - this function returns @@ -484,7 +529,7 @@ impl Type { /// they shouldn't be bound over until monomorphization. pub fn is_bindable(&self) -> bool { match self { - Type::TypeVariable(binding, _) => match &*binding.borrow() { + Type::TypeVariable(binding, _) => match &*binding.0.borrow() { TypeBinding::Bound(binding) => binding.is_bindable(), TypeBinding::Unbound(_) => true, }, @@ -508,7 +553,7 @@ impl Type { // True if the given type is a NamedGeneric with the target_id let named_generic_id_matches_target = |typ: &Type| { if let Type::NamedGeneric(type_variable, _) = typ { - match &*type_variable.borrow() { + match &*type_variable.0.borrow() { TypeBinding::Bound(_) => { unreachable!("Named generics should not be bound until monomorphization") } @@ -530,7 +575,7 @@ impl Type { | Type::NamedGeneric(_, _) | Type::NotConstant | Type::Forall(_, _) - | Type::TraitAsType(_) => false, + | Type::TraitAsType(..) => false, Type::Array(length, elem) => { elem.contains_numeric_typevar(target_id) || named_generic_id_matches_target(length) @@ -608,7 +653,7 @@ impl Type { match self { Type::Forall(generics, _) => generics.len(), Type::TypeVariable(type_variable, _) | Type::NamedGeneric(type_variable, _) => { - match &*type_variable.borrow() { + match &*type_variable.0.borrow() { TypeBinding::Bound(binding) => binding.generic_count(), TypeBinding::Unbound(_) => 0, } @@ -617,31 +662,12 @@ impl Type { } } - /// Takes a monomorphic type and generalizes it over each of the given type variables. - pub(crate) fn generalize_from_variables( - self, - type_vars: HashMap, - ) -> Type { - let polymorphic_type_vars = vecmap(type_vars, |type_var| type_var); - Type::Forall(polymorphic_type_vars, Box::new(self)) - } - /// Takes a monomorphic type and generalizes it over each of the type variables in the /// given type bindings, ignoring what each type variable is bound to in the TypeBindings. pub(crate) fn generalize_from_substitutions(self, type_bindings: TypeBindings) -> Type { let polymorphic_type_vars = vecmap(type_bindings, |(id, (type_var, _))| (id, type_var)); Type::Forall(polymorphic_type_vars, Box::new(self)) } - - /// Takes a monomorphic type and generalizes it over each type variable found within. - /// - /// Note that Noir's type system assumes any Type::Forall are only present at top-level, - /// and thus all type variable's within a type are free. - pub(crate) fn generalize(self) -> Type { - let mut type_variables = HashMap::new(); - self.find_all_unbound_type_variables(&mut type_variables); - self.generalize_from_variables(type_variables) - } } impl std::fmt::Display for Type { @@ -661,23 +687,23 @@ impl std::fmt::Display for Type { Signedness::Signed => write!(f, "i{num_bits}"), Signedness::Unsigned => write!(f, "u{num_bits}"), }, - Type::TypeVariable(id, TypeVariableKind::Normal) => write!(f, "{}", id.borrow()), + Type::TypeVariable(var, TypeVariableKind::Normal) => write!(f, "{}", var.0.borrow()), Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) => { - if let TypeBinding::Unbound(_) = &*binding.borrow() { + if let TypeBinding::Unbound(_) = &*binding.0.borrow() { // Show a Field by default if this TypeVariableKind::IntegerOrField is unbound, since that is // what they bind to by default anyway. It is less confusing than displaying it // as a generic. write!(f, "Field") } else { - write!(f, "{}", binding.borrow()) + write!(f, "{}", binding.0.borrow()) } } Type::TypeVariable(binding, TypeVariableKind::Constant(n)) => { - if let TypeBinding::Unbound(_) = &*binding.borrow() { + if let TypeBinding::Unbound(_) = &*binding.0.borrow() { // TypeVariableKind::Constant(n) binds to Type::Constant(n) by default, so just show that. write!(f, "{n}") } else { - write!(f, "{}", binding.borrow()) + write!(f, "{}", binding.0.borrow()) } } Type::Struct(s, args) => { @@ -688,8 +714,8 @@ impl std::fmt::Display for Type { write!(f, "{}<{}>", s.borrow(), args.join(", ")) } } - Type::TraitAsType(tr) => { - write!(f, "impl {}", tr.name) + Type::TraitAsType(_id, name) => { + write!(f, "impl {}", name) } Type::Tuple(elements) => { let elements = vecmap(elements, ToString::to_string); @@ -702,7 +728,7 @@ impl std::fmt::Display for Type { } Type::Unit => write!(f, "()"), Type::Error => write!(f, "error"), - Type::NamedGeneric(binding, name) => match &*binding.borrow() { + Type::NamedGeneric(binding, name) => match &*binding.0.borrow() { TypeBinding::Bound(binding) => binding.fmt(f), TypeBinding::Unbound(_) if name.is_empty() => write!(f, "_"), TypeBinding::Unbound(_) => write!(f, "{name}"), @@ -761,58 +787,63 @@ pub struct UnificationError; impl Type { /// Try to bind a MaybeConstant variable to self, succeeding if self is a Constant, - /// MaybeConstant, or type variable. - pub fn try_bind_to_maybe_constant( + /// MaybeConstant, or type variable. If successful, the binding is placed in the + /// given TypeBindings map rather than linked immediately. + fn try_bind_to_maybe_constant( &self, var: &TypeVariable, target_length: u64, + bindings: &mut TypeBindings, ) -> Result<(), UnificationError> { - let target_id = match &*var.borrow() { + let target_id = match &*var.0.borrow() { TypeBinding::Bound(_) => unreachable!(), TypeBinding::Unbound(id) => *id, }; - match self { + let this = self.substitute(bindings); + + match &this { Type::Constant(length) if *length == target_length => { - *var.borrow_mut() = TypeBinding::Bound(self.clone()); + bindings.insert(target_id, (var.clone(), this)); Ok(()) } Type::NotConstant => { - *var.borrow_mut() = TypeBinding::Bound(Type::NotConstant); + bindings.insert(target_id, (var.clone(), Type::NotConstant)); Ok(()) } - Type::TypeVariable(binding, kind) => { - let borrow = binding.borrow(); + // A TypeVariable is less specific than a MaybeConstant, so we bind + // to the other type variable instead. + Type::TypeVariable(new_var, kind) => { + let borrow = new_var.0.borrow(); match &*borrow { - TypeBinding::Bound(typ) => typ.try_bind_to_maybe_constant(var, target_length), + TypeBinding::Bound(typ) => { + typ.try_bind_to_maybe_constant(var, target_length, bindings) + } // Avoid infinitely recursive bindings TypeBinding::Unbound(id) if *id == target_id => Ok(()), - TypeBinding::Unbound(_) => match kind { + TypeBinding::Unbound(new_target_id) => match kind { TypeVariableKind::Normal => { - drop(borrow); let clone = Type::TypeVariable( var.clone(), TypeVariableKind::Constant(target_length), ); - *binding.borrow_mut() = TypeBinding::Bound(clone); + bindings.insert(*new_target_id, (new_var.clone(), clone)); Ok(()) } TypeVariableKind::Constant(length) if *length == target_length => { - drop(borrow); let clone = Type::TypeVariable( var.clone(), TypeVariableKind::Constant(target_length), ); - *binding.borrow_mut() = TypeBinding::Bound(clone); + bindings.insert(*new_target_id, (new_var.clone(), clone)); Ok(()) } // The lengths don't match, but neither are set in stone so we can // just set them both to NotConstant. See issue 2370 TypeVariableKind::Constant(_) => { // *length != target_length - drop(borrow); - *var.borrow_mut() = TypeBinding::Bound(Type::NotConstant); - *binding.borrow_mut() = TypeBinding::Bound(Type::NotConstant); + bindings.insert(target_id, (var.clone(), Type::NotConstant)); + bindings.insert(*new_target_id, (new_var.clone(), Type::NotConstant)); Ok(()) } TypeVariableKind::IntegerOrField => Err(UnificationError), @@ -824,44 +855,49 @@ impl Type { } /// Try to bind a PolymorphicInt variable to self, succeeding if self is an integer, field, - /// other PolymorphicInt type, or type variable. - pub fn try_bind_to_polymorphic_int(&self, var: &TypeVariable) -> Result<(), UnificationError> { - let target_id = match &*var.borrow() { + /// other PolymorphicInt type, or type variable. If successful, the binding is placed in the + /// given TypeBindings map rather than linked immediately. + pub fn try_bind_to_polymorphic_int( + &self, + var: &TypeVariable, + bindings: &mut TypeBindings, + ) -> Result<(), UnificationError> { + let target_id = match &*var.0.borrow() { TypeBinding::Bound(_) => unreachable!(), TypeBinding::Unbound(id) => *id, }; - match self { + let this = self.substitute(bindings); + + match &this { Type::FieldElement | Type::Integer(..) => { - *var.borrow_mut() = TypeBinding::Bound(self.clone()); + bindings.insert(target_id, (var.clone(), this)); Ok(()) } Type::TypeVariable(self_var, TypeVariableKind::IntegerOrField) => { - let borrow = self_var.borrow(); + let borrow = self_var.0.borrow(); match &*borrow { - TypeBinding::Bound(typ) => typ.try_bind_to_polymorphic_int(var), + TypeBinding::Bound(typ) => typ.try_bind_to_polymorphic_int(var, bindings), // Avoid infinitely recursive bindings TypeBinding::Unbound(id) if *id == target_id => Ok(()), TypeBinding::Unbound(_) => { - drop(borrow); - *var.borrow_mut() = TypeBinding::Bound(self.clone()); + bindings.insert(target_id, (var.clone(), this.clone())); Ok(()) } } } Type::TypeVariable(binding, TypeVariableKind::Normal) => { - let borrow = binding.borrow(); + let borrow = binding.0.borrow(); match &*borrow { - TypeBinding::Bound(typ) => typ.try_bind_to_polymorphic_int(var), + TypeBinding::Bound(typ) => typ.try_bind_to_polymorphic_int(var, bindings), // Avoid infinitely recursive bindings TypeBinding::Unbound(id) if *id == target_id => Ok(()), - TypeBinding::Unbound(_) => { - drop(borrow); - // PolymorphicInt is more specific than TypeVariable so we bind the type - // variable to PolymorphicInt instead. + TypeBinding::Unbound(new_target_id) => { + // IntegerOrField is more specific than TypeVariable so we bind the type + // variable to IntegerOrField instead. let clone = Type::TypeVariable(var.clone(), TypeVariableKind::IntegerOrField); - *binding.borrow_mut() = TypeBinding::Bound(clone); + bindings.insert(*new_target_id, (binding.clone(), clone)); Ok(()) } } @@ -870,102 +906,113 @@ impl Type { } } - pub fn try_bind_to(&self, var: &TypeVariable) -> Result<(), UnificationError> { - let target_id = match &*var.borrow() { + /// Try to bind the given type variable to self. Although the given type variable + /// is expected to be of TypeVariableKind::Normal, this binding can still fail + /// if the given type variable occurs within `self` as that would create a recursive type. + /// + /// If successful, the binding is placed in the + /// given TypeBindings map rather than linked immediately. + fn try_bind_to( + &self, + var: &TypeVariable, + bindings: &mut TypeBindings, + ) -> Result<(), UnificationError> { + let target_id = match &*var.0.borrow() { TypeBinding::Bound(_) => unreachable!(), TypeBinding::Unbound(id) => *id, }; - if let Some(binding) = self.get_inner_type_variable() { + let this = self.substitute(bindings); + + if let Some(binding) = this.get_inner_type_variable() { match &*binding.borrow() { - TypeBinding::Bound(typ) => return typ.try_bind_to(var), + TypeBinding::Bound(typ) => return typ.try_bind_to(var, bindings), // Don't recursively bind the same id to itself TypeBinding::Unbound(id) if *id == target_id => return Ok(()), _ => (), } } - // Check if the target id occurs within self before binding. Otherwise this could + // Check if the target id occurs within `this` before binding. Otherwise this could // cause infinitely recursive types - if self.occurs(target_id) { + if this.occurs(target_id) { Err(UnificationError) } else { - *var.borrow_mut() = TypeBinding::Bound(self.clone()); + bindings.insert(target_id, (var.clone(), this.clone())); Ok(()) } } fn get_inner_type_variable(&self) -> Option> { match self { - Type::TypeVariable(var, _) | Type::NamedGeneric(var, _) => Some(var.clone()), + Type::TypeVariable(var, _) | Type::NamedGeneric(var, _) => Some(var.0.clone()), _ => None, } } /// Try to unify this type with another, setting any type variables found - /// equal to the other type in the process. Unification is more strict - /// than sub-typing but less strict than Eq. Returns true if the unification - /// succeeded. Note that any bindings performed in a failed unification are - /// not undone. This may cause further type errors later on. + /// equal to the other type in the process. When comparing types, unification + /// (including try_unify) are almost always preferred over Type::eq as unification + /// will correctly handle generic types. pub fn unify( &self, expected: &Type, errors: &mut Vec, make_error: impl FnOnce() -> TypeCheckError, ) { - if let Err(UnificationError) = self.try_unify(expected) { - errors.push(make_error()); + let mut bindings = TypeBindings::new(); + + match self.try_unify(expected, &mut bindings) { + Ok(()) => { + // Commit any type bindings on success + Self::apply_type_bindings(bindings); + } + Err(UnificationError) => errors.push(make_error()), } } /// `try_unify` is a bit of a misnomer since although errors are not committed, /// any unified bindings are on success. - pub fn try_unify(&self, other: &Type) -> Result<(), UnificationError> { + pub fn try_unify( + &self, + other: &Type, + bindings: &mut TypeBindings, + ) -> Result<(), UnificationError> { use Type::*; use TypeVariableKind as Kind; match (self, other) { (Error, _) | (_, Error) => Ok(()), - (TypeVariable(binding, Kind::IntegerOrField), other) - | (other, TypeVariable(binding, Kind::IntegerOrField)) => { - // If it is already bound, unify against what it is bound to - if let TypeBinding::Bound(link) = &*binding.borrow() { - return link.try_unify(other); - } - - // Otherwise, check it is unified against an integer and bind it - other.try_bind_to_polymorphic_int(binding) + (TypeVariable(var, Kind::IntegerOrField), other) + | (other, TypeVariable(var, Kind::IntegerOrField)) => { + other.try_unify_to_type_variable(var, bindings, |bindings| { + other.try_bind_to_polymorphic_int(var, bindings) + }) } - (TypeVariable(binding, Kind::Normal), other) - | (other, TypeVariable(binding, Kind::Normal)) => { - if let TypeBinding::Bound(link) = &*binding.borrow() { - return link.try_unify(other); - } - - other.try_bind_to(binding) + (TypeVariable(var, Kind::Normal), other) | (other, TypeVariable(var, Kind::Normal)) => { + other.try_unify_to_type_variable(var, bindings, |bindings| { + other.try_bind_to(var, bindings) + }) } - (TypeVariable(binding, Kind::Constant(length)), other) - | (other, TypeVariable(binding, Kind::Constant(length))) => { - if let TypeBinding::Bound(link) = &*binding.borrow() { - return link.try_unify(other); - } - - other.try_bind_to_maybe_constant(binding, *length) - } + (TypeVariable(var, Kind::Constant(length)), other) + | (other, TypeVariable(var, Kind::Constant(length))) => other + .try_unify_to_type_variable(var, bindings, |bindings| { + other.try_bind_to_maybe_constant(var, *length, bindings) + }), (Array(len_a, elem_a), Array(len_b, elem_b)) => { - len_a.try_unify(len_b)?; - elem_a.try_unify(elem_b) + len_a.try_unify(len_b, bindings)?; + elem_a.try_unify(elem_b, bindings) } - (String(len_a), String(len_b)) => len_a.try_unify(len_b), + (String(len_a), String(len_b)) => len_a.try_unify(len_b, bindings), (FmtString(len_a, elements_a), FmtString(len_b, elements_b)) => { - len_a.try_unify(len_b)?; - elements_a.try_unify(elements_b) + len_a.try_unify(len_b, bindings)?; + elements_a.try_unify(elements_b, bindings) } (Tuple(elements_a), Tuple(elements_b)) => { @@ -973,7 +1020,7 @@ impl Type { Err(UnificationError) } else { for (a, b) in elements_a.iter().zip(elements_b) { - a.try_unify(b)?; + a.try_unify(b, bindings)?; } Ok(()) } @@ -985,7 +1032,7 @@ impl Type { (Struct(id_a, args_a), Struct(id_b, args_b)) => { if id_a == id_b && args_a.len() == args_b.len() { for (a, b) in args_a.iter().zip(args_b) { - a.try_unify(b)?; + a.try_unify(b, bindings)?; } Ok(()) } else { @@ -993,26 +1040,20 @@ impl Type { } } - (NamedGeneric(binding, _), other) if !binding.borrow().is_unbound() => { - if let TypeBinding::Bound(link) = &*binding.borrow() { - link.try_unify(other) - } else { - unreachable!("If guard ensures binding is bound") - } - } - - (other, NamedGeneric(binding, _)) if !binding.borrow().is_unbound() => { - if let TypeBinding::Bound(link) = &*binding.borrow() { - other.try_unify(link) + (NamedGeneric(binding, _), other) | (other, NamedGeneric(binding, _)) + if !binding.0.borrow().is_unbound() => + { + if let TypeBinding::Bound(link) = &*binding.0.borrow() { + link.try_unify(other, bindings) } else { unreachable!("If guard ensures binding is bound") } } (NamedGeneric(binding_a, name_a), NamedGeneric(binding_b, name_b)) => { - // Unbound NamedGenerics are caught by the checks above - assert!(binding_a.borrow().is_unbound()); - assert!(binding_b.borrow().is_unbound()); + // Bound NamedGenerics are caught by the check above + assert!(binding_a.0.borrow().is_unbound()); + assert!(binding_b.0.borrow().is_unbound()); if name_a == name_b { Ok(()) @@ -1024,17 +1065,19 @@ impl Type { (Function(params_a, ret_a, env_a), Function(params_b, ret_b, env_b)) => { if params_a.len() == params_b.len() { for (a, b) in params_a.iter().zip(params_b.iter()) { - a.try_unify(b)?; + a.try_unify(b, bindings)?; } - env_a.try_unify(env_b)?; - ret_b.try_unify(ret_a) + env_a.try_unify(env_b, bindings)?; + ret_b.try_unify(ret_a, bindings) } else { Err(UnificationError) } } - (MutableReference(elem_a), MutableReference(elem_b)) => elem_a.try_unify(elem_b), + (MutableReference(elem_a), MutableReference(elem_b)) => { + elem_a.try_unify(elem_b, bindings) + } (other_a, other_b) => { if other_a == other_b { @@ -1046,6 +1089,34 @@ impl Type { } } + /// Try to unify a type variable to `self`. + /// This is a helper function factored out from try_unify. + fn try_unify_to_type_variable( + &self, + type_variable: &TypeVariable, + bindings: &mut TypeBindings, + + // Bind the type variable to a type. This is factored out since depending on the + // TypeVariableKind, there are different methods to check whether the variable can + // bind to the given type or not. + bind_variable: impl FnOnce(&mut TypeBindings) -> Result<(), UnificationError>, + ) -> Result<(), UnificationError> { + match &*type_variable.0.borrow() { + // If it is already bound, unify against what it is bound to + TypeBinding::Bound(link) => link.try_unify(self, bindings), + TypeBinding::Unbound(id) => { + // We may have already "bound" this type variable in this call to + // try_unify, so check those bindings as well. + match bindings.get(id) { + Some((_, binding)) => binding.clone().try_unify(self, bindings), + + // Otherwise, bind it + None => bind_variable(bindings), + } + } + } + } + /// Similar to `unify` but if the check fails this will attempt to coerce the /// argument to the target type. When this happens, the given expression is wrapped in /// a new expression to convert its type. E.g. `array` -> `array.as_slice()` @@ -1059,10 +1130,14 @@ impl Type { errors: &mut Vec, make_error: impl FnOnce() -> TypeCheckError, ) { - if let Err(UnificationError) = self.try_unify(expected) { + let mut bindings = TypeBindings::new(); + + if let Err(UnificationError) = self.try_unify(expected, &mut bindings) { if !self.try_array_to_slice_coercion(expected, expression, interner) { errors.push(make_error()); } + } else { + Type::apply_type_bindings(bindings); } } @@ -1085,8 +1160,10 @@ impl Type { if matches!(size1, Type::Constant(_)) && matches!(size2, Type::NotConstant) { // Still have to ensure the element types match. // Don't need to issue an error here if not, it will be done in unify_with_coercions - if element1.try_unify(element2).is_ok() { + let mut bindings = TypeBindings::new(); + if element1.try_unify(element2, &mut bindings).is_ok() { convert_array_expression_to_slice(expression, this, target, interner); + Self::apply_type_bindings(bindings); return true; } } @@ -1094,6 +1171,14 @@ impl Type { false } + /// Apply the given type bindings, making them permanently visible for each + /// clone of each type variable bound. + pub fn apply_type_bindings(bindings: TypeBindings) { + for (type_variable, binding) in bindings.values() { + type_variable.bind(binding.clone()); + } + } + /// If this type is a Type::Constant (used in array lengths), or is bound /// to a Type::Constant, return the constant as a u64. pub fn evaluate_to_u64(&self) -> Option { @@ -1194,7 +1279,7 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Unit - | Type::TraitAsType(_) + | Type::TraitAsType(..) | Type::Constant(_) | Type::NotConstant | Type::Error => (), @@ -1229,7 +1314,7 @@ impl Type { } Type::Forall(_, typ) => typ.find_all_unbound_type_variables(type_variables), Type::TypeVariable(type_variable, _) | Type::NamedGeneric(type_variable, _) => { - match &*type_variable.borrow() { + match &*type_variable.0.borrow() { TypeBinding::Bound(binding) => { binding.find_all_unbound_type_variables(type_variables); } @@ -1251,7 +1336,7 @@ impl Type { return self.clone(); } - let substitute_binding = |binding: &TypeVariable| match &*binding.borrow() { + let substitute_binding = |binding: &TypeVariable| match &*binding.0.borrow() { TypeBinding::Bound(binding) => binding.substitute(type_bindings), TypeBinding::Unbound(id) => match type_bindings.get(id) { Some((_, binding)) => binding.clone(), @@ -1287,7 +1372,6 @@ impl Type { let fields = vecmap(fields, |field| field.substitute(type_bindings)); Type::Tuple(fields) } - Type::TraitAsType(_) => todo!(), Type::Forall(typevars, typ) => { // Trying to substitute a variable defined within a nested Forall // is usually impossible and indicative of an error in the type checker somewhere. @@ -1311,6 +1395,7 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Constant(_) + | Type::TraitAsType(..) | Type::Error | Type::NotConstant | Type::Unit => self.clone(), @@ -1327,11 +1412,10 @@ impl Type { let field_occurs = fields.occurs(target_id); len_occurs || field_occurs } - Type::TraitAsType(_) => todo!(), Type::Struct(_, generic_args) => generic_args.iter().any(|arg| arg.occurs(target_id)), Type::Tuple(fields) => fields.iter().any(|field| field.occurs(target_id)), Type::NamedGeneric(binding, _) | Type::TypeVariable(binding, _) => { - match &*binding.borrow() { + match &*binding.0.borrow() { TypeBinding::Bound(binding) => binding.occurs(target_id), TypeBinding::Unbound(id) => *id == target_id, } @@ -1350,6 +1434,7 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Constant(_) + | Type::TraitAsType(..) | Type::Error | Type::NotConstant | Type::Unit => false, @@ -1380,7 +1465,7 @@ impl Type { } Tuple(args) => Tuple(vecmap(args, |arg| arg.follow_bindings())), TypeVariable(var, _) | NamedGeneric(var, _) => { - if let TypeBinding::Bound(typ) = &*var.borrow() { + if let TypeBinding::Bound(typ) = &*var.0.borrow() { return typ.follow_bindings(); } self.clone() @@ -1397,7 +1482,7 @@ impl Type { // Expect that this function should only be called on instantiated types Forall(..) => unreachable!(), - TraitAsType(_) + TraitAsType(..) | FieldElement | Integer(_, _) | Bool @@ -1485,7 +1570,7 @@ impl From<&Type> for PrintableType { Signedness::Signed => PrintableType::SignedInteger { width: *bit_width }, }, Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) => { - match &*binding.borrow() { + match &*binding.0.borrow() { TypeBinding::Bound(typ) => typ.into(), TypeBinding::Unbound(_) => Type::default_int_type().into(), } @@ -1505,7 +1590,7 @@ impl From<&Type> for PrintableType { let fields = vecmap(fields, |(name, typ)| (name, typ.into())); PrintableType::Struct { fields, name: struct_type.name.to_string() } } - Type::TraitAsType(_) => unreachable!(), + Type::TraitAsType(..) => unreachable!(), Type::Tuple(_) => todo!("printing tuple types is not yet implemented"), Type::TypeVariable(_, _) => unreachable!(), Type::NamedGeneric(..) => unreachable!(), diff --git a/noir/compiler/noirc_frontend/src/lexer/lexer.rs b/noir/compiler/noirc_frontend/src/lexer/lexer.rs index 7a2197ebb93..fd8168e36c6 100644 --- a/noir/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/noir/compiler/noirc_frontend/src/lexer/lexer.rs @@ -323,11 +323,29 @@ impl<'a> Lexer<'a> { let start = self.position; let integer_str = self.eat_while(Some(initial_char), |ch| { - ch.is_ascii_digit() | ch.is_ascii_hexdigit() | (ch == 'x') + ch.is_ascii_digit() | ch.is_ascii_hexdigit() | (ch == 'x') | (ch == '_') }); let end = self.position; + // We want to enforce some simple rules about usage of underscores: + // 1. Underscores cannot appear at the end of a integer literal. e.g. 0x123_. + // 2. There cannot be more than one underscore consecutively, e.g. 0x5__5, 5__5. + // + // We're not concerned with an underscore at the beginning of a decimal literal + // such as `_5` as this would be lexed into an ident rather than an integer literal. + let invalid_underscore_location = integer_str.ends_with('_'); + let consecutive_underscores = integer_str.contains("__"); + if invalid_underscore_location || consecutive_underscores { + return Err(LexerErrorKind::InvalidIntegerLiteral { + span: Span::inclusive(start, end), + found: integer_str, + }); + } + + // Underscores needs to be stripped out before the literal can be converted to a `FieldElement. + let integer_str = integer_str.replace('_', ""); + let integer = match FieldElement::try_from_str(&integer_str) { None => { return Err(LexerErrorKind::InvalidIntegerLiteral { @@ -633,15 +651,18 @@ mod tests { } #[test] - fn test_attribute_with_apostrophe() { - let input = r#"#[test(should_fail_with = "the eagle's feathers")]"#; + fn test_attribute_with_common_punctuation() { + let input = + r#"#[test(should_fail_with = "stmt. q? exclaim! & symbols, 1% shouldn't fail")]"#; let mut lexer = Lexer::new(input); let token = lexer.next_token().unwrap().token().clone(); assert_eq!( token, Token::Attribute(Attribute::Function(FunctionAttribute::Test( - TestScope::ShouldFailWith { reason: "the eagle's feathers".to_owned().into() } + TestScope::ShouldFailWith { + reason: "stmt. q? exclaim! & symbols, 1% shouldn't fail".to_owned().into() + } ))) ); } @@ -927,15 +948,33 @@ mod tests { } #[test] - fn test_eat_hex_int() { - let input = "0x05"; - - let expected = vec![Token::Int(5_i128.into())]; - let mut lexer = Lexer::new(input); + fn test_eat_integer_literals() { + let test_cases: Vec<(&str, Token)> = vec![ + ("0x05", Token::Int(5_i128.into())), + ("5", Token::Int(5_i128.into())), + ("0x1234_5678", Token::Int(0x1234_5678_u128.into())), + ("0x_01", Token::Int(0x1_u128.into())), + ("1_000_000", Token::Int(1_000_000_u128.into())), + ]; - for token in expected.into_iter() { + for (input, expected_token) in test_cases { + let mut lexer = Lexer::new(input); let got = lexer.next_token().unwrap(); - assert_eq!(got, token); + assert_eq!(got.token(), &expected_token); + } + } + + #[test] + fn test_reject_invalid_underscores_in_integer_literal() { + let test_cases: Vec<&str> = vec!["0x05_", "5_", "5__5", "0x5__5"]; + + for input in test_cases { + let mut lexer = Lexer::new(input); + let token = lexer.next_token(); + assert!( + matches!(token, Err(LexerErrorKind::InvalidIntegerLiteral { .. })), + "expected {input} to throw error" + ); } } diff --git a/noir/compiler/noirc_frontend/src/lexer/token.rs b/noir/compiler/noirc_frontend/src/lexer/token.rs index b16de42c0ba..e6542c643ad 100644 --- a/noir/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/compiler/noirc_frontend/src/lexer/token.rs @@ -468,13 +468,8 @@ impl Attribute { .all(|ch| { ch.is_ascii_alphabetic() || ch.is_numeric() - || ch == '_' - || ch == '(' - || ch == ')' - || ch == '=' - || ch == '"' + || ch.is_ascii_punctuation() || ch == ' ' - || ch == '\'' }) .then_some(()); @@ -644,6 +639,7 @@ pub enum Keyword { Assert, AssertEq, Bool, + CallData, Char, CompTime, Constrain, @@ -667,6 +663,7 @@ pub enum Keyword { Open, Pub, Return, + ReturnData, String, Struct, Trait, @@ -685,6 +682,7 @@ impl fmt::Display for Keyword { Keyword::AssertEq => write!(f, "assert_eq"), Keyword::Bool => write!(f, "bool"), Keyword::Char => write!(f, "char"), + Keyword::CallData => write!(f, "call_data"), Keyword::CompTime => write!(f, "comptime"), Keyword::Constrain => write!(f, "constrain"), Keyword::Contract => write!(f, "contract"), @@ -707,6 +705,7 @@ impl fmt::Display for Keyword { Keyword::Open => write!(f, "open"), Keyword::Pub => write!(f, "pub"), Keyword::Return => write!(f, "return"), + Keyword::ReturnData => write!(f, "return_data"), Keyword::String => write!(f, "str"), Keyword::Struct => write!(f, "struct"), Keyword::Trait => write!(f, "trait"), @@ -727,6 +726,7 @@ impl Keyword { "assert" => Keyword::Assert, "assert_eq" => Keyword::AssertEq, "bool" => Keyword::Bool, + "call_data" => Keyword::CallData, "char" => Keyword::Char, "comptime" => Keyword::CompTime, "constrain" => Keyword::Constrain, @@ -750,6 +750,7 @@ impl Keyword { "open" => Keyword::Open, "pub" => Keyword::Pub, "return" => Keyword::Return, + "return_data" => Keyword::ReturnData, "str" => Keyword::String, "struct" => Keyword::Struct, "trait" => Keyword::Trait, diff --git a/noir/compiler/noirc_frontend/src/monomorphization/ast.rs b/noir/compiler/noirc_frontend/src/monomorphization/ast.rs index 0a005d766fe..5a5f07b0a38 100644 --- a/noir/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/noir/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -2,7 +2,9 @@ use acvm::FieldElement; use iter_extended::vecmap; use noirc_errors::Location; -use crate::{hir_def::function::FunctionSignature, BinaryOpKind, Distinctness, Signedness}; +use crate::{ + hir_def::function::FunctionSignature, BinaryOpKind, Distinctness, Signedness, Visibility, +}; /// The monomorphized AST is expression-based, all statements are also /// folded into this expression enum. Compared to the HIR, the monomorphized @@ -243,6 +245,7 @@ pub struct Program { /// forwarding to the next phase. pub return_distinctness: Distinctness, pub return_location: Option, + pub return_visibility: Visibility, } impl Program { @@ -251,8 +254,15 @@ impl Program { main_function_signature: FunctionSignature, return_distinctness: Distinctness, return_location: Option, + return_visibility: Visibility, ) -> Program { - Program { functions, main_function_signature, return_distinctness, return_location } + Program { + functions, + main_function_signature, + return_distinctness, + return_location, + return_visibility, + } } pub fn main(&self) -> &Function { diff --git a/noir/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/compiler/noirc_frontend/src/monomorphization/mod.rs index 57e4e6cdeb0..52b8d5bfd79 100644 --- a/noir/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -92,6 +92,7 @@ type HirType = crate::Type; /// this function. Typically, this is the function named "main" in the source project, /// but it can also be, for example, an arbitrary test function for running `nargo test`. pub fn monomorphize(main: node_interner::FuncId, interner: &NodeInterner) -> Program { + log::trace!("Start monomorphization"); let mut monomorphizer = Monomorphizer::new(interner); let function_sig = monomorphizer.compile_main(main); @@ -105,8 +106,16 @@ pub fn monomorphize(main: node_interner::FuncId, interner: &NodeInterner) -> Pro } let functions = vecmap(monomorphizer.finished_functions, |(_, f)| f); - let FuncMeta { return_distinctness, .. } = interner.function_meta(&main); - Program::new(functions, function_sig, return_distinctness, monomorphizer.return_location) + let FuncMeta { return_distinctness, return_visibility, .. } = interner.function_meta(&main); + + log::trace!("Finish monomorphization"); + Program::new( + functions, + function_sig, + return_distinctness, + monomorphizer.return_location, + return_visibility, + ) } impl<'interner> Monomorphizer<'interner> { @@ -215,7 +224,7 @@ impl<'interner> Monomorphizer<'interner> { fn function(&mut self, f: node_interner::FuncId, id: FuncId) { if let Some((self_type, trait_id)) = self.interner.get_function_trait(&f) { let the_trait = self.interner.get_trait(trait_id); - *the_trait.self_type_typevar.borrow_mut() = TypeBinding::Bound(self_type); + the_trait.self_type_typevar.force_bind(self_type); } let meta = self.interner.function_meta(&f); @@ -225,7 +234,7 @@ impl<'interner> Monomorphizer<'interner> { let body_expr_id = *self.interner.function(&f).as_expr(); let body_return_type = self.interner.id_type(body_expr_id); let return_type = self.convert_type(match meta.return_type() { - Type::TraitAsType(_) => &body_return_type, + Type::TraitAsType(..) => &body_return_type, _ => meta.return_type(), }); @@ -310,10 +319,23 @@ impl<'interner> Monomorphizer<'interner> { )) } HirExpression::Literal(HirLiteral::Bool(value)) => Literal(Bool(value)), - HirExpression::Literal(HirLiteral::Integer(value)) => { - let typ = self.convert_type(&self.interner.id_type(expr)); - let location = self.interner.id_location(expr); - Literal(Integer(value, typ, location)) + HirExpression::Literal(HirLiteral::Integer(value, sign)) => { + if sign { + let typ = self.convert_type(&self.interner.id_type(expr)); + let location = self.interner.id_location(expr); + match typ { + ast::Type::Field => Literal(Integer(-value, typ, location)), + ast::Type::Integer(_, bit_size) => { + let base = 1_u128 << bit_size; + Literal(Integer(FieldElement::from(base) - value, typ, location)) + } + _ => unreachable!("Integer literal must be numeric"), + } + } else { + let typ = self.convert_type(&self.interner.id_type(expr)); + let location = self.interner.id_location(expr); + Literal(Integer(value, typ, location)) + } } HirExpression::Literal(HirLiteral::Array(array)) => match array { HirArrayLiteral::Standard(array) => self.standard_array(expr, array), @@ -701,7 +723,7 @@ impl<'interner> Monomorphizer<'interner> { ast::Type::Slice(element) } } - HirType::TraitAsType(_) => { + HirType::TraitAsType(..) => { unreachable!("All TraitAsType should be replaced before calling convert_type"); } HirType::NamedGeneric(binding, _) => { @@ -712,11 +734,7 @@ impl<'interner> Monomorphizer<'interner> { // Default any remaining unbound type variables. // This should only happen if the variable in question is unused // and within a larger generic type. - // NOTE: Make sure to review this if there is ever type-directed dispatch, - // like automatic solving of traits. It should be fine since it is strictly - // after type checking, but care should be taken that it doesn't change which - // impls are chosen. - *binding.borrow_mut() = TypeBinding::Bound(HirType::default_int_type()); + binding.bind(HirType::default_int_type()); ast::Type::Field } @@ -728,10 +746,6 @@ impl<'interner> Monomorphizer<'interner> { // Default any remaining unbound type variables. // This should only happen if the variable in question is unused // and within a larger generic type. - // NOTE: Make sure to review this if there is ever type-directed dispatch, - // like automatic solving of traits. It should be fine since it is strictly - // after type checking, but care should be taken that it doesn't change which - // impls are chosen. let default = if self.is_range_loop && matches!(kind, TypeVariableKind::IntegerOrField) { Type::default_range_loop_type() @@ -740,7 +754,7 @@ impl<'interner> Monomorphizer<'interner> { }; let monomorphized_default = self.convert_type(&default); - *binding.borrow_mut() = TypeBinding::Bound(default); + binding.bind(default); monomorphized_default } @@ -875,7 +889,6 @@ impl<'interner> Monomorphizer<'interner> { let original_func = Box::new(self.expr(call.func)); let mut arguments = vecmap(&call.arguments, |id| self.expr(*id)); let hir_arguments = vecmap(&call.arguments, |id| self.interner.expression(id)); - let func: Box; let return_type = self.interner.id_type(id); let return_type = self.convert_type(&return_type); @@ -883,10 +896,11 @@ impl<'interner> Monomorphizer<'interner> { if let ast::Expression::Ident(ident) = original_func.as_ref() { if let Definition::Oracle(name) = &ident.definition { - if name.as_str() == "println" { + if name.as_str() == "print" { // Oracle calls are required to be wrapped in an unconstrained function - // Thus, the only argument to the `println` oracle is expected to always be an ident - self.append_printable_type_info(&hir_arguments[0], &mut arguments); + // The first argument to the `print` oracle is a bool, indicating a newline to be inserted at the end of the input + // The second argument is expected to always be an ident + self.append_printable_type_info(&hir_arguments[1], &mut arguments); } } } @@ -895,7 +909,8 @@ impl<'interner> Monomorphizer<'interner> { let func_type = self.interner.id_type(call.func); let func_type = self.convert_type(&func_type); let is_closure = self.is_function_closure(func_type); - if is_closure { + + let func = if is_closure { let local_id = self.next_local_id(); // store the function in a temporary variable before calling it @@ -917,14 +932,13 @@ impl<'interner> Monomorphizer<'interner> { typ: self.convert_type(&self.interner.id_type(call.func)), }); - func = Box::new(ast::Expression::ExtractTupleField( - Box::new(extracted_func.clone()), - 1usize, - )); - let env_argument = ast::Expression::ExtractTupleField(Box::new(extracted_func), 0usize); + let env_argument = + ast::Expression::ExtractTupleField(Box::new(extracted_func.clone()), 0usize); arguments.insert(0, env_argument); + + Box::new(ast::Expression::ExtractTupleField(Box::new(extracted_func), 1usize)) } else { - func = original_func.clone(); + original_func.clone() }; let call = self @@ -1430,12 +1444,12 @@ fn unwrap_struct_type(typ: &HirType) -> Vec<(String, HirType)> { fn perform_instantiation_bindings(bindings: &TypeBindings) { for (var, binding) in bindings.values() { - *var.borrow_mut() = TypeBinding::Bound(binding.clone()); + var.force_bind(binding.clone()); } } fn undo_instantiation_bindings(bindings: TypeBindings) { for (id, (var, _)) in bindings { - *var.borrow_mut() = TypeBinding::Unbound(id); + var.unbind(id); } } diff --git a/noir/compiler/noirc_frontend/src/node_interner.rs b/noir/compiler/noirc_frontend/src/node_interner.rs index e66a6d57605..236f1e0b513 100644 --- a/noir/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/compiler/noirc_frontend/src/node_interner.rs @@ -9,6 +9,7 @@ use crate::ast::Ident; use crate::graph::CrateId; use crate::hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait, UnresolvedTypeAlias}; use crate::hir::def_map::{LocalModuleId, ModuleId}; + use crate::hir_def::stmt::HirLetStatement; use crate::hir_def::traits::TraitImpl; use crate::hir_def::traits::{Trait, TraitConstraint}; @@ -21,7 +22,7 @@ use crate::hir_def::{ use crate::token::{Attributes, SecondaryAttribute}; use crate::{ ContractFunctionType, FunctionDefinition, FunctionVisibility, Generics, Shared, TypeAliasType, - TypeBinding, TypeBindings, TypeVariable, TypeVariableId, TypeVariableKind, + TypeBindings, TypeVariable, TypeVariableId, TypeVariableKind, }; /// An arbitrary number to limit the recursion depth when searching for trait impls. @@ -36,6 +37,7 @@ type StructAttributes = Vec; /// each definition or struct, etc. Because it is used on the Hir, the NodeInterner is /// useful in passes where the Hir is used - name resolution, type checking, and /// monomorphization - and it is not useful afterward. +#[derive(Debug)] pub struct NodeInterner { nodes: Arena, func_meta: HashMap, @@ -156,7 +158,7 @@ pub enum TraitImplKind { /// /// Additionally, types can define specialized impls with methods of the same name /// as long as these specialized impls do not overlap. E.g. `impl Struct` and `impl Struct` -#[derive(Default)] +#[derive(Default, Debug)] pub struct Methods { direct: Vec, trait_impl_methods: Vec, @@ -165,6 +167,7 @@ pub struct Methods { /// All the information from a function that is filled out during definition collection rather than /// name resolution. As a result, if information about a function is needed during name resolution, /// this is the only place where it is safe to retrieve it (where all fields are guaranteed to be initialized). +#[derive(Debug, Clone)] pub struct FunctionModifiers { pub name: String, @@ -352,6 +355,7 @@ pub struct DefinitionInfo { pub name: String, pub mutable: bool, pub kind: DefinitionKind, + pub location: Location, } impl DefinitionInfo { @@ -451,6 +455,30 @@ impl NodeInterner { self.id_to_location.insert(expr_id.into(), Location::new(span, file)); } + /// Scans the interner for the item which is located at that [Location] + /// + /// The [Location] may not necessarily point to the beginning of the item + /// so we check if the location's span is contained within the start or end + /// of each items [Span] + pub fn find_location_index(&self, location: Location) -> Option> { + let mut location_candidate: Option<(&Index, &Location)> = None; + + // Note: we can modify this in the future to not do a linear + // scan by storing a separate map of the spans or by sorting the locations. + for (index, interned_location) in self.id_to_location.iter() { + if interned_location.contains(&location) { + if let Some(current_location) = location_candidate { + if interned_location.span.is_smaller(¤t_location.1.span) { + location_candidate = Some((index, interned_location)); + } + } else { + location_candidate = Some((index, interned_location)); + } + } + } + location_candidate.map(|(index, _location)| *index) + } + /// Interns a HIR Function. pub fn push_fn(&mut self, func: HirFunction) -> FuncId { FuncId(self.nodes.insert(Node::Function(func))) @@ -461,29 +489,31 @@ impl NodeInterner { self.id_to_type.insert(expr_id.into(), typ); } - pub fn push_empty_trait(&mut self, type_id: TraitId, typ: &UnresolvedTrait) { + pub fn push_empty_trait(&mut self, type_id: TraitId, unresolved_trait: &UnresolvedTrait) { let self_type_typevar_id = self.next_type_variable_id(); - let self_type_typevar = Shared::new(TypeBinding::Unbound(self_type_typevar_id)); - self.traits.insert( - type_id, - Trait::new( - type_id, - typ.trait_def.name.clone(), - typ.crate_id, - typ.trait_def.span, - vecmap(&typ.trait_def.generics, |_| { - // Temporary type variable ids before the trait is resolved to its actual ids. - // This lets us record how many arguments the type expects so that other types - // can refer to it with generic arguments before the generic parameters themselves - // are resolved. - let id = TypeVariableId(0); - (id, Shared::new(TypeBinding::Unbound(id))) - }), - self_type_typevar_id, - self_type_typevar, - ), - ); + let new_trait = Trait { + id: type_id, + name: unresolved_trait.trait_def.name.clone(), + crate_id: unresolved_trait.crate_id, + span: unresolved_trait.trait_def.span, + generics: vecmap(&unresolved_trait.trait_def.generics, |_| { + // Temporary type variable ids before the trait is resolved to its actual ids. + // This lets us record how many arguments the type expects so that other types + // can refer to it with generic arguments before the generic parameters themselves + // are resolved. + let id = TypeVariableId(0); + (id, TypeVariable::unbound(id)) + }), + self_type_typevar_id, + self_type_typevar: TypeVariable::unbound(self_type_typevar_id), + methods: Vec::new(), + method_ids: unresolved_trait.method_ids.clone(), + constants: Vec::new(), + types: Vec::new(), + }; + + self.traits.insert(type_id, new_trait); } pub fn new_struct( @@ -491,6 +521,7 @@ impl NodeInterner { typ: &UnresolvedStruct, krate: CrateId, local_id: LocalModuleId, + file_id: FileId, ) -> StructId { let struct_id = StructId(ModuleId { krate, local_id }); let name = typ.struct_def.name.clone(); @@ -503,10 +534,11 @@ impl NodeInterner { // can refer to it with generic arguments before the generic parameters themselves // are resolved. let id = TypeVariableId(0); - (id, Shared::new(TypeBinding::Unbound(id))) + (id, TypeVariable::unbound(id)) }); - let new_struct = StructType::new(struct_id, name, typ.struct_def.span, no_fields, generics); + let location = Location::new(typ.struct_def.span, file_id); + let new_struct = StructType::new(struct_id, name, location, no_fields, generics); self.structs.insert(struct_id, Shared::new(new_struct)); self.struct_attributes.insert(struct_id, typ.struct_def.attributes.clone()); struct_id @@ -522,7 +554,7 @@ impl NodeInterner { Type::Error, vecmap(&typ.type_alias_def.generics, |_| { let id = TypeVariableId(0); - (id, Shared::new(TypeBinding::Unbound(id))) + (id, TypeVariable::unbound(id)) }), )); @@ -635,13 +667,14 @@ impl NodeInterner { name: String, mutable: bool, definition: DefinitionKind, + location: Location, ) -> DefinitionId { let id = DefinitionId(self.definitions.len()); if let DefinitionKind::Function(func_id) = definition { self.function_definition_ids.insert(func_id, id); } - self.definitions.push(DefinitionInfo { name, mutable, kind: definition }); + self.definitions.push(DefinitionInfo { name, mutable, kind: definition, location }); id } @@ -652,7 +685,8 @@ impl NodeInterner { let mut modifiers = FunctionModifiers::new(); modifiers.name = name; let module = ModuleId::dummy_id(); - self.push_function_definition(id, modifiers, module); + let location = Location::dummy(); + self.push_function_definition(id, modifiers, module, location); id } @@ -661,6 +695,7 @@ impl NodeInterner { id: FuncId, function: &FunctionDefinition, module: ModuleId, + location: Location, ) -> DefinitionId { use ContractFunctionType::*; @@ -674,7 +709,7 @@ impl NodeInterner { contract_function_type: Some(if function.is_open { Open } else { Secret }), is_internal: Some(function.is_internal), }; - self.push_function_definition(id, modifiers, module) + self.push_function_definition(id, modifiers, module, location) } pub fn push_function_definition( @@ -682,11 +717,12 @@ impl NodeInterner { func: FuncId, modifiers: FunctionModifiers, module: ModuleId, + location: Location, ) -> DefinitionId { let name = modifiers.name.clone(); self.function_modifiers.insert(func, modifiers); self.function_modules.insert(func, module); - self.push_definition(name, false, DefinitionKind::Function(func)) + self.push_definition(name, false, DefinitionKind::Function(func), location) } pub fn set_function_trait(&mut self, func: FuncId, self_type: Type, trait_id: TraitId) { @@ -830,12 +866,16 @@ impl NodeInterner { self.structs[&id].clone() } - pub fn get_trait(&self, id: TraitId) -> Trait { - self.traits[&id].clone() + pub fn get_trait(&self, id: TraitId) -> &Trait { + &self.traits[&id] + } + + pub fn get_trait_mut(&mut self, id: TraitId) -> &mut Trait { + self.traits.get_mut(&id).expect("get_trait_mut given invalid TraitId") } - pub fn try_get_trait(&self, id: TraitId) -> Option { - self.traits.get(&id).cloned() + pub fn try_get_trait(&self, id: TraitId) -> Option<&Trait> { + self.traits.get(&id) } pub fn get_type_alias(&self, id: TypeAliasId) -> &TypeAliasType { @@ -859,7 +899,7 @@ impl NodeInterner { let typ = self.id_type(def_id); if let Type::Function(args, ret, env) = &typ { let def = self.definition(def_id); - if let Type::TraitAsType(_trait) = ret.as_ref() { + if let Type::TraitAsType(..) = ret.as_ref() { if let DefinitionKind::Function(func_id) = def.kind { let f = self.function(&func_id); let func_body = f.as_expr(); @@ -973,13 +1013,32 @@ impl NodeInterner { object_type: &Type, trait_id: TraitId, ) -> Result> { - self.lookup_trait_implementation_helper(object_type, trait_id, IMPL_SEARCH_RECURSION_LIMIT) + let (impl_kind, bindings) = self.try_lookup_trait_implementation(object_type, trait_id)?; + Type::apply_type_bindings(bindings); + Ok(impl_kind) + } + + /// Similar to `lookup_trait_implementation` but does not apply any type bindings on success. + pub fn try_lookup_trait_implementation( + &self, + object_type: &Type, + trait_id: TraitId, + ) -> Result<(TraitImplKind, TypeBindings), Vec> { + let mut bindings = TypeBindings::new(); + let impl_kind = self.lookup_trait_implementation_helper( + object_type, + trait_id, + &mut bindings, + IMPL_SEARCH_RECURSION_LIMIT, + )?; + Ok((impl_kind, bindings)) } fn lookup_trait_implementation_helper( &self, object_type: &Type, trait_id: TraitId, + type_bindings: &mut TypeBindings, recursion_limit: u32, ) -> Result> { let make_constraint = || TraitConstraint::new(object_type.clone(), trait_id); @@ -989,20 +1048,29 @@ impl NodeInterner { return Err(vec![make_constraint()]); } + let object_type = object_type.substitute(type_bindings); + let impls = self.trait_implementation_map.get(&trait_id).ok_or_else(|| vec![make_constraint()])?; for (existing_object_type, impl_kind) in impls { - let (existing_object_type, type_bindings) = existing_object_type.instantiate(self); + let (existing_object_type, instantiation_bindings) = + existing_object_type.instantiate(self); + + let mut fresh_bindings = TypeBindings::new(); + + if object_type.try_unify(&existing_object_type, &mut fresh_bindings).is_ok() { + // The unification was successful so we can append fresh_bindings to our bindings list + type_bindings.extend(fresh_bindings); - if object_type.try_unify(&existing_object_type).is_ok() { if let TraitImplKind::Normal(impl_id) = impl_kind { let trait_impl = self.get_trait_implementation(*impl_id); let trait_impl = trait_impl.borrow(); if let Err(mut errors) = self.validate_where_clause( &trait_impl.where_clause, - &type_bindings, + type_bindings, + &instantiation_bindings, recursion_limit, ) { errors.push(make_constraint()); @@ -1022,14 +1090,20 @@ impl NodeInterner { fn validate_where_clause( &self, where_clause: &[TraitConstraint], - type_bindings: &TypeBindings, + type_bindings: &mut TypeBindings, + instantiation_bindings: &TypeBindings, recursion_limit: u32, ) -> Result<(), Vec> { for constraint in where_clause { - let constraint_type = constraint.typ.substitute(type_bindings); + let constraint_type = constraint.typ.substitute(instantiation_bindings); + let constraint_type = constraint_type.substitute(type_bindings); + self.lookup_trait_implementation_helper( &constraint_type, constraint.trait_id, + // Use a fresh set of type bindings here since the constraint_type originates from + // our impl list, which we don't want to bind to. + &mut TypeBindings::new(), recursion_limit - 1, )?; } @@ -1050,7 +1124,7 @@ impl NodeInterner { trait_id: TraitId, ) -> bool { // Make sure there are no overlapping impls - if self.lookup_trait_implementation(&object_type, trait_id).is_ok() { + if self.try_lookup_trait_implementation(&object_type, trait_id).is_ok() { return false; } @@ -1078,8 +1152,8 @@ impl NodeInterner { let (instantiated_object_type, substitutions) = object_type.instantiate_type_variables(self); - if let Ok(TraitImplKind::Normal(existing)) = - self.lookup_trait_implementation(&instantiated_object_type, trait_id) + if let Ok((TraitImplKind::Normal(existing), _)) = + self.try_lookup_trait_implementation(&instantiated_object_type, trait_id) { let existing_impl = self.get_trait_implementation(existing); let existing_impl = existing_impl.borrow(); @@ -1184,12 +1258,99 @@ impl NodeInterner { self.selected_trait_implementations.insert(ident_id, trait_impl); } - /// Tags the given identifier with the selected trait_impl so that monomorphization - /// can later recover which impl was selected, or alternatively see if it needs to - /// decide which (because the impl was Assumed). + /// Retrieves the impl selected for a given IdentId during name resolution. + /// From type checking and on, the "ident" referred to is changed to a TraitMethodReference node. pub fn get_selected_impl_for_ident(&self, ident_id: ExprId) -> Option { self.selected_trait_implementations.get(&ident_id).cloned() } + + /// For a given [Index] we return [Location] to which we resolved to + /// We currently return None for features not yet implemented + /// TODO(#3659): LSP goto def should error when Ident at Location could not resolve + pub(crate) fn resolve_location(&self, index: impl Into) -> Option { + let node = self.nodes.get(index.into())?; + + match node { + Node::Function(func) => self.resolve_location(func.as_expr()), + Node::Expression(expression) => self.resolve_expression_location(expression), + _ => None, + } + } + + /// Resolves the [Location] of the definition for a given [HirExpression] + /// + /// Note: current the code returns None because some expressions are not yet implemented. + fn resolve_expression_location(&self, expression: &HirExpression) -> Option { + match expression { + HirExpression::Ident(ident) => { + let definition_info = self.definition(ident.id); + match definition_info.kind { + DefinitionKind::Function(func_id) => { + Some(self.function_meta(&func_id).location) + } + DefinitionKind::Local(_local_id) => Some(definition_info.location), + _ => None, + } + } + HirExpression::Constructor(expr) => { + let struct_type = &expr.r#type.borrow(); + + eprintln!("\n -> Resolve Constructor {struct_type:?}\n"); + + Some(struct_type.location) + } + HirExpression::MemberAccess(expr_member_access) => { + self.resolve_struct_member_access(expr_member_access) + } + HirExpression::Call(expr_call) => { + let func = expr_call.func; + self.resolve_location(func) + } + + _ => None, + } + } + + /// Resolves the [Location] of the definition for a given [crate::hir_def::expr::HirMemberAccess] + /// This is used to resolve the location of a struct member access. + /// For example, in the expression `foo.bar` we want to resolve the location of `bar` + /// to the location of the definition of `bar` in the struct `foo`. + fn resolve_struct_member_access( + &self, + expr_member_access: &crate::hir_def::expr::HirMemberAccess, + ) -> Option { + let expr_lhs = &expr_member_access.lhs; + let expr_rhs = &expr_member_access.rhs; + + let found_ident = self.nodes.get(expr_lhs.into())?; + + let ident = match found_ident { + Node::Expression(HirExpression::Ident(ident)) => ident, + _ => return None, + }; + + let definition_info = self.definition(ident.id); + + let local_id = match definition_info.kind { + DefinitionKind::Local(Some(local_id)) => local_id, + _ => return None, + }; + + let constructor_expression = match self.nodes.get(local_id.into()) { + Some(Node::Expression(HirExpression::Constructor(constructor_expression))) => { + constructor_expression + } + _ => return None, + }; + + let struct_type = constructor_expression.r#type.borrow(); + let field_names = struct_type.field_names(); + + match field_names.iter().find(|field_name| field_name.0 == expr_rhs.0) { + Some(found) => Some(Location::new(found.span(), struct_type.location.file)), + None => None, + } + } } impl Methods { @@ -1227,8 +1388,10 @@ impl Methods { match interner.function_meta(&method).typ.instantiate(interner).0 { Type::Function(args, _, _) => { if let Some(object) = args.get(0) { - // TODO #3089: This is dangerous! try_unify may commit type bindings even on failure - if object.try_unify(typ).is_ok() { + let mut bindings = TypeBindings::new(); + + if object.try_unify(typ, &mut bindings).is_ok() { + Type::apply_type_bindings(bindings); return Some(method); } } @@ -1242,7 +1405,7 @@ impl Methods { } /// These are the primitive type variants that we support adding methods to -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] enum TypeMethodKey { /// Fields and integers share methods for ease of use. These methods may still /// accept only fields or integers, it is just that their names may not clash. @@ -1281,6 +1444,6 @@ fn get_type_method_key(typ: &Type) -> Option { | Type::Error | Type::NotConstant | Type::Struct(_, _) - | Type::TraitAsType(_) => None, + | Type::TraitAsType(..) => None, } } diff --git a/noir/compiler/noirc_frontend/src/parser/parser.rs b/noir/compiler/noirc_frontend/src/parser/parser.rs index 7f0bf6376c6..660c85759b9 100644 --- a/noir/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/compiler/noirc_frontend/src/parser/parser.rs @@ -414,7 +414,12 @@ fn trait_definition() -> impl NoirParser { .then(trait_body()) .then_ignore(just(Token::RightBrace)) .validate(|(((name, generics), where_clause), items), span, emit| { - emit(ParserError::with_reason(ParserErrorReason::ExperimentalFeature("Traits"), span)); + if !generics.is_empty() { + emit(ParserError::with_reason( + ParserErrorReason::ExperimentalFeature("Generic traits"), + span, + )); + } TopLevelStatement::Trait(NoirTrait { name, generics, where_clause, span, items }) }) } @@ -437,7 +442,13 @@ fn trait_constant_declaration() -> impl NoirParser { .then(parse_type()) .then(optional_default_value()) .then_ignore(just(Token::Semicolon)) - .map(|((name, typ), default_value)| TraitItem::Constant { name, typ, default_value }) + .validate(|((name, typ), default_value), span, emit| { + emit(ParserError::with_reason( + ParserErrorReason::ExperimentalFeature("Associated constants"), + span, + )); + TraitItem::Constant { name, typ, default_value } + }) } /// trait_function_declaration: 'fn' ident generics '(' declaration_parameters ')' function_return_type @@ -544,10 +555,15 @@ fn function_declaration_parameters() -> impl NoirParser impl NoirParser { - keyword(Keyword::Type) - .ignore_then(ident()) - .then_ignore(just(Token::Semicolon)) - .map(|name| TraitItem::Type { name }) + keyword(Keyword::Type).ignore_then(ident()).then_ignore(just(Token::Semicolon)).validate( + |name, span, emit| { + emit(ParserError::with_reason( + ParserErrorReason::ExperimentalFeature("Associated types"), + span, + )); + TraitItem::Type { name } + }, + ) } /// Parses a non-trait implementation, adding a set of methods to a type. @@ -581,11 +597,10 @@ fn trait_implementation() -> impl NoirParser { .then_ignore(just(Token::LeftBrace)) .then(trait_implementation_body()) .then_ignore(just(Token::RightBrace)) - .validate(|args, span, emit| { + .map(|args| { let ((other_args, where_clause), items) = args; let (((impl_generics, trait_name), trait_generics), object_type) = other_args; - emit(ParserError::with_reason(ParserErrorReason::ExperimentalFeature("Traits"), span)); TopLevelStatement::TraitImpl(NoirTraitImpl { impl_generics, trait_name, @@ -616,12 +631,10 @@ fn where_clause() -> impl NoirParser> { trait_bounds: Vec, } - let constraints = parse_type().then_ignore(just(Token::Colon)).then(trait_bounds()).validate( - |(typ, trait_bounds), span, emit| { - emit(ParserError::with_reason(ParserErrorReason::ExperimentalFeature("Traits"), span)); - MultiTraitConstraint { typ, trait_bounds } - }, - ); + let constraints = parse_type() + .then_ignore(just(Token::Colon)) + .then(trait_bounds()) + .map(|(typ, trait_bounds)| MultiTraitConstraint { typ, trait_bounds }); keyword(Keyword::Where) .ignore_then(constraints.separated_by(just(Token::Comma))) @@ -726,21 +739,21 @@ fn token_kind(token_kind: TokenKind) -> impl NoirParser { fn path() -> impl NoirParser { let idents = || ident().separated_by(just(Token::DoubleColon)).at_least(1); - let make_path = |kind| move |segments| Path { segments, kind }; + let make_path = |kind| move |segments, span| Path { segments, kind, span }; let prefix = |key| keyword(key).ignore_then(just(Token::DoubleColon)); - let path_kind = |key, kind| prefix(key).ignore_then(idents()).map(make_path(kind)); + let path_kind = |key, kind| prefix(key).ignore_then(idents()).map_with_span(make_path(kind)); choice(( path_kind(Keyword::Crate, PathKind::Crate), path_kind(Keyword::Dep, PathKind::Dep), - idents().map(make_path(PathKind::Plain)), + idents().map_with_span(make_path(PathKind::Plain)), )) } fn empty_path() -> impl NoirParser { - let make_path = |kind| move |_| Path { segments: Vec::new(), kind }; - let path_kind = |key, kind| keyword(key).map(make_path(kind)); + let make_path = |kind| move |_, span| Path { segments: Vec::new(), kind, span }; + let path_kind = |key, kind| keyword(key).map_with_span(make_path(kind)); choice((path_kind(Keyword::Crate, PathKind::Crate), path_kind(Keyword::Dep, PathKind::Dep))) } @@ -1015,18 +1028,37 @@ fn parse_type_inner( named_type(recursive_type_parser.clone()), named_trait(recursive_type_parser.clone()), array_type(recursive_type_parser.clone()), - recursive_type_parser.clone().delimited_by(just(Token::LeftParen), just(Token::RightParen)), + parenthesized_type(recursive_type_parser.clone()), tuple_type(recursive_type_parser.clone()), function_type(recursive_type_parser.clone()), mutable_reference_type(recursive_type_parser), )) } +fn parenthesized_type( + recursive_type_parser: impl NoirParser, +) -> impl NoirParser { + recursive_type_parser + .delimited_by(just(Token::LeftParen), just(Token::RightParen)) + .map_with_span(|typ, span| UnresolvedType { + typ: UnresolvedTypeData::Parenthesized(Box::new(typ)), + span: span.into(), + }) +} + fn optional_visibility() -> impl NoirParser { - keyword(Keyword::Pub).or_not().map(|opt| match opt { - Some(_) => Visibility::Public, - None => Visibility::Private, - }) + keyword(Keyword::Pub) + .or(keyword(Keyword::CallData)) + .or(keyword(Keyword::ReturnData)) + .or_not() + .map(|opt| match opt { + Some(Token::Keyword(Keyword::Pub)) => Visibility::Public, + Some(Token::Keyword(Keyword::CallData)) | Some(Token::Keyword(Keyword::ReturnData)) => { + Visibility::DataBus + } + None => Visibility::Private, + _ => unreachable!("unexpected token found"), + }) } fn optional_distinctness() -> impl NoirParser { @@ -1087,14 +1119,7 @@ fn int_type() -> impl NoirParser { Err(ParserError::expected_label(ParsingRuleLabel::IntegerType, unexpected, span)) } })) - .validate(|(_, token), span, emit| { - let typ = UnresolvedTypeData::from_int_token(token).with_span(span); - if let UnresolvedTypeData::Integer(crate::Signedness::Signed, _) = &typ.typ { - let reason = ParserErrorReason::ExperimentalFeature("Signed integer types"); - emit(ParserError::with_reason(reason, span)); - } - typ - }) + .map_with_span(|(_, token), span| UnresolvedTypeData::from_int_token(token).with_span(span)) } fn named_type(type_parser: impl NoirParser) -> impl NoirParser { @@ -1177,7 +1202,9 @@ where .ignore_then(type_parser.clone()) .then_ignore(just(Token::RightBracket)) .or_not() - .map_with_span(|t, span| t.unwrap_or_else(|| UnresolvedTypeData::Unit.with_span(span))); + .map_with_span(|t, span| { + t.unwrap_or_else(|| UnresolvedTypeData::Unit.with_span(Span::empty(span.end()))) + }); keyword(Keyword::Fn) .ignore_then(env) @@ -1663,10 +1690,22 @@ fn literal() -> impl NoirParser { }) } +fn literal_with_sign() -> impl NoirParser { + choice(( + literal(), + just(Token::Minus).then(literal()).map(|(_, exp)| match exp { + ExpressionKind::Literal(Literal::Integer(value, sign)) => { + ExpressionKind::Literal(Literal::Integer(value, !sign)) + } + _ => unreachable!(), + }), + )) +} + fn literal_or_collection<'a>( expr_parser: impl ExprParser + 'a, ) -> impl NoirParser + 'a { - choice((literal(), constructor(expr_parser.clone()), array_expr(expr_parser))) + choice((literal_with_sign(), constructor(expr_parser.clone()), array_expr(expr_parser))) } #[cfg(test)] @@ -2243,7 +2282,7 @@ mod test { let hex = parse_with(literal(), "0x05").unwrap(); match (expr_to_lit(int), expr_to_lit(hex)) { - (Literal::Integer(int), Literal::Integer(hex)) => assert_eq!(int, hex), + (Literal::Integer(int, false), Literal::Integer(hex, false)) => assert_eq!(int, hex), _ => unreachable!(), } } diff --git a/noir/compiler/noirc_frontend/src/tests.rs b/noir/compiler/noirc_frontend/src/tests.rs index 13ce71c4616..cd0c34f7e09 100644 --- a/noir/compiler/noirc_frontend/src/tests.rs +++ b/noir/compiler/noirc_frontend/src/tests.rs @@ -9,6 +9,7 @@ mod test { use fm::FileId; + use iter_extended::vecmap; use noirc_errors::Location; use crate::hir::def_collector::dc_crate::CompilationError; @@ -18,10 +19,8 @@ mod test { use crate::hir::resolution::import::PathResolutionError; use crate::hir::type_check::TypeCheckError; use crate::hir::Context; - use crate::macros_api::MacroProcessor; use crate::node_interner::{NodeInterner, StmtId}; - use crate::graph::CrateGraph; use crate::hir::def_collector::dc_crate::DefCollector; use crate::hir_def::expr::HirExpression; use crate::hir_def::stmt::HirStatement; @@ -39,41 +38,33 @@ mod test { errors.iter().any(|(e, _f)| matches!(e, CompilationError::ParseError(_))) } - pub(crate) fn remove_experimental_feature_warnings( - errors: Vec<(CompilationError, FileId)>, - ) -> Vec<(CompilationError, FileId)> { - errors - .iter() - .filter(|(e, _f)| match e.clone() { - CompilationError::ParseError(parser_error) => !matches!( - parser_error.reason(), - Some(ParserErrorReason::ExperimentalFeature(_)) - ), - _ => true, - }) - .cloned() - .collect() + pub(crate) fn remove_experimental_warnings(errors: &mut Vec<(CompilationError, FileId)>) { + errors.retain(|(error, _)| match error { + CompilationError::ParseError(error) => { + !matches!(error.reason(), Some(ParserErrorReason::ExperimentalFeature(..))) + } + _ => true, + }); } pub(crate) fn get_program( src: &str, ) -> (ParsedModule, Context, Vec<(CompilationError, FileId)>) { let root = std::path::Path::new("/"); - let fm = FileManager::new(root, Box::new(|path| std::fs::read_to_string(path))); - //let fm = FileManager::new(root, Box::new(get_non_stdlib_asset)); - let graph = CrateGraph::default(); - let mut context = Context::new(fm, graph); + let fm = FileManager::new(root); + let mut context = Context::new(fm); let root_file_id = FileId::dummy(); let root_crate_id = context.crate_graph.add_crate_root(root_file_id); let (program, parser_errors) = parse_program(src); - let mut errors = remove_experimental_feature_warnings( - parser_errors.iter().cloned().map(|e| (e.into(), root_file_id)).collect(), - ); + let mut errors = vecmap(parser_errors, |e| (e.into(), root_file_id)); + remove_experimental_warnings(&mut errors); + if !has_parser_error(&errors) { // Allocate a default Module for the root, giving it a ModuleId let mut modules: Arena = Arena::default(); let location = Location::new(Default::default(), root_file_id); let root = modules.insert(ModuleData::new(None, location, false)); + let def_map = CrateDefMap { root: LocalModuleId(root), modules, @@ -81,33 +72,20 @@ mod test { extern_prelude: BTreeMap::new(), }; - let empty_macro_processors: Vec<&dyn MacroProcessor> = Vec::new(); - // Now we want to populate the CrateDefMap using the DefCollector errors.extend(DefCollector::collect( def_map, &mut context, program.clone().into_sorted(), root_file_id, - empty_macro_processors, + Vec::new(), // No macro processors )); } (program, context, errors) } pub(crate) fn get_program_errors(src: &str) -> Vec<(CompilationError, FileId)> { - let (_program, _context, errors) = get_program(src); - errors - .iter() - .filter(|(e, _f)| match e.clone() { - CompilationError::ParseError(parser_error) => !matches!( - parser_error.reason(), - Some(ParserErrorReason::ExperimentalFeature(_)) - ), - _ => true, - }) - .cloned() - .collect() + get_program(src).2 } #[test] @@ -462,7 +440,7 @@ mod test { }"; let errors = get_program_errors(src); assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); for (err, _file_id) in errors { match &err { diff --git a/noir/compiler/noirc_printable_type/src/lib.rs b/noir/compiler/noirc_printable_type/src/lib.rs index 1c4f597add2..e10e400b0db 100644 --- a/noir/compiler/noirc_printable_type/src/lib.rs +++ b/noir/compiler/noirc_printable_type/src/lib.rs @@ -168,15 +168,24 @@ fn fetch_printable_type( fn to_string(value: &PrintableValue, typ: &PrintableType) -> Option { let mut output = String::new(); match (value, typ) { - ( - PrintableValue::Field(f), - PrintableType::Field - // TODO(#2401): We should print the sign for these and probably print normal integers instead of field strings - | PrintableType::SignedInteger { .. } - | PrintableType::UnsignedInteger { .. }, - ) => { + (PrintableValue::Field(f), PrintableType::Field) => { output.push_str(&format_field_string(*f)); } + (PrintableValue::Field(f), PrintableType::UnsignedInteger { width }) => { + let uint_cast = f.to_u128() & ((1 << width) - 1); // Retain the lower 'width' bits + output.push_str(&uint_cast.to_string()); + } + (PrintableValue::Field(f), PrintableType::SignedInteger { width }) => { + let mut uint = f.to_u128(); // Interpret as uint + + // Extract sign relative to width of input + if (uint >> (width - 1)) == 1 { + output.push('-'); + uint = (uint ^ ((1 << width) - 1)) + 1; // Two's complement relative to width of input + } + + output.push_str(&uint.to_string()); + } (PrintableValue::Field(f), PrintableType::Boolean) => { if f.is_one() { output.push_str("true"); @@ -187,8 +196,11 @@ fn to_string(value: &PrintableValue, typ: &PrintableType) -> Option { (PrintableValue::Vec(vector), PrintableType::Array { typ, .. }) => { output.push('['); let mut values = vector.iter().peekable(); - while let Some(value) = values.next() { - output.push_str(&format!("{}", PrintableValueDisplay::Plain(value.clone(), *typ.clone()))); + while let Some(value) = values.next() { + output.push_str(&format!( + "{}", + PrintableValueDisplay::Plain(value.clone(), *typ.clone()) + )); if values.peek().is_some() { output.push_str(", "); } @@ -204,9 +216,12 @@ fn to_string(value: &PrintableValue, typ: &PrintableType) -> Option { output.push_str(&format!("{name} {{ ")); let mut fields = fields.iter().peekable(); - while let Some((key, field_type)) = fields.next() { + while let Some((key, field_type)) = fields.next() { let value = &map[key]; - output.push_str(&format!("{key}: {}", PrintableValueDisplay::Plain(value.clone(), field_type.clone()))); + output.push_str(&format!( + "{key}: {}", + PrintableValueDisplay::Plain(value.clone(), field_type.clone()) + )); if fields.peek().is_some() { output.push_str(", "); } @@ -215,7 +230,7 @@ fn to_string(value: &PrintableValue, typ: &PrintableType) -> Option { output.push_str(" }"); } - _ => return None + _ => return None, }; Some(output) diff --git a/noir/compiler/source-resolver/.eslintrc.js b/noir/compiler/source-resolver/.eslintrc.js deleted file mode 100644 index 33335c2a877..00000000000 --- a/noir/compiler/source-resolver/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ["../../.eslintrc.js"], -}; diff --git a/noir/compiler/source-resolver/lib-node/index.js b/noir/compiler/source-resolver/lib-node/index.js new file mode 100644 index 00000000000..7de637b6853 --- /dev/null +++ b/noir/compiler/source-resolver/lib-node/index.js @@ -0,0 +1,32 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.initializeResolver = exports.read_file = void 0; +let resolveFunction = null; +const read_file = function (source_id) { + if (resolveFunction) { + const result = resolveFunction(source_id); + if (typeof result === 'string') { + return result; + } + else { + throw new Error('Noir source resolver function MUST return String synchronously. Are you trying to return anything else, eg. `Promise`?'); + } + } + else { + throw new Error('Not yet initialized. Use initializeResolver(() => string)'); + } +}; +exports.read_file = read_file; +function initialize(noir_resolver) { + if (typeof noir_resolver === 'function') { + return noir_resolver; + } + else { + throw new Error('Provided Noir Resolver is not a function, hint: use function(module_id) => NoirSource as second parameter'); + } +} +function initializeResolver(resolver) { + resolveFunction = initialize(resolver); +} +exports.initializeResolver = initializeResolver; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/noir/compiler/source-resolver/lib-node/index.js.map b/noir/compiler/source-resolver/lib-node/index.js.map new file mode 100644 index 00000000000..4ac7301ddc9 --- /dev/null +++ b/noir/compiler/source-resolver/lib-node/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,IAAI,eAAe,GAA2C,IAAI,CAAC;AAE5D,MAAM,SAAS,GAAG,UAAU,SAAiB;IAClD,IAAI,eAAe,EAAE;QACnB,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAE1C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC9B,OAAO,MAAM,CAAC;SACf;aAAM;YACL,MAAM,IAAI,KAAK,CACb,wHAAwH,CACzH,CAAC;SACH;KACF;SAAM;QACL,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;KAC9E;AACH,CAAC,CAAC;AAdW,QAAA,SAAS,aAcpB;AAEF,SAAS,UAAU,CAAC,aAA4C;IAC9D,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE;QACvC,OAAO,aAAa,CAAC;KACtB;SAAM;QACL,MAAM,IAAI,KAAK,CACb,2GAA2G,CAC5G,CAAC;KACH;AACH,CAAC;AAED,SAAgB,kBAAkB,CAAC,QAAuC;IACxE,eAAe,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC;AAFD,gDAEC"} \ No newline at end of file diff --git a/noir/compiler/source-resolver/lib-node/index_node.js b/noir/compiler/source-resolver/lib-node/index_node.js new file mode 100644 index 00000000000..7d54737ce49 --- /dev/null +++ b/noir/compiler/source-resolver/lib-node/index_node.js @@ -0,0 +1,20 @@ +"use strict"; +/// +Object.defineProperty(exports, "__esModule", { value: true }); +exports.read_file = exports.initializeResolver = void 0; +const index_js_1 = require("./index.js"); +Object.defineProperty(exports, "initializeResolver", { enumerable: true, get: function () { return index_js_1.initializeResolver; } }); +Object.defineProperty(exports, "read_file", { enumerable: true, get: function () { return index_js_1.read_file; } }); +(0, index_js_1.initializeResolver)((source_id) => { + let fileContent = ''; + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const fs = require('fs'); + fileContent = fs.readFileSync(source_id, { encoding: 'utf8' }); + } + catch (e) { + console.log(e); + } + return fileContent; +}); +//# sourceMappingURL=index_node.js.map \ No newline at end of file diff --git a/noir/compiler/source-resolver/lib-node/index_node.js.map b/noir/compiler/source-resolver/lib-node/index_node.js.map new file mode 100644 index 00000000000..920818232c3 --- /dev/null +++ b/noir/compiler/source-resolver/lib-node/index_node.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index_node.js","sourceRoot":"","sources":["../src/index_node.ts"],"names":[],"mappings":";AAAA,8BAA8B;;;AAE9B,yCAA2D;AAclD,mGAdA,6BAAkB,OAcA;AAAE,0FAdA,oBAAS,OAcA;AAZtC,IAAA,6BAAkB,EAAC,CAAC,SAAiB,EAAE,EAAE;IACvC,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI;QACF,8DAA8D;QAC9D,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACzB,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAW,CAAC;KAC1E;IAAC,OAAO,CAAC,EAAE;QACV,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAChB;IACD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/noir/compiler/source-resolver/lib/index.js b/noir/compiler/source-resolver/lib/index.js new file mode 100644 index 00000000000..079b4460592 --- /dev/null +++ b/noir/compiler/source-resolver/lib/index.js @@ -0,0 +1,27 @@ +let resolveFunction = null; +export const read_file = function (source_id) { + if (resolveFunction) { + const result = resolveFunction(source_id); + if (typeof result === 'string') { + return result; + } + else { + throw new Error('Noir source resolver function MUST return String synchronously. Are you trying to return anything else, eg. `Promise`?'); + } + } + else { + throw new Error('Not yet initialized. Use initializeResolver(() => string)'); + } +}; +function initialize(noir_resolver) { + if (typeof noir_resolver === 'function') { + return noir_resolver; + } + else { + throw new Error('Provided Noir Resolver is not a function, hint: use function(module_id) => NoirSource as second parameter'); + } +} +export function initializeResolver(resolver) { + resolveFunction = initialize(resolver); +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/noir/compiler/source-resolver/lib/index.js.map b/noir/compiler/source-resolver/lib/index.js.map new file mode 100644 index 00000000000..e62ae1e4c8a --- /dev/null +++ b/noir/compiler/source-resolver/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,IAAI,eAAe,GAA2C,IAAI,CAAC;AAEnE,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,SAAiB;IAClD,IAAI,eAAe,EAAE;QACnB,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAE1C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC9B,OAAO,MAAM,CAAC;SACf;aAAM;YACL,MAAM,IAAI,KAAK,CACb,wHAAwH,CACzH,CAAC;SACH;KACF;SAAM;QACL,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;KAC9E;AACH,CAAC,CAAC;AAEF,SAAS,UAAU,CAAC,aAA4C;IAC9D,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE;QACvC,OAAO,aAAa,CAAC;KACtB;SAAM;QACL,MAAM,IAAI,KAAK,CACb,2GAA2G,CAC5G,CAAC;KACH;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAuC;IACxE,eAAe,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC"} \ No newline at end of file diff --git a/noir/compiler/source-resolver/package.json b/noir/compiler/source-resolver/package.json deleted file mode 100644 index 85d6c4343aa..00000000000 --- a/noir/compiler/source-resolver/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@noir-lang/source-resolver", - "version": "0.19.4", - "license": "MIT", - "main": "./lib-node/index_node.js", - "types": "./types/index_node.d.ts", - "module": "./lib/index.js", - "browser": "./lib/index.js", - "exports": { - ".": { - "require": "./lib-node/index_node.js", - "import": "./lib/index.js" - } - }, - "repository": { - "type": "git", - "url": "https://github.com/noir-lang/noir.git" - }, - "scripts": { - "clean-modules": "rm -rf lib", - "build:node": "tsc -p tsconfig.cjs.json", - "build:web": "tsc -p tsconfig.esm.json", - "build": "npm run clean-modules && npm run build:node && npm run build:web && npm run generate-types", - "test": "ava", - "generate-types": "tsc src/*.ts --declaration --emitDeclarationOnly --outDir types", - "clean": "rm -rf ./lib ./lib-node", - "nightly:version": "jq --arg new_version \"-$(git rev-parse --short HEAD)$1\" '.version = .version + $new_version' package.json > package-tmp.json && mv package-tmp.json package.json", - "publish": "echo 📡 publishing `$npm_package_name` && yarn npm publish", - "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" - }, - "devDependencies": { - "@types/node": "^20.5.7", - "ava": "^5.2.0", - "typescript": "4.9.4" - }, - "files": [ - "lib", - "lib-node", - "src", - "types", - "package.json" - ] -} diff --git a/noir/compiler/source-resolver/src/index.ts b/noir/compiler/source-resolver/src/index.ts deleted file mode 100644 index 3498c195fbd..00000000000 --- a/noir/compiler/source-resolver/src/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -let resolveFunction: ((source_id: string) => string) | null = null; - -export const read_file = function (source_id: string): string { - if (resolveFunction) { - const result = resolveFunction(source_id); - - if (typeof result === 'string') { - return result; - } else { - throw new Error( - 'Noir source resolver function MUST return String synchronously. Are you trying to return anything else, eg. `Promise`?', - ); - } - } else { - throw new Error('Not yet initialized. Use initializeResolver(() => string)'); - } -}; - -function initialize(noir_resolver: (source_id: string) => string): (source_id: string) => string { - if (typeof noir_resolver === 'function') { - return noir_resolver; - } else { - throw new Error( - 'Provided Noir Resolver is not a function, hint: use function(module_id) => NoirSource as second parameter', - ); - } -} - -export function initializeResolver(resolver: (source_id: string) => string): void { - resolveFunction = initialize(resolver); -} diff --git a/noir/compiler/source-resolver/src/index_node.ts b/noir/compiler/source-resolver/src/index_node.ts deleted file mode 100644 index 14b7efd30c5..00000000000 --- a/noir/compiler/source-resolver/src/index_node.ts +++ /dev/null @@ -1,17 +0,0 @@ -/// - -import { initializeResolver, read_file } from './index.js'; - -initializeResolver((source_id: string) => { - let fileContent = ''; - try { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const fs = require('fs'); - fileContent = fs.readFileSync(source_id, { encoding: 'utf8' }) as string; - } catch (e) { - console.log(e); - } - return fileContent; -}); - -export { initializeResolver, read_file }; diff --git a/noir/compiler/source-resolver/test/cjs_initialization.test.cjs b/noir/compiler/source-resolver/test/cjs_initialization.test.cjs deleted file mode 100644 index 1dc7784fa40..00000000000 --- a/noir/compiler/source-resolver/test/cjs_initialization.test.cjs +++ /dev/null @@ -1,51 +0,0 @@ -const test = require('ava'); - -const { initializeResolver, read_file } = require("../lib-node/index_node.js"); - -test('It reads file from file system within read_file using default implementation.', t => { - - const readResult = read_file("./package.json"); - - t.assert(readResult, "return from `read_file` should by truthy"); - -}); - -test('It calls function from initializer within read_file function.', t => { - - const RESULT_RESPONSE = "TEST"; - - initializeResolver((source) => { - return source; - }); - - const readResult = read_file(RESULT_RESPONSE); - - t.is(readResult, RESULT_RESPONSE); - -}); - -test('It communicates error when resolver returns non-String to read_file function.', t => { - - const RESULT_RESPONSE = "TEST"; - - initializeResolver((source) => { - return Promise.resolve(source); - }); - - const error = t.throws(() => { - read_file(RESULT_RESPONSE); - }, { instanceOf: Error }); - - t.is(error.message, 'Noir source resolver function MUST return String synchronously. Are you trying to return anything else, eg. `Promise`?'); - -}); - -test('It communicates error when resolver is initialized to anything but a function.', t => { - - const error = t.throws(() => { - initializeResolver(null); - }, { instanceOf: Error }); - - t.is(error.message, 'Provided Noir Resolver is not a function, hint: use function(module_id) => NoirSource as second parameter'); - -}); diff --git a/noir/compiler/source-resolver/test/esm_initialization.test.mjs b/noir/compiler/source-resolver/test/esm_initialization.test.mjs deleted file mode 100644 index 197b48e48d0..00000000000 --- a/noir/compiler/source-resolver/test/esm_initialization.test.mjs +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Below tests are commented because they require - * "type": "module", in package.json - * Seems that both CJS and MJS modes are not going to work. -*/ -import test from 'ava'; - -import { initializeResolver, read_file } from "../lib-node/index.js"; - -test('It communicates error when read_file was called before initializeResolver.', t => { - - const error = t.throws(() => { - const readResult = read_file("./package.json"); - }, { instanceOf: Error }); - - t.is(error.message, 'Not yet initialized. Use initializeResolver(() => string)'); - -}); - -test('It calls function from initializer within read_file function.', t => { - - const RESULT_RESPONSE = "TEST"; - - initializeResolver((source) => { - return source; - }); - - const readResult = read_file(RESULT_RESPONSE); - - t.is(readResult, RESULT_RESPONSE); - -}); - -test('It communicates error when resolver returns non-String to read_file function.', t => { - - const RESULT_RESPONSE = "TEST"; - - initializeResolver((source) => { - return Promise.resolve(source); - }); - - const error = t.throws(() => { - read_file(RESULT_RESPONSE); - }, { instanceOf: Error }); - - t.is(error.message, 'Noir source resolver function MUST return String synchronously. Are you trying to return anything else, eg. `Promise`?'); - -}); - -test('It communicates error when resolver is initialized to anything but a function.', t => { - - const error = t.throws(() => { - initializeResolver(null); - }, { instanceOf: Error }); - - t.is(error.message, 'Provided Noir Resolver is not a function, hint: use function(module_id) => NoirSource as second parameter'); - -}); diff --git a/noir/compiler/source-resolver/tsconfig.cjs.json b/noir/compiler/source-resolver/tsconfig.cjs.json deleted file mode 100644 index 51863a34cec..00000000000 --- a/noir/compiler/source-resolver/tsconfig.cjs.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "es2018", - "moduleResolution": "node", - "outDir": "lib-node", - "module": "commonjs", - "strict": true, - "esModuleInterop": true, - "noImplicitAny": true, - "removeComments": false, - "preserveConstEnums": true, - "sourceMap": true, - "importHelpers": true - }, - "include": ["src"] -} diff --git a/noir/compiler/source-resolver/tsconfig.esm.json b/noir/compiler/source-resolver/tsconfig.esm.json deleted file mode 100644 index dcf4441c4ad..00000000000 --- a/noir/compiler/source-resolver/tsconfig.esm.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "es2018", - "moduleResolution": "node", - "outDir": "lib", - "module": "ES6", - "strict": true, - "esModuleInterop": true, - "noImplicitAny": true, - "removeComments": false, - "preserveConstEnums": true, - "sourceMap": true, - "importHelpers": true - }, - "include": ["src/index.ts"] -} diff --git a/noir/compiler/source-resolver/types/index.d.ts b/noir/compiler/source-resolver/types/index.d.ts deleted file mode 100644 index a17f7bc36bb..00000000000 --- a/noir/compiler/source-resolver/types/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export declare const read_file: (source_id: string) => string; -export declare function initializeResolver(resolver: (source_id: string) => string): void; diff --git a/noir/compiler/source-resolver/types/index_node.d.ts b/noir/compiler/source-resolver/types/index_node.d.ts deleted file mode 100644 index 3a109e47e73..00000000000 --- a/noir/compiler/source-resolver/types/index_node.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { initializeResolver, read_file } from './index.js'; -export { initializeResolver, read_file }; diff --git a/noir/compiler/wasm/Cargo.toml b/noir/compiler/wasm/Cargo.toml index 9ece26c6df4..58ad7764fdc 100644 --- a/noir/compiler/wasm/Cargo.toml +++ b/noir/compiler/wasm/Cargo.toml @@ -21,11 +21,10 @@ noirc_errors.workspace = true wasm-bindgen.workspace = true serde.workspace = true js-sys.workspace = true -cfg-if.workspace = true console_error_panic_hook.workspace = true gloo-utils.workspace = true +log.workspace = true -log = "0.4.17" wasm-logger = "0.2.0" # This is an unused dependency, we are adding it diff --git a/noir/compiler/wasm/package.json b/noir/compiler/wasm/package.json index eb1163ad62b..352142eb3e3 100644 --- a/noir/compiler/wasm/package.json +++ b/noir/compiler/wasm/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.19.4", + "version": "0.22.0", "license": "(MIT OR Apache-2.0)", "main": "./nodejs/noir_wasm.js", "types": "./web/noir_wasm.d.ts", @@ -30,9 +30,6 @@ "build:nix": "nix build -L .#noir_wasm", "install:from:nix": "yarn clean && yarn build:nix && cp -rL ./result/noir_wasm/nodejs ./ && cp -rL ./result/noir_wasm/web ./" }, - "peerDependencies": { - "@noir-lang/source-resolver": "workspace:*" - }, "devDependencies": { "@esm-bundle/chai": "^4.3.4-fix.0", "@web/dev-server-esbuild": "^0.3.6", diff --git a/noir/compiler/wasm/src/compile.rs b/noir/compiler/wasm/src/compile.rs index e7fd3dd5212..4012effd947 100644 --- a/noir/compiler/wasm/src/compile.rs +++ b/noir/compiler/wasm/src/compile.rs @@ -11,7 +11,7 @@ use noirc_driver::{ CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, }; use noirc_frontend::{ - graph::{CrateGraph, CrateId, CrateName}, + graph::{CrateId, CrateName}, hir::Context, }; use serde::Deserialize; @@ -20,8 +20,6 @@ use wasm_bindgen::prelude::*; use crate::errors::{CompileError, JsCompileError}; -const BACKEND_IDENTIFIER: &str = "acvm-backend-barretenberg"; - #[wasm_bindgen(typescript_custom_section)] const DEPENDENCY_GRAPH: &'static str = r#" export type DependencyGraph = { @@ -32,14 +30,12 @@ export type DependencyGraph = { export type CompiledContract = { noir_version: string; name: string; - backend: string; functions: Array; events: Array; }; export type CompiledProgram = { noir_version: string; - backend: string; abi: any; bytecode: string; } @@ -120,10 +116,34 @@ impl JsCompileResult { } } -#[derive(Deserialize)] -struct DependencyGraph { - root_dependencies: Vec, - library_dependencies: HashMap>, +#[derive(Deserialize, Default)] +pub(crate) struct DependencyGraph { + pub(crate) root_dependencies: Vec, + pub(crate) library_dependencies: HashMap>, +} +#[wasm_bindgen] +// This is a map containing the paths of all of the files in the entry-point crate and +// the transitive dependencies of the entry-point crate. +// +// This is for all intents and purposes the file system that the compiler will use to resolve/compile +// files in the crate being compiled and its dependencies. +#[derive(Deserialize, Default)] +pub struct PathToFileSourceMap(pub(crate) HashMap); + +#[wasm_bindgen] +impl PathToFileSourceMap { + #[wasm_bindgen(constructor)] + pub fn new() -> PathToFileSourceMap { + PathToFileSourceMap::default() + } + // Inserts a path and its source code into the map. + // + // Returns true, if there was already source code in the map for the given path + pub fn add_source_code(&mut self, path: String, source_code: String) -> bool { + let path_buf = Path::new(&path).to_path_buf(); + let old_value = self.0.insert(path_buf, source_code); + old_value.is_some() + } } pub enum CompileResult { @@ -136,6 +156,7 @@ pub fn compile( entry_point: String, contracts: Option, dependency_graph: Option, + file_source_map: PathToFileSourceMap, ) -> Result { console_error_panic_hook::set_once(); @@ -146,10 +167,9 @@ pub fn compile( DependencyGraph { root_dependencies: vec![], library_dependencies: HashMap::new() } }; - let root = Path::new("/"); - let fm = FileManager::new(root, Box::new(get_non_stdlib_asset)); - let graph = CrateGraph::default(); - let mut context = Context::new(fm, graph); + let fm = file_manager_with_source_map(file_source_map); + + let mut context = Context::new(fm); let path = Path::new(&entry_point); let crate_id = prepare_crate(&mut context, path); @@ -158,10 +178,8 @@ pub fn compile( let compile_options = CompileOptions::default(); - // For now we default to plonk width = 3, though we can add it as a parameter - let np_language = acvm::Language::PLONKCSat { width: 3 }; - #[allow(deprecated)] - let is_opcode_supported = acvm::pwg::default_is_opcode_supported(np_language); + // For now we default to a bounded width of 3, though we can add it as a parameter + let expression_width = acvm::ExpressionWidth::Bounded { width: 3 }; if contracts.unwrap_or_default() { let compiled_contract = compile_contract(&mut context, crate_id, &compile_options) @@ -174,9 +192,7 @@ pub fn compile( })? .0; - let optimized_contract = - nargo::ops::optimize_contract(compiled_contract, np_language, &is_opcode_supported) - .expect("Contract optimization failed"); + let optimized_contract = nargo::ops::optimize_contract(compiled_contract, expression_width); let compile_output = preprocess_contract(optimized_contract); Ok(JsCompileResult::new(compile_output)) @@ -191,15 +207,38 @@ pub fn compile( })? .0; - let optimized_program = - nargo::ops::optimize_program(compiled_program, np_language, &is_opcode_supported) - .expect("Program optimization failed"); + let optimized_program = nargo::ops::optimize_program(compiled_program, expression_width); let compile_output = preprocess_program(optimized_program); Ok(JsCompileResult::new(compile_output)) } } +// Create a new FileManager with the given source map +// +// Note: Use this method whenever initializing a new FileManager +// to ensure that the file manager contains all of the files +// that one intends the compiler to use. +// +// For all intents and purposes, the file manager being returned +// should be considered as immutable. +pub(crate) fn file_manager_with_source_map(source_map: PathToFileSourceMap) -> FileManager { + let root = Path::new(""); + let mut fm = FileManager::new(root); + + for (path, source) in source_map.0 { + fm.add_file_with_source(path.as_path(), source); + } + + fm +} + +// Root dependencies are dependencies which the entry-point package relies upon. +// These will be in the Nargo.toml of the package being compiled. +// +// Library dependencies are transitive dependencies; for example, if the entry-point relies +// upon some library `lib1`. Then the packages that `lib1` depend upon will be placed in the +// `library_dependencies` list and the `lib1` will be placed in the `root_dependencies` list. fn process_dependency_graph(context: &mut Context, dependency_graph: DependencyGraph) { let mut crate_names: HashMap<&CrateName, CrateId> = HashMap::new(); @@ -232,7 +271,7 @@ fn add_noir_lib(context: &mut Context, library_name: &CrateName) -> CrateId { prepare_dependency(context, &path_to_lib) } -fn preprocess_program(program: CompiledProgram) -> CompileResult { +pub(crate) fn preprocess_program(program: CompiledProgram) -> CompileResult { let debug_artifact = DebugArtifact { debug_symbols: vec![program.debug], file_map: program.file_map, @@ -241,7 +280,6 @@ fn preprocess_program(program: CompiledProgram) -> CompileResult { let preprocessed_program = PreprocessedProgram { hash: program.hash, - backend: String::from(BACKEND_IDENTIFIER), abi: program.abi, noir_version: NOIR_ARTIFACT_VERSION_STRING.to_string(), bytecode: program.circuit, @@ -250,7 +288,8 @@ fn preprocess_program(program: CompiledProgram) -> CompileResult { CompileResult::Program { program: preprocessed_program, debug: debug_artifact } } -fn preprocess_contract(contract: CompiledContract) -> CompileResult { +// TODO: This method should not be doing so much, most of this should be done in nargo or the driver +pub(crate) fn preprocess_contract(contract: CompiledContract) -> CompileResult { let debug_artifact = DebugArtifact { debug_symbols: contract.functions.iter().map(|function| function.debug.clone()).collect(), file_map: contract.file_map, @@ -271,7 +310,6 @@ fn preprocess_contract(contract: CompiledContract) -> CompileResult { let preprocessed_contract = PreprocessedContract { noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: contract.name, - backend: String::from(BACKEND_IDENTIFIER), functions: preprocessed_functions, events: contract.events, }; @@ -279,51 +317,22 @@ fn preprocess_contract(contract: CompiledContract) -> CompileResult { CompileResult::Contract { contract: preprocessed_contract, debug: debug_artifact } } -cfg_if::cfg_if! { - if #[cfg(target_os = "wasi")] { - fn get_non_stdlib_asset(path_to_file: &Path) -> std::io::Result { - std::fs::read_to_string(path_to_file) - } - } else { - use std::io::{Error, ErrorKind}; - - #[wasm_bindgen(module = "@noir-lang/source-resolver")] - extern "C" { - #[wasm_bindgen(catch)] - fn read_file(path: &str) -> Result; - } - - fn get_non_stdlib_asset(path_to_file: &Path) -> std::io::Result { - let path_str = path_to_file.to_str().unwrap(); - match read_file(path_str) { - Ok(buffer) => Ok(buffer), - Err(_) => Err(Error::new(ErrorKind::Other, "could not read file using wasm")), - } - } - } -} - #[cfg(test)] mod test { - use fm::FileManager; use noirc_driver::prepare_crate; - use noirc_frontend::{ - graph::{CrateGraph, CrateName}, - hir::Context, - }; + use noirc_frontend::{graph::CrateName, hir::Context}; - use super::{process_dependency_graph, DependencyGraph}; - use std::{collections::HashMap, path::Path}; + use crate::compile::PathToFileSourceMap; - fn mock_get_non_stdlib_asset(_path_to_file: &Path) -> std::io::Result { - Ok("".to_string()) - } + use super::{file_manager_with_source_map, process_dependency_graph, DependencyGraph}; + use std::{collections::HashMap, path::Path}; - fn setup_test_context() -> Context { - let fm = FileManager::new(Path::new("/"), Box::new(mock_get_non_stdlib_asset)); - let graph = CrateGraph::default(); - let mut context = Context::new(fm, graph); + fn setup_test_context(source_map: PathToFileSourceMap) -> Context { + let mut fm = file_manager_with_source_map(source_map); + // Add this due to us calling prepare_crate on "/main.nr" below + fm.add_file_with_source(Path::new("/main.nr"), "fn foo() {}".to_string()); + let mut context = Context::new(fm); prepare_crate(&mut context, Path::new("/main.nr")); context @@ -335,10 +344,12 @@ mod test { #[test] fn test_works_with_empty_dependency_graph() { - let mut context = setup_test_context(); let dependency_graph = DependencyGraph { root_dependencies: vec![], library_dependencies: HashMap::new() }; + let source_map = PathToFileSourceMap::default(); + let mut context = setup_test_context(source_map); + process_dependency_graph(&mut context, dependency_graph); // one stdlib + one root crate @@ -347,12 +358,19 @@ mod test { #[test] fn test_works_with_root_dependencies() { - let mut context = setup_test_context(); let dependency_graph = DependencyGraph { root_dependencies: vec![crate_name("lib1")], library_dependencies: HashMap::new(), }; + let source_map = PathToFileSourceMap( + vec![(Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string())] + .into_iter() + .collect(), + ); + + let mut context = setup_test_context(source_map); + process_dependency_graph(&mut context, dependency_graph); assert_eq!(context.crate_graph.number_of_crates(), 3); @@ -360,12 +378,18 @@ mod test { #[test] fn test_works_with_duplicate_root_dependencies() { - let mut context = setup_test_context(); let dependency_graph = DependencyGraph { root_dependencies: vec![crate_name("lib1"), crate_name("lib1")], library_dependencies: HashMap::new(), }; + let source_map = PathToFileSourceMap( + vec![(Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string())] + .into_iter() + .collect(), + ); + let mut context = setup_test_context(source_map); + process_dependency_graph(&mut context, dependency_graph); assert_eq!(context.crate_graph.number_of_crates(), 3); @@ -373,7 +397,6 @@ mod test { #[test] fn test_works_with_transitive_dependencies() { - let mut context = setup_test_context(); let dependency_graph = DependencyGraph { root_dependencies: vec![crate_name("lib1")], library_dependencies: HashMap::from([ @@ -382,6 +405,17 @@ mod test { ]), }; + let source_map = PathToFileSourceMap( + vec![ + (Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib2/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib3/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + ] + .into_iter() + .collect(), + ); + + let mut context = setup_test_context(source_map); process_dependency_graph(&mut context, dependency_graph); assert_eq!(context.crate_graph.number_of_crates(), 5); @@ -389,12 +423,22 @@ mod test { #[test] fn test_works_with_missing_dependencies() { - let mut context = setup_test_context(); let dependency_graph = DependencyGraph { root_dependencies: vec![crate_name("lib1")], library_dependencies: HashMap::from([(crate_name("lib2"), vec![crate_name("lib3")])]), }; + let source_map = PathToFileSourceMap( + vec![ + (Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib2/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib3/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + ] + .into_iter() + .collect(), + ); + + let mut context = setup_test_context(source_map); process_dependency_graph(&mut context, dependency_graph); assert_eq!(context.crate_graph.number_of_crates(), 5); diff --git a/noir/compiler/wasm/src/compile_new.rs b/noir/compiler/wasm/src/compile_new.rs new file mode 100644 index 00000000000..cd09d0fcc49 --- /dev/null +++ b/noir/compiler/wasm/src/compile_new.rs @@ -0,0 +1,334 @@ +use crate::compile::{ + file_manager_with_source_map, preprocess_contract, preprocess_program, JsCompileResult, + PathToFileSourceMap, +}; +use crate::errors::{CompileError, JsCompileError}; +use noirc_driver::{ + add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions, +}; +use noirc_frontend::{ + graph::{CrateId, CrateName}, + hir::Context, +}; +use std::path::Path; +use wasm_bindgen::prelude::wasm_bindgen; + +/// This is a wrapper class that is wasm-bindgen compatible +/// We do not use js_name and rename it like CrateId because +/// then the impl block is not picked up in javascript. +#[wasm_bindgen] +pub struct CompilerContext { + context: Context, +} + +#[wasm_bindgen(js_name = "CrateId")] +#[derive(Debug, Copy, Clone)] +pub struct CrateIDWrapper(CrateId); + +#[wasm_bindgen] +impl CompilerContext { + #[wasm_bindgen(constructor)] + pub fn new(source_map: PathToFileSourceMap) -> CompilerContext { + console_error_panic_hook::set_once(); + + let fm = file_manager_with_source_map(source_map); + CompilerContext { context: Context::new(fm) } + } + + #[cfg(test)] + pub(crate) fn crate_graph(&self) -> &noirc_frontend::graph::CrateGraph { + &self.context.crate_graph + } + #[cfg(test)] + pub(crate) fn root_crate_id(&self) -> CrateIDWrapper { + CrateIDWrapper(*self.context.root_crate_id()) + } + + // Processes the root crate by adding it to the package graph and automatically + // importing the stdlib as a dependency for it. + // + // Its ID in the package graph is returned + pub fn process_root_crate(&mut self, path_to_crate: String) -> CrateIDWrapper { + let path_to_crate = Path::new(&path_to_crate); + + // Adds the root crate to the crate graph and returns its crate id + CrateIDWrapper(prepare_crate(&mut self.context, path_to_crate)) + } + + pub fn process_dependency_crate(&mut self, path_to_crate: String) -> CrateIDWrapper { + let path_to_crate = Path::new(&path_to_crate); + + // Adds the root crate to the crate graph and returns its crate id + CrateIDWrapper(prepare_dependency(&mut self.context, path_to_crate)) + } + + // Adds a named edge from one crate to the other. + // + // For example, lets say we have two crates CrateId1 and CrateId2 + // This function will add an edge from CrateId1 to CrateId2 and the edge will be named `crate_name` + // + // This essentially says that CrateId1 depends on CrateId2 and the dependency is named `crate_name` + // + // We pass references to &CrateIdWrapper even though it is a copy because Rust's move semantics are + // not respected once we use javascript. ie it will actually allocated a new object in javascript + // then deallocate that object if we do not pass as a reference. + pub fn add_dependency_edge( + &mut self, + crate_name: String, + from: &CrateIDWrapper, + to: &CrateIDWrapper, + ) { + let parsed_crate_name: CrateName = crate_name + .parse() + .unwrap_or_else(|_| panic!("Failed to parse crate name {}", crate_name)); + add_dep(&mut self.context, from.0, to.0, parsed_crate_name); + } + + pub fn compile_program( + mut self, + program_width: usize, + ) -> Result { + let compile_options = CompileOptions::default(); + let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + + let root_crate_id = *self.context.root_crate_id(); + + let compiled_program = + compile_main(&mut self.context, root_crate_id, &compile_options, None, true) + .map_err(|errs| { + CompileError::with_file_diagnostics( + "Failed to compile program", + errs, + &self.context.file_manager, + ) + })? + .0; + + let optimized_program = nargo::ops::optimize_program(compiled_program, np_language); + + let compile_output = preprocess_program(optimized_program); + Ok(JsCompileResult::new(compile_output)) + } + + pub fn compile_contract( + mut self, + program_width: usize, + ) -> Result { + let compile_options = CompileOptions::default(); + let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let root_crate_id = *self.context.root_crate_id(); + + let compiled_contract = + compile_contract(&mut self.context, root_crate_id, &compile_options) + .map_err(|errs| { + CompileError::with_file_diagnostics( + "Failed to compile contract", + errs, + &self.context.file_manager, + ) + })? + .0; + + let optimized_contract = nargo::ops::optimize_contract(compiled_contract, np_language); + + let compile_output = preprocess_contract(optimized_contract); + Ok(JsCompileResult::new(compile_output)) + } +} + +/// This is a method that exposes the same API as `compile` +/// But uses the Context based APi internally +#[wasm_bindgen] +pub fn compile_( + entry_point: String, + contracts: Option, + dependency_graph: Option, + file_source_map: PathToFileSourceMap, +) -> Result { + use std::collections::HashMap; + + console_error_panic_hook::set_once(); + + let dependency_graph: crate::compile::DependencyGraph = + if let Some(dependency_graph) = dependency_graph { + ::into_serde( + &wasm_bindgen::JsValue::from(dependency_graph), + ) + .map_err(|err| err.to_string())? + } else { + crate::compile::DependencyGraph::default() + }; + + let mut compiler_context = CompilerContext::new(file_source_map); + + // Set the root crate + let root_id = compiler_context.process_root_crate(entry_point.clone()); + + let add_noir_lib = |context: &mut CompilerContext, lib_name: &CrateName| -> CrateIDWrapper { + let lib_name_string = lib_name.to_string(); + let path_to_lib = Path::new(&lib_name_string) + .join("lib.nr") + .to_str() + .expect("paths are expected to be valid utf-8") + .to_string(); + context.process_dependency_crate(path_to_lib) + }; + + // Add the dependency graph + let mut crate_names: HashMap = HashMap::new(); + // + // Process the direct dependencies of the root + for lib_name in dependency_graph.root_dependencies { + let lib_name_string = lib_name.to_string(); + + let crate_id = add_noir_lib(&mut compiler_context, &lib_name); + + crate_names.insert(lib_name.clone(), crate_id); + + // Add the dependency edges + compiler_context.add_dependency_edge(lib_name_string, &root_id, &crate_id); + } + + // Process the transitive dependencies of the root + for (lib_name, dependencies) in &dependency_graph.library_dependencies { + // first create the library crate if needed + // this crate might not have been registered yet because of the order of the HashMap + // e.g. {root: [lib1], libs: { lib2 -> [lib3], lib1 -> [lib2] }} + let crate_id = *crate_names + .entry(lib_name.clone()) + .or_insert_with(|| add_noir_lib(&mut compiler_context, lib_name)); + + for dependency_name in dependencies { + let dependency_name_string = dependency_name.to_string(); + + let dep_crate_id = crate_names + .entry(dependency_name.clone()) + .or_insert_with(|| add_noir_lib(&mut compiler_context, dependency_name)); + + compiler_context.add_dependency_edge(dependency_name_string, &crate_id, dep_crate_id); + } + } + + let is_contract = contracts.unwrap_or(false); + let program_width = 3; + + if is_contract { + compiler_context.compile_contract(program_width) + } else { + compiler_context.compile_program(program_width) + } +} + +#[cfg(test)] +mod test { + use noirc_driver::prepare_crate; + use noirc_frontend::hir::Context; + + use crate::compile::{file_manager_with_source_map, PathToFileSourceMap}; + + use std::path::Path; + + use super::CompilerContext; + + fn setup_test_context(source_map: PathToFileSourceMap) -> CompilerContext { + let mut fm = file_manager_with_source_map(source_map); + // Add this due to us calling prepare_crate on "/main.nr" below + fm.add_file_with_source(Path::new("/main.nr"), "fn foo() {}".to_string()); + + let mut context = Context::new(fm); + prepare_crate(&mut context, Path::new("/main.nr")); + + CompilerContext { context } + } + + #[test] + fn test_works_with_empty_dependency_graph() { + let source_map = PathToFileSourceMap::default(); + let context = setup_test_context(source_map); + + // one stdlib + one root crate + assert_eq!(context.crate_graph().number_of_crates(), 2); + } + + #[test] + fn test_works_with_root_dependencies() { + let source_map = PathToFileSourceMap( + vec![(Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string())] + .into_iter() + .collect(), + ); + + let mut context = setup_test_context(source_map); + context.process_dependency_crate("lib1/lib.nr".to_string()); + + assert_eq!(context.crate_graph().number_of_crates(), 3); + } + + #[test] + fn test_works_with_duplicate_root_dependencies() { + let source_map = PathToFileSourceMap( + vec![(Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string())] + .into_iter() + .collect(), + ); + let mut context = setup_test_context(source_map); + + let lib1_crate_id = context.process_dependency_crate("lib1/lib.nr".to_string()); + let root_crate_id = context.root_crate_id(); + + context.add_dependency_edge("lib1".to_string(), &root_crate_id, &lib1_crate_id); + context.add_dependency_edge("lib1".to_string(), &root_crate_id, &lib1_crate_id); + + assert_eq!(context.crate_graph().number_of_crates(), 3); + } + + #[test] + fn test_works_with_transitive_dependencies() { + let source_map = PathToFileSourceMap( + vec![ + (Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib2/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib3/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + ] + .into_iter() + .collect(), + ); + + let mut context = setup_test_context(source_map); + + let lib1_crate_id = context.process_dependency_crate("lib1/lib.nr".to_string()); + let lib2_crate_id = context.process_dependency_crate("lib2/lib.nr".to_string()); + let lib3_crate_id = context.process_dependency_crate("lib3/lib.nr".to_string()); + let root_crate_id = context.root_crate_id(); + + context.add_dependency_edge("lib1".to_string(), &root_crate_id, &lib1_crate_id); + context.add_dependency_edge("lib2".to_string(), &lib1_crate_id, &lib2_crate_id); + context.add_dependency_edge("lib3".to_string(), &lib2_crate_id, &lib3_crate_id); + + assert_eq!(context.crate_graph().number_of_crates(), 5); + } + + #[test] + fn test_works_with_missing_dependencies() { + let source_map = PathToFileSourceMap( + vec![ + (Path::new("lib1/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib2/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + (Path::new("lib3/lib.nr").to_path_buf(), "fn foo() {}".to_string()), + ] + .into_iter() + .collect(), + ); + let mut context = setup_test_context(source_map); + + let lib1_crate_id = context.process_dependency_crate("lib1/lib.nr".to_string()); + let lib2_crate_id = context.process_dependency_crate("lib2/lib.nr".to_string()); + let lib3_crate_id = context.process_dependency_crate("lib3/lib.nr".to_string()); + let root_crate_id = context.root_crate_id(); + + context.add_dependency_edge("lib1".to_string(), &root_crate_id, &lib1_crate_id); + context.add_dependency_edge("lib3".to_string(), &lib2_crate_id, &lib3_crate_id); + + assert_eq!(context.crate_graph().number_of_crates(), 5); + } +} diff --git a/noir/compiler/wasm/src/lib.rs b/noir/compiler/wasm/src/lib.rs index 9f2f558f85c..43095fee4d4 100644 --- a/noir/compiler/wasm/src/lib.rs +++ b/noir/compiler/wasm/src/lib.rs @@ -14,11 +14,15 @@ use wasm_bindgen::prelude::*; mod circuit; mod compile; +mod compile_new; mod errors; pub use circuit::{acir_read_bytes, acir_write_bytes}; pub use compile::compile; +// Expose the new Context-Centric API +pub use compile_new::{compile_, CompilerContext, CrateIDWrapper}; + #[derive(Serialize, Deserialize)] pub struct BuildInfo { git_hash: &'static str, diff --git a/noir/compiler/wasm/test/browser/index.test.ts b/noir/compiler/wasm/test/browser/index.test.ts index 8a3f82ffff9..7364a8a4d11 100644 --- a/noir/compiler/wasm/test/browser/index.test.ts +++ b/noir/compiler/wasm/test/browser/index.test.ts @@ -1,6 +1,5 @@ import { expect } from '@esm-bundle/chai'; -import initNoirWasm, { compile } from '@noir-lang/noir_wasm'; -import { initializeResolver } from '@noir-lang/source-resolver'; +import initNoirWasm, { PathToFileSourceMap, compile } from '@noir-lang/noir_wasm'; import { depsScriptExpectedArtifact, depsScriptSourcePath, @@ -28,23 +27,11 @@ async function getPrecompiledSource(path: string): Promise { describe('noir wasm', () => { describe('can compile script without dependencies', () => { - beforeEach(async () => { - const source = await getFileContent(simpleScriptSourcePath); - initializeResolver((id: string) => { - console.log(`Resolving source ${id}`); - - if (typeof source === 'undefined') { - throw Error(`Could not resolve source for '${id}'`); - } else if (id !== '/main.nr') { - throw Error(`Unexpected id: '${id}'`); - } else { - return source; - } - }); - }); - it('matching nargos compilation', async () => { - const wasmCircuit = await compile('/main.nr'); + const sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code('main.nr', await getFileContent(simpleScriptSourcePath)); + + const wasmCircuit = await compile('main.nr', undefined, undefined, sourceMap); const cliCircuit = await getPrecompiledSource(simpleScriptExpectedArtifact); if (!('program' in wasmCircuit)) { @@ -52,44 +39,36 @@ describe('noir wasm', () => { } // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.program.noir_version).to.eq(cliCircuit.noir_version); expect(wasmCircuit.program.bytecode).to.eq(cliCircuit.bytecode); expect(wasmCircuit.program.abi).to.deep.eq(cliCircuit.abi); - expect(wasmCircuit.program.backend).to.eq(cliCircuit.backend); }).timeout(20e3); // 20 seconds }); describe('can compile script with dependencies', () => { - beforeEach(async () => { + it('matching nargos compilation', async () => { const [scriptSource, libASource, libBSource] = await Promise.all([ getFileContent(depsScriptSourcePath), getFileContent(libASourcePath), getFileContent(libBSourcePath), ]); - initializeResolver((file: string) => { - switch (file) { - case '/script/main.nr': - return scriptSource; - - case '/lib_a/lib.nr': - return libASource; - - case '/lib_b/lib.nr': - return libBSource; - - default: - return ''; - } - }); - }); - - it('matching nargos compilation', async () => { - const wasmCircuit = await compile('/script/main.nr', false, { - root_dependencies: ['lib_a'], - library_dependencies: { - lib_a: ['lib_b'], + const sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code('script/main.nr', scriptSource); + sourceMap.add_source_code('lib_a/lib.nr', libASource); + sourceMap.add_source_code('lib_b/lib.nr', libBSource); + + const wasmCircuit = await compile( + 'script/main.nr', + false, + { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], + }, }, - }); + sourceMap, + ); if (!('program' in wasmCircuit)) { throw Error('Expected program to be present'); @@ -98,9 +77,9 @@ describe('noir wasm', () => { const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.program.noir_version).to.eq(cliCircuit.noir_version); expect(wasmCircuit.program.bytecode).to.eq(cliCircuit.bytecode); expect(wasmCircuit.program.abi).to.deep.eq(cliCircuit.abi); - expect(wasmCircuit.program.backend).to.eq(cliCircuit.backend); }).timeout(20e3); // 20 seconds }); }); diff --git a/noir/compiler/wasm/test/node/index.test.ts b/noir/compiler/wasm/test/node/index.test.ts index c0d5f88e407..57c1b459d60 100644 --- a/noir/compiler/wasm/test/node/index.test.ts +++ b/noir/compiler/wasm/test/node/index.test.ts @@ -9,8 +9,7 @@ import { } from '../shared'; import { readFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; -import { compile } from '@noir-lang/noir_wasm'; -import { initializeResolver } from '@noir-lang/source-resolver'; +import { compile, compile_, CompilerContext, PathToFileSourceMap } from '@noir-lang/noir_wasm'; // eslint-disable-next-line @typescript-eslint/no-explicit-any async function getPrecompiledSource(path: string): Promise { @@ -21,7 +20,12 @@ async function getPrecompiledSource(path: string): Promise { describe('noir wasm compilation', () => { describe('can compile simple scripts', () => { it('matching nargos compilation', async () => { - const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath)); + const sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code( + join(__dirname, simpleScriptSourcePath), + readFileSync(join(__dirname, simpleScriptSourcePath), 'utf-8'), + ); + const wasmCircuit = await compile(join(__dirname, simpleScriptSourcePath), undefined, undefined, sourceMap); const cliCircuit = await getPrecompiledSource(simpleScriptExpectedArtifact); if (!('program' in wasmCircuit)) { @@ -29,39 +33,32 @@ describe('noir wasm compilation', () => { } // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.program.noir_version).to.eq(cliCircuit.noir_version); expect(wasmCircuit.program.bytecode).to.eq(cliCircuit.bytecode); expect(wasmCircuit.program.abi).to.deep.eq(cliCircuit.abi); - expect(wasmCircuit.program.backend).to.eq(cliCircuit.backend); }).timeout(10e3); }); describe('can compile scripts with dependencies', () => { + const sourceMap: PathToFileSourceMap = new PathToFileSourceMap(); beforeEach(() => { - // this test requires a custom resolver in order to correctly resolve dependencies - initializeResolver((file) => { - switch (file) { - case '/script/main.nr': - return readFileSync(join(__dirname, depsScriptSourcePath), 'utf-8'); - - case '/lib_a/lib.nr': - return readFileSync(join(__dirname, libASourcePath), 'utf-8'); - - case '/lib_b/lib.nr': - return readFileSync(join(__dirname, libBSourcePath), 'utf-8'); - - default: - return ''; - } - }); + sourceMap.add_source_code('script/main.nr', readFileSync(join(__dirname, depsScriptSourcePath), 'utf-8')); + sourceMap.add_source_code('lib_a/lib.nr', readFileSync(join(__dirname, libASourcePath), 'utf-8')); + sourceMap.add_source_code('lib_b/lib.nr', readFileSync(join(__dirname, libBSourcePath), 'utf-8')); }); it('matching nargos compilation', async () => { - const wasmCircuit = await compile('/script/main.nr', false, { - root_dependencies: ['lib_a'], - library_dependencies: { - lib_a: ['lib_b'], + const wasmCircuit = await compile( + 'script/main.nr', + false, + { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], + }, }, - }); + sourceMap, + ); const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); @@ -70,9 +67,83 @@ describe('noir wasm compilation', () => { } // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.program.noir_version).to.eq(cliCircuit.noir_version); + expect(wasmCircuit.program.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.program.abi).to.deep.eq(cliCircuit.abi); + }).timeout(10e3); + }); + + describe('can compile scripts with dependencies -- context-api', () => { + let sourceMap: PathToFileSourceMap; + beforeEach(() => { + sourceMap = new PathToFileSourceMap(); + sourceMap.add_source_code('script/main.nr', readFileSync(join(__dirname, depsScriptSourcePath), 'utf-8')); + sourceMap.add_source_code('lib_a/lib.nr', readFileSync(join(__dirname, libASourcePath), 'utf-8')); + sourceMap.add_source_code('lib_b/lib.nr', readFileSync(join(__dirname, libBSourcePath), 'utf-8')); + }); + + it('matching nargos compilation - context-api', async () => { + const compilerContext = new CompilerContext(sourceMap); + + // Process root crate + const root_crate_id = compilerContext.process_root_crate('script/main.nr'); + // Process dependencies + // + // This can be direct dependencies or transitive dependencies + // I have named these crate_id_1 and crate_id_2 instead of `lib_a_crate_id` and `lib_b_crate_id` + // because the names of crates in a dependency graph are not determined by the actual package. + // + // It is true that each package is given a name, but if I include a `lib_a` as a dependency + // in my library, I do not need to refer to it as `lib_a` in my dependency graph. + // See https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml + // + // If you have looked at graphs before, then you can think of the dependency graph as a directed acyclic graph (DAG) + const crate_id_1 = compilerContext.process_dependency_crate('lib_a/lib.nr'); + const crate_id_2 = compilerContext.process_dependency_crate('lib_b/lib.nr'); + + // Root crate depends on `crate_id_1` and this edge is called `lib_a` + compilerContext.add_dependency_edge('lib_a', root_crate_id, crate_id_1); + // `crate_id_1` depends on `crate_id_2` and this edge is called `lib_b` + compilerContext.add_dependency_edge('lib_b', crate_id_1, crate_id_2); + + const program_width = 3; + const wasmCircuit = await compilerContext.compile_program(program_width); + + const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); + + if (!('program' in wasmCircuit)) { + throw Error('Expected program to be present'); + } + + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.program.noir_version).to.eq(cliCircuit.noir_version); + expect(wasmCircuit.program.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.program.abi).to.deep.eq(cliCircuit.abi); + }).timeout(10e3); + + it('matching nargos compilation - context-implementation-compile-api', async () => { + const wasmCircuit = await compile_( + 'script/main.nr', + false, + { + root_dependencies: ['lib_a'], + library_dependencies: { + lib_a: ['lib_b'], + }, + }, + sourceMap, + ); + + const cliCircuit = await getPrecompiledSource(depsScriptExpectedArtifact); + + if (!('program' in wasmCircuit)) { + throw Error('Expected program to be present'); + } + + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.program.noir_version).to.eq(cliCircuit.noir_version); expect(wasmCircuit.program.bytecode).to.eq(cliCircuit.bytecode); expect(wasmCircuit.program.abi).to.deep.eq(cliCircuit.abi); - expect(wasmCircuit.program.backend).to.eq(cliCircuit.backend); }).timeout(10e3); }); }); diff --git a/noir/cspell.json b/noir/cspell.json index 90d3963566d..e02e68871bb 100644 --- a/noir/cspell.json +++ b/noir/cspell.json @@ -5,6 +5,7 @@ "acir", "acvm", "aeiou", + "appender", "arithmetization", "arity", "arkworks", @@ -79,15 +80,18 @@ "monomorphizes", "nand", "nargo", + "newtype", "nixpkgs", "noirc", "noirup", + "nomicfoundation", "pedersen", "peekable", "plonkc", "pprof", "preprocess", "prettytable", + "println", "printstd", "pseudocode", "quantile", diff --git a/noir/compiler/source-resolver/.eslintignore b/noir/docs/.eslintignore similarity index 68% rename from noir/compiler/source-resolver/.eslintignore rename to noir/docs/.eslintignore index 3c3629e647f..dd87e2d73f9 100644 --- a/noir/compiler/source-resolver/.eslintignore +++ b/noir/docs/.eslintignore @@ -1 +1,2 @@ node_modules +build diff --git a/noir/docs/.gitignore b/noir/docs/.gitignore index e6e00b5b355..4f6eee8284e 100644 --- a/noir/docs/.gitignore +++ b/noir/docs/.gitignore @@ -7,7 +7,7 @@ # Generated files .docusaurus .cache-loader -/docs/docs/noir_js/reference/ +/docs/docs/reference/NoirJS # Misc .DS_Store @@ -22,3 +22,4 @@ yarn-debug.log* yarn-error.log* package-lock.json +versions.json diff --git a/noir/docs/.prettierrc b/noir/docs/.prettierrc deleted file mode 100644 index 6031f40b267..00000000000 --- a/noir/docs/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "arrowParens": "avoid", - "singleQuote": true, - "trailingComma": "all", - "printWidth": 100 -} diff --git a/noir/docs/babel.config.js b/noir/docs/babel.config.js deleted file mode 100644 index e00595dae7d..00000000000 --- a/noir/docs/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], -}; diff --git a/noir/docs/docs/explainers/explainer-recursion.md b/noir/docs/docs/explainers/explainer-recursion.md new file mode 100644 index 00000000000..cc431a878dc --- /dev/null +++ b/noir/docs/docs/explainers/explainer-recursion.md @@ -0,0 +1,175 @@ +--- +title: Recursive proofs +description: Explore the concept of recursive proofs in Zero-Knowledge programming. Understand how recursion works in Noir, a language for writing smart contracts on the EVM blockchain. Learn through practical examples like Alice and Bob's guessing game, Charlie's recursive merkle tree, and Daniel's reusable components. Discover how to use recursive proofs to optimize computational resources and improve efficiency. + +keywords: + [ + "Recursive Proofs", + "Zero-Knowledge Programming", + "Noir", + "EVM Blockchain", + "Smart Contracts", + "Recursion in Noir", + "Alice and Bob Guessing Game", + "Recursive Merkle Tree", + "Reusable Components", + "Optimizing Computational Resources", + "Improving Efficiency", + "Verification Key", + "Aggregation Objects", + "Recursive zkSNARK schemes", + "PLONK", + "Proving and Verification Keys" + ] +sidebar_position: 1 +--- + +In programming, we tend to think of recursion as something calling itself. A classic example would be the calculation of the factorial of a number: + +```js +function factorial(n) { + if (n === 0 || n === 1) { + return 1; + } else { + return n * factorial(n - 1); + } +} +``` + +In this case, while `n` is not `1`, this function will keep calling itself until it hits the base case, bubbling up the result on the call stack: + +```md + Is `n` 1? <--------- + /\ / + / \ n = n -1 + / \ / + Yes No -------- +``` + +In Zero-Knowledge, recursion has some similarities. + +It is not a Noir function calling itself, but a proof being used as an input to another circuit. In short, you verify one proof *inside* another proof, returning the proof that both proofs are valid. + +This means that, given enough computational resources, you can prove the correctness of any arbitrary number of proofs in a single proof. This could be useful to design state channels (for which a common example would be [Bitcoin's Lightning Network](https://en.wikipedia.org/wiki/Lightning_Network)), to save on gas costs by settling one proof on-chain, or simply to make business logic less dependent on a consensus mechanism. + +## Examples + +Let us look at some of these examples + +### Alice and Bob - Guessing game + +Alice and Bob are friends, and they like guessing games. They want to play a guessing game online, but for that, they need a trusted third-party that knows both of their secrets and finishes the game once someone wins. + +So, they use zero-knowledge proofs. Alice tries to guess Bob's number, and Bob will generate a ZK proof stating whether she succeeded or failed. + +This ZK proof can go on a smart contract, revealing the winner and even giving prizes. However, this means every turn needs to be verified on-chain. This incurs some cost and waiting time that may simply make the game too expensive or time-consuming to be worth it. + +So, Alice started thinking: "what if Bob generates his proof, and instead of sending it on-chain, I verify it *within* my own proof before playing my own turn?". She can then generate a proof that she verified his proof, and so on. + +```md + Did you fail? <-------------------------- + / \ / + / \ n = n -1 + / \ / + Yes No / + | | / + | | / + | You win / + | / + | / +Generate proof of that / + + / + my own guess ---------------- +``` + +### Charlie - Recursive merkle tree + +Charlie is a concerned citizen, and wants to be sure his vote in an election is accounted for. He votes with a ZK proof, but he has no way of knowing that his ZK proof was included in the total vote count! + +So, the tallier puts all the votes in a merkle tree, and everyone can also prove the verification of two proofs within one proof, as such: + +```md + abcd + __________|______________ + | | + ab cd + _____|_____ ______|______ + | | | | + alice bob charlie daniel +``` + +Doing this recursively allows us to arrive on a final proof `abcd` which if true, verifies the correctness of all the votes. + +### Daniel - Reusable components + +Daniel has a big circuit and a big headache. A part of his circuit is a setup phase that finishes with some assertions that need to be made. But that section alone takes most of the proving time, and is largely independent of the rest of the circuit. + +He could find it more efficient to generate a proof for that setup phase separately, and verifying it in his actual business logic section of the circuit. This will allow for parallelization of both proofs, which results in a considerable speedup. + +## What params do I need + +As you can see in the [recursion reference](noir/standard_library/recursion.md), a simple recursive proof requires: + +- The proof to verify +- The Verification Key of the circuit that generated the proof +- A hash of this verification key, as it's needed for some backends +- The public inputs for the proof +- The input aggregation object + +It also returns the `output aggregation object`. These aggregation objects can be confusing at times, so let's dive in a little bit. + +### Aggregation objects + +Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. + +In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points. + +So, taking the example of Alice and Bob and their guessing game: + +- Alice makes her guess. Her proof is *not* recursive: it doesn't verify any proof within it! It's just a standard `assert(x != y)` circuit +- Bob verifies Alice's proof and makes his own guess. In this circuit, he is verifying a proof, so it needs to output an `aggregation object`: he is generating a recursive proof! +- Alice verifies Bob's *recursive proof*, and uses Bob's `output aggregation object` as the `input aggregation object` in her proof... Which in turn, generates another `output aggregation object`. + +One should notice that when Bob generates his first proof, he has no input aggregation object. Because he is not verifying an recursive proof, he has no `input aggregation object`. In this case, he may use zeros instead. + +We can imagine the `aggregation object` as the baton in a [relay race](https://en.wikipedia.org/wiki/Relay_race). The first runner doesn't have to receive the baton from anyone else, as he/she already starts with it. But when his/her turn is over, the next runner needs to receive it, run a bit more, and pass it along. Even though every runner could theoretically verify the baton mid-run (why not? 🏃🔍), only at the end of the race does the referee verify that the whole race is valid. + +## Some architecture + +As with everything in computer science, there's no one-size-fits all. But there are some patterns that could help understanding and implementing them. To give three examples: + +### Adding some logic to a proof verification + +This would be an approach for something like our guessing game, where proofs are sent back and forth and are verified by each opponent. This circuit would be divided in two sections: + +- A `recursive verification` section, which would be just the call to `std::verify_proof`, and that would be skipped on the first move (since there's no proof to verify) +- A `guessing` section, which is basically the logic part where the actual guessing happens + +In such a situation, and assuming Alice is first, she would skip the first part and try to guess Bob's number. Bob would then verify her proof on the first section of his run, and try to guess Alice's number on the second part, and so on. + +### Aggregating proofs + +In some one-way interaction situations, recursiveness would allow for aggregation of simple proofs that don't need to be immediately verified on-chain or elsewhere. + +To give a practical example, a barman wouldn't need to verify a "proof-of-age" on-chain every time he serves alcohol to a customer. Instead, the architecture would comprise two circuits: + +- A `main`, non-recursive circuit with some logic +- A `recursive` circuit meant to verify two proofs in one proof + +The customer's proofs would be intermediate, and made on their phones, and the barman could just verify them locally. He would then aggregate them into a final proof sent on-chain (or elsewhere) at the end of the day. + +### Recursively verifying different circuits + +Nothing prevents you from verifying different circuits in a recursive proof, for example: + +- A `circuit1` circuit +- A `circuit2` circuit +- A `recursive` circuit + +In this example, a regulator could verify that taxes were paid for a specific purchase by aggregating both a `payer` circuit (proving that a purchase was made and taxes were paid), and a `receipt` circuit (proving that the payment was received) + +## How fast is it + +At the time of writing, verifying recursive proofs is surprisingly fast. This is because most of the time is spent on generating the verification key that will be used to generate the next proof. So you are able to cache the verification key and reuse it later. + +Currently, Noir JS packages don't expose the functionality of loading proving and verification keys, but that feature exists in the underlying `bb.js` package. diff --git a/noir/docs/docs/explanations/noir/traits.md b/noir/docs/docs/explanations/noir/traits.md new file mode 100644 index 00000000000..7ba07e74f40 --- /dev/null +++ b/noir/docs/docs/explanations/noir/traits.md @@ -0,0 +1,348 @@ +--- +title: Traits +description: + Traits in Noir can be used to abstract out a common interface for functions across + several data types. +keywords: [noir programming language, traits, interfaces, generic, protocol] +--- + +## Overview + +Traits in Noir are a useful abstraction similar to interfaces or protocols in other languages. Each trait defines +the interface of several methods contained within the trait. Types can then implement this trait by providing +implementations for these methods. For example in the program: + +```rust +struct Rectangle { + width: Field, + height: Field, +} + +impl Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +fn log_area(r: Rectangle) { + println(r.area()); +} +``` + +We have a function `log_area` to log the area of a `Rectangle`. Now how should we change the program if we want this +function to work on `Triangle`s as well?: + +```rust +struct Triangle { + width: Field, + height: Field, +} + +impl Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Making `log_area` generic over all types `T` would be invalid since not all types have an `area` method. Instead, we can +introduce a new `Area` trait and make `log_area` generic over all types `T` that implement `Area`: + +```rust +trait Area { + fn area(self) -> Field; +} + +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +We also need to explicitly implement `Area` for `Rectangle` and `Triangle`. We can do that by changing their existing +impls slightly. Note that the parameter types and return type of each of our `area` methods must match those defined +by the `Area` trait. + +```rust +impl Area for Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +impl Area for Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Now we have a working program that is generic over any type of Shape that is used! Others can even use this program +as a library with their own types - such as `Circle` - as long as they also implement `Area` for these types. + +## Where Clauses + +As seen in `log_area` above, when we want to create a function or method that is generic over any type that implements +a trait, we can add a where clause to the generic function. + +```rust +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +It is also possible to apply multiple trait constraints on the same variable at once by combining traits with the `+` +operator. Similarly, we can have multiple trait constraints by separating each with a comma: + +```rust +fn foo(elements: [T], thing: U) where + T: Default + Add + Eq, + U: Bar, +{ + let mut sum = T::default(); + + for element in elements { + sum += element; + } + + if sum == T::default() { + thing.bar(); + } +} +``` + +## Generic Implementations + +You can add generics to a trait implementation by adding the generic list after the `impl` keyword: + +```rust +trait Second { + fn second(self) -> Field; +} + +impl Second for (T, Field) { + fn second(self) -> Field { + self.1 + } +} +``` + +You can also implement a trait for every type this way: + +```rust +trait Debug { + fn debug(self); +} + +impl Debug for T { + fn debug(self) { + println(self); + } +} + +fn main() { + 1.debug(); +} +``` + +### Generic Trait Implementations With Where Clauses + +Where clauses can also be placed on trait implementations themselves to restrict generics in a similar way. +For example, while `impl Foo for T` implements the trait `Foo` for every type, `impl Foo for T where T: Bar` +will implement `Foo` only for types that also implement `Bar`. This is often used for implementing generic types. +For example, here is the implementation for array equality: + +```rust +impl Eq for [T; N] where T: Eq { + // Test if two arrays have the same elements. + // Because both arrays must have length N, we know their lengths already match. + fn eq(self, other: Self) -> bool { + let mut result = true; + + for i in 0 .. self.len() { + // The T: Eq constraint is needed to call == on the array elements here + result &= self[i] == other[i]; + } + + result + } +} +``` + +## Trait Methods With No `self` + +A trait can contain any number of methods, each of which have access to the `Self` type which represents each type +that eventually implements the trait. Similarly, the `self` variable is available as well but is not required to be used. +For example, we can define a trait to create a default value for a type. This trait will need to return the `Self` type +but doesn't need to take any parameters: + +```rust +trait Default { + fn default() -> Self; +} +``` + +Implementing this trait can be done similarly to any other trait: + +```rust +impl Default for Field { + fn default() -> Field { + 0 + } +} + +struct MyType {} + +impl Default for MyType { + fn default() -> Field { + MyType {} + } +} +``` + +However, since there is no `self` parameter, we cannot call it via the method call syntax `object.method()`. +Instead, we'll need to refer to the function directly. This can be done either by referring to the +specific impl `MyType::default()` or referring to the trait itself `Default::default()`. In the later +case, type inference determines the impl that is selected. + +```rust +let my_struct = MyStruct::default(); + +let x: Field = Default::default(); +let result = x + Default::default(); +``` + +:::warning + +```rust +let _ = Default::default(); +``` + +If type inference cannot select which impl to use because of an ambiguous `Self` type, an impl will be +arbitrarily selected. This occurs most often when the result of a trait function call with no parameters +is unused. To avoid this, when calling a trait function with no `self` or `Self` parameters or return type, +always refer to it via the implementation type's namespace - e.g. `MyType::default()`. +This is set to change to an error in future Noir versions. + +::: + +## Default Method Implementations + +A trait can also have default implementations of its methods by giving a body to the desired functions. +Note that this body must be valid for all types that may implement the trait. As a result, the only +valid operations on `self` will be operations valid for any type or other operations on the trait itself. + +```rust +trait Numeric { + fn add(self, other: Self) -> Self; + + // Default implementation of double is (self + self) + fn double(self) -> Self { + self.add(self) + } +} +``` + +When implementing a trait with default functions, a type may choose to implement only the required functions: + +```rust +impl Numeric for Field { + fn add(self, other: Field) -> Field { + self + other + } +} +``` + +Or it may implement the optional methods as well: + +```rust +impl Numeric for u32 { + fn add(self, other: u32) -> u32 { + self + other + } + + fn double(self) -> u32 { + self * 2 + } +} +``` + +## Impl Specialization + +When implementing traits for a generic type it is possible to implement the trait for only a certain combination +of generics. This can be either as an optimization or because those specific generics are required to implement the trait. + +```rust +trait Sub { + fn sub(self, other: Self) -> Self; +} + +struct NonZero { + value: T, +} + +impl Sub for NonZero { + fn sub(self, other: Self) -> Self { + let value = self.value - other.value; + assert(value != 0); + NonZero { value } + } +} +``` + +## Overlapping Implementations + +Overlapping implementations are disallowed by Noir to ensure Noir's decision on which impl to select is never ambiguous. +This means if a trait `Foo` is already implemented +by a type `Bar` for all `T`, then we cannot also have a separate impl for `Bar` (or any other +type argument). Similarly, if there is an impl for all `T` such as `impl Debug for T`, we cannot create +any more impls to `Debug` for other types since it would be ambiguous which impl to choose for any given +method call. + +```rust +trait Trait {} + +// Previous impl defined here +impl Trait for (A, B) {} + +// error: Impl for type `(Field, Field)` overlaps with existing impl +impl Trait for (Field, Field) {} +``` + +## Trait Coherence + +Another restriction on trait implementations is coherence. This restriction ensures other crates cannot create +impls that may overlap with other impls, even if several unrelated crates are used as dependencies in the same +program. + +The coherence restriction is: to implement a trait, either the trait itself or the object type must be declared +in the crate the impl is in. + +In practice this often comes up when using types provided by libraries. If a library provides a type `Foo` that does +not implement a trait in the standard library such as `Default`, you may not `impl Default for Foo` in your own crate. +While restrictive, this prevents later issues or silent changes in the program if the `Foo` library later added its +own impl for `Default`. If you are a user of the `Foo` library in this scenario and need a trait not implemented by the +library your choices are to either submit a patch to the library or use the newtype pattern. + +### The Newtype Pattern + +The newtype pattern gets around the coherence restriction by creating a new wrapper type around the library type +that we cannot create `impl`s for. Since the new wrapper type is defined in our current crate, we can create +impls for any trait we need on it. + +```rust +struct Wrapper { + foo: dep::some_library::Foo, +} + +impl Default for Wrapper { + fn default() -> Wrapper { + Wrapper { + foo: dep::some_library::Foo::new(), + } + } +} +``` + +Since we have an impl for our own type, the behavior of this code will not change even if `some_library` is updated +to provide its own `impl Default for Foo`. The downside of this pattern is that it requires extra wrapping and +unwrapping of values when converting to and from the `Wrapper` and `Foo` types. diff --git a/noir/docs/docs/explanations/standard_library/traits.md b/noir/docs/docs/explanations/standard_library/traits.md new file mode 100644 index 00000000000..63b4f3d6f0b --- /dev/null +++ b/noir/docs/docs/explanations/standard_library/traits.md @@ -0,0 +1,140 @@ +--- +title: Traits +description: Noir's stdlib provides a few commonly used traits. +keywords: [traits, trait, interface, protocol, default, add, eq] +--- + +## `std::default` + +### `std::default::Default` + +```rust +trait Default { + fn default() -> Self; +} +``` + +Constructs a default value of a type. + +Implementations: +```rust +impl Default for Field { .. } + +impl Default for i8 { .. } +impl Default for i16 { .. } +impl Default for i32 { .. } +impl Default for i64 { .. } + +impl Default for u8 { .. } +impl Default for u16 { .. } +impl Default for u32 { .. } +impl Default for u64 { .. } + +impl Default for () { .. } +impl Default for bool { .. } + +impl Default for [T; N] + where T: Default { .. } + +impl Default for (A, B) + where A: Default, B: Default { .. } + +impl Default for (A, B, C) + where A: Default, B: Default, C: Default { .. } + +impl Default for (A, B, C, D) + where A: Default, B: Default, C: Default, D: Default { .. } + +impl Default for (A, B, C, D, E) + where A: Default, B: Default, C: Default, D: Default, E: Default { .. } +``` + +For primitive integer types, the return value of `default` is `0`. Container +types such as arrays are filled with default values of their element type. + +## `std::ops` + +### `std::ops::Eq` + +```rust +trait Eq { + fn eq(self, other: Self) -> bool; +} +``` +Returns `true` if `self` is equal to `other`. + +Implementations: +```rust +impl Eq for Field { .. } + +impl Eq for i8 { .. } +impl Eq for i16 { .. } +impl Eq for i32 { .. } +impl Eq for i64 { .. } + +impl Eq for u8 { .. } +impl Eq for u16 { .. } +impl Eq for u32 { .. } +impl Eq for u64 { .. } + +impl Eq for () { .. } +impl Eq for bool { .. } + +impl Eq for [T; N] + where T: Eq { .. } + +impl Eq for (A, B) + where A: Eq, B: Eq { .. } + +impl Eq for (A, B, C) + where A: Eq, B: Eq, C: Eq { .. } + +impl Eq for (A, B, C, D) + where A: Eq, B: Eq, C: Eq, D: Eq { .. } + +impl Eq for (A, B, C, D, E) + where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } +``` + +### `std::ops::Add`, `std::ops::Sub`, `std::ops::Mul`, and `std::ops::Div` + +These traits abstract over addition, subtraction, multiplication, and division respectively. +Although Noir does not currently have operator overloading, in the future implementing these +traits for a given type will also allow that type to be used with the corresponding operator +for that trait (`+` for Add, etc) in addition to the normal method names. + +```rust +trait Add { + fn add(self, other: Self) -> Self; +} + +trait Sub { + fn sub(self, other: Self) -> Self; +} + +trait Mul { + fn mul(self, other: Self) -> Self; +} + +trait Div { + fn div(self, other: Self) -> Self; +} +``` + +The implementations block below is given for the `Add` trait, but the same types that implement +`Add` also implement `Sub`, `Mul`, and `Div`. + +Implementations: +```rust +impl Add for Field { .. } + +impl Add for i8 { .. } +impl Add for i16 { .. } +impl Add for i32 { .. } +impl Add for i64 { .. } + +impl Add for u8 { .. } +impl Add for u16 { .. } +impl Add for u32 { .. } +impl Add for u64 { .. } +``` diff --git a/noir/docs/docs/getting_started/_category_.json b/noir/docs/docs/getting_started/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/docs/getting_started/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.10.5/getting_started/01_hello_world.md b/noir/docs/docs/getting_started/create_a_project.md similarity index 90% rename from noir/docs/versioned_docs/version-v0.10.5/getting_started/01_hello_world.md rename to noir/docs/docs/getting_started/create_a_project.md index 8b4416beba1..f10916c39c5 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/getting_started/01_hello_world.md +++ b/noir/docs/docs/getting_started/create_a_project.md @@ -1,5 +1,5 @@ --- -title: Create A Project +title: Creating A Project description: Learn how to create and verify your first Noir program using Nargo, a programming language for zero-knowledge proofs. @@ -13,6 +13,8 @@ keywords: verify Noir program, step-by-step guide, ] +sidebar_position: 1 + --- Now that we have installed Nargo, it is time to make our first hello world program! @@ -30,13 +32,6 @@ mkdir ~/projects cd ~/projects ``` -For Windows CMD, run: - -```sh -> mkdir "%USERPROFILE%\projects" -> cd /d "%USERPROFILE%\projects" -``` - ## Create Our First Nargo Project Now that we are in the projects directory, create a new Nargo project by running: @@ -74,7 +69,7 @@ x : Field, y : pub Field Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the keyword `pub` (e.g. `y`). To learn more about private and public values, check the -[Data Types](../language_concepts/data_types) section. +[Data Types](../noir/syntax/data_types/index.md) section. The next line of the program specifies its body: @@ -84,7 +79,7 @@ assert(x != y); The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. -For more Noir syntax, check the [Language Concepts](../language_concepts/comments) chapter. +For more Noir syntax, check the [Language Concepts](../noir/syntax/comments.md) chapter. ## Build In/Output Files @@ -144,4 +139,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./project_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/docs/getting_started/installation/_category_.json b/noir/docs/docs/getting_started/installation/_category_.json new file mode 100644 index 00000000000..0c02fb5d4d7 --- /dev/null +++ b/noir/docs/docs/getting_started/installation/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 0, + "label": "Install Nargo", + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/docs/getting_started/installation/index.md b/noir/docs/docs/getting_started/installation/index.md new file mode 100644 index 00000000000..ddb8a250eb4 --- /dev/null +++ b/noir/docs/docs/getting_started/installation/index.md @@ -0,0 +1,45 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs. This page is a quick guide on how to install Nargo though the most common and easy method, noirup +keywords: [ + Nargo + Noir + Rust + Cargo + Noirup + Installation + Terminal Commands + Version Check + Nightlies + Specific Versions + Branches + Noirup Repository +] +--- + +`nargo` is the one-stop-shop for almost everything related with Noir. The name comes from our love for Rust and its package manager `cargo`. + +With `nargo`, you can start new projects, compile, execute, prove, verify, test, generate solidity contracts, and do pretty much all that is available in Noir. + +Similarly to `rustup`, we also maintain an easy installation method that covers most machines: `noirup`. + +## Installing Noirup + +Open a terminal on your machine, and write: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done. That's it. You should have the latest version working. You can check with `nargo --version`. + +You can also install nightlies, specific versions +or branches, check out the [noirup repository](https://github.com/noir-lang/noirup) for more +information. diff --git a/noir/docs/docs/getting_started/installation/other_install_methods.md b/noir/docs/docs/getting_started/installation/other_install_methods.md new file mode 100644 index 00000000000..36f05657277 --- /dev/null +++ b/noir/docs/docs/getting_started/installation/other_install_methods.md @@ -0,0 +1,190 @@ +--- +title: Alternative Install Methods +description: + There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains other methods that don't rely on noirup, such as compiling from source, installing from binaries, and using WSL for windows +keywords: [ + Installation + Nargo + Noirup + Binaries + Compiling from Source + WSL for Windows + macOS + Linux + Nix + Direnv + Shell & editor experience + Building and testing + Uninstalling Nargo + Noir vs code extension +] +sidebar_position: 1 +--- + + +## Installation + +The most common method of installing Nargo is through [Noirup](./index.md) + +However, there are other methods for installing Nargo: + +- [Binaries](#binaries) +- [Compiling from Source](#compile-from-source) +- [WSL for Windows](#wsl-for-windows) + +### Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --version`. You should get a version number. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +### Option 3: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. It helps mitigating ssues commonly associated with dependency management, such as conflicts between required package versions for different projects (often referred to as "dependency hell"). + +Combined with direnv, which automatically sets or unsets environment variables based on the directory, it further simplifies the development process by seamlessly integrating with the developer's shell, facilitating an efficient and reliable workflow for managing and deploying Noir projects with multiple dependencies. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). + 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `rust-toolchain.toml`, which is 1.71.1 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +### Option 4: WSL (for Windows) + +The default backend for Noir (Barretenberg) doesn't provide Windows binaries at this time. For that reason, Noir cannot be installed nativerly. However, it is available by using Windows Subsystem for Linux (WSL). + +Step 1: Follow the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install) to install and run WSL. + +step 2: Follow the [Noirup instructions](./index.md). + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/getting_started/02_breakdown.md b/noir/docs/docs/getting_started/project_breakdown.md similarity index 90% rename from noir/docs/versioned_docs/version-v0.10.5/getting_started/02_breakdown.md rename to noir/docs/docs/getting_started/project_breakdown.md index 3fa3a35766b..5a214804f7b 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/getting_started/02_breakdown.md +++ b/noir/docs/docs/getting_started/project_breakdown.md @@ -5,6 +5,7 @@ description: files, and how to prove and verify your program. keywords: [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] +sidebar_position: 2 --- This section breaks down our hello world program in section _1.2_. We elaborate on the project @@ -51,7 +52,7 @@ license = "MIT" ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"} ``` -Nargo.toml for a [workspace](../modules_packages_crates/workspaces) will look a bit different. For example: +Nargo.toml for a [workspace](../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: ```toml [workspace] @@ -66,7 +67,7 @@ The package section requires a number of fields including: - `name` (**required**) - the name of the package - `type` (**required**) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract - `authors` (optional) - authors of the project -- `compiler_version` (optional) - specifies the version of the compiler to use. This is not currently enforced by the compiler, but will be in future versions. +- `compiler_version` - specifies the version of the compiler to use. This is enforced by the compiler and follow's [Rust's versioning](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field), so a `compiler_version = 0.18.0` will enforce Nargo version 0.18.0, `compiler_version = ^0.18.0` will enforce anything above 0.18.0 but below 0.19.0, etc. For more information, see how [Rust handles these operators](https://docs.rs/semver/latest/semver/enum.Op.html) - `description` (optional) - `entry` (optional) - a relative filepath to use as the entry point into your package (overrides the default of `src/lib.nr` or `src/main.nr`) - `backend` (optional) @@ -74,7 +75,7 @@ The package section requires a number of fields including: #### Dependencies section -This is where you will specify any dependencies for your project. See the [Dependencies page](../modules_packages_crates/dependencies) for more info. +This is where you will specify any dependencies for your project. See the [Dependencies page](../noir/modules_packages_crates/dependencies.md) for more info. `./proofs/` and `./contract/` directories will not be immediately visible until you create a proof or verifier contract respectively. @@ -196,5 +197,3 @@ verify the proof submitted against it. If the verification passes, additional fu verifier contract could trigger (e.g. approve the asset transfer). Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code. - -In the [next section](language_server), we will explain how to utilize the Noir Language Server. diff --git a/noir/docs/docs/getting_started/tooling/_category_.json b/noir/docs/docs/getting_started/tooling/_category_.json new file mode 100644 index 00000000000..dff520ebc41 --- /dev/null +++ b/noir/docs/docs/getting_started/tooling/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 3, + "label": "Tooling", + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/docs/getting_started/tooling/index.md b/noir/docs/docs/getting_started/tooling/index.md new file mode 100644 index 00000000000..55df833005a --- /dev/null +++ b/noir/docs/docs/getting_started/tooling/index.md @@ -0,0 +1,33 @@ +--- +title: Tooling +Description: This section provides information about the various tools and utilities available for Noir development. It covers the Noir playground, IDE tools, Codespaces, and community projects. +Keywords: [Noir, Development, Playground, IDE Tools, Language Service Provider, VS Code Extension, Codespaces, noir-starter, Community Projects, Awesome Noir Repository, Developer Tooling] +--- + +Noir is meant to be easy to develop with. For that reason, a number of utilities have been put together to ease the development process as much as feasible in the zero-knowledge world. + +## Playground + +The Noir playground is an easy way to test small ideas, share snippets, and integrate in other websites. You can access it at [play.noir-lang.org](https://play.noir-lang.org). + +## IDE tools + +When you install Nargo, you're also installing a Language Service Provider (LSP), which can be used by IDEs to provide syntax highlighting, codelens, warnings, and more. + +The easiest way to use these tools is by installing the [Noir VS Code extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). + +## Codespaces + +Some Noir repos have leveraged Codespaces in order to ease the development process. You can visit the [noir-starter](https://github.com/noir-lang/noir-starter) for an example. + +## GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file in the Noir repo](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) for an example usage. + +## Community projects + +As an open-source project, Noir has received many contributions over time. Some of them are related with developer tooling, and you can see some of them in [Awesome Noir repository](https://github.com/noir-lang/awesome-noir#dev-tools) diff --git a/noir/docs/versioned_docs/version-v0.10.5/getting_started/03_language_server.md b/noir/docs/docs/getting_started/tooling/language_server.md similarity index 60% rename from noir/docs/versioned_docs/version-v0.10.5/getting_started/03_language_server.md rename to noir/docs/docs/getting_started/tooling/language_server.md index 49bd1d24675..81e0356ef8a 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/getting_started/03_language_server.md +++ b/noir/docs/docs/getting_started/tooling/language_server.md @@ -1,9 +1,8 @@ --- title: Language Server -description: - Learn about the Noir Language Server, how to install the components, and configuration that may be required. -keywords: - [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +description: Learn about the Noir Language Server, how to install the components, and configuration that may be required. +keywords: [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +sidebar_position: 0 --- This section helps you install and configure the Noir Language Server. @@ -23,14 +22,22 @@ The Client component is usually an editor plugin that launches the Server. It co Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). -When you language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, execution, and tests: +> **Note:** Noir's Language Server Protocol support currently assumes users' VSCode workspace root to be the same as users' Noir project root (i.e. where Nargo.toml lies). +> +> If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. + +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: ![Compile and Execute](@site/static/img/codelens_compile_execute.png) ![Run test](@site/static/img/codelens_run_test.png) +You should also see your tests in the `testing` panel: + +![Testing panel](@site/static/img/codelens_testing_panel.png) + ### Configuration -* __Noir: Enable LSP__ - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. -* __Noir: Nargo Flags__ - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. -* __Noir: Nargo Path__ - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. -* __Noir > Trace: Server__ - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. +- **Noir: Enable LSP** - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. +- **Noir: Nargo Flags** - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. +- **Noir: Nargo Path** - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. +- **Noir > Trace: Server** - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/noir/docs/versioned_docs/version-v0.10.5/nargo/02_testing.md b/noir/docs/docs/getting_started/tooling/testing.md similarity index 68% rename from noir/docs/versioned_docs/version-v0.10.5/nargo/02_testing.md rename to noir/docs/docs/getting_started/tooling/testing.md index 106952c44c0..868a061200d 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/nargo/02_testing.md +++ b/noir/docs/docs/getting_started/tooling/testing.md @@ -2,6 +2,7 @@ title: Testing in Noir description: Learn how to use Nargo to test your Noir program in a quick and easy way keywords: [Nargo, testing, Noir, compile, test] +sidebar_position: 1 --- You can test your Noir programs using Noir circuits. @@ -40,3 +41,22 @@ fn test_add() { assert(add(2,2) == 5); } ``` + +You can be more specific and make it fail with a specific reason by using `should_fail_with = "`: + +```rust +fn main(african_swallow_avg_speed : Field) { + assert(african_swallow_avg_speed == 65, "What is the airspeed velocity of an unladen swallow"); +} + +#[test] +fn test_king_arthur() { + main(65); +} + +#[test(should_fail_with = "What is the airspeed velocity of an unladen swallow")] +fn test_bridgekeeper() { + main(32); +} + +``` diff --git a/noir/docs/docs/how_to/_category_.json b/noir/docs/docs/how_to/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/noir/docs/docs/how_to/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/docs/how_to/how-to-recursion.md b/noir/docs/docs/how_to/how-to-recursion.md new file mode 100644 index 00000000000..226f7e6e73d --- /dev/null +++ b/noir/docs/docs/how_to/how-to-recursion.md @@ -0,0 +1,184 @@ +--- +title: How to use recursion on NoirJS +description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `backend_barretenberg`. +keywords: + [ + "NoirJS", + "EVM blockchain", + "smart contracts", + "recursion", + "solidity verifiers", + "Barretenberg backend", + "noir_js", + "backend_barretenberg", + "intermediate proofs", + "final proofs", + "nargo compile", + "json import", + "recursive circuit", + "recursive app" + ] +sidebar_position: 1 +--- + +This guide shows you how to use recursive proofs in your NoirJS app. For the sake of clarity, it is assumed that: + +- You already have a NoirJS app. If you don't, please visit the [NoirJS tutorial](../tutorials/noirjs_app.md) and the [reference](../reference/NoirJS/noir_js/index.md). +- You are familiar with what are recursive proofs and you have read the [recursion explainer](../explainers/explainer-recursion.md) +- You already built a recursive circuit following [the reference](../noir/standard_library/recursion.md), and understand how it works. + +It is also assumed that you're not using `noir_wasm` for compilation, and instead you've used [`nargo compile`](../reference/nargo_commands.md) to generate the `json` you're now importing into your project. However, the guide should work just the same if you're using `noir_wasm`. + +:::info + +As you've read in the [explainer](../explainers/explainer-recursion.md), a recursive proof is an intermediate proof. Meaning it doesn't necessarily generate the final step that makes it verifiable in a smart contract. However, it is easy to verify within another circuit. + +While "standard" usage of NoirJS packages abstracts final proofs, it currently lacks the necessary interface to abstract away intermediate proofs. Which means these proofs need to be created by using the backend directly. + +In short: + +- `noir_js` generates *only* final proofs +- `backend_barretenberg` generates both types of proofs + +::: + +In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume these two: + +- `main`: a circuit of type `assert(x != y)` +- `recursive`: a circuit that verifies `main` + +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir/noir-examples) repository. We will *not* be using it as a reference for this guide. + +## Step 1: Setup + +In a common NoirJS app, you need to instantiate a backend with something like `const backend = new Backend(circuit)`. Then you feed it to the `noir_js` interface. + +For recursiveness, this doesn't happen, and the only need for `noir_js` is only to `execute` a circuit and get its witness and return value. Everything else is not interfaced, so it needs to happen on the `backend` object. + +It is also recommended that you instantiate the backend with as many threads as possible, to allow for maximum concurrency: + +```js +const backend = new Backend(circuit, { threads: 8 }) +``` + +:::tip +You can use the [`os.cpus()`](https://nodejs.org/api/os.html#oscpus) object in `nodejs` or [`navigator.hardwareConcurrency`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency) on the browser to make the most out of those glorious cpu cores +::: + +## Step 2: Generating the witness and the proof for `main` + +After instantiating the backend, you should also instantiate `noir_js`. We will use it to execute the circuit and get the witness. + +```js +const noir = new Noir(circuit, backend) +const { witness } = noir.execute(input) +``` + +With this witness, you are now able to generate the intermediate proof for the main circuit: + +```js +const { proof, publicInputs } = await backend.generateIntermediateProof(witness) +``` + +:::warning + +Always keep in mind what is actually happening on your development process, otherwise you'll quickly become confused about what circuit are we actually running and why! + +In this case, you can imagine that Alice (running the `main` circuit) is proving something to Bob (running the `recursive` circuit), and Bob is verifying her proof within his proof. + +With this in mind, it becomes clear that our intermediate proof is the one *meant to be verified within another circuit*. So it is Alice's. Actually, the only final proof in this theoretical scenario would be the last one, sent on-chain. + +::: + +## Step 3 - Verification and proof artifacts + +Optionally, you are able to verify the intermediate proof: + +```js +const verified = await backend.verifyIntermediateProof({ proof, publicInputs }) +``` + +This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate the intermediate artifacts: + +```js +const { proofAsFields, vkAsFields, vkHash } = await backend.generateIntermediateProofArtifacts( { publicInputs, proof }, publicInputsCount) +``` + +This call takes the public inputs and the proof, but also the public inputs count. While this is easily retrievable by simply counting the `publicInputs` length, the backend interface doesn't currently abstract it away. + +:::info + +The `proofAsFields` has a constant size `[Field; 93]`. However, currently the backend doesn't remove the public inputs from the proof when converting it. + +This means that if your `main` circuit has two public inputs, then you should also modify the recursive circuit to accept a proof with the public inputs appended. This means that in our example, since `y` is a public input, our `proofAsFields` is of type `[Field; 94]`. + +Verification keys in Barretenberg are always of size 114. + +::: + +:::warning + +One common mistake is to forget *who* makes this call. + +In a situation where Alice is generating the `main` proof, if she generates the proof artifacts and sends them to Bob, which gladly takes them as true, this would mean Alice could prove anything! + +Instead, Bob needs to make sure *he* extracts the proof artifacts, using his own instance of the `main` circuit backend. This way, Alice has to provide a valid proof for the correct `main` circuit. + +::: + +## Step 4 - Recursive proof generation + +With the artifacts, generating a recursive proof is no different from a normal proof. You simply use the `backend` (with the recursive circuit) to generate it: + +```js +const recursiveInputs = { + verification_key: vkAsFields, // array of length 114 + proof: proofAsFields, // array of length 93 + size of public inputs + publicInputs: [mainInput.y], // using the example above, where `y` is the only public input + key_hash: vkHash, + input_aggregation_object: Array(16).fill(0) // this circuit is verifying a non-recursive proof, so there's no input aggregation object: just use zero +} + +const { witness, returnValue } = noir.execute(recursiveInputs) // we're executing the recursive circuit now! +const { proof, publicInputs } = backend.generateFinalProof(witness) +const verified = backend.verifyFinalProof({ proof, publicInputs }) +``` + +You can obviously chain this proof into another proof. In fact, if you're using recursive proofs, you're probably interested of using them this way! In that case, you should keep in mind the `returnValue`, as it will contain the `input_aggregation_object` for the next proof. + +:::tip + +Managing circuits and "who does what" can be confusing. To make sure your naming is consistent, you can keep them in an object. For example: + +```js +const circuits = { +main: mainJSON, +recursive: recursiveJSON +} +const backends = { +main: new BarretenbergBackend(circuits.main), +recursive: new BarretenbergBackend(circuits.recursive) +} +const noirs = { +main: new Noir(circuits.main, backends.main), +recursive: new Noir(circuits.recursive, backends.recursive) +} +``` + +This allows you to neatly call exactly the method you want without conflicting names: + +```js +// Alice runs this 👇 +const { witness: mainWitness } = await noirs.main.execute(input) +const proof = await backends.main.generateIntermediateProof(mainWitness) + +// Bob runs this 👇 +const verified = await backends.main.verifyIntermediateProof(proof) +const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateIntermediateProofArtifacts( + proof, + numPublicInputs, +); +const recursiveProof = await noirs.recursive.generateFinalProof(recursiveInputs) +``` + +::: diff --git a/noir/docs/versioned_docs/version-v0.10.5/examples/merkle-proof.mdx b/noir/docs/docs/how_to/merkle-proof.mdx similarity index 96% rename from noir/docs/versioned_docs/version-v0.10.5/examples/merkle-proof.mdx rename to noir/docs/docs/how_to/merkle-proof.mdx index 6430780817c..34074659ac1 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/examples/merkle-proof.mdx +++ b/noir/docs/docs/how_to/merkle-proof.mdx @@ -1,5 +1,5 @@ --- -title: Merkle Proof Membership +title: Prove Merkle Tree Membership description: Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a merkle tree with a specified root, at a given index. @@ -23,7 +23,7 @@ fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Fie The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen by the backend. The only requirement is that this hash function can heuristically be used as a -random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen` +random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen_hash` instead. ```rust diff --git a/noir/docs/versioned_docs/version-v0.10.5/nargo/03_solidity_verifier.md b/noir/docs/docs/how_to/solidity_verifier.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.10.5/nargo/03_solidity_verifier.md rename to noir/docs/docs/how_to/solidity_verifier.md index 9ac60cb0ba7..8022b0e5f20 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/nargo/03_solidity_verifier.md +++ b/noir/docs/docs/how_to/solidity_verifier.md @@ -1,9 +1,9 @@ --- -title: Solidity Verifier +title: Generate a Solidity Verifier description: Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart - contract. Read more to find out! + contract. Read more to find out keywords: [ solidity verifier, @@ -16,6 +16,7 @@ keywords: proving backend, Barretenberg, ] +sidebar_position: 0 --- For certain applications, it may be desirable to run the verifier as a smart contract instead of on diff --git a/noir/docs/docs/index.md b/noir/docs/docs/index.md index 75e1abf2932..016832f9f5e 100644 --- a/noir/docs/docs/index.md +++ b/noir/docs/docs/index.md @@ -1,9 +1,8 @@ --- -title: Introducing Noir +title: Noir description: - Learn about the public alpha release of Noir, a domain specific language heavily influenced by - Rust that compiles to an intermediate language which can be compiled to an arithmetic circuit or a - rank-1 constraint system. + Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to + an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. keywords: [ Noir, @@ -18,83 +17,69 @@ keywords: Proving System, Smart Contract Language, ] -slug: / +sidebar_position: 0 --- -## What is Noir? +## What's new about Noir? -Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. +Noir, a domain-specific language crafted for SNARK proving systems, stands out with its simplicity, flexibility, +and robust capabilities. Unlike conventional approaches that compile directly to a fixed NP-complete language, +Noir takes a two-pronged path. It first compiles to an adaptable intermediate language known as ACIR. From there, +depending on the project's needs, ACIR can be further compiled into an arithmetic circuit for integration with Aztec's +barretenberg backend or transformed into a rank-1 constraint system suitable for R1CS backends like Arkwork's Marlin +backend, among others. -It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. +This innovative design introduces unique challenges, yet it strategically separates the programming language from the +backend. Noir's approach echoes the modular philosophy of LLVM, offering developers a versatile toolkit for cryptographic +programming. ## Who is Noir for? -Noir can be used for a variety of purposes. - ### Solidity Developers -Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will -be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create -a verifier contract. +Noir streamlines the creation of Solidity contracts that interface with SNARK systems. +[`Utilize the nargo codegen-verifier`](./reference/nargo_commands.md#nargo-codegen-verifier) command to construct verifier +contracts efficiently. While the current alpha version offers this as a direct feature, future updates aim +to modularize this process for even greater ease of use. + +Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will be +modularised in the future; however, as of the alpha, you can use the + command to create a verifier contract. ### Protocol Developers -As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for -your stack, or maybe you simply want to use a different proving system. Since Noir does not compile -to a specific proof system, it is possible for protocol developers to replace the PLONK-based -proving system with a different proving system altogether. +Should the Aztec backend not align with your existing tech stack, or if you're inclined to integrate alternative +proving systems, Noir's agnostic compilation to a proof-agnostic intermediate language offers unmatched flexibility. +This allows protocol engineers the freedom to substitute the default PLONK-based system with an alternative of their +choice, tailoring the proving system to their specific needs. ### Blockchain developers -As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the -proving system and smart contract language has been pre-defined). In order for you to use Noir in -your blockchain, a proving system backend and a smart contract interface -must be implemented for it. - -## What's new about Noir? - -Noir is simple and flexible in its design, as it does not compile immediately to a fixed -NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled -to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). - -This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. - -## Current Features - -Compiler: - -- Module System -- For expressions -- Arrays -- Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] -- Unsigned integers -- If statements -- Structures and Tuples -- Generics - -ACIR Supported OPCODES: - -- Sha256 -- Blake2s -- Schnorr signature verification -- MerkleMembership -- Pedersen Commitment -- Pedersen Hash -- HashToField +Blockchain developers often face environmental constraints, such as predetermined proving systems and smart contract +languages. Noir addresses this by enabling the implementation of custom proving system backends and smart contract +interfaces, ensuring seamless integration with your blockchain's architecture, and expanding the horizons for innovation +within your projects. ## Libraries -Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). +Noir does not currently have an official package manager. You can find a list of available Noir libraries in the +[awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). Some libraries that are available today include: - [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library -- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) -- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers -- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address -- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees -- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir -- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers - -See the section on [dependencies](./modules_packages_crates/dependencies) for more information. +- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains + the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage + proof verification (or verification of any trie proof involving 32-byte long keys) +- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing + for computations on large unsigned integers +- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and + return the source Ethereum address +- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of + sparse Merkle trees +- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data + type, allowing access to negative numbers on Noir +- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, + allowing results that aren't whole numbers + +See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/noir/docs/docs/migration_notes.md b/noir/docs/docs/migration_notes.md index e87eb1feaba..d5d0682cf0c 100644 --- a/noir/docs/docs/migration_notes.md +++ b/noir/docs/docs/migration_notes.md @@ -16,7 +16,7 @@ To update, please make sure this field in `Nargo.toml` matches the output of `na ## ≥0.14 -The index of the [for loops](./language_concepts/02_control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: +The index of the [for loops](noir/syntax/control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: ```rust for i in 0..10 { @@ -78,7 +78,7 @@ nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/bar This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. -The gzipped filed is running this bash script: , where we need to gzip it as the Nargo currently expect the backend to be zipped up. +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. Then run: diff --git a/noir/docs/docs/noir/modules_packages_crates/_category_.json b/noir/docs/docs/noir/modules_packages_crates/_category_.json new file mode 100644 index 00000000000..1debcfe7675 --- /dev/null +++ b/noir/docs/docs/noir/modules_packages_crates/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Modules, Packages and Crates", + "position": 2, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/crates_and_packages.md b/noir/docs/docs/noir/modules_packages_crates/crates_and_packages.md similarity index 99% rename from noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/crates_and_packages.md rename to noir/docs/docs/noir/modules_packages_crates/crates_and_packages.md index fb83a33d94e..aae6795b229 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/crates_and_packages.md +++ b/noir/docs/docs/noir/modules_packages_crates/crates_and_packages.md @@ -2,6 +2,7 @@ title: Crates and Packages description: Learn how to use Crates and Packages in your Noir project keywords: [Nargo, dependencies, package management, crates, package] +sidebar_position: 0 --- ## Crates diff --git a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/dependencies.md b/noir/docs/docs/noir/modules_packages_crates/dependencies.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/dependencies.md rename to noir/docs/docs/noir/modules_packages_crates/dependencies.md index 9e6463801b7..57f0f9fd420 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/dependencies.md +++ b/noir/docs/docs/noir/modules_packages_crates/dependencies.md @@ -4,6 +4,7 @@ description: Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub and use them easily in your project. keywords: [Nargo, dependencies, GitHub, package management, versioning] +sidebar_position: 1 --- Nargo allows you to upload packages to GitHub and use them as dependencies. @@ -77,7 +78,7 @@ You can also import only the specific parts of dependency that you want to use, ```rust use dep::std::hash::sha256; -use dep::std::scalar_mul::fixed_base; +use dep::std::scalar_mul::fixed_base_embedded_curve; ``` Lastly, as demonstrated in the diff --git a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/modules.md b/noir/docs/docs/noir/modules_packages_crates/modules.md similarity index 99% rename from noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/modules.md rename to noir/docs/docs/noir/modules_packages_crates/modules.md index 147c9b284e8..f9f15aee8be 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/modules.md +++ b/noir/docs/docs/noir/modules_packages_crates/modules.md @@ -4,6 +4,7 @@ description: Learn how to organize your files using modules in Noir, following the same convention as Rust's module system. Examples included. keywords: [Noir, Rust, modules, organizing files, sub-modules] +sidebar_position: 2 --- Noir's module system follows the same convention as the _newer_ version of Rust's module system. diff --git a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/workspaces.md b/noir/docs/docs/noir/modules_packages_crates/workspaces.md similarity index 89% rename from noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/workspaces.md rename to noir/docs/docs/noir/modules_packages_crates/workspaces.md index eaa09506698..67a1dafa372 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/modules_packages_crates/workspaces.md +++ b/noir/docs/docs/noir/modules_packages_crates/workspaces.md @@ -1,5 +1,6 @@ --- title: Workspaces +sidebar_position: 3 --- Workspaces are a feature of nargo that allow you to manage multiple related Noir packages in a single repository. A workspace is essentially a group of related projects that share common build output directories and configurations. @@ -34,6 +35,6 @@ default-member = "crates/a" `default-member` indicates which package various commands process by default. -Libraries can be defined in a workspace. We just don't have a way to consume libraries from inside a workspace as external dependencies right now. +Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/noir/docs/docs/noir/standard_library/_category_.json b/noir/docs/docs/noir/standard_library/_category_.json new file mode 100644 index 00000000000..af04c0933fd --- /dev/null +++ b/noir/docs/docs/noir/standard_library/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Standard Library", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/docs/standard_library/black_box_fns.md b/noir/docs/docs/noir/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/docs/standard_library/black_box_fns.md rename to noir/docs/docs/noir/standard_library/black_box_fns.md diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json b/noir/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md similarity index 99% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md index 6e6b19b6861..8d573adb3be 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -1,6 +1,7 @@ --- title: Elliptic Curve Primitives keywords: [cryptographic primitives, Noir project] +sidebar_position: 4 --- Data structures and methods on them that allow you to carry out computations involving elliptic diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx similarity index 93% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx index 3934a0338d0..1376c51dfde 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -2,9 +2,10 @@ title: ECDSA Signature Verification description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 and secp256r1 curves keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, secp256r1, signatures] +sidebar_position: 3 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx similarity index 82% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx index 8f060ed3316..a9c10da6c06 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx @@ -2,9 +2,10 @@ title: EdDSA Verification description: Learn about the cryptographic primitives regarding EdDSA keywords: [cryptographic primitives, Noir project, eddsa, signatures] +sidebar_position: 5 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## eddsa::eddsa_poseidon_verify diff --git a/noir/docs/docs/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx similarity index 99% rename from noir/docs/docs/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx index 38077af1ce1..9250cb4a0c0 100644 --- a/noir/docs/docs/standard_library/cryptographic_primitives/00_hashes.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -5,6 +5,7 @@ description: blake2s, pedersen, mimc_bn254 and mimc keywords: [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] +sidebar_position: 0 --- import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives.md b/noir/docs/docs/noir/standard_library/cryptographic_primitives/index.md similarity index 92% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives.md rename to noir/docs/docs/noir/standard_library/cryptographic_primitives/index.md index 2df4f929474..650f30165d5 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives.md +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/index.md @@ -1,5 +1,5 @@ --- -title: Cryptographic primitives in Noir +title: Cryptographic Primitives description: Learn about the cryptographic primitives ready to use for any Noir project keywords: diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx new file mode 100644 index 00000000000..1e686303c18 --- /dev/null +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -0,0 +1,28 @@ +--- +title: Scalar multiplication +description: See how you can perform scalar multiplications over a fixed base in Noir +keywords: [cryptographic primitives, Noir project, scalar multiplication] +sidebar_position: 1 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## scalar_mul::fixed_base_embedded_curve + +Performs scalar multiplication over the embedded curve whose coordinates are defined by the +configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. + +```rust +fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base_embedded_curve(x); + std::println(scal); +} +``` + + diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx similarity index 91% rename from noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx index 0e219c0e5ff..7a2c9c20226 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -2,9 +2,10 @@ title: Schnorr Signatures description: Learn how you can verify Schnorr signatures using Noir keywords: [cryptographic primitives, Noir project, schnorr, signatures] +sidebar_position: 2 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## schnorr::verify_signature diff --git a/noir/docs/docs/noir/standard_library/logging.md b/noir/docs/docs/noir/standard_library/logging.md new file mode 100644 index 00000000000..16daf922e15 --- /dev/null +++ b/noir/docs/docs/noir/standard_library/logging.md @@ -0,0 +1,77 @@ +--- +title: Logging +description: + Learn how to use the println statement for debugging in Noir with this tutorial. Understand the + basics of logging in Noir and how to implement it in your code. +keywords: + [ + noir logging, + println statement, + print statement, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides two familiar statements you can use: `println` and `print`. Despite being a limited implementation of rust's `println!` and `print!` macros, these constructs can be useful for debugging. + +You can print the output of both statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are print statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constrains with `println` or `print` statements. This is due to every input in a test being a constant rather than a witness, so we issue an error during compilation while we only print during execution (which comes after compilation). Neither `println`, nor `print` are callable for failed constraints caught at compile time. + +Both `print` and `println` are generic functions which can work on integers, fields, strings, and even structs or expressions. Note however, that slices are currently unsupported. For example: + +```rust +use dep::std; + +struct Person { + age : Field, + height : Field, +} + +fn main(age : Field, height : Field) { + let person = Person { age : age, height : height }; + std::println(person); + std::println(age + height); + std::println("Hello world!"); +} +``` + +You can print different types in the same statement (including strings) with a type called `fmtstr`. It can be specified in the same way as a normal string, just prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + std::println(fmt_str); + + let s = myStruct { y: x, x: y }; + std::println(s); + + std::println(f"i: {i}, s: {s}"); + + std::println(x); + std::println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + std::println(f"s: {s}, foo: {foo}"); + + std::println(15); // prints 0x0f, implicit Field + std::println(-1 as u8); // prints 255 + std::println(-1 as i8); // prints -1 +``` + +Examples shown above are interchangeable between the two `print` statements: + +```rust +let person = Person { age : age, height : height }; + +std::println(person); +std::print(person); + +std::println("Hello world!"); // Prints with a newline at the end of the input +std::print("Hello world!"); // Prints the input and keeps cursor on the same line +``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/merkle_trees.md b/noir/docs/docs/noir/standard_library/merkle_trees.md similarity index 91% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/merkle_trees.md rename to noir/docs/docs/noir/standard_library/merkle_trees.md index 57d8c4a9e4f..5b45617812a 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/merkle_trees.md +++ b/noir/docs/docs/noir/standard_library/merkle_trees.md @@ -17,7 +17,7 @@ keywords: ## compute_merkle_root -Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](cryptographic_primitives/00_hashes.mdx#pedersen). +Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](./cryptographic_primitives/hashes.mdx#pedersen_hash). ```rust fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field @@ -39,7 +39,7 @@ example: */ fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { - let pubkey = std::scalar_mul::fixed_base(priv_key); + let pubkey = std::scalar_mul::fixed_base_embedded_curve(priv_key); let pubkey_x = pubkey[0]; let pubkey_y = pubkey[1]; let note_commitment = std::hash::pedersen([pubkey_x, pubkey_y, secret]); diff --git a/noir/docs/docs/standard_library/options.md b/noir/docs/docs/noir/standard_library/options.md similarity index 100% rename from noir/docs/docs/standard_library/options.md rename to noir/docs/docs/noir/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/recursion.md b/noir/docs/docs/noir/standard_library/recursion.md similarity index 65% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/recursion.md rename to noir/docs/docs/noir/standard_library/recursion.md index ff4c63acaa7..67962082a8f 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/recursion.md +++ b/noir/docs/docs/noir/standard_library/recursion.md @@ -19,11 +19,7 @@ This is a black box function. Read [this section](./black_box_fns) to learn more ::: -## Aggregation Object - -The purpose of the input aggregation object is a little less clear though (and the output aggregation object that is returned from the `std::verify_proof` method). Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points (thus completing the recursive verification). - -So for example in this circuit: +## Example usage ```rust use dep::std; @@ -37,17 +33,17 @@ fn main( proof_b : [Field; 94], ) -> pub [Field; 16] { let output_aggregation_object_a = std::verify_proof( - verification_key, - proof, - public_inputs, + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), key_hash, input_aggregation_object ); let output_aggregation_object = std::verify_proof( - verification_key, - proof_b, - public_inputs, + verification_key.as_slice(), + proof_b.as_slice(), + public_inputs.as_slice(), key_hash, output_aggregation_object_a ); @@ -60,8 +56,6 @@ fn main( } ``` -In this example we have a circuit, that generates proofs A and B, that is being verified in circuit C. Assuming that the proof being passed in is not already a recursive proof, the `input_aggregation_object` will be all zeros. It will then generate an `output_aggregation_object`. This blob of data then becomes the `input_aggregation_object` of the next recursive aggregation we wish to compute. We can see here as the same public inputs, verification key, and key hash are used that we are verifying two proofs generated from the same circuit in this single circuit. `std::verify_proof` returns a `[Field]` because the size of an aggregation object is proof system dependent--in barretenberg, aggregation objects are two G1 points, while in Halo2, the aggregation object is a list of G1 points that is log the circuit size. So for the final step we convert the slice into an array of size 16 because we are generating proofs using UltraPlonk. - ## Parameters ### `verification_key` diff --git a/noir/docs/docs/standard_library/zeroed.md b/noir/docs/docs/noir/standard_library/zeroed.md similarity index 100% rename from noir/docs/docs/standard_library/zeroed.md rename to noir/docs/docs/noir/standard_library/zeroed.md diff --git a/noir/docs/docs/noir/syntax/_category_.json b/noir/docs/docs/noir/syntax/_category_.json new file mode 100644 index 00000000000..666b691ae91 --- /dev/null +++ b/noir/docs/docs/noir/syntax/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Syntax", + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/04_assert.md b/noir/docs/docs/noir/syntax/assert.md similarity index 61% rename from noir/docs/versioned_docs/version-v0.6.0/language_concepts/04_assert.md rename to noir/docs/docs/noir/syntax/assert.md index a25a946123d..c5f9aff139c 100644 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/04_assert.md +++ b/noir/docs/docs/noir/syntax/assert.md @@ -5,13 +5,12 @@ description: comparison expression that follows to be true, and what happens if the expression is false at runtime. keywords: [Noir programming language, assert statement, predicate expression, comparison expression] +sidebar_position: 4 --- Noir includes a special `assert` function which will explicitly constrain the predicate/comparison expression that follows to be true. If this expression is false at runtime, the program will fail to -be proven. - -### Example +be proven. Example: ```rust fn main(x : Field, y : Field) { @@ -19,16 +18,10 @@ fn main(x : Field, y : Field) { } ``` -The above snippet compiles because `==` is a predicate operation. Conversely, the following will not -compile: +You can optionally provide a message to be logged when the assertion fails: ```rust -// INCORRECT - -fn main(x : Field, y : Field) { - assert(x + y); -} +assert(x == y, "x and y are not equal"); ``` -> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should -> equate to `x + y == 0` or if it should check the truthiness of the result. +> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/09_comments.md b/noir/docs/docs/noir/syntax/comments.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/09_comments.md rename to noir/docs/docs/noir/syntax/comments.md index 3bb4d2f25a4..f76ab49094b 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/09_comments.md +++ b/noir/docs/docs/noir/syntax/comments.md @@ -5,6 +5,7 @@ description: ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments are supported in Noir. keywords: [Noir programming language, comments, single-line comments, multi-line comments] +sidebar_position: 9 --- A comment is a line in your codebase which the compiler ignores, however it can be read by diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/02_control_flow.md b/noir/docs/docs/noir/syntax/control_flow.md similarity index 93% rename from noir/docs/versioned_docs/version-v0.7.1/language_concepts/02_control_flow.md rename to noir/docs/docs/noir/syntax/control_flow.md index 691c514d9a8..4ce65236db3 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/02_control_flow.md +++ b/noir/docs/docs/noir/syntax/control_flow.md @@ -4,6 +4,7 @@ description: Learn how to use loops and if expressions in the Noir programming language. Discover the syntax and examples for for loops and if-else statements. keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] +sidebar_position: 2 --- ## Loops @@ -19,6 +20,8 @@ for i in 0..10 { }; ``` +The index for loops is of type `u64`. + ## If Expressions Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required diff --git a/noir/docs/docs/noir/syntax/data_bus.md b/noir/docs/docs/noir/syntax/data_bus.md new file mode 100644 index 00000000000..6c7e9b60891 --- /dev/null +++ b/noir/docs/docs/noir/syntax/data_bus.md @@ -0,0 +1,21 @@ +--- +title: Data Bus +sidebar_position: 12 +--- +**Disclaimer** this feature is experimental, do not use it! + +The data bus is an optimization that the backend can use to make recursion more efficient. +In order to use it, you must define some inputs of the program entry points (usually the `main()` +function) with the `call_data` modifier, and the return values with the `return_data` modifier. +These modifiers are incompatible with `pub` and `mut` modifiers. + +## Example + +```rust +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + let a = z[x]; + a+y +} +``` + +As a result, both call_data and return_data will be treated as private inputs and encapsulated into a read-only array each, for the backend to process. diff --git a/noir/docs/docs/noir/syntax/data_types/_category_.json b/noir/docs/docs/noir/syntax/data_types/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/docs/noir/syntax/data_types/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/04_arrays.md b/noir/docs/docs/noir/syntax/data_types/arrays.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/04_arrays.md rename to noir/docs/docs/noir/syntax/data_types/arrays.md index f826b39bf39..075d39dadd4 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/04_arrays.md +++ b/noir/docs/docs/noir/syntax/data_types/arrays.md @@ -10,6 +10,7 @@ keywords: examples, indexing, ] +sidebar_position: 4 --- An array is one way of grouping together values into one compound type. Array types can be inferred @@ -63,6 +64,13 @@ let array: [Field; 32] = [0; 32]; let sl = array.as_slice() ``` +You can define multidimensional arrays: + +```rust +let array : [[Field; 2]; 2]; +let element = array[0][0]; +``` + ## Types You can create arrays of primitive types or structs. There is not yet support for nested arrays diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/02_booleans.md b/noir/docs/docs/noir/syntax/data_types/booleans.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/02_booleans.md rename to noir/docs/docs/noir/syntax/data_types/booleans.md index 885db167d83..69826fcd724 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/02_booleans.md +++ b/noir/docs/docs/noir/syntax/data_types/booleans.md @@ -10,6 +10,7 @@ keywords: examples, logical operations, ] +sidebar_position: 2 --- diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/00_fields.md b/noir/docs/docs/noir/syntax/data_types/fields.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/00_fields.md rename to noir/docs/docs/noir/syntax/data_types/fields.md index 658a0441ffb..a1c67945d66 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/00_fields.md +++ b/noir/docs/docs/noir/syntax/data_types/fields.md @@ -10,6 +10,7 @@ keywords: examples, best practices, ] +sidebar_position: 0 --- The field type corresponds to the native field type of the proving backend. @@ -158,7 +159,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/10_function_types.md b/noir/docs/docs/noir/syntax/data_types/function_types.md similarity index 84% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/10_function_types.md rename to noir/docs/docs/noir/syntax/data_types/function_types.md index 1ec92efd594..61e4076adaf 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/10_function_types.md +++ b/noir/docs/docs/noir/syntax/data_types/function_types.md @@ -1,5 +1,6 @@ --- title: Function types +sidebar_position: 10 --- Noir supports higher-order functions. The syntax for a function type is as follows: @@ -22,4 +23,4 @@ fn main() { ``` A function type also has an optional capture environment - this is necessary to support closures. -See [Lambdas](../08_lambdas.md) for more details. +See [Lambdas](@site/docs/noir/syntax/lambdas.md) for more details. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types.md b/noir/docs/docs/noir/syntax/data_types/index.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types.md rename to noir/docs/docs/noir/syntax/data_types/index.md index d546cc463a8..52e568e9b7e 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types.md +++ b/noir/docs/docs/noir/syntax/data_types/index.md @@ -79,7 +79,7 @@ fn main() { } ``` -Type aliases can also be used with [generics](./06_generics.md): +Type aliases can also be used with [generics](@site/docs/noir/syntax/generics.md): ```rust type Id = Size; diff --git a/noir/docs/docs/noir/syntax/data_types/integers.md b/noir/docs/docs/noir/syntax/data_types/integers.md new file mode 100644 index 00000000000..7d1e83cf4e9 --- /dev/null +++ b/noir/docs/docs/noir/syntax/data_types/integers.md @@ -0,0 +1,113 @@ +--- +title: Integers +description: Explore the Integer data type in Noir. Learn about its methods, see real-world examples, and grasp how to efficiently use Integers in your Noir code. +keywords: [noir, integer types, methods, examples, arithmetic] +sidebar_position: 1 +--- + +An integer type is a range constrained field type. The Noir frontend supports arbitrarily-sized, both unsigned and signed integer types. + +:::info + +When an integer is defined in Noir without a specific type, it will default to `Field`. + +The one exception is for loop indices which default to `u64` since comparisons on `Field`s are not possible. + +::: + +## Unsigned Integers + +An unsigned integer type is specified first with the letter `u` (indicating its unsigned nature) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: u8 = 1; + let y: u8 = 1; + let z = x + y; + assert (z == 2); +} +``` + +The bit size determines the maximum value the integer type can store. For example, a `u8` variable can store a value in the range of 0 to 255 (i.e. $\\2^{8}-1\\$). + +## Signed Integers + +A signed integer type is specified first with the letter `i` (which stands for integer) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: i8 = -1; + let y: i8 = -1; + let z = x + y; + assert (z == -2); +} +``` + +The bit size determines the maximum and minimum range of value the integer type can store. For example, an `i8` variable can store a value in the range of -128 to 127 (i.e. $\\-2^{7}\\$ to $\\2^{7}-1\\$). + +:::tip + +If you are using the default proving backend with Noir, both even (e.g. _u2_, _i2_) and odd (e.g. _u3_, _i3_) arbitrarily-sized integer types up to 127 bits (i.e. _u127_ and _i127_) are supported. + +::: + +## Overflows + +Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: + +```rust +fn main(x: u8, y: u8) { + let z = x + y; +} +``` + +With: + +```toml +x = "255" +y = "1" +``` + +Would result in: + +``` +$ nargo prove +error: Assertion failed: 'attempt to add with overflow' +┌─ ~/src/main.nr:9:13 +│ +│ let z = x + y; +│ ----- +│ += Call stack: + ... +``` + +A similar error would happen with signed integers: + +```rust +fn main() { + let x: i8 = -118; + let y: i8 = -11; + let z = x + y; +} +``` + +### Wrapping methods + +Although integer overflow is expected to error, some use-cases rely on wrapping. For these use-cases, the standard library provides `wrapping` variants of certain common operations: + +```rust +fn wrapping_add(x: T, y: T) -> T; +fn wrapping_sub(x: T, y: T) -> T; +fn wrapping_mul(x: T, y: T) -> T; +``` + +Example of how it is used: + +```rust +use dep::std; + +fn main(x: u8, y: u8) -> pub u8 { + std::wrapping_add(x + y) +} +``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/09_references.md b/noir/docs/docs/noir/syntax/data_types/references.md similarity index 96% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/09_references.md rename to noir/docs/docs/noir/syntax/data_types/references.md index b0c35ce2cb9..a5293d11cfb 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/09_references.md +++ b/noir/docs/docs/noir/syntax/data_types/references.md @@ -1,5 +1,6 @@ --- title: References +sidebar_position: 9 --- Noir supports first-class references. References are a bit like pointers: they point to a specific address that can be followed to access the data stored at that address. You can use Rust-like syntax to use pointers in Noir: the `&` operator references the variable, the `*` operator dereferences it. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/05_slices.md b/noir/docs/docs/noir/syntax/data_types/slices.mdx similarity index 86% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/05_slices.md rename to noir/docs/docs/noir/syntax/data_types/slices.mdx index bc7f5c531e7..4a6ee816aa2 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/05_slices.md +++ b/noir/docs/docs/noir/syntax/data_types/slices.mdx @@ -1,23 +1,13 @@ --- title: Slices -description: - Explore the Slice data type in Noir. Understand its methods, see real-world examples, and learn how to effectively use Slices in your Noir programs. -keywords: - [ - noir, - slice type, - methods, - examples, - subarrays, - ] +description: Explore the Slice data type in Noir. Understand its methods, see real-world examples, and learn how to effectively use Slices in your Noir programs. +keywords: [noir, slice type, methods, examples, subarrays] +sidebar_position: 5 --- -:::caution +import Experimental from '@site/src/components/Notes/_experimental.mdx'; -This feature is experimental. You should expect it to change in future versions, -cause unexpected behavior, or simply not work at all. - -::: + A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size. @@ -32,7 +22,7 @@ fn main() -> pub Field { } ``` -View the corresponding test file [here]([test-file]. +View the corresponding test file [here][test-file]. [test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr diff --git a/noir/docs/docs/language_concepts/data_types/03_strings.md b/noir/docs/docs/noir/syntax/data_types/strings.md similarity index 99% rename from noir/docs/docs/language_concepts/data_types/03_strings.md rename to noir/docs/docs/noir/syntax/data_types/strings.md index e647a58472f..8d76d4ca654 100644 --- a/noir/docs/docs/language_concepts/data_types/03_strings.md +++ b/noir/docs/docs/noir/syntax/data_types/strings.md @@ -10,6 +10,7 @@ keywords: examples, concatenation, ] +sidebar_position: 3 --- diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/08_structs.md b/noir/docs/docs/noir/syntax/data_types/structs.md similarity index 94% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/08_structs.md rename to noir/docs/docs/noir/syntax/data_types/structs.md index 85649dfb389..dbf68c99813 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/08_structs.md +++ b/noir/docs/docs/noir/syntax/data_types/structs.md @@ -10,6 +10,7 @@ keywords: examples, data structures, ] +sidebar_position: 8 --- A struct also allows for grouping multiple values of different types. Unlike tuples, we can also @@ -67,7 +68,3 @@ fn get_octopus() -> Animal { The new variables can be bound with names different from the original struct field names, as showcased in the `legs --> feet` binding in the example above. - -:::note -You can use Structs as inputs to the `main` function, but you can't output them -::: diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/07_tuples.md b/noir/docs/docs/noir/syntax/data_types/tuples.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/07_tuples.md rename to noir/docs/docs/noir/syntax/data_types/tuples.md index 5f6cab974a8..2ec5c9c4113 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/07_tuples.md +++ b/noir/docs/docs/noir/syntax/data_types/tuples.md @@ -10,6 +10,7 @@ keywords: examples, multi-value containers, ] +sidebar_position: 7 --- A tuple collects multiple values like an array, but with the added ability to collect values of diff --git a/noir/docs/docs/noir/syntax/data_types/vectors.mdx b/noir/docs/docs/noir/syntax/data_types/vectors.mdx new file mode 100644 index 00000000000..10e35711b74 --- /dev/null +++ b/noir/docs/docs/noir/syntax/data_types/vectors.mdx @@ -0,0 +1,173 @@ +--- +title: Vectors +description: Delve into the Vector data type in Noir. Learn about its methods, practical examples, and best practices for using Vectors in your Noir code. +keywords: [noir, vector type, methods, examples, dynamic arrays] +sidebar_position: 6 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. + +Example: + +```rust +use dep::std::collections::vec::Vec; + +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` + +## Methods + +### new + +Creates a new, empty vector. + +```rust +pub fn new() -> Self { + Self { slice: [] } +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### from_slice + +Creates a vector containing each element from a given slice. Mutations to the resulting vector will not affect the original slice. + +```rust +pub fn from_slice(slice: [T]) -> Self { + Self { slice } +} +``` + +Example: + +```rust +let arr: [Field] = [1, 2, 3]; +let vector_from_slice = Vec::from_slice(arr); +assert(vector_from_slice.len() == 3); +``` + +### get + +Retrieves an element from the vector at a given index. Panics if the index points beyond the vector's end. + +```rust +pub fn get(self, index: Field) -> T { + self.slice[index] +} +``` + +Example: + +```rust +let vector: Vec = Vec::from_slice([10, 20, 30]); +assert(vector.get(1) == 20); +``` + +### push + +Adds a new element to the vector's end, returning a new vector with a length one greater than the original unmodified vector. + +```rust +pub fn push(&mut self, elem: T) { + self.slice = self.slice.push_back(elem); +} +``` + +Example: + +```rust +let mut vector: Vec = Vec::new(); +vector.push(10); +assert(vector.len() == 1); +``` + +### pop + +Removes an element from the vector's end, returning a new vector with a length one less than the original vector, along with the removed element. Panics if the vector's length is zero. + +```rust +pub fn pop(&mut self) -> T { + let (popped_slice, last_elem) = self.slice.pop_back(); + self.slice = popped_slice; + last_elem +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 20]); +let popped_elem = vector.pop(); +assert(popped_elem == 20); +assert(vector.len() == 1); +``` + +### insert + +Inserts an element at a specified index, shifting subsequent elements to the right. + +```rust +pub fn insert(&mut self, index: Field, elem: T) { + self.slice = self.slice.insert(index, elem); +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 30]); +vector.insert(1, 20); +assert(vector.get(1) == 20); +``` + +### remove + +Removes an element at a specified index, shifting subsequent elements to the left, and returns the removed element. + +```rust +pub fn remove(&mut self, index: Field) -> T { + let (new_slice, elem) = self.slice.remove(index); + self.slice = new_slice; + elem +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 20, 30]); +let removed_elem = vector.remove(1); +assert(removed_elem == 20); +assert(vector.len() == 2); +``` + +### len + +Returns the number of elements in the vector. + +```rust +pub fn len(self) -> Field { + self.slice.len() +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/09_distinct.md b/noir/docs/docs/noir/syntax/distinct.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.9.0/language_concepts/09_distinct.md rename to noir/docs/docs/noir/syntax/distinct.md index e7ff7f5017a..b59e0296b23 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/09_distinct.md +++ b/noir/docs/docs/noir/syntax/distinct.md @@ -1,5 +1,6 @@ --- title: Distinct Witnesses +sidebar_position: 10 --- The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures diff --git a/noir/docs/docs/noir/syntax/functions.md b/noir/docs/docs/noir/syntax/functions.md new file mode 100644 index 00000000000..48aba9cd058 --- /dev/null +++ b/noir/docs/docs/noir/syntax/functions.md @@ -0,0 +1,226 @@ +--- +title: Functions +description: + Learn how to declare functions and methods in Noir, a programming language with Rust semantics. + This guide covers parameter declaration, return types, call expressions, and more. +keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] +sidebar_position: 1 +--- + +Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. + +To declare a function the `fn` keyword is used. + +```rust +fn foo() {} +``` + +By default, functions are visible only within the package they are defined. To make them visible outside of that package (for example, as part of a [library](../modules_packages_crates/crates_and_packages.md#libraries)), you should mark them as `pub`: + +```rust +pub fn foo() {} +``` + +You can also restrict the visibility of the function to only the crate it was defined in, by specifying `pub(crate)`: + +```rust +pub(crate) fn foo() {} //foo can only be called within its crate +``` + +All parameters in a function must have a type and all types are known at compile time. The parameter +is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. + +```rust +fn foo(x : Field, y : Field){} +``` + +The return type of a function can be stated by using the `->` arrow notation. The function below +states that the foo function must return a `Field`. If the function returns no value, then the arrow +is omitted. + +```rust +fn foo(x : Field, y : Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## Main function + +If you're writing a binary, the `main` function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time: + +```rust +fn main(x : Field) // this is fine: passing a Field +fn main(x : [Field; 2]) // this is also fine: passing a Field with known size at compile-time +fn main(x : (Field, bool)) // 👌: passing a (Field, bool) tuple means size 2 +fn main(x : str<5>) // this is fine, as long as you pass a string of size 5 + +fn main(x : Vec) // can't compile, has variable size +fn main(x : [Field]) // can't compile, has variable size +fn main(....// i think you got it by now +``` + +Keep in mind [tests](../../getting_started/tooling/testing.md) don't differentiate between `main` and any other function. The following snippet passes tests, but won't compile or prove: + +```rust +fn main(x : [Field]) { + assert(x[0] == 1); +} + +#[test] +fn test_one() { + main([1, 2]); +} +``` + +```bash +$ nargo test +[testing] Running 1 test functions +[testing] Testing test_one... ok +[testing] All tests passed + +$ nargo check +The application panicked (crashed). +Message: Cannot have variable sized arrays as a parameter to main +``` + +## Call Expressions + +Calling a function in Noir is executed by using the function name and passing in the necessary +arguments. + +Below we show how to call the `foo` function from the `main` function using a call expression: + +```rust +fn main(x : Field, y : Field) { + let z = foo(x); +} + +fn foo(x : Field) -> Field { + x + x +} +``` + +## Methods + +You can define methods in Noir on any struct type in scope. + +```rust +struct MyStruct { + foo: Field, + bar: Field, +} + +impl MyStruct { + fn new(foo: Field) -> MyStruct { + MyStruct { + foo, + bar: 2, + } + } + + fn sum(self) -> Field { + self.foo + self.bar + } +} + +fn main() { + let s = MyStruct::new(40); + assert(s.sum() == 42); +} +``` + +Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as +follows: + +```rust +assert(MyStruct::sum(s) == 42); +``` + +It is also possible to specialize which method is chosen depending on the [generic](./generics.md) type that is used. In this example, the `foo` function returns different values depending on its type: + +```rust +struct Foo {} + +impl Foo { + fn foo(self) -> Field { 1 } +} + +impl Foo { + fn foo(self) -> Field { 2 } +} + +fn main() { + let f1: Foo = Foo{}; + let f2: Foo = Foo{}; + assert(f1.foo() + f2.foo() == 3); +} +``` + +Also note that impls with the same method name defined in them cannot overlap. For example, if we already have `foo` defined for `Foo` and `Foo` like we do above, we cannot also define `foo` in an `impl Foo` since it would be ambiguous which version of `foo` to choose. + +```rust +// Including this impl in the same project as the above snippet would +// cause an overlapping impls error +impl Foo { + fn foo(self) -> Field { 3 } +} +``` + +## Lambdas + +Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +See [Lambdas](./lambdas.md) for more details. + +## Attributes + +Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. + +Supported attributes include: + +- **builtin**: the function is implemented by the compiler, for efficiency purposes. +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` +- **field**: Used to enable conditional compilation of code depending on the field size. See below for more details +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./unconstrained.md) and [NoirJS](../../reference/NoirJS/noir_js/index.md) for more details. +- **test**: mark the function as unit tests. See [Tests](../../getting_started/tooling/testing.md) for more details + +### Field Attribute + +The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. +The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. +As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. + +Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + +```rust +#[field(bn254)] +fn foo() -> u32 { + 1 +} + +#[field(23)] +fn foo() -> u32 { + 2 +} + +// This commented code would not compile as foo would be defined twice because it is the same field as bn254 +// #[field(21888242871839275222246405745257275088548364400416034343698204186575808495617)] +// fn foo() -> u32 { +// 2 +// } + +#[field(bls12_381)] +fn foo() -> u32 { + 3 +} +``` + +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/06_generics.md b/noir/docs/docs/noir/syntax/generics.md similarity index 99% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/06_generics.md rename to noir/docs/docs/noir/syntax/generics.md index 9fb4177c2a8..443ca2b45a5 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/06_generics.md +++ b/noir/docs/docs/noir/syntax/generics.md @@ -2,6 +2,7 @@ title: Generics description: Learn how to use Generics in Noir keywords: [Noir, Rust, generics, functions, structs] +sidebar_position: 6 --- Generics allow you to use the same functions with multiple different concrete data types. You can diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/08_lambdas.md b/noir/docs/docs/noir/syntax/lambdas.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/08_lambdas.md rename to noir/docs/docs/noir/syntax/lambdas.md index ae1e6aecab1..e0a267adfda 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/08_lambdas.md +++ b/noir/docs/docs/noir/syntax/lambdas.md @@ -2,6 +2,7 @@ title: Lambdas description: Learn how to use anonymous functions in Noir programming language. keywords: [Noir programming language, lambda, closure, function, anonymous function] +sidebar_position: 8 --- ## Introduction @@ -43,7 +44,7 @@ It may catch you by surprise that the following code fails to compile: ```rust fn foo(f: fn () -> Field) -> Field { - f() + f() } fn main() { @@ -69,7 +70,7 @@ with closures with any environment, as well as with regular functions: ```rust fn foo(f: fn[Env]() -> Field) -> Field { - f() + f() } fn main() { diff --git a/noir/docs/docs/language_concepts/07_mutability.md b/noir/docs/docs/noir/syntax/mutability.md similarity index 98% rename from noir/docs/docs/language_concepts/07_mutability.md rename to noir/docs/docs/noir/syntax/mutability.md index 4641521b1d9..58e9c1cecfb 100644 --- a/noir/docs/docs/language_concepts/07_mutability.md +++ b/noir/docs/docs/noir/syntax/mutability.md @@ -4,6 +4,7 @@ description: Learn about mutable variables, constants, and globals in Noir programming language. Discover how to declare, modify, and use them in your programs. keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +sidebar_position: 7 --- Variables in noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned @@ -37,7 +38,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/03_ops.md b/noir/docs/docs/noir/syntax/ops.md similarity index 90% rename from noir/docs/versioned_docs/version-v0.7.1/language_concepts/03_ops.md rename to noir/docs/docs/noir/syntax/ops.md index da02b126059..977c8ba1203 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/03_ops.md +++ b/noir/docs/docs/noir/syntax/ops.md @@ -14,6 +14,7 @@ keywords: short-circuiting, backend, ] +sidebar_position: 3 --- # Operations @@ -29,11 +30,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/10_shadowing.md b/noir/docs/docs/noir/syntax/shadowing.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.9.0/language_concepts/10_shadowing.md rename to noir/docs/docs/noir/syntax/shadowing.md index efd743e764f..b5a6b6b38b9 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/10_shadowing.md +++ b/noir/docs/docs/noir/syntax/shadowing.md @@ -1,5 +1,6 @@ --- title: Shadowing +sidebar_position: 11 --- Noir allows for inheriting variables' values and re-declaring them with the same name similar to Rust, known as shadowing. diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/05_unconstrained.md b/noir/docs/docs/noir/syntax/unconstrained.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.9.0/language_concepts/05_unconstrained.md rename to noir/docs/docs/noir/syntax/unconstrained.md index 6b621eda3eb..7a61d3953ef 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/05_unconstrained.md +++ b/noir/docs/docs/noir/syntax/unconstrained.md @@ -3,10 +3,9 @@ title: Unconstrained Functions description: "Learn about what unconstrained functions in Noir are, how to use them and when you'd want to." keywords: [Noir programming language, unconstrained, open] +sidebar_position: 5 --- - - Unconstrained functions are functions which do not constrain any of the included computation and allow for non-determinisitic computation. ## Why? diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/.nojekyll b/noir/docs/docs/reference/NoirJS/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/noir/docs/docs/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..5cbe9421b92 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,185 @@ +# BarretenbergBackend + +## Implements + +- [`Backend`](../interfaces/Backend.md) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`destroy`](../interfaces/Backend.md#destroy) + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateFinalProof`](../interfaces/Backend.md#generatefinalproof) + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(witness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `witness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProof`](../interfaces/Backend.md#generateintermediateproof) + +#### Example + +```typescript +const intermediateProof = await backend.generateIntermediateProof(witness); +``` + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProofArtifacts`](../interfaces/Backend.md#generateintermediateproofartifacts) + +#### Example + +```typescript +const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyFinalProof`](../interfaces/Backend.md#verifyfinalproof) + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyIntermediateProof`](../interfaces/Backend.md#verifyintermediateproof) + +#### Example + +```typescript +const isValidIntermediate = await backend.verifyIntermediateProof(proof); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/index.md b/noir/docs/docs/reference/NoirJS/backend_barretenberg/index.md new file mode 100644 index 00000000000..bfbecb52864 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/index.md @@ -0,0 +1,45 @@ +# backend_barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | + +### Interfaces + +| Interface | Description | +| :------ | :------ | +| [Backend](interfaces/Backend.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | + +## Functions + +### flattenPublicInputs() + +```ts +flattenPublicInputs(publicInputs): string[] +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `WitnessMap` | + +#### Returns + +`string`[] + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/interfaces/Backend.md b/noir/docs/docs/reference/NoirJS/backend_barretenberg/interfaces/Backend.md new file mode 100644 index 00000000000..3eb9645c8d2 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/interfaces/Backend.md @@ -0,0 +1,132 @@ +# Backend + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates an intermediate proof (meant to be verified in another circuit) + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | +| `numOfPublicInputs` | `number` | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Retrieves the artifacts from a proof in the Field format + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies an intermediate proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..266ade75d17 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,19 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md b/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/noir/docs/docs/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..2aaa55bccf6 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"}]},{"type":"category","label":"Interfaces","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/interfaces/Backend","label":"Backend"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/ProofData","label":"ProofData"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/docs/reference/NoirJS/noir_js/.nojekyll b/noir/docs/docs/reference/NoirJS/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/docs/reference/NoirJS/noir_js/classes/Noir.md b/noir/docs/docs/reference/NoirJS/noir_js/classes/Noir.md new file mode 100644 index 00000000000..34e20d99684 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/classes/Noir.md @@ -0,0 +1,132 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `backend`? | `Backend` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateFinalProof() + +```ts +generateFinalProof(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateFinalProof(input) +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyFinalProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/and.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/blake2s256.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..0ba5783f0d5 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,29 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/keccak256.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/sha256.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/functions/xor.md b/noir/docs/docs/reference/NoirJS/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/index.md b/noir/docs/docs/reference/NoirJS/noir_js/index.md new file mode 100644 index 00000000000..8b9e35bc9a1 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/index.md @@ -0,0 +1,37 @@ +# noir_js + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [InputMap](type-aliases/InputMap.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/InputMap.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/InputMap.md new file mode 100644 index 00000000000..c714e999d93 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/InputMap.md @@ -0,0 +1,13 @@ +# InputMap + +```ts +type InputMap: object; +``` + +## Index signature + + \[`key`: `string`\]: `InputValue` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ProofData.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/docs/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/noir/docs/docs/reference/NoirJS/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..fe2629ddc9f --- /dev/null +++ b/noir/docs/docs/reference/NoirJS/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/InputMap","label":"InputMap"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ProofData","label":"ProofData"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_js/functions/and","label":"and"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/docs/reference/_category_.json b/noir/docs/docs/reference/_category_.json new file mode 100644 index 00000000000..5b6a20a609a --- /dev/null +++ b/noir/docs/docs/reference/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 4, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/docs/reference/nargo_commands.md b/noir/docs/docs/reference/nargo_commands.md new file mode 100644 index 00000000000..ff3dee8973f --- /dev/null +++ b/noir/docs/docs/reference/nargo_commands.md @@ -0,0 +1,250 @@ +--- +title: Nargo +description: + Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, + generate Solidity verifier smart contract and compile into JSON file containing ACIR + representation and ABI of circuit. +keywords: + [ + Nargo, + Noir CLI, + Noir Prover, + Noir Verifier, + generate Solidity verifier, + compile JSON file, + ACIR representation, + ABI of circuit, + TypeScript, + ] +sidebar_position: 0 +--- + +## General options + +| Option | Description | +| -------------------- | -------------------------------------------------- | +| `--show-ssa` | Emit debug information for the intermediate SSA IR | +| `--deny-warnings` | Quit execution when warnings are emitted | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +| Argument | Description | +| -------------- | -------------------------------------------- | +| `` | The subcommand whose help message to display | + +## `nargo backend` + +Installs and selects custom backends used to generate and verify proofs. + +### Commands + +| Command | Description | +| ----------- | --------------------------------------------------------- | +| `current` | Prints the name of the currently active backend | +| `ls` | Prints the list of currently installed backends | +| `use` | Select the backend to use | +| `install` | Install a new backend from a URL | +| `uninstall` | Uninstalls a backend | +| `help` | Print this message or the help of the given subcommand(s) | + +### Options + +| Option | Description | +| ------------ | ----------- | +| `-h, --help` | Print help | + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to check | +| `--workspace` | Check all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +### `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to codegen | +| `--workspace` | Codegen all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo compile` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +You can also use "build" as an alias for compile (e.g. `nargo build`). + +### Options + +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `--package ` | The name of the package to compile | +| `--workspace` | Compile all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo new ` + +Creates a new Noir project in a new folder. + +**Arguments** + +| Argument | Description | +| -------- | -------------------------------- | +| `` | The path to save the new project | + +### Options + +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: package directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | + +## `nargo init` + +Creates a new Noir project in the current directory. + +### Options + +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: current directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | + +## `nargo execute [WITNESS_NAME]` + +Runs the Noir program and prints its return value. + +**Arguments** + +| Argument | Description | +| ---------------- | ----------------------------------------- | +| `[WITNESS_NAME]` | Write the execution witness to named file | + +### Options + +| Option | Description | +| --------------------------------- | ------------------------------------------------------------------------------------ | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `--package ` | The name of the package to execute | +| `--workspace` | Execute all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A +`.tr` file will then be saved in the `./target` folder. + +## `nargo prove` + +Creates a proof for the program. + +### Options + +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--verify` | Verify proof after proving | +| `--package ` | The name of the package to prove | +| `--workspace` | Prove all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid. + +### Options + +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--package ` | The name of the package to verify | +| `--workspace` | Verify all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo test [TEST_NAME]` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. + +Takes an optional `--exact` flag which allows you to select tests based on an exact name. + +See an example on the [testing page](../getting_started/tooling/testing.md). + +### Options + +| Option | Description | +| --------------------- | -------------------------------------- | +| `--show-output` | Display output of `println` statements | +| `--exact` | Only run tests that match exactly | +| `--package ` | The name of the package to test | +| `--workspace` | Test all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo info` + +Prints a table containing the information of the package. + +Currently the table provide + +1. The number of ACIR opcodes +2. The final number gates in the circuit used by a backend + +If the file contains a contract the table will provide the +above information about each function of the contract. + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). + +## `nargo fmt` + +Automatically formats your Noir source code based on the default formatting settings. diff --git a/noir/docs/docs/tutorials/noirjs_app.md b/noir/docs/docs/tutorials/noirjs_app.md new file mode 100644 index 00000000000..302ee4aeade --- /dev/null +++ b/noir/docs/docs/tutorials/noirjs_app.md @@ -0,0 +1,261 @@ +--- +title: Tiny NoirJS app +description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment +keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs] +sidebar_position: 0 +--- + +NoirJS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Before we start + +:::note + +Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.18.x matches `noir_js@0.18.x`, etc. + +In this guide, we will be pinned to 0.17.0. + +::: + +Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). + +First of all, follow the the [Nargo guide](../getting_started/installation/index.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: + +```bash +nargo compile +``` + +Your folder structure should look like: + +```tree +. +└── circuit + ├── Nargo.toml + ├── src + │ └── main.nr + └── target + └── circuit.json +``` + +## Starting a new project + +Go back to the previous folder and start a new project by running run `npm init`. You can configure your project or just leave the defaults, and see a `package.json` appear in your root folder. + +## Installing dependencies + +We'll need two `npm` packages. These packages will provide us the methods we need to run and verify proofs: + +```bash +npm i @noir-lang/backend_barretenberg@^0.17.0 @noir-lang/noir_js@^0.17.0 +``` + +To serve our page, we can use a build tool such as `vite`. Because we're gonna use some `wasm` files, we need to install a plugin as well. Run: + +```bash +npm i --save-dev vite rollup-plugin-copy +``` + +Since we're on the dependency world, we may as well define a nice starting script. Vite makes it easy. Just open `package.json`, find the block "scripts" and add this just below the line with `"test" : "echo......."`: + +```json + "start": "vite --open" +``` + +If you want do build a static website, you can also add some build and preview scripts: + +```json + "build": "vite build", + "preview": "vite preview" +``` + +## Vite plugins + +Vite is great, but support from `wasm` doesn't work out-of-the-box. We're gonna write a quick plugin and use another one. Just copy and paste this into a file named `vite.config.js`. You don't need to understand it, just trust me bro. + +```js +import { defineConfig } from 'vite'; +import copy from 'rollup-plugin-copy'; +import fs from 'fs'; +import path from 'path'; + +const wasmContentTypePlugin = { + name: 'wasm-content-type-plugin', + configureServer(server) { + server.middlewares.use(async (req, res, next) => { + if (req.url.endsWith('.wasm')) { + res.setHeader('Content-Type', 'application/wasm'); + const newPath = req.url.replace('deps', 'dist'); + const targetPath = path.join(__dirname, newPath); + const wasmContent = fs.readFileSync(targetPath); + return res.end(wasmContent); + } + next(); + }); + }, +}; + +export default defineConfig(({ command }) => { + if (command === 'serve') { + return { + plugins: [ + copy({ + targets: [{ src: 'node_modules/**/*.wasm', dest: 'node_modules/.vite/dist' }], + copySync: true, + hook: 'buildStart', + }), + command === 'serve' ? wasmContentTypePlugin : [], + ], + }; + } + + return {}; +}); +``` + +## HTML + +Here's the simplest HTML with some terrible UI. Create a file called `index.html` and paste this: + +```html + + + + + + +

Very basic Noir app

+
+

Logs

+

Proof

+
+ + +``` + +## Some good old vanilla Javascript + +Create a new file `app.js`, which is where our javascript code will live. Let's start with this code inside: + +```js +document.addEventListener('DOMContentLoaded', async () => { + // here's where the magic happens +}); + +function display(container, msg) { + const c = document.getElementById(container); + const p = document.createElement('p'); + p.textContent = msg; + c.appendChild(p); +} +``` + +We can manipulate our website with this little function, so we can see our website working. + +## Adding Noir + +If you come from the previous page, your folder structure should look like this: + +```tree +├── app.js +├── circuit +│ ├── Nargo.toml +│ ├── src +│ │ └── main.nr +│ └── target +│ └── circuit.json +├── index.html +├── package.json +└── vite.config.js +``` + +You'll see other files and folders showing up (like `package-lock.json`, `yarn.lock`, `node_modules`) but you shouldn't have to care about those. + +## Importing our dependencies + +We're starting with the good stuff now. At the top of the new javascript file, import the packages: + +```ts +import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { Noir } from '@noir-lang/noir_js'; +``` + +We also need to import the `circuit` JSON file we created. If you have the suggested folder structure, you can add this line: + +```ts +import circuit from './circuit/target/circuit.json'; +``` + +## Write code + +:::note + +We're gonna be adding code inside the `document.addEventListener...etc` block: + +```js +// forget stuff here +document.addEventListener('DOMContentLoaded', async () => { + // here's where the magic happens +}); +// forget stuff here +``` + +::: + +Our dependencies exported two classes: `BarretenbergBackend` and `Noir`. Let's `init` them and add some logs, just to flex: + +```ts +const backend = new BarretenbergBackend(circuit); +const noir = new Noir(circuit, backend); +``` + +## Proving + +Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: + +```js +const input = { x: 1, y: 2 }; +display('logs', 'Generating proof... ⌛'); +const proof = await noir.generateFinalProof(input); +display('logs', 'Generating proof... ✅'); +display('results', proof.proof); +``` + +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm start` (or `yarn start`). If it doesn't open a browser for you, just visit `localhost:5173`. On a modern laptop, proof will generate in less than 100ms, and you'll see this: + +![Getting Started 0](@site/static/img/noir_getting_started_1.png) + +If you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human. + +In any case, this means your proof was generated! But you shouldn't trust me just yet. Add these lines to see it being verified: + +```js +display('logs', 'Verifying proof... ⌛'); +const verification = await noir.verifyFinalProof(proof); +if (verification) display('logs', 'Verifying proof... ✅'); +``` + +By saving, your app will refresh and here's our complete Tiny Noir App! + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Further Reading + +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. + +You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/docusaurus.config.js b/noir/docs/docusaurus.config.js deleted file mode 100644 index c571fdc223a..00000000000 --- a/noir/docs/docusaurus.config.js +++ /dev/null @@ -1,215 +0,0 @@ -// @ts-check -// Note: type annotations allow type checking and IDEs autocompletion - -const lightCodeTheme = require('prism-react-renderer/themes/github'); -const darkCodeTheme = require('prism-react-renderer/themes/dracula'); - -const math = require('remark-math'); -const katex = require('rehype-katex'); - -/** @type {import('@docusaurus/types').Config} */ -const config = { - title: 'Noir Documentation', - tagline: 'The Universal ZK Circuit Language', - favicon: 'img/favicon.ico', - url: 'https://noir-lang.org', - // Set the // pathname under which your site is served - // For GitHub pages deployment, it is often '//' - baseUrl: '/', - onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'throw', - - // Even if you don't use internalization, you can use this field to set useful - // metadata like html lang. For example, if your site is Chinese, you may want - // to replace "en" with "zh-Hans". - i18n: { - defaultLocale: 'en', - locales: ['en'], - }, - - presets: [ - [ - '@docusaurus/preset-classic', - { - // gtag: { - // trackingID: 'G-SZQHEQZK3L', - // anonymizeIP: true, - // }, - docs: { - sidebarPath: require.resolve('./sidebars.js'), - routeBasePath: '/', - remarkPlugins: [math], - rehypePlugins: [katex], - versions: { - current: { - label: 'dev', - path: 'dev', - }, - }, - editUrl: ({ versionDocsDirPath, docPath }) => - `https://github.com/noir-lang/noir/edit/master/docs/${versionDocsDirPath}/${docPath}`, - }, - blog: false, - theme: { - customCss: require.resolve('./src/css/custom.css'), - }, - }, - ], - ], - - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - { - // Replace with your project's social card - navbar: { - logo: { - alt: 'Noir Logo', - src: 'img/logo.svg', - srcDark: 'img/logoDark.svg', - href: '/', - }, - items: [ - { - href: 'https://github.com/noir-lang/noir/tree/master/docs', - label: 'GitHub', - position: 'right', - }, - { - type: 'docsVersionDropdown', - position: 'left', - dropdownActiveClassDisabled: true, - }, - ], - }, - metadata: [ - { - name: 'Noir', - content: 'noir, programming, language, documentation, zk, zero-knowledge, l2, crypto, layer2, ethereum', - }, - ], - footer: { - style: 'dark', - links: [ - { - title: 'Community', - items: [ - { - label: 'Noir Forum', - href: 'https://discourse.aztec.network/c/noir/7', - }, - { - label: 'Twitter', - href: 'https://twitter.com/NoirLang', - }, - { - label: 'Discord', - href: 'https://discord.gg/JtqzkdeQ6G', - }, - ], - }, - { - title: 'Code', - items: [ - { - label: 'Noir GitHub', - href: 'https://github.com/noir-lang', - }, - { - label: 'Docs GitHub', - href: 'https://github.com/noir-lang/docs', - }, - ], - }, - ], - copyright: `Noir will be dual licensed under MIT/Apache (Version 2.0).`, - }, - prism: { - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ['rust', 'powershell', 'solidity', 'toml'], - }, - stylesheets: [ - { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', - integrity: 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', - }, - ], - algolia: { - // The application ID provided by Algolia - appId: '97APAVUL6H', - - // Public API key: it is safe to commit it - apiKey: 'b9b94d2f1c58f7d509f0bc1f13b381fb', - - indexName: 'noir-lang', - }, - }, - plugins: [ - [ - 'docusaurus-plugin-typedoc', - { - id: 'noir_js', - entryPoints: ['../tooling/noir_js/src/index.ts'], - tsconfig: '../tooling/noir_js/tsconfig.json', - entryPointStrategy: 'resolve', - out: 'docs/noir_js/reference/noir_js', - plugin: ['typedoc-plugin-markdown'], - name: 'Noir JS', - disableSources: true, - excludePrivate: true, - - sidebar: { - filteredIds: ['noir_js/reference/noir_js/index'], - }, - readme: 'none', - hidePageHeader: true, - hideBreadcrumbs: true, - hideInPageTOC: true, - useCodeBlocks: true, - typeDeclarationFormat: 'table', - propertiesFormat: 'table', - parametersFormat: 'table', - enumMembersFormat: 'table', - indexFormat: 'table', - outputFileStrategy: 'members', - memberPageTitle: '{name}', - membersWithOwnFile: ['Interface', 'Class', 'TypeAlias', 'Function'], - }, - ], - [ - 'docusaurus-plugin-typedoc', - { - id: 'noir_js_backend_barretenberg', - entryPoints: ['../tooling/noir_js_backend_barretenberg/src/index.ts'], - tsconfig: '../tooling/noir_js_backend_barretenberg/tsconfig.json', - entryPointStrategy: 'resolve', - out: 'docs/noir_js/reference/backend_barretenberg', - plugin: ['typedoc-plugin-markdown'], - name: 'Backend Barretenberg', - disableSources: true, - excludePrivate: true, - - sidebar: { - filteredIds: ['noir_js/reference/backend_barretenberg/index'], - }, - readme: 'none', - hidePageHeader: true, - hideBreadcrumbs: true, - hideInPageTOC: true, - useCodeBlocks: true, - typeDeclarationFormat: 'table', - propertiesFormat: 'table', - parametersFormat: 'table', - enumMembersFormat: 'table', - indexFormat: 'table', - outputFileStrategy: 'members', - memberPageTitle: '{name}', - membersWithOwnFile: ['Interface', 'Class', 'TypeAlias'], - }, - ], - ], -}; - -module.exports = config; diff --git a/noir/docs/docusaurus.config.ts b/noir/docs/docusaurus.config.ts new file mode 100644 index 00000000000..7516d35c6d9 --- /dev/null +++ b/noir/docs/docusaurus.config.ts @@ -0,0 +1,212 @@ +import type { Config } from '@docusaurus/types'; + +const { themes } = require('prism-react-renderer'); +const lightTheme = themes.github; +const darkTheme = themes.dracula; + +import math from 'remark-math'; +import katex from 'rehype-katex'; + +export default { + title: 'Noir Documentation', + tagline: 'The Universal ZK Circuit Language', + favicon: 'img/favicon.ico', + url: 'https://noir-lang.org', + baseUrl: '/', + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'throw', + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + '@docusaurus/preset-classic', + { + docs: { + sidebarPath: './sidebars.js', + routeBasePath: '/docs', + remarkPlugins: [math], + rehypePlugins: [katex], + versions: { + current: { + label: 'dev', + path: 'dev', + }, + }, + editUrl: ({ versionDocsDirPath, docPath }) => + `https://github.com/noir-lang/noir/edit/master/docs/${versionDocsDirPath}/${docPath}`, + }, + blog: false, + theme: { + customCss: ['./src/css/custom.css', './src/css/sidebar.css'], + }, + }, + ], + ], + + themeConfig: { + navbar: { + logo: { + alt: 'Noir Logo', + src: 'img/logo.svg', + srcDark: 'img/logoDark.svg', + href: '/', + }, + items: [ + { + href: 'https://github.com/noir-lang/noir/tree/master/docs', + label: 'GitHub', + position: 'right', + }, + { + type: 'docsVersionDropdown', + position: 'left', + dropdownActiveClassDisabled: true, + }, + ], + }, + metadata: [ + { + name: 'Noir', + content: 'noir, programming, language, documentation, zk, zero-knowledge, l2, crypto, layer2, ethereum', + }, + ], + footer: { + style: 'dark', + links: [ + { + title: 'Community', + items: [ + { + label: 'Noir Forum', + href: 'https://discourse.aztec.network/c/noir/7', + }, + { + label: 'Twitter', + href: 'https://twitter.com/NoirLang', + }, + { + label: 'Discord', + href: 'https://discord.gg/JtqzkdeQ6G', + }, + ], + }, + { + title: 'Code', + items: [ + { + label: 'Noir GitHub', + href: 'https://github.com/noir-lang', + }, + { + label: 'Docs GitHub', + href: 'https://github.com/noir-lang/docs', + }, + ], + }, + ], + copyright: `Noir will be dual licensed under MIT/Apache (Version 2.0).`, + }, + prism: { + theme: lightTheme, + darkTheme: darkTheme, + additionalLanguages: ['rust', 'powershell', 'solidity', 'toml'], + }, + stylesheets: [ + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', + }, + ], + algolia: { + // The application ID provided by Algolia + appId: '97APAVUL6H', + + // Public API key: it is safe to commit it + apiKey: 'b9b94d2f1c58f7d509f0bc1f13b381fb', + + indexName: 'noir-lang', + }, + }, + plugins: [ + () => ({ + name: 'resolve-react', + configureWebpack() { + return { + optimization: { + innerGraph: false, + }, + }; + }, + }), + [ + 'docusaurus-plugin-typedoc', + { + id: 'noir_js', + entryPoints: ['../tooling/noir_js/src/index.ts'], + tsconfig: '../tooling/noir_js/tsconfig.json', + entryPointStrategy: 'resolve', + out: 'docs/reference/NoirJS/noir_js', + plugin: ['typedoc-plugin-markdown'], + name: 'noir_js', + disableSources: true, + excludePrivate: true, + skipErrorChecking: true, + sidebar: { + filteredIds: ['reference/NoirJS/noir_js/index'], + }, + readme: 'none', + hidePageHeader: true, + hideBreadcrumbs: true, + hideInPageTOC: true, + useCodeBlocks: true, + typeDeclarationFormat: 'table', + propertiesFormat: 'table', + parametersFormat: 'table', + enumMembersFormat: 'table', + indexFormat: 'table', + outputFileStrategy: 'members', + memberPageTitle: '{name}', + membersWithOwnFile: ['Interface', 'Class', 'TypeAlias', 'Function'], + }, + ], + [ + 'docusaurus-plugin-typedoc', + { + id: 'noir_js_backend_barretenberg', + entryPoints: ['../tooling/noir_js_backend_barretenberg/src/index.ts'], + tsconfig: '../tooling/noir_js_backend_barretenberg/tsconfig.json', + entryPointStrategy: 'resolve', + out: 'docs/reference/NoirJS/backend_barretenberg', + plugin: ['typedoc-plugin-markdown'], + name: 'backend_barretenberg', + disableSources: true, + excludePrivate: true, + skipErrorChecking: true, + sidebar: { + filteredIds: ['reference/NoirJS/backend_barretenberg/index'], + }, + readme: 'none', + hidePageHeader: true, + hideBreadcrumbs: true, + hideInPageTOC: true, + useCodeBlocks: true, + typeDeclarationFormat: 'table', + propertiesFormat: 'table', + parametersFormat: 'table', + enumMembersFormat: 'table', + indexFormat: 'table', + outputFileStrategy: 'members', + memberPageTitle: '{name}', + membersWithOwnFile: ['Interface', 'Class', 'TypeAlias'], + }, + ], + ], + markdown: { + format: 'detect', + }, +} satisfies Config; diff --git a/noir/docs/package.json b/noir/docs/package.json index db0efbe7543..1fa4ab79b85 100644 --- a/noir/docs/package.json +++ b/noir/docs/package.json @@ -3,34 +3,45 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "docusaurus start", - "build": "docusaurus build", - "setStable": "node ./scripts/setStable.js" + "start": "yarn version::stables && docusaurus start", + "build": "yarn version::stables && docusaurus build", + "version::stables": "ts-node ./scripts/setStable.ts", + "serve": "serve build" }, "dependencies": { - "@docusaurus/core": "^2.4.0", - "@docusaurus/plugin-google-gtag": "^2.4.0", - "@docusaurus/preset-classic": "^2.4.0", + "@docusaurus/core": "^3.0.1", + "@docusaurus/preset-classic": "^3.0.1", "@easyops-cn/docusaurus-search-local": "^0.35.0", - "@mdx-js/react": "^1.6.22", + "@mdx-js/react": "^3.0.0", "@noir-lang/noir_js": "workspace:*", + "@noir-lang/noirc_abi": "workspace:*", + "@noir-lang/types": "workspace:*", + "@signorecello/noir_playground": "^0.6.0", "axios": "^1.4.0", "clsx": "^1.2.1", - "docusaurus-plugin-typedoc": "1.0.0-next.18", "hast-util-is-element": "^1.1.0", - "prism-react-renderer": "^1.3.5", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "rehype-katex": "^5.0.0", - "remark-math": "^3.0.1", + "prism-react-renderer": "^2.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-spinners": "^0.13.8", + "rehype-katex": "^7.0.0", + "remark-math": "^6.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^3.0.1", + "@docusaurus/tsconfig": "^3.0.1", + "@docusaurus/types": "^3.0.1", + "@types/prettier": "^3", + "docusaurus-plugin-typedoc": "1.0.0-next.18", + "eslint-plugin-prettier": "^5.0.0", + "prettier": "3.0.3", + "serve": "^14.2.1", + "ts-node": "^10.9.1", "typedoc": "^0.25.0", "typedoc-plugin-frontmatter": "^0.0.2", "typedoc-plugin-markdown": "4.0.0-next.25", "typedoc-plugin-merge-modules": "^5.1.0", - "typescript": "^5.2.2" - }, - "devDependencies": { - "@docusaurus/module-type-aliases": "^2.4.0" + "typescript": "~5.2.2" }, "browserslist": { "production": [ @@ -45,6 +56,6 @@ ] }, "engines": { - "node": ">=16.14" + "node": ">=18-0" } } diff --git a/noir/docs/scripts/setStable.js b/noir/docs/scripts/setStable.js deleted file mode 100644 index 4bbe283f4be..00000000000 --- a/noir/docs/scripts/setStable.js +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable */ -const fs = require('fs'); -const path = require('path'); -const axios = require('axios'); -const { release } = require('os'); - -const IGNORE_VERSIONS = ['0.16.0']; -const NUMBER_OF_VERSIONS_TO_SHOW = 4; - -async function main() { - const versionsFile = path.join(__dirname, '../versions.json'); - - const axiosOpts = { - params: { per_page: 100 }, - }; - - console.log(process.env.GITHUB_TOKEN); - // cool if you have a GITHUB_TOKEN because of rate limiting - // but fine if you don't - if (process.env.GITHUB_TOKEN) axiosOpts.headers = { Authorization: `token ${process.env.GITHUB_TOKEN}` }; - - const { data } = await axios.get('https://api.github.com/repos/noir-lang/noir/releases', axiosOpts); - - const all = data.map((release) => release.tag_name); - console.log('All versions: ', all); - const aztecs = data.filter((release) => release.tag_name.includes('aztec')).map((release) => release.tag_name); - console.log('Removing aztecs: ', aztecs); - const prereleases = data.filter((release) => !release.prerelease).map((release) => release.tag_name); - console.log('Removing prereleases: ', prereleases); - - const stables = data - .filter((release) => !release.prerelease && !release.tag_name.includes('aztec')) - .filter((release) => !IGNORE_VERSIONS.includes(release.tag_name.replace('v', ''))) - .map((release) => release.tag_name) - .slice(0, NUMBER_OF_VERSIONS_TO_SHOW); - - console.log('Stables: ', stables); - - fs.writeFileSync(versionsFile, JSON.stringify(stables, null, 2)); -} - -main(); diff --git a/noir/docs/scripts/setStable.ts b/noir/docs/scripts/setStable.ts new file mode 100644 index 00000000000..0f86c4afd59 --- /dev/null +++ b/noir/docs/scripts/setStable.ts @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require('fs'); +const path = require('path'); +const axios = require('axios'); + +const GITHUB_PAGES = 3; +const IGNORE_VERSIONS = ['0.16.0']; +const NUMBER_OF_VERSIONS_TO_SHOW = 2; + +async function main() { + const axiosOpts = { + params: { per_page: 100 }, + headers: {}, + }; + + if (process.env.GITHUB_TOKEN) axiosOpts.headers = { Authorization: `token ${process.env.GITHUB_TOKEN}` }; + + let stables = []; + console.log('Retrieved versions:'); + + for (let i = 0; i < GITHUB_PAGES; i++) { + const { data } = await axios.get(`https://api.github.com/repos/noir-lang/noir/releases?page=${i + 1}`, axiosOpts); + + console.log(data.map((release) => release.tag_name)); + stables.push( + ...data + .filter( + (release) => + !release.prerelease && !release.tag_name.includes('aztec') && !release.tag_name.includes('aztec'), + ) + .filter((release) => !IGNORE_VERSIONS.includes(release.tag_name.replace('v', ''))) + .map((release) => release.tag_name), + ); + } + + stables = stables.slice(0, NUMBER_OF_VERSIONS_TO_SHOW); + + console.log('Filtered down to stables: ', stables); + + const onlyLatestPatches = []; + const minorsSet = new Set(stables.map((el) => el.split('.')[1])); + for (const minor of minorsSet) { + const minorVersions = stables.filter((el) => el.split('.')[1] === minor); + const max = minorVersions.reduce((prev, current) => { + return prev > current ? prev : current; + }); + onlyLatestPatches.push(max); + } + + console.log('Only latest patches: ', onlyLatestPatches); + + fs.writeFileSync(path.resolve(__dirname, '../versions.json'), JSON.stringify(onlyLatestPatches, null, 2)); +} + +main(); diff --git a/noir/docs/sidebars.js b/noir/docs/sidebars.js index 3fd391cf09c..f1e79ba9ebc 100644 --- a/noir/docs/sidebars.js +++ b/noir/docs/sidebars.js @@ -1,145 +1,75 @@ -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ - -// @ts-check - /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ -const sidebars = { +export default { sidebar: [ { type: 'doc', id: 'index', - label: 'Noir', }, { type: 'category', label: 'Getting Started', - items: [{ type: 'autogenerated', dirName: 'getting_started' }], + items: [ + { + type: 'autogenerated', + dirName: 'getting_started', + }, + ], }, { type: 'category', - label: 'Examples', - items: [{ type: 'autogenerated', dirName: 'examples' }], + label: 'The Noir Language', + items: [ + { + type: 'autogenerated', + dirName: 'noir', + }, + ], }, { - type: 'category', - label: 'Nargo', - items: [{ type: 'autogenerated', dirName: 'nargo' }], + type: 'html', + value: '
', + defaultStyle: true, }, { type: 'category', - label: 'Language Concepts', + label: 'How To Guides', items: [ { - type: 'category', - label: 'Data Types', - link: { - type: 'doc', - id: 'language_concepts/data_types', - }, - items: [ - { - type: 'autogenerated', - dirName: 'language_concepts/data_types', - }, - ], + type: 'autogenerated', + dirName: 'how_to', }, - 'language_concepts/functions', - 'language_concepts/control_flow', - 'language_concepts/ops', - 'language_concepts/assert', - 'language_concepts/unconstrained', - 'language_concepts/generics', - 'language_concepts/mutability', - 'language_concepts/lambdas', - 'language_concepts/comments', - 'language_concepts/distinct', - 'language_concepts/shadowing', ], }, { type: 'category', - label: 'Noir Standard Library', + label: 'Explainers', items: [ { - type: 'category', - label: 'Cryptographic Primitives', - link: { - type: 'doc', - id: 'standard_library/cryptographic_primitives', - }, - items: [ - { - type: 'autogenerated', - dirName: 'standard_library/cryptographic_primitives', - }, - ], + type: 'autogenerated', + dirName: 'explainers', }, - 'standard_library/recursion', - 'standard_library/logging', - 'standard_library/merkle_trees', - 'standard_library/zeroed', - 'standard_library/black_box_fns', - 'standard_library/options', ], }, { type: 'category', - label: 'Modules, Packages and Crates', - items: [{ type: 'autogenerated', dirName: 'modules_packages_crates' }], - }, - { - type: 'category', - label: 'NoirJS', - link: { - type: 'doc', - id: 'noir_js/noir_js', - }, + label: 'Tutorials', items: [ { - type: 'category', - label: 'Guides', - items: [ - { - type: 'autogenerated', - dirName: 'noir_js/getting_started', - }, - ], - }, - { - type: 'category', - label: 'Reference', - items: [ - { - type: 'category', - label: 'Noir JS', - link: { - type: 'doc', - id: 'noir_js/reference/noir_js/index', - }, - items: require('./docs/noir_js/reference/noir_js/typedoc-sidebar.cjs'), - }, - { - type: 'category', - label: 'Backend Barretenberg', - link: { - type: 'doc', - id: 'noir_js/reference/backend_barretenberg/index', - }, - items: require('./docs/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs'), - }, - ], + type: 'autogenerated', + dirName: 'tutorials', }, ], }, + { + type: 'category', + label: 'Reference', + items: [{ type: 'autogenerated', dirName: 'reference' }], + }, + { + type: 'html', + value: '
', + defaultStyle: true, + }, { type: 'doc', id: 'migration_notes', @@ -147,5 +77,3 @@ const sidebars = { }, ], }; - -module.exports = sidebars; diff --git a/noir/docs/src/components/GithubCode/index.js b/noir/docs/src/components/GithubCode/index.js deleted file mode 100644 index 69ba17ef791..00000000000 --- a/noir/docs/src/components/GithubCode/index.js +++ /dev/null @@ -1,63 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import axios from 'axios'; -import Highlight, { defaultProps } from "prism-react-renderer"; -import github from 'prism-react-renderer/themes/github'; -//import vsDark from 'prism-react-renderer/themes/vsDark'; - -const GitHubCode = ({ owner, repo, branch = 'master', filePath, language, startLine = 1, endLine = Infinity }) => { - const [code, setCode] = useState(''); - const [response, setResponse] = useState(''); - - useEffect(() => { - const fetchCode = async () => { - const url = `https://api.github.com/repos/${owner}/${repo}/contents/${filePath}?ref=${branch}` - try { - const response = await axios.get(url); - const content = response.data.content; - const decodedContent = atob(content); // Decode Base64 content - - const lines = decodedContent.split('\n'); - const desiredLines = lines.slice(startLine - 1, endLine).join('\n').trimEnd(); - - setResponse(response); - setCode(desiredLines); - } catch (error) { - console.error('Failed to fetch GitHub code:', error); - } - }; - - fetchCode(); - }, [owner, repo, branch, filePath, startLine, endLine]); - - const highlightedCode = ( - - {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
-
-                        {tokens.map((line, i) => (
-                            
- {/* uncomment for line numbers */} - {/* {i + 1} */} - {line.map((token, key) => ( - - ))} -
- ))} -
- { - response.data?.html_url ? Link to source code. : '' - } -
- )} -
- ) - - return highlightedCode; -}; - -export default GitHubCode; \ No newline at end of file diff --git a/noir/docs/src/components/HomepageFeatures/index.js b/noir/docs/src/components/HomepageFeatures/index.js deleted file mode 100644 index 78f410ba688..00000000000 --- a/noir/docs/src/components/HomepageFeatures/index.js +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import clsx from 'clsx'; -import styles from './styles.module.css'; - -const FeatureList = [ - { - title: 'Easy to Use', - Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, - description: ( - <> - Docusaurus was designed from the ground up to be easily installed and - used to get your website up and running quickly. - - ), - }, - { - title: 'Focus on What Matters', - Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, - description: ( - <> - Docusaurus lets you focus on your docs, and we'll do the chores. Go - ahead and move your docs into the docs directory. - - ), - }, - { - title: 'Powered by React', - Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, - description: ( - <> - Extend or customize your website layout by reusing React. Docusaurus can - be extended while reusing the same header and footer. - - ), - }, -]; - -function Feature({Svg, title, description}) { - return ( -
-
- -
-
-

{title}

-

{description}

-
-
- ); -} - -export default function HomepageFeatures() { - return ( -
-
-
- {FeatureList.map((props, idx) => ( - - ))} -
-
-
- ); -} diff --git a/noir/docs/src/components/HomepageFeatures/styles.module.css b/noir/docs/src/components/HomepageFeatures/styles.module.css deleted file mode 100644 index b248eb2e5de..00000000000 --- a/noir/docs/src/components/HomepageFeatures/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.features { - display: flex; - align-items: center; - padding: 2rem 0; - width: 100%; -} - -.featureSvg { - height: 200px; - width: 200px; -} diff --git a/noir/docs/src/css/custom.css b/noir/docs/src/css/custom.css index c1faa9d3139..53dec741513 100644 --- a/noir/docs/src/css/custom.css +++ b/noir/docs/src/css/custom.css @@ -68,3 +68,58 @@ html[data-theme='dark'] { .katex-html { display: none; } + +.homepage_layout { + max-width: 800px; + margin: 0 auto; +} + +.homepage_h1 { + display: block; + margin: 40px auto; + text-align: center; +} + +.homepage_p { + display: block; + margin: 0 auto; + text-align: center; +} + +.homepage_cta_container { + display: flex; + justify-content: center; + margin: 0 auto; + text-align: center; + background: white; + border: none; + width: 50%; +} + +.homepage_cta { + display: block; + margin: 50px auto; + text-align: center; +} + +.cards__container { + margin: 0 auto; +} + + +.card__body { + display: flex; + flex-wrap: wrap; +} + +.card__body.align_right { + justify-content: end; + text-align: right; +} + +*, +::before, +::after { + border-width: 0; + border-style: solid; +} diff --git a/noir/docs/src/css/sidebar.css b/noir/docs/src/css/sidebar.css new file mode 100644 index 00000000000..3c03c374058 --- /dev/null +++ b/noir/docs/src/css/sidebar.css @@ -0,0 +1,4 @@ +.divider { + border-top: 2px solid #eee; + margin: 0.5em 0; +} diff --git a/noir/docs/src/pages/index.jsx b/noir/docs/src/pages/index.jsx new file mode 100644 index 00000000000..8485a730785 --- /dev/null +++ b/noir/docs/src/pages/index.jsx @@ -0,0 +1,71 @@ +import React, { lazy, Suspense } from 'react'; +import Layout from '@theme/Layout'; +import Link from '@docusaurus/Link'; + +import headerPic from '../../static/img/homepage_header_pic.png'; +import { BeatLoader } from 'react-spinners'; + +const NoirEditor = lazy(() => import('@signorecello/noir_playground')); + +const Spinner = () => { + return ( +
+ +
+ ); +}; + +export default function Landing() { + const [tryIt, setTryIt] = React.useState(false); + + return ( + +
+
+
+

+ Noir +

+

+ Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR + compatible proving system. It's design choices are influenced heavily by Rust and focuses on a simple, + familiar syntax. +

+ + {tryIt && ( + }> + + + + + + )} + + {!tryIt && ( +
+ + + + +
+ )} +
+
+ + ); +} diff --git a/noir/docs/static/img/homepage_header_pic.png b/noir/docs/static/img/homepage_header_pic.png new file mode 100644 index 00000000000..d629e202232 Binary files /dev/null and b/noir/docs/static/img/homepage_header_pic.png differ diff --git a/noir/docs/tsconfig.json b/noir/docs/tsconfig.json new file mode 100644 index 00000000000..241fcf4b5e3 --- /dev/null +++ b/noir/docs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@docusaurus/tsconfig", + "compilerOptions": { + "baseUrl": ".", + "downlevelIteration": true + }, +} diff --git a/noir/docs/versioned_docs/version-v../explainers/explainer-recursion.md b/noir/docs/versioned_docs/version-v../explainers/explainer-recursion.md new file mode 100644 index 00000000000..cc431a878dc --- /dev/null +++ b/noir/docs/versioned_docs/version-v../explainers/explainer-recursion.md @@ -0,0 +1,175 @@ +--- +title: Recursive proofs +description: Explore the concept of recursive proofs in Zero-Knowledge programming. Understand how recursion works in Noir, a language for writing smart contracts on the EVM blockchain. Learn through practical examples like Alice and Bob's guessing game, Charlie's recursive merkle tree, and Daniel's reusable components. Discover how to use recursive proofs to optimize computational resources and improve efficiency. + +keywords: + [ + "Recursive Proofs", + "Zero-Knowledge Programming", + "Noir", + "EVM Blockchain", + "Smart Contracts", + "Recursion in Noir", + "Alice and Bob Guessing Game", + "Recursive Merkle Tree", + "Reusable Components", + "Optimizing Computational Resources", + "Improving Efficiency", + "Verification Key", + "Aggregation Objects", + "Recursive zkSNARK schemes", + "PLONK", + "Proving and Verification Keys" + ] +sidebar_position: 1 +--- + +In programming, we tend to think of recursion as something calling itself. A classic example would be the calculation of the factorial of a number: + +```js +function factorial(n) { + if (n === 0 || n === 1) { + return 1; + } else { + return n * factorial(n - 1); + } +} +``` + +In this case, while `n` is not `1`, this function will keep calling itself until it hits the base case, bubbling up the result on the call stack: + +```md + Is `n` 1? <--------- + /\ / + / \ n = n -1 + / \ / + Yes No -------- +``` + +In Zero-Knowledge, recursion has some similarities. + +It is not a Noir function calling itself, but a proof being used as an input to another circuit. In short, you verify one proof *inside* another proof, returning the proof that both proofs are valid. + +This means that, given enough computational resources, you can prove the correctness of any arbitrary number of proofs in a single proof. This could be useful to design state channels (for which a common example would be [Bitcoin's Lightning Network](https://en.wikipedia.org/wiki/Lightning_Network)), to save on gas costs by settling one proof on-chain, or simply to make business logic less dependent on a consensus mechanism. + +## Examples + +Let us look at some of these examples + +### Alice and Bob - Guessing game + +Alice and Bob are friends, and they like guessing games. They want to play a guessing game online, but for that, they need a trusted third-party that knows both of their secrets and finishes the game once someone wins. + +So, they use zero-knowledge proofs. Alice tries to guess Bob's number, and Bob will generate a ZK proof stating whether she succeeded or failed. + +This ZK proof can go on a smart contract, revealing the winner and even giving prizes. However, this means every turn needs to be verified on-chain. This incurs some cost and waiting time that may simply make the game too expensive or time-consuming to be worth it. + +So, Alice started thinking: "what if Bob generates his proof, and instead of sending it on-chain, I verify it *within* my own proof before playing my own turn?". She can then generate a proof that she verified his proof, and so on. + +```md + Did you fail? <-------------------------- + / \ / + / \ n = n -1 + / \ / + Yes No / + | | / + | | / + | You win / + | / + | / +Generate proof of that / + + / + my own guess ---------------- +``` + +### Charlie - Recursive merkle tree + +Charlie is a concerned citizen, and wants to be sure his vote in an election is accounted for. He votes with a ZK proof, but he has no way of knowing that his ZK proof was included in the total vote count! + +So, the tallier puts all the votes in a merkle tree, and everyone can also prove the verification of two proofs within one proof, as such: + +```md + abcd + __________|______________ + | | + ab cd + _____|_____ ______|______ + | | | | + alice bob charlie daniel +``` + +Doing this recursively allows us to arrive on a final proof `abcd` which if true, verifies the correctness of all the votes. + +### Daniel - Reusable components + +Daniel has a big circuit and a big headache. A part of his circuit is a setup phase that finishes with some assertions that need to be made. But that section alone takes most of the proving time, and is largely independent of the rest of the circuit. + +He could find it more efficient to generate a proof for that setup phase separately, and verifying it in his actual business logic section of the circuit. This will allow for parallelization of both proofs, which results in a considerable speedup. + +## What params do I need + +As you can see in the [recursion reference](noir/standard_library/recursion.md), a simple recursive proof requires: + +- The proof to verify +- The Verification Key of the circuit that generated the proof +- A hash of this verification key, as it's needed for some backends +- The public inputs for the proof +- The input aggregation object + +It also returns the `output aggregation object`. These aggregation objects can be confusing at times, so let's dive in a little bit. + +### Aggregation objects + +Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. + +In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points. + +So, taking the example of Alice and Bob and their guessing game: + +- Alice makes her guess. Her proof is *not* recursive: it doesn't verify any proof within it! It's just a standard `assert(x != y)` circuit +- Bob verifies Alice's proof and makes his own guess. In this circuit, he is verifying a proof, so it needs to output an `aggregation object`: he is generating a recursive proof! +- Alice verifies Bob's *recursive proof*, and uses Bob's `output aggregation object` as the `input aggregation object` in her proof... Which in turn, generates another `output aggregation object`. + +One should notice that when Bob generates his first proof, he has no input aggregation object. Because he is not verifying an recursive proof, he has no `input aggregation object`. In this case, he may use zeros instead. + +We can imagine the `aggregation object` as the baton in a [relay race](https://en.wikipedia.org/wiki/Relay_race). The first runner doesn't have to receive the baton from anyone else, as he/she already starts with it. But when his/her turn is over, the next runner needs to receive it, run a bit more, and pass it along. Even though every runner could theoretically verify the baton mid-run (why not? 🏃🔍), only at the end of the race does the referee verify that the whole race is valid. + +## Some architecture + +As with everything in computer science, there's no one-size-fits all. But there are some patterns that could help understanding and implementing them. To give three examples: + +### Adding some logic to a proof verification + +This would be an approach for something like our guessing game, where proofs are sent back and forth and are verified by each opponent. This circuit would be divided in two sections: + +- A `recursive verification` section, which would be just the call to `std::verify_proof`, and that would be skipped on the first move (since there's no proof to verify) +- A `guessing` section, which is basically the logic part where the actual guessing happens + +In such a situation, and assuming Alice is first, she would skip the first part and try to guess Bob's number. Bob would then verify her proof on the first section of his run, and try to guess Alice's number on the second part, and so on. + +### Aggregating proofs + +In some one-way interaction situations, recursiveness would allow for aggregation of simple proofs that don't need to be immediately verified on-chain or elsewhere. + +To give a practical example, a barman wouldn't need to verify a "proof-of-age" on-chain every time he serves alcohol to a customer. Instead, the architecture would comprise two circuits: + +- A `main`, non-recursive circuit with some logic +- A `recursive` circuit meant to verify two proofs in one proof + +The customer's proofs would be intermediate, and made on their phones, and the barman could just verify them locally. He would then aggregate them into a final proof sent on-chain (or elsewhere) at the end of the day. + +### Recursively verifying different circuits + +Nothing prevents you from verifying different circuits in a recursive proof, for example: + +- A `circuit1` circuit +- A `circuit2` circuit +- A `recursive` circuit + +In this example, a regulator could verify that taxes were paid for a specific purchase by aggregating both a `payer` circuit (proving that a purchase was made and taxes were paid), and a `receipt` circuit (proving that the payment was received) + +## How fast is it + +At the time of writing, verifying recursive proofs is surprisingly fast. This is because most of the time is spent on generating the verification key that will be used to generate the next proof. So you are able to cache the verification key and reuse it later. + +Currently, Noir JS packages don't expose the functionality of loading proving and verification keys, but that feature exists in the underlying `bb.js` package. diff --git a/noir/docs/versioned_docs/version-v../explanations/noir/traits.md b/noir/docs/versioned_docs/version-v../explanations/noir/traits.md new file mode 100644 index 00000000000..7ba07e74f40 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../explanations/noir/traits.md @@ -0,0 +1,348 @@ +--- +title: Traits +description: + Traits in Noir can be used to abstract out a common interface for functions across + several data types. +keywords: [noir programming language, traits, interfaces, generic, protocol] +--- + +## Overview + +Traits in Noir are a useful abstraction similar to interfaces or protocols in other languages. Each trait defines +the interface of several methods contained within the trait. Types can then implement this trait by providing +implementations for these methods. For example in the program: + +```rust +struct Rectangle { + width: Field, + height: Field, +} + +impl Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +fn log_area(r: Rectangle) { + println(r.area()); +} +``` + +We have a function `log_area` to log the area of a `Rectangle`. Now how should we change the program if we want this +function to work on `Triangle`s as well?: + +```rust +struct Triangle { + width: Field, + height: Field, +} + +impl Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Making `log_area` generic over all types `T` would be invalid since not all types have an `area` method. Instead, we can +introduce a new `Area` trait and make `log_area` generic over all types `T` that implement `Area`: + +```rust +trait Area { + fn area(self) -> Field; +} + +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +We also need to explicitly implement `Area` for `Rectangle` and `Triangle`. We can do that by changing their existing +impls slightly. Note that the parameter types and return type of each of our `area` methods must match those defined +by the `Area` trait. + +```rust +impl Area for Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +impl Area for Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Now we have a working program that is generic over any type of Shape that is used! Others can even use this program +as a library with their own types - such as `Circle` - as long as they also implement `Area` for these types. + +## Where Clauses + +As seen in `log_area` above, when we want to create a function or method that is generic over any type that implements +a trait, we can add a where clause to the generic function. + +```rust +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +It is also possible to apply multiple trait constraints on the same variable at once by combining traits with the `+` +operator. Similarly, we can have multiple trait constraints by separating each with a comma: + +```rust +fn foo(elements: [T], thing: U) where + T: Default + Add + Eq, + U: Bar, +{ + let mut sum = T::default(); + + for element in elements { + sum += element; + } + + if sum == T::default() { + thing.bar(); + } +} +``` + +## Generic Implementations + +You can add generics to a trait implementation by adding the generic list after the `impl` keyword: + +```rust +trait Second { + fn second(self) -> Field; +} + +impl Second for (T, Field) { + fn second(self) -> Field { + self.1 + } +} +``` + +You can also implement a trait for every type this way: + +```rust +trait Debug { + fn debug(self); +} + +impl Debug for T { + fn debug(self) { + println(self); + } +} + +fn main() { + 1.debug(); +} +``` + +### Generic Trait Implementations With Where Clauses + +Where clauses can also be placed on trait implementations themselves to restrict generics in a similar way. +For example, while `impl Foo for T` implements the trait `Foo` for every type, `impl Foo for T where T: Bar` +will implement `Foo` only for types that also implement `Bar`. This is often used for implementing generic types. +For example, here is the implementation for array equality: + +```rust +impl Eq for [T; N] where T: Eq { + // Test if two arrays have the same elements. + // Because both arrays must have length N, we know their lengths already match. + fn eq(self, other: Self) -> bool { + let mut result = true; + + for i in 0 .. self.len() { + // The T: Eq constraint is needed to call == on the array elements here + result &= self[i] == other[i]; + } + + result + } +} +``` + +## Trait Methods With No `self` + +A trait can contain any number of methods, each of which have access to the `Self` type which represents each type +that eventually implements the trait. Similarly, the `self` variable is available as well but is not required to be used. +For example, we can define a trait to create a default value for a type. This trait will need to return the `Self` type +but doesn't need to take any parameters: + +```rust +trait Default { + fn default() -> Self; +} +``` + +Implementing this trait can be done similarly to any other trait: + +```rust +impl Default for Field { + fn default() -> Field { + 0 + } +} + +struct MyType {} + +impl Default for MyType { + fn default() -> Field { + MyType {} + } +} +``` + +However, since there is no `self` parameter, we cannot call it via the method call syntax `object.method()`. +Instead, we'll need to refer to the function directly. This can be done either by referring to the +specific impl `MyType::default()` or referring to the trait itself `Default::default()`. In the later +case, type inference determines the impl that is selected. + +```rust +let my_struct = MyStruct::default(); + +let x: Field = Default::default(); +let result = x + Default::default(); +``` + +:::warning + +```rust +let _ = Default::default(); +``` + +If type inference cannot select which impl to use because of an ambiguous `Self` type, an impl will be +arbitrarily selected. This occurs most often when the result of a trait function call with no parameters +is unused. To avoid this, when calling a trait function with no `self` or `Self` parameters or return type, +always refer to it via the implementation type's namespace - e.g. `MyType::default()`. +This is set to change to an error in future Noir versions. + +::: + +## Default Method Implementations + +A trait can also have default implementations of its methods by giving a body to the desired functions. +Note that this body must be valid for all types that may implement the trait. As a result, the only +valid operations on `self` will be operations valid for any type or other operations on the trait itself. + +```rust +trait Numeric { + fn add(self, other: Self) -> Self; + + // Default implementation of double is (self + self) + fn double(self) -> Self { + self.add(self) + } +} +``` + +When implementing a trait with default functions, a type may choose to implement only the required functions: + +```rust +impl Numeric for Field { + fn add(self, other: Field) -> Field { + self + other + } +} +``` + +Or it may implement the optional methods as well: + +```rust +impl Numeric for u32 { + fn add(self, other: u32) -> u32 { + self + other + } + + fn double(self) -> u32 { + self * 2 + } +} +``` + +## Impl Specialization + +When implementing traits for a generic type it is possible to implement the trait for only a certain combination +of generics. This can be either as an optimization or because those specific generics are required to implement the trait. + +```rust +trait Sub { + fn sub(self, other: Self) -> Self; +} + +struct NonZero { + value: T, +} + +impl Sub for NonZero { + fn sub(self, other: Self) -> Self { + let value = self.value - other.value; + assert(value != 0); + NonZero { value } + } +} +``` + +## Overlapping Implementations + +Overlapping implementations are disallowed by Noir to ensure Noir's decision on which impl to select is never ambiguous. +This means if a trait `Foo` is already implemented +by a type `Bar` for all `T`, then we cannot also have a separate impl for `Bar` (or any other +type argument). Similarly, if there is an impl for all `T` such as `impl Debug for T`, we cannot create +any more impls to `Debug` for other types since it would be ambiguous which impl to choose for any given +method call. + +```rust +trait Trait {} + +// Previous impl defined here +impl Trait for (A, B) {} + +// error: Impl for type `(Field, Field)` overlaps with existing impl +impl Trait for (Field, Field) {} +``` + +## Trait Coherence + +Another restriction on trait implementations is coherence. This restriction ensures other crates cannot create +impls that may overlap with other impls, even if several unrelated crates are used as dependencies in the same +program. + +The coherence restriction is: to implement a trait, either the trait itself or the object type must be declared +in the crate the impl is in. + +In practice this often comes up when using types provided by libraries. If a library provides a type `Foo` that does +not implement a trait in the standard library such as `Default`, you may not `impl Default for Foo` in your own crate. +While restrictive, this prevents later issues or silent changes in the program if the `Foo` library later added its +own impl for `Default`. If you are a user of the `Foo` library in this scenario and need a trait not implemented by the +library your choices are to either submit a patch to the library or use the newtype pattern. + +### The Newtype Pattern + +The newtype pattern gets around the coherence restriction by creating a new wrapper type around the library type +that we cannot create `impl`s for. Since the new wrapper type is defined in our current crate, we can create +impls for any trait we need on it. + +```rust +struct Wrapper { + foo: dep::some_library::Foo, +} + +impl Default for Wrapper { + fn default() -> Wrapper { + Wrapper { + foo: dep::some_library::Foo::new(), + } + } +} +``` + +Since we have an impl for our own type, the behavior of this code will not change even if `some_library` is updated +to provide its own `impl Default for Foo`. The downside of this pattern is that it requires extra wrapping and +unwrapping of values when converting to and from the `Wrapper` and `Foo` types. diff --git a/noir/docs/versioned_docs/version-v../explanations/standard_library/traits.md b/noir/docs/versioned_docs/version-v../explanations/standard_library/traits.md new file mode 100644 index 00000000000..63b4f3d6f0b --- /dev/null +++ b/noir/docs/versioned_docs/version-v../explanations/standard_library/traits.md @@ -0,0 +1,140 @@ +--- +title: Traits +description: Noir's stdlib provides a few commonly used traits. +keywords: [traits, trait, interface, protocol, default, add, eq] +--- + +## `std::default` + +### `std::default::Default` + +```rust +trait Default { + fn default() -> Self; +} +``` + +Constructs a default value of a type. + +Implementations: +```rust +impl Default for Field { .. } + +impl Default for i8 { .. } +impl Default for i16 { .. } +impl Default for i32 { .. } +impl Default for i64 { .. } + +impl Default for u8 { .. } +impl Default for u16 { .. } +impl Default for u32 { .. } +impl Default for u64 { .. } + +impl Default for () { .. } +impl Default for bool { .. } + +impl Default for [T; N] + where T: Default { .. } + +impl Default for (A, B) + where A: Default, B: Default { .. } + +impl Default for (A, B, C) + where A: Default, B: Default, C: Default { .. } + +impl Default for (A, B, C, D) + where A: Default, B: Default, C: Default, D: Default { .. } + +impl Default for (A, B, C, D, E) + where A: Default, B: Default, C: Default, D: Default, E: Default { .. } +``` + +For primitive integer types, the return value of `default` is `0`. Container +types such as arrays are filled with default values of their element type. + +## `std::ops` + +### `std::ops::Eq` + +```rust +trait Eq { + fn eq(self, other: Self) -> bool; +} +``` +Returns `true` if `self` is equal to `other`. + +Implementations: +```rust +impl Eq for Field { .. } + +impl Eq for i8 { .. } +impl Eq for i16 { .. } +impl Eq for i32 { .. } +impl Eq for i64 { .. } + +impl Eq for u8 { .. } +impl Eq for u16 { .. } +impl Eq for u32 { .. } +impl Eq for u64 { .. } + +impl Eq for () { .. } +impl Eq for bool { .. } + +impl Eq for [T; N] + where T: Eq { .. } + +impl Eq for (A, B) + where A: Eq, B: Eq { .. } + +impl Eq for (A, B, C) + where A: Eq, B: Eq, C: Eq { .. } + +impl Eq for (A, B, C, D) + where A: Eq, B: Eq, C: Eq, D: Eq { .. } + +impl Eq for (A, B, C, D, E) + where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } +``` + +### `std::ops::Add`, `std::ops::Sub`, `std::ops::Mul`, and `std::ops::Div` + +These traits abstract over addition, subtraction, multiplication, and division respectively. +Although Noir does not currently have operator overloading, in the future implementing these +traits for a given type will also allow that type to be used with the corresponding operator +for that trait (`+` for Add, etc) in addition to the normal method names. + +```rust +trait Add { + fn add(self, other: Self) -> Self; +} + +trait Sub { + fn sub(self, other: Self) -> Self; +} + +trait Mul { + fn mul(self, other: Self) -> Self; +} + +trait Div { + fn div(self, other: Self) -> Self; +} +``` + +The implementations block below is given for the `Add` trait, but the same types that implement +`Add` also implement `Sub`, `Mul`, and `Div`. + +Implementations: +```rust +impl Add for Field { .. } + +impl Add for i8 { .. } +impl Add for i16 { .. } +impl Add for i32 { .. } +impl Add for i64 { .. } + +impl Add for u8 { .. } +impl Add for u16 { .. } +impl Add for u32 { .. } +impl Add for u64 { .. } +``` diff --git a/noir/docs/versioned_docs/version-v../getting_started/_category_.json b/noir/docs/versioned_docs/version-v../getting_started/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/versioned_docs/version-v../getting_started/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.7.1/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v../getting_started/create_a_project.md similarity index 86% rename from noir/docs/versioned_docs/version-v0.7.1/getting_started/01_hello_world.md rename to noir/docs/versioned_docs/version-v../getting_started/create_a_project.md index 0f21ad45569..f10916c39c5 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v../getting_started/create_a_project.md @@ -1,5 +1,5 @@ --- -title: Create A Project +title: Creating A Project description: Learn how to create and verify your first Noir program using Nargo, a programming language for zero-knowledge proofs. @@ -13,6 +13,8 @@ keywords: verify Noir program, step-by-step guide, ] +sidebar_position: 1 + --- Now that we have installed Nargo, it is time to make our first hello world program! @@ -30,13 +32,6 @@ mkdir ~/projects cd ~/projects ``` -For Windows CMD, run: - -```sh -> mkdir "%USERPROFILE%\projects" -> cd /d "%USERPROFILE%\projects" -``` - ## Create Our First Nargo Project Now that we are in the projects directory, create a new Nargo project by running: @@ -74,7 +69,7 @@ x : Field, y : pub Field Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the keyword `pub` (e.g. `y`). To learn more about private and public values, check the -[Data Types](../language_concepts/data_types) section. +[Data Types](../noir/syntax/data_types/index.md) section. The next line of the program specifies its body: @@ -84,7 +79,7 @@ assert(x != y); The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. -For more Noir syntax, check the [Language Concepts](../language_concepts/comments) chapter. +For more Noir syntax, check the [Language Concepts](../noir/syntax/comments.md) chapter. ## Build In/Output Files @@ -110,14 +105,14 @@ x = "1" y = "2" ``` -Prove the valid execution of your Noir program with your preferred proof name, for example `p`: +Prove the valid execution of your Noir program: ```sh -nargo prove p +nargo prove ``` A new folder _proofs_ would then be generated in your project directory, containing the proof file -`p.proof`. +`.proof`, where the project name is defined in Nargo.toml. The _Verifier.toml_ file would also be updated with the public values computed from program execution (in this case the value of `y`): @@ -133,10 +128,10 @@ y = "0x0000000000000000000000000000000000000000000000000000000000000002" Once a proof is generated, we can verify correct execution of our Noir program by verifying the proof file. -Verify your proof of name `p` by running: +Verify your proof by running: ```sh -nargo verify p +nargo verify ``` The verification will complete in silence if it is successful. If it fails, it will log the @@ -144,4 +139,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./project_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v../getting_started/installation/_category_.json b/noir/docs/versioned_docs/version-v../getting_started/installation/_category_.json new file mode 100644 index 00000000000..0c02fb5d4d7 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../getting_started/installation/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 0, + "label": "Install Nargo", + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v../getting_started/installation/index.md b/noir/docs/versioned_docs/version-v../getting_started/installation/index.md new file mode 100644 index 00000000000..ddb8a250eb4 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../getting_started/installation/index.md @@ -0,0 +1,45 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs. This page is a quick guide on how to install Nargo though the most common and easy method, noirup +keywords: [ + Nargo + Noir + Rust + Cargo + Noirup + Installation + Terminal Commands + Version Check + Nightlies + Specific Versions + Branches + Noirup Repository +] +--- + +`nargo` is the one-stop-shop for almost everything related with Noir. The name comes from our love for Rust and its package manager `cargo`. + +With `nargo`, you can start new projects, compile, execute, prove, verify, test, generate solidity contracts, and do pretty much all that is available in Noir. + +Similarly to `rustup`, we also maintain an easy installation method that covers most machines: `noirup`. + +## Installing Noirup + +Open a terminal on your machine, and write: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done. That's it. You should have the latest version working. You can check with `nargo --version`. + +You can also install nightlies, specific versions +or branches, check out the [noirup repository](https://github.com/noir-lang/noirup) for more +information. diff --git a/noir/docs/versioned_docs/version-v../getting_started/installation/other_install_methods.md b/noir/docs/versioned_docs/version-v../getting_started/installation/other_install_methods.md new file mode 100644 index 00000000000..36f05657277 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../getting_started/installation/other_install_methods.md @@ -0,0 +1,190 @@ +--- +title: Alternative Install Methods +description: + There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains other methods that don't rely on noirup, such as compiling from source, installing from binaries, and using WSL for windows +keywords: [ + Installation + Nargo + Noirup + Binaries + Compiling from Source + WSL for Windows + macOS + Linux + Nix + Direnv + Shell & editor experience + Building and testing + Uninstalling Nargo + Noir vs code extension +] +sidebar_position: 1 +--- + + +## Installation + +The most common method of installing Nargo is through [Noirup](./index.md) + +However, there are other methods for installing Nargo: + +- [Binaries](#binaries) +- [Compiling from Source](#compile-from-source) +- [WSL for Windows](#wsl-for-windows) + +### Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --version`. You should get a version number. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +### Option 3: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. It helps mitigating ssues commonly associated with dependency management, such as conflicts between required package versions for different projects (often referred to as "dependency hell"). + +Combined with direnv, which automatically sets or unsets environment variables based on the directory, it further simplifies the development process by seamlessly integrating with the developer's shell, facilitating an efficient and reliable workflow for managing and deploying Noir projects with multiple dependencies. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). + 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `rust-toolchain.toml`, which is 1.71.1 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +### Option 4: WSL (for Windows) + +The default backend for Noir (Barretenberg) doesn't provide Windows binaries at this time. For that reason, Noir cannot be installed nativerly. However, it is available by using Windows Subsystem for Linux (WSL). + +Step 1: Follow the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install) to install and run WSL. + +step 2: Follow the [Noirup instructions](./index.md). + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/getting_started/02_breakdown.md b/noir/docs/versioned_docs/version-v../getting_started/project_breakdown.md similarity index 63% rename from noir/docs/versioned_docs/version-v0.9.0/getting_started/02_breakdown.md rename to noir/docs/versioned_docs/version-v../getting_started/project_breakdown.md index 7c320cef9c5..5a214804f7b 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/getting_started/02_breakdown.md +++ b/noir/docs/versioned_docs/version-v../getting_started/project_breakdown.md @@ -5,6 +5,7 @@ description: files, and how to prove and verify your program. keywords: [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] +sidebar_position: 2 --- This section breaks down our hello world program in section _1.2_. We elaborate on the project @@ -23,13 +24,60 @@ commands, you would get a minimal Nargo project of the following structure: The source directory _src_ holds the source code for your Noir program. By default only a _main.nr_ file will be generated within it. +### Prover.toml + _Prover.toml_ is used for specifying the input values for executing and proving the program. You can specify `toml` files with different names by using the `--prover-name` or `-p` flags, see the [Prover](#provertoml) section below. Optionally you may specify expected output values for prove-time checking as well. +### Verifier.toml + _Verifier.toml_ contains public in/output values computed when executing the Noir program. -_Nargo.toml_ contains the environmental options of your project. +### Nargo.toml + +_Nargo.toml_ contains the environmental options of your project. It contains a "package" section and a "dependencies" section. + +Example Nargo.toml: + +```toml +[package] +name = "noirstarter" +type = "bin" +authors = ["Alice"] +compiler_version = "0.9.0" +description = "Getting started with Noir" +entry = "circuit/main.nr" +license = "MIT" + +[dependencies] +ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"} +``` + +Nargo.toml for a [workspace](../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: -_proofs_ and _contract_ directories will not be immediately visible until you create a proof or +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +#### Package section + +The package section requires a number of fields including: + +- `name` (**required**) - the name of the package +- `type` (**required**) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract +- `authors` (optional) - authors of the project +- `compiler_version` - specifies the version of the compiler to use. This is enforced by the compiler and follow's [Rust's versioning](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field), so a `compiler_version = 0.18.0` will enforce Nargo version 0.18.0, `compiler_version = ^0.18.0` will enforce anything above 0.18.0 but below 0.19.0, etc. For more information, see how [Rust handles these operators](https://docs.rs/semver/latest/semver/enum.Op.html) +- `description` (optional) +- `entry` (optional) - a relative filepath to use as the entry point into your package (overrides the default of `src/lib.nr` or `src/main.nr`) +- `backend` (optional) +- `license` (optional) + +#### Dependencies section + +This is where you will specify any dependencies for your project. See the [Dependencies page](../noir/modules_packages_crates/dependencies.md) for more info. + +`./proofs/` and `./contract/` directories will not be immediately visible until you create a proof or verifier contract respectively. ### main.nr @@ -66,13 +114,12 @@ x = "1" y = "2" ``` -When the command `nargo prove my_proof` is executed, two processes happen: +When the command `nargo prove` is executed, two processes happen: 1. Noir creates a proof that `x` which holds the value of `1` and `y` which holds the value of `2` is not equal. This not equal constraint is due to the line `assert(x != y)`. -2. Noir creates and stores the proof of this statement in the _proofs_ directory and names the proof - file _my_proof_. Opening this file will display the proof in hex format. +2. Noir creates and stores the proof of this statement in the _proofs_ directory in a file called your-project.proof. So if your project is named "private_voting" (defined in the project Nargo.toml), the proof will be saved at `./proofs/private_voting.proof`. Opening this file will display the proof in hex format. #### Arrays of Structs @@ -110,23 +157,23 @@ baz = 2 You can specify a `toml` file with a different name to use for proving by using the `--prover-name` or `-p` flags. -This command looks for proof inputs in the default **Prover.toml** and generates proof `p`: +This command looks for proof inputs in the default **Prover.toml** and generates the proof and saves it at `./proofs/.proof`: ```bash -nargo prove p +nargo prove ``` -This command looks for proof inputs in the custom **OtherProver.toml** and generates proof `pp`: +This command looks for proof inputs in the custom **OtherProver.toml** and generates proof and saves it at `./proofs/.proof`: ```bash -nargo prove -p OtherProver pp +nargo prove -p OtherProver ``` ## Verifying a Proof -When the command `nargo verify my_proof` is executed, two processes happen: +When the command `nargo verify` is executed, two processes happen: -1. Noir checks in the _proofs_ directory for a file called _my_proof_ +1. Noir checks in the _proofs_ directory for a proof file with the project name (eg. test_project.proof) 2. If that file is found, the proof's validity is checked @@ -150,5 +197,3 @@ verify the proof submitted against it. If the verification passes, additional fu verifier contract could trigger (e.g. approve the asset transfer). Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code. - -In the [next section](language_server), we will explain how to utilize the Noir Language Server. diff --git a/noir/docs/versioned_docs/version-v../getting_started/tooling/_category_.json b/noir/docs/versioned_docs/version-v../getting_started/tooling/_category_.json new file mode 100644 index 00000000000..dff520ebc41 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../getting_started/tooling/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 3, + "label": "Tooling", + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v../getting_started/tooling/index.md b/noir/docs/versioned_docs/version-v../getting_started/tooling/index.md new file mode 100644 index 00000000000..55df833005a --- /dev/null +++ b/noir/docs/versioned_docs/version-v../getting_started/tooling/index.md @@ -0,0 +1,33 @@ +--- +title: Tooling +Description: This section provides information about the various tools and utilities available for Noir development. It covers the Noir playground, IDE tools, Codespaces, and community projects. +Keywords: [Noir, Development, Playground, IDE Tools, Language Service Provider, VS Code Extension, Codespaces, noir-starter, Community Projects, Awesome Noir Repository, Developer Tooling] +--- + +Noir is meant to be easy to develop with. For that reason, a number of utilities have been put together to ease the development process as much as feasible in the zero-knowledge world. + +## Playground + +The Noir playground is an easy way to test small ideas, share snippets, and integrate in other websites. You can access it at [play.noir-lang.org](https://play.noir-lang.org). + +## IDE tools + +When you install Nargo, you're also installing a Language Service Provider (LSP), which can be used by IDEs to provide syntax highlighting, codelens, warnings, and more. + +The easiest way to use these tools is by installing the [Noir VS Code extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). + +## Codespaces + +Some Noir repos have leveraged Codespaces in order to ease the development process. You can visit the [noir-starter](https://github.com/noir-lang/noir-starter) for an example. + +## GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file in the Noir repo](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) for an example usage. + +## Community projects + +As an open-source project, Noir has received many contributions over time. Some of them are related with developer tooling, and you can see some of them in [Awesome Noir repository](https://github.com/noir-lang/awesome-noir#dev-tools) diff --git a/noir/docs/versioned_docs/version-v0.9.0/getting_started/03_language_server.md b/noir/docs/versioned_docs/version-v../getting_started/tooling/language_server.md similarity index 56% rename from noir/docs/versioned_docs/version-v0.9.0/getting_started/03_language_server.md rename to noir/docs/versioned_docs/version-v../getting_started/tooling/language_server.md index e6f5dfc2faa..81e0356ef8a 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/getting_started/03_language_server.md +++ b/noir/docs/versioned_docs/version-v../getting_started/tooling/language_server.md @@ -1,9 +1,8 @@ --- title: Language Server -description: - Learn about the Noir Language Server, how to install the components, and configuration that may be required. -keywords: - [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +description: Learn about the Noir Language Server, how to install the components, and configuration that may be required. +keywords: [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +sidebar_position: 0 --- This section helps you install and configure the Noir Language Server. @@ -23,9 +22,22 @@ The Client component is usually an editor plugin that launches the Server. It co Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). +> **Note:** Noir's Language Server Protocol support currently assumes users' VSCode workspace root to be the same as users' Noir project root (i.e. where Nargo.toml lies). +> +> If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. + +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: + +![Compile and Execute](@site/static/img/codelens_compile_execute.png) +![Run test](@site/static/img/codelens_run_test.png) + +You should also see your tests in the `testing` panel: + +![Testing panel](@site/static/img/codelens_testing_panel.png) + ### Configuration -* __Noir: Enable LSP__ - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. -* __Noir: Nargo Flags__ - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. -* __Noir: Nargo Path__ - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. -* __Noir > Trace: Server__ - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. +- **Noir: Enable LSP** - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. +- **Noir: Nargo Flags** - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. +- **Noir: Nargo Path** - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. +- **Noir > Trace: Server** - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/noir/docs/versioned_docs/version-v0.7.1/nargo/02_testing.md b/noir/docs/versioned_docs/version-v../getting_started/tooling/testing.md similarity index 51% rename from noir/docs/versioned_docs/version-v0.7.1/nargo/02_testing.md rename to noir/docs/versioned_docs/version-v../getting_started/tooling/testing.md index ba0bebd658b..868a061200d 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/nargo/02_testing.md +++ b/noir/docs/versioned_docs/version-v../getting_started/tooling/testing.md @@ -2,6 +2,7 @@ title: Testing in Noir description: Learn how to use Nargo to test your Noir program in a quick and easy way keywords: [Nargo, testing, Noir, compile, test] +sidebar_position: 1 --- You can test your Noir programs using Noir circuits. @@ -27,6 +28,35 @@ Running `nargo test` will test that the `test_add` function can be executed whil the contraints which allows you to test that add returns the expected values. Test functions can't have any arguments currently. -This is much faster compared to testing in Typescript but the only downside is that you can't -explicitly test that a certain set of inputs are invalid. i.e. you can't say that you want -add(2^64-1, 2^64-1) to fail. +### Test fail + +You can write tests that are expected to fail by using the decorator `#[test(should_fail)]`. For example: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test(should_fail)] +fn test_add() { + assert(add(2,2) == 5); +} +``` + +You can be more specific and make it fail with a specific reason by using `should_fail_with = "`: + +```rust +fn main(african_swallow_avg_speed : Field) { + assert(african_swallow_avg_speed == 65, "What is the airspeed velocity of an unladen swallow"); +} + +#[test] +fn test_king_arthur() { + main(65); +} + +#[test(should_fail_with = "What is the airspeed velocity of an unladen swallow")] +fn test_bridgekeeper() { + main(32); +} + +``` diff --git a/noir/docs/versioned_docs/version-v../how_to/_category_.json b/noir/docs/versioned_docs/version-v../how_to/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/noir/docs/versioned_docs/version-v../how_to/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v../how_to/how-to-recursion.md b/noir/docs/versioned_docs/version-v../how_to/how-to-recursion.md new file mode 100644 index 00000000000..226f7e6e73d --- /dev/null +++ b/noir/docs/versioned_docs/version-v../how_to/how-to-recursion.md @@ -0,0 +1,184 @@ +--- +title: How to use recursion on NoirJS +description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `backend_barretenberg`. +keywords: + [ + "NoirJS", + "EVM blockchain", + "smart contracts", + "recursion", + "solidity verifiers", + "Barretenberg backend", + "noir_js", + "backend_barretenberg", + "intermediate proofs", + "final proofs", + "nargo compile", + "json import", + "recursive circuit", + "recursive app" + ] +sidebar_position: 1 +--- + +This guide shows you how to use recursive proofs in your NoirJS app. For the sake of clarity, it is assumed that: + +- You already have a NoirJS app. If you don't, please visit the [NoirJS tutorial](../tutorials/noirjs_app.md) and the [reference](../reference/NoirJS/noir_js/index.md). +- You are familiar with what are recursive proofs and you have read the [recursion explainer](../explainers/explainer-recursion.md) +- You already built a recursive circuit following [the reference](../noir/standard_library/recursion.md), and understand how it works. + +It is also assumed that you're not using `noir_wasm` for compilation, and instead you've used [`nargo compile`](../reference/nargo_commands.md) to generate the `json` you're now importing into your project. However, the guide should work just the same if you're using `noir_wasm`. + +:::info + +As you've read in the [explainer](../explainers/explainer-recursion.md), a recursive proof is an intermediate proof. Meaning it doesn't necessarily generate the final step that makes it verifiable in a smart contract. However, it is easy to verify within another circuit. + +While "standard" usage of NoirJS packages abstracts final proofs, it currently lacks the necessary interface to abstract away intermediate proofs. Which means these proofs need to be created by using the backend directly. + +In short: + +- `noir_js` generates *only* final proofs +- `backend_barretenberg` generates both types of proofs + +::: + +In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume these two: + +- `main`: a circuit of type `assert(x != y)` +- `recursive`: a circuit that verifies `main` + +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir/noir-examples) repository. We will *not* be using it as a reference for this guide. + +## Step 1: Setup + +In a common NoirJS app, you need to instantiate a backend with something like `const backend = new Backend(circuit)`. Then you feed it to the `noir_js` interface. + +For recursiveness, this doesn't happen, and the only need for `noir_js` is only to `execute` a circuit and get its witness and return value. Everything else is not interfaced, so it needs to happen on the `backend` object. + +It is also recommended that you instantiate the backend with as many threads as possible, to allow for maximum concurrency: + +```js +const backend = new Backend(circuit, { threads: 8 }) +``` + +:::tip +You can use the [`os.cpus()`](https://nodejs.org/api/os.html#oscpus) object in `nodejs` or [`navigator.hardwareConcurrency`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency) on the browser to make the most out of those glorious cpu cores +::: + +## Step 2: Generating the witness and the proof for `main` + +After instantiating the backend, you should also instantiate `noir_js`. We will use it to execute the circuit and get the witness. + +```js +const noir = new Noir(circuit, backend) +const { witness } = noir.execute(input) +``` + +With this witness, you are now able to generate the intermediate proof for the main circuit: + +```js +const { proof, publicInputs } = await backend.generateIntermediateProof(witness) +``` + +:::warning + +Always keep in mind what is actually happening on your development process, otherwise you'll quickly become confused about what circuit are we actually running and why! + +In this case, you can imagine that Alice (running the `main` circuit) is proving something to Bob (running the `recursive` circuit), and Bob is verifying her proof within his proof. + +With this in mind, it becomes clear that our intermediate proof is the one *meant to be verified within another circuit*. So it is Alice's. Actually, the only final proof in this theoretical scenario would be the last one, sent on-chain. + +::: + +## Step 3 - Verification and proof artifacts + +Optionally, you are able to verify the intermediate proof: + +```js +const verified = await backend.verifyIntermediateProof({ proof, publicInputs }) +``` + +This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate the intermediate artifacts: + +```js +const { proofAsFields, vkAsFields, vkHash } = await backend.generateIntermediateProofArtifacts( { publicInputs, proof }, publicInputsCount) +``` + +This call takes the public inputs and the proof, but also the public inputs count. While this is easily retrievable by simply counting the `publicInputs` length, the backend interface doesn't currently abstract it away. + +:::info + +The `proofAsFields` has a constant size `[Field; 93]`. However, currently the backend doesn't remove the public inputs from the proof when converting it. + +This means that if your `main` circuit has two public inputs, then you should also modify the recursive circuit to accept a proof with the public inputs appended. This means that in our example, since `y` is a public input, our `proofAsFields` is of type `[Field; 94]`. + +Verification keys in Barretenberg are always of size 114. + +::: + +:::warning + +One common mistake is to forget *who* makes this call. + +In a situation where Alice is generating the `main` proof, if she generates the proof artifacts and sends them to Bob, which gladly takes them as true, this would mean Alice could prove anything! + +Instead, Bob needs to make sure *he* extracts the proof artifacts, using his own instance of the `main` circuit backend. This way, Alice has to provide a valid proof for the correct `main` circuit. + +::: + +## Step 4 - Recursive proof generation + +With the artifacts, generating a recursive proof is no different from a normal proof. You simply use the `backend` (with the recursive circuit) to generate it: + +```js +const recursiveInputs = { + verification_key: vkAsFields, // array of length 114 + proof: proofAsFields, // array of length 93 + size of public inputs + publicInputs: [mainInput.y], // using the example above, where `y` is the only public input + key_hash: vkHash, + input_aggregation_object: Array(16).fill(0) // this circuit is verifying a non-recursive proof, so there's no input aggregation object: just use zero +} + +const { witness, returnValue } = noir.execute(recursiveInputs) // we're executing the recursive circuit now! +const { proof, publicInputs } = backend.generateFinalProof(witness) +const verified = backend.verifyFinalProof({ proof, publicInputs }) +``` + +You can obviously chain this proof into another proof. In fact, if you're using recursive proofs, you're probably interested of using them this way! In that case, you should keep in mind the `returnValue`, as it will contain the `input_aggregation_object` for the next proof. + +:::tip + +Managing circuits and "who does what" can be confusing. To make sure your naming is consistent, you can keep them in an object. For example: + +```js +const circuits = { +main: mainJSON, +recursive: recursiveJSON +} +const backends = { +main: new BarretenbergBackend(circuits.main), +recursive: new BarretenbergBackend(circuits.recursive) +} +const noirs = { +main: new Noir(circuits.main, backends.main), +recursive: new Noir(circuits.recursive, backends.recursive) +} +``` + +This allows you to neatly call exactly the method you want without conflicting names: + +```js +// Alice runs this 👇 +const { witness: mainWitness } = await noirs.main.execute(input) +const proof = await backends.main.generateIntermediateProof(mainWitness) + +// Bob runs this 👇 +const verified = await backends.main.verifyIntermediateProof(proof) +const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateIntermediateProofArtifacts( + proof, + numPublicInputs, +); +const recursiveProof = await noirs.recursive.generateFinalProof(recursiveInputs) +``` + +::: diff --git a/noir/docs/versioned_docs/version-v0.9.0/examples/merkle-proof.mdx b/noir/docs/versioned_docs/version-v../how_to/merkle-proof.mdx similarity index 96% rename from noir/docs/versioned_docs/version-v0.9.0/examples/merkle-proof.mdx rename to noir/docs/versioned_docs/version-v../how_to/merkle-proof.mdx index 6430780817c..34074659ac1 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/examples/merkle-proof.mdx +++ b/noir/docs/versioned_docs/version-v../how_to/merkle-proof.mdx @@ -1,5 +1,5 @@ --- -title: Merkle Proof Membership +title: Prove Merkle Tree Membership description: Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a merkle tree with a specified root, at a given index. @@ -23,7 +23,7 @@ fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Fie The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen by the backend. The only requirement is that this hash function can heuristically be used as a -random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen` +random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen_hash` instead. ```rust diff --git a/noir/docs/versioned_docs/version-v0.7.1/nargo/03_solidity_verifier.md b/noir/docs/versioned_docs/version-v../how_to/solidity_verifier.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.7.1/nargo/03_solidity_verifier.md rename to noir/docs/versioned_docs/version-v../how_to/solidity_verifier.md index 9ac60cb0ba7..8022b0e5f20 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/nargo/03_solidity_verifier.md +++ b/noir/docs/versioned_docs/version-v../how_to/solidity_verifier.md @@ -1,9 +1,9 @@ --- -title: Solidity Verifier +title: Generate a Solidity Verifier description: Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart - contract. Read more to find out! + contract. Read more to find out keywords: [ solidity verifier, @@ -16,6 +16,7 @@ keywords: proving backend, Barretenberg, ] +sidebar_position: 0 --- For certain applications, it may be desirable to run the verifier as a smart contract instead of on diff --git a/noir/docs/versioned_docs/version-v../index.md b/noir/docs/versioned_docs/version-v../index.md new file mode 100644 index 00000000000..016832f9f5e --- /dev/null +++ b/noir/docs/versioned_docs/version-v../index.md @@ -0,0 +1,85 @@ +--- +title: Noir +description: + Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to + an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. +keywords: + [ + Noir, + Domain Specific Language, + Rust, + Intermediate Language, + Arithmetic Circuit, + Rank-1 Constraint System, + Ethereum Developers, + Protocol Developers, + Blockchain Developers, + Proving System, + Smart Contract Language, + ] +sidebar_position: 0 +--- + +## What's new about Noir? + +Noir, a domain-specific language crafted for SNARK proving systems, stands out with its simplicity, flexibility, +and robust capabilities. Unlike conventional approaches that compile directly to a fixed NP-complete language, +Noir takes a two-pronged path. It first compiles to an adaptable intermediate language known as ACIR. From there, +depending on the project's needs, ACIR can be further compiled into an arithmetic circuit for integration with Aztec's +barretenberg backend or transformed into a rank-1 constraint system suitable for R1CS backends like Arkwork's Marlin +backend, among others. + +This innovative design introduces unique challenges, yet it strategically separates the programming language from the +backend. Noir's approach echoes the modular philosophy of LLVM, offering developers a versatile toolkit for cryptographic +programming. + +## Who is Noir for? + +### Solidity Developers + +Noir streamlines the creation of Solidity contracts that interface with SNARK systems. +[`Utilize the nargo codegen-verifier`](./reference/nargo_commands.md#nargo-codegen-verifier) command to construct verifier +contracts efficiently. While the current alpha version offers this as a direct feature, future updates aim +to modularize this process for even greater ease of use. + +Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will be +modularised in the future; however, as of the alpha, you can use the + command to create a verifier contract. + +### Protocol Developers + +Should the Aztec backend not align with your existing tech stack, or if you're inclined to integrate alternative +proving systems, Noir's agnostic compilation to a proof-agnostic intermediate language offers unmatched flexibility. +This allows protocol engineers the freedom to substitute the default PLONK-based system with an alternative of their +choice, tailoring the proving system to their specific needs. + +### Blockchain developers + +Blockchain developers often face environmental constraints, such as predetermined proving systems and smart contract +languages. Noir addresses this by enabling the implementation of custom proving system backends and smart contract +interfaces, ensuring seamless integration with your blockchain's architecture, and expanding the horizons for innovation +within your projects. + +## Libraries + +Noir does not currently have an official package manager. You can find a list of available Noir libraries in the +[awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). + +Some libraries that are available today include: + +- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library +- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains + the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage + proof verification (or verification of any trie proof involving 32-byte long keys) +- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing + for computations on large unsigned integers +- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and + return the source Ethereum address +- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of + sparse Merkle trees +- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data + type, allowing access to negative numbers on Noir +- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, + allowing results that aren't whole numbers + +See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/noir/docs/versioned_docs/version-v../migration_notes.md b/noir/docs/versioned_docs/version-v../migration_notes.md new file mode 100644 index 00000000000..d5d0682cf0c --- /dev/null +++ b/noir/docs/versioned_docs/version-v../migration_notes.md @@ -0,0 +1,91 @@ +--- +title: Migration notes +description: Read about migration notes from previous versions, which could solve problems while updating +keywords: [Noir, notes, migration, updating, upgrading] +--- + +Noir is in full-speed development. Things break fast, wild, and often. This page attempts to leave some notes on errors you might encounter when upgrading and how to resolve them until proper patches are built. + +## ≥0.19 + +### Enforcing `compiler_version` + +From this version on, the compiler will check for the `compiler_version` field in `Nargo.toml`, and will error if it doesn't match the current Nargo version in use. + +To update, please make sure this field in `Nargo.toml` matches the output of `nargo --version`. + +## ≥0.14 + +The index of the [for loops](noir/syntax/control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: + +```rust +for i in 0..10 { + let i = i as Field; +} +``` + +## ≥v0.11.0 and Nargo backend + +From this version onwards, Nargo starts managing backends through the `nargo backend` command. Upgrading to the versions per usual steps might lead to: + +### `backend encountered an error` + +This is likely due to the existing locally installed version of proving backend (e.g. barretenberg) is incompatible with the version of Nargo in use. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo prove +``` + +with you Noir program. + +This will trigger the download and installation of the latest version of barretenberg compatible with your Nargo in use. + +### `backend encountered an error: illegal instruction` + +On certain Intel-based systems, an `illegal instruction` error may arise due to incompatibility of barretenberg with certain CPU instructions. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/barretenberg-js-binary/raw/master/run-bb.tar.gz +``` + +This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. + +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. + +Then run: + +``` +DESIRED_BINARY_VERSION=0.8.1 nargo info +``` + +This overrides the bb native binary with a bb.js node application instead, which should be compatible with most if not all hardware. This does come with the drawback of being generally slower than native binary. + +0.8.1 indicates bb.js version 0.8.1, so if you change that it will update to a different version or the default version in the script if none was supplied. diff --git a/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/_category_.json b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/_category_.json new file mode 100644 index 00000000000..1debcfe7675 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Modules, Packages and Crates", + "position": 2, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/crates_and_packages.md b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/crates_and_packages.md similarity index 70% rename from noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/crates_and_packages.md rename to noir/docs/versioned_docs/version-v../noir/modules_packages_crates/crates_and_packages.md index 34f28a71148..aae6795b229 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/crates_and_packages.md +++ b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/crates_and_packages.md @@ -1,8 +1,8 @@ --- title: Crates and Packages -description: - Learn how to use Crates and Packages in your Noir project +description: Learn how to use Crates and Packages in your Noir project keywords: [Nargo, dependencies, package management, crates, package] +sidebar_position: 0 --- ## Crates @@ -12,12 +12,20 @@ Crates can contain modules, and the modules may be defined in other files that g ### Crate Types -A Noir crate can come in one of two forms: a binary crate or a library crate. +A Noir crate can come in several forms: binaries, libraries or contracts. + +#### Binaries _Binary crates_ are programs which you can compile to an ACIR circuit which you can then create proofs against. Each must have a function called `main` that defines the ACIR circuit which is to be proved. +#### Libraries + _Library crates_ don't have a `main` function and they don't compile down to ACIR. Instead they define functionality intended to be shared with multiple projects, and eventually included in a binary crate. +#### Contracts + +Contract crates are similar to binary crates in that they compile to ACIR which you can create proofs against. They are different in that they do not have a single `main` function, but are a collection of functions to be deployed to the [Aztec network](https://aztec.network). You can learn more about the technical details of Aztec in the [monorepo](https://github.com/AztecProtocol/aztec-packages) or contract [examples](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/src/contracts). + ### Crate Root Every crate has a root, which is the source file that the compiler starts, this is also known as the root module. The Noir compiler does not enforce any conditions on the name of the file which is the crate root, however if you are compiling via Nargo the crate root must be called `lib.nr` or `main.nr` for library or binary crates respectively. diff --git a/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/dependencies.md b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/dependencies.md similarity index 86% rename from noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/dependencies.md rename to noir/docs/versioned_docs/version-v../noir/modules_packages_crates/dependencies.md index 2807ad52046..57f0f9fd420 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/dependencies.md +++ b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/dependencies.md @@ -1,9 +1,10 @@ --- -title: Managing Dependencies +title: Dependencies description: Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub and use them easily in your project. keywords: [Nargo, dependencies, GitHub, package management, versioning] +sidebar_position: 1 --- Nargo allows you to upload packages to GitHub and use them as dependencies. @@ -28,13 +29,22 @@ For example, to add the [ecrecover-noir library](https://github.com/colinnielsen ecrecover = {tag = "v0.8.0", git = "https://github.com/colinnielsen/ecrecover-noir"} ``` +If the module is in a subdirectory, you can define a subdirectory in your git repository, for example: + +```toml +# Nargo.toml + +[dependencies] +easy_private_token_contract = {tag ="v0.1.0-alpha62", git = "https://github.com/AztecProtocol/aztec-packages", directory = "yarn-project/noir-contracts/src/contracts/easy_private_token_contract"} +``` + ## Specifying a local dependency You can also specify dependencies that are local to your machine. For example, this file structure has a library and binary crate -``` +```tree ├── binary_crate │   ├── Nargo.toml │   └── src @@ -68,7 +78,7 @@ You can also import only the specific parts of dependency that you want to use, ```rust use dep::std::hash::sha256; -use dep::std::scalar_mul::fixed_base; +use dep::std::scalar_mul::fixed_base_embedded_curve; ``` Lastly, as demonstrated in the @@ -79,6 +89,10 @@ can import multiple items in the same line by enclosing them in curly braces: use dep::std::ec::tecurve::affine::{Curve, Point}; ``` +We don't have a way to consume libraries from inside a [workspace](./workspaces) as external dependencies right now. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + ## Dependencies of Dependencies Note that when you import a dependency, you also get access to all of the dependencies of that package. diff --git a/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/modules.md b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/modules.md similarity index 89% rename from noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/modules.md rename to noir/docs/versioned_docs/version-v../noir/modules_packages_crates/modules.md index e429b336511..f9f15aee8be 100644 --- a/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/modules.md +++ b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/modules.md @@ -1,13 +1,12 @@ --- -title: Understanding Modules +title: Modules description: Learn how to organize your files using modules in Noir, following the same convention as Rust's module system. Examples included. keywords: [Noir, Rust, modules, organizing files, sub-modules] +sidebar_position: 2 --- -# Modules - Noir's module system follows the same convention as the _newer_ version of Rust's module system. ## Purpose of Modules @@ -51,7 +50,8 @@ crate ``` ### Importing a module throughout the tree -All modules are accessible from the ``crate::`` namespace. + +All modules are accessible from the `crate::` namespace. ``` crate @@ -60,7 +60,8 @@ crate └── main ``` -In the above snippet, if ``bar`` would like to use functions in ``foo``, it can do so by ``use crate::foo::function_name``. + +In the above snippet, if `bar` would like to use functions in `foo`, it can do so by `use crate::foo::function_name`. ### Sub-modules diff --git a/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/workspaces.md b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/workspaces.md new file mode 100644 index 00000000000..67a1dafa372 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/modules_packages_crates/workspaces.md @@ -0,0 +1,40 @@ +--- +title: Workspaces +sidebar_position: 3 +--- + +Workspaces are a feature of nargo that allow you to manage multiple related Noir packages in a single repository. A workspace is essentially a group of related projects that share common build output directories and configurations. + +Each Noir project (with it's own Nargo.toml file) can be thought of as a package. Each package is expected to contain exactly one "named circuit", being the "name" defined in Nargo.toml with the program logic defined in `./src/main.nr`. + +For a project with the following structure: + +```tree +├── crates +│   ├── a +│   │   ├── Nargo.toml +│   │   └── src +│   │   └── main.nr +│   └── b +│   ├── Nargo.toml +│   └── src +│   └── main.nr +├── Nargo.toml +└── Prover.toml +``` + +You can define a workspace in Nargo.toml like so: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +`members` indicates which packages are included in the workspace. As such, all member packages of a workspace will be processed when the `--workspace` flag is used with various commands or if a `default-member` is not specified. + +`default-member` indicates which package various commands process by default. + +Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/noir/docs/versioned_docs/version-v../noir/standard_library/_category_.json b/noir/docs/versioned_docs/version-v../noir/standard_library/_category_.json new file mode 100644 index 00000000000..af04c0933fd --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Standard Library", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/black_box_fns.md b/noir/docs/versioned_docs/version-v../noir/standard_library/black_box_fns.md similarity index 94% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/black_box_fns.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/black_box_fns.md index c758846b688..1dfabfe8f22 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/black_box_fns.md +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/black_box_fns.md @@ -29,7 +29,8 @@ Here is a list of the current black box functions that are supported by UltraPlo - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) - [Fixed base scalar multiplication](./cryptographic_primitives/scalar) diff --git a/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/_category_.json b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/ec_primitives.md similarity index 99% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/ec_primitives.md index 6e6b19b6861..8d573adb3be 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -1,6 +1,7 @@ --- title: Elliptic Curve Primitives keywords: [cryptographic primitives, Noir project] +sidebar_position: 4 --- Data structures and methods on them that allow you to carry out computations involving elliptic diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx similarity index 93% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx index 3934a0338d0..1376c51dfde 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -2,9 +2,10 @@ title: ECDSA Signature Verification description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 and secp256r1 curves keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, secp256r1, signatures] +sidebar_position: 3 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/eddsa.mdx similarity index 82% rename from noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/eddsa.mdx index 8f060ed3316..a9c10da6c06 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/eddsa.mdx @@ -2,9 +2,10 @@ title: EdDSA Verification description: Learn about the cryptographic primitives regarding EdDSA keywords: [cryptographic primitives, Noir project, eddsa, signatures] +sidebar_position: 5 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## eddsa::eddsa_poseidon_verify diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/hashes.mdx similarity index 70% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/hashes.mdx index 31a84cdb753..9250cb4a0c0 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/hashes.mdx @@ -5,9 +5,10 @@ description: blake2s, pedersen, mimc_bn254 and mimc keywords: [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] +sidebar_position: 0 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## sha256 @@ -21,7 +22,7 @@ example: ```rust fn main() { - let x = [163, 117, 178, 149] // some random bytes + let x = [163, 117, 178, 149]; // some random bytes let hash = std::hash::sha256(x); } ``` @@ -40,27 +41,48 @@ example: ```rust fn main() { - let x = [163, 117, 178, 149] // some random bytes + let x = [163, 117, 178, 149]; // some random bytes let hash = std::hash::blake2s(x); } ``` -## pedersen +## pedersen_hash Given an array of Fields, returns the Pedersen hash. ```rust -fn pedersen(_input : [Field]) -> [Field; 2] +fn pedersen_hash(_input : [Field]) -> Field ``` example: ```rust fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::pedersen(x); + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::pedersen_hash(x); +} +``` + + + + + +## pedersen_commitment + +Given an array of Fields, returns the Pedersen commitment. + +```rust +fn pedersen_commitment(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let commitment = std::hash::pedersen_commitment(x); } ``` @@ -80,7 +102,7 @@ example: ```rust fn main() { - let x = [163, 117, 178, 149] // some random bytes + let x = [163, 117, 178, 149]; // some random bytes let message_size = 4; let hash = std::hash::keccak256(x, message_size); } @@ -103,8 +125,8 @@ example: ```rust fn main() { - let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); - assert(hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); + let hash_2 = std::hash::poseidon::bn254::hash_2([1, 2]); + assert(hash2 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); } ``` @@ -129,8 +151,8 @@ example: ```rust fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::mimc_bn254(x); + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::mimc::mimc_bn254(x); } ``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives.md b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/index.md similarity index 92% rename from noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/index.md index 2df4f929474..650f30165d5 100644 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives.md +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/index.md @@ -1,5 +1,5 @@ --- -title: Cryptographic primitives in Noir +title: Cryptographic Primitives description: Learn about the cryptographic primitives ready to use for any Noir project keywords: diff --git a/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/scalar.mdx new file mode 100644 index 00000000000..1e686303c18 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/scalar.mdx @@ -0,0 +1,28 @@ +--- +title: Scalar multiplication +description: See how you can perform scalar multiplications over a fixed base in Noir +keywords: [cryptographic primitives, Noir project, scalar multiplication] +sidebar_position: 1 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## scalar_mul::fixed_base_embedded_curve + +Performs scalar multiplication over the embedded curve whose coordinates are defined by the +configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. + +```rust +fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base_embedded_curve(x); + std::println(scal); +} +``` + + diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/schnorr.mdx similarity index 91% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/schnorr.mdx index 0e219c0e5ff..7a2c9c20226 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -2,9 +2,10 @@ title: Schnorr Signatures description: Learn how you can verify Schnorr signatures using Noir keywords: [cryptographic primitives, Noir project, schnorr, signatures] +sidebar_position: 2 --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## schnorr::verify_signature diff --git a/noir/docs/versioned_docs/version-v../noir/standard_library/logging.md b/noir/docs/versioned_docs/version-v../noir/standard_library/logging.md new file mode 100644 index 00000000000..16daf922e15 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/logging.md @@ -0,0 +1,77 @@ +--- +title: Logging +description: + Learn how to use the println statement for debugging in Noir with this tutorial. Understand the + basics of logging in Noir and how to implement it in your code. +keywords: + [ + noir logging, + println statement, + print statement, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides two familiar statements you can use: `println` and `print`. Despite being a limited implementation of rust's `println!` and `print!` macros, these constructs can be useful for debugging. + +You can print the output of both statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are print statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constrains with `println` or `print` statements. This is due to every input in a test being a constant rather than a witness, so we issue an error during compilation while we only print during execution (which comes after compilation). Neither `println`, nor `print` are callable for failed constraints caught at compile time. + +Both `print` and `println` are generic functions which can work on integers, fields, strings, and even structs or expressions. Note however, that slices are currently unsupported. For example: + +```rust +use dep::std; + +struct Person { + age : Field, + height : Field, +} + +fn main(age : Field, height : Field) { + let person = Person { age : age, height : height }; + std::println(person); + std::println(age + height); + std::println("Hello world!"); +} +``` + +You can print different types in the same statement (including strings) with a type called `fmtstr`. It can be specified in the same way as a normal string, just prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + std::println(fmt_str); + + let s = myStruct { y: x, x: y }; + std::println(s); + + std::println(f"i: {i}, s: {s}"); + + std::println(x); + std::println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + std::println(f"s: {s}, foo: {foo}"); + + std::println(15); // prints 0x0f, implicit Field + std::println(-1 as u8); // prints 255 + std::println(-1 as i8); // prints -1 +``` + +Examples shown above are interchangeable between the two `print` statements: + +```rust +let person = Person { age : age, height : height }; + +std::println(person); +std::print(person); + +std::println("Hello world!"); // Prints with a newline at the end of the input +std::print("Hello world!"); // Prints the input and keeps cursor on the same line +``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/merkle_trees.md b/noir/docs/versioned_docs/version-v../noir/standard_library/merkle_trees.md similarity index 91% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/merkle_trees.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/merkle_trees.md index 57d8c4a9e4f..5b45617812a 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/merkle_trees.md +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/merkle_trees.md @@ -17,7 +17,7 @@ keywords: ## compute_merkle_root -Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](cryptographic_primitives/00_hashes.mdx#pedersen). +Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](./cryptographic_primitives/hashes.mdx#pedersen_hash). ```rust fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field @@ -39,7 +39,7 @@ example: */ fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { - let pubkey = std::scalar_mul::fixed_base(priv_key); + let pubkey = std::scalar_mul::fixed_base_embedded_curve(priv_key); let pubkey_x = pubkey[0]; let pubkey_y = pubkey[1]; let note_commitment = std::hash::pedersen([pubkey_x, pubkey_y, secret]); diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/options.md b/noir/docs/versioned_docs/version-v../noir/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/options.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/recursion.md b/noir/docs/versioned_docs/version-v../noir/standard_library/recursion.md similarity index 63% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/recursion.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/recursion.md index 4705ae6c575..67962082a8f 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/recursion.md +++ b/noir/docs/versioned_docs/version-v../noir/standard_library/recursion.md @@ -19,11 +19,7 @@ This is a black box function. Read [this section](./black_box_fns) to learn more ::: -## Aggregation Object - -The purpose of the input aggregation object is a little less clear though (and the output aggregation object that is returned from the `std::verify_proof` method). Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points (thus completing the recursive verification). - -So for example in this circuit: +## Example usage ```rust use dep::std; @@ -37,17 +33,17 @@ fn main( proof_b : [Field; 94], ) -> pub [Field; 16] { let output_aggregation_object_a = std::verify_proof( - verification_key, - proof, - public_inputs, + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), key_hash, input_aggregation_object ); let output_aggregation_object = std::verify_proof( - verification_key, - proof_b, - public_inputs, + verification_key.as_slice(), + proof_b.as_slice(), + public_inputs.as_slice(), key_hash, output_aggregation_object_a ); @@ -60,8 +56,6 @@ fn main( } ``` -In this example we have a circuit, that generates proofs A and B, that is being verified in circuit C. Assuming that the proof being passed in is not already a recursive proof, the `input_aggregation_object` will be all zeros. It will then generate an `output_aggregation_object`. This blob of data then becomes the `input_aggregation_object` of the next recursive aggregation we wish to compute. We can see here as the same public inputs, verification key, and key hash are used that we are verifying two proofs generated from the same circuit in this single circuit. `std::verify_proof` returns a `[Field]` because the size of an aggregation object is proof system dependent--in barretenberg, aggregation objects are two G1 points, while in Halo2, the aggregation object is a list of G1 points that is log the circuit size. So for the final step we convert the slice into an array of size 16 because we are generating proofs using UltraPlonk. - ## Parameters ### `verification_key` @@ -93,4 +87,4 @@ The next verifier can either perform a final verification (returning true or fal ## Example -You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/Savio-Sou/recursion-demo/tree/main). +You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/noir-lang/noir-examples/tree/master/recursion). diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/zeroed.md b/noir/docs/versioned_docs/version-v../noir/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/zeroed.md rename to noir/docs/versioned_docs/version-v../noir/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/_category_.json b/noir/docs/versioned_docs/version-v../noir/syntax/_category_.json new file mode 100644 index 00000000000..666b691ae91 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Syntax", + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/04_assert.md b/noir/docs/versioned_docs/version-v../noir/syntax/assert.md similarity index 61% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/04_assert.md rename to noir/docs/versioned_docs/version-v../noir/syntax/assert.md index a25a946123d..c5f9aff139c 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/04_assert.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/assert.md @@ -5,13 +5,12 @@ description: comparison expression that follows to be true, and what happens if the expression is false at runtime. keywords: [Noir programming language, assert statement, predicate expression, comparison expression] +sidebar_position: 4 --- Noir includes a special `assert` function which will explicitly constrain the predicate/comparison expression that follows to be true. If this expression is false at runtime, the program will fail to -be proven. - -### Example +be proven. Example: ```rust fn main(x : Field, y : Field) { @@ -19,16 +18,10 @@ fn main(x : Field, y : Field) { } ``` -The above snippet compiles because `==` is a predicate operation. Conversely, the following will not -compile: +You can optionally provide a message to be logged when the assertion fails: ```rust -// INCORRECT - -fn main(x : Field, y : Field) { - assert(x + y); -} +assert(x == y, "x and y are not equal"); ``` -> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should -> equate to `x + y == 0` or if it should check the truthiness of the result. +> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/08_comments.md b/noir/docs/versioned_docs/version-v../noir/syntax/comments.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.9.0/language_concepts/08_comments.md rename to noir/docs/versioned_docs/version-v../noir/syntax/comments.md index 3bb4d2f25a4..f76ab49094b 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/08_comments.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/comments.md @@ -5,6 +5,7 @@ description: ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments are supported in Noir. keywords: [Noir programming language, comments, single-line comments, multi-line comments] +sidebar_position: 9 --- A comment is a line in your codebase which the compiler ignores, however it can be read by diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/02_control_flow.md b/noir/docs/versioned_docs/version-v../noir/syntax/control_flow.md similarity index 93% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/02_control_flow.md rename to noir/docs/versioned_docs/version-v../noir/syntax/control_flow.md index 691c514d9a8..4ce65236db3 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/02_control_flow.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/control_flow.md @@ -4,6 +4,7 @@ description: Learn how to use loops and if expressions in the Noir programming language. Discover the syntax and examples for for loops and if-else statements. keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] +sidebar_position: 2 --- ## Loops @@ -19,6 +20,8 @@ for i in 0..10 { }; ``` +The index for loops is of type `u64`. + ## If Expressions Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_bus.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_bus.md new file mode 100644 index 00000000000..6c7e9b60891 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_bus.md @@ -0,0 +1,21 @@ +--- +title: Data Bus +sidebar_position: 12 +--- +**Disclaimer** this feature is experimental, do not use it! + +The data bus is an optimization that the backend can use to make recursion more efficient. +In order to use it, you must define some inputs of the program entry points (usually the `main()` +function) with the `call_data` modifier, and the return values with the `return_data` modifier. +These modifiers are incompatible with `pub` and `mut` modifiers. + +## Example + +```rust +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + let a = z[x]; + a+y +} +``` + +As a result, both call_data and return_data will be treated as private inputs and encapsulated into a read-only array each, for the backend to process. diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/_category_.json b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/array_methods.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/arrays.md similarity index 59% rename from noir/docs/versioned_docs/version-v0.7.1/standard_library/array_methods.md rename to noir/docs/versioned_docs/version-v../noir/syntax/data_types/arrays.md index 8d8a9531243..075d39dadd4 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/array_methods.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/arrays.md @@ -1,16 +1,86 @@ --- -title: Array Methods +title: Arrays description: - Learn about the commonly used methods available for arrays in Noir, including len, sort, fold, - reduce, all, and any. -keywords: [rust, array, methods, len, sort, fold, reduce, all, any] + Dive into the Array data type in Noir. Grasp its methods, practical examples, and best practices for efficiently using Arrays in your Noir code. +keywords: + [ + noir, + array type, + methods, + examples, + indexing, + ] +sidebar_position: 4 --- -# Array +An array is one way of grouping together values into one compound type. Array types can be inferred +or explicitly specified via the syntax `[; ]`: -For convenience, the STD provides some ready-to-use, common methods for arrays[^migrationnote]: +```rust +fn main(x : Field, y : Field) { + let my_arr = [x, y]; + let your_arr: [Field; 2] = [x, y]; +} +``` + +Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. + +Array elements can be accessed using indexing: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group +a `Field` value and a `u8` value together for example. + +You can write mutable arrays, like: + +```rust +fn main() { + let mut arr = [1, 2, 3, 4, 5]; + assert(arr[0] == 1); + + arr[0] = 42; + assert(arr[0] == 42); +} +``` + +You can instantiate a new array of a fixed size with the same value repeated for each element. The following example instantiates an array of length 32 where each element is of type Field and has the value 0. + +```rust +let array: [Field; 32] = [0; 32]; +``` + +Like in Rust, arrays in Noir are a fixed size. However, if you wish to convert an array to a [slice](./slices), you can just call `as_slice` on your array: + +```rust +let array: [Field; 32] = [0; 32]; +let sl = array.as_slice() +``` -## len +You can define multidimensional arrays: + +```rust +let array : [[Field; 2]; 2]; +let element = array[0][0]; +``` + +## Types + +You can create arrays of primitive types or structs. There is not yet support for nested arrays +(arrays of arrays) or arrays of structs that contain arrays. + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for arrays: + +### len Returns the length of an array @@ -27,7 +97,7 @@ fn main() { } ``` -## sort +### sort Returns a new sorted array. The original array remains untouched. Notice that this function will only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting @@ -48,7 +118,7 @@ fn main() { } ``` -## sort_via +### sort_via Sorts the array with a custom comparison function @@ -69,7 +139,7 @@ fn main() { } ``` -## map +### map Applies a function to each element of the array, returning a new array containing the mapped elements. @@ -84,7 +154,7 @@ let a = [1, 2, 3]; let b = a.map(|a| a * 2); // b is now [2, 4, 6] ``` -## fold +### fold Applies a function to each element of the array, returning the final accumulated value. The first parameter is the initial value. @@ -119,7 +189,7 @@ fn main() { ``` -## reduce +### reduce Same as fold, but uses the first element as starting element. @@ -137,7 +207,7 @@ fn main() { } ``` -## all +### all Returns true if all the elements satisfy the given predicate @@ -155,7 +225,7 @@ fn main() { } ``` -## any +### any Returns true if any of the elements satisfy the given predicate @@ -173,8 +243,3 @@ fn main() { } ``` - -[^migrationnote]: - Migration Note: These methods were previously free functions, called via `std::array::len()`. - For the sake of ease of use and readability, these functions are now methods and the old syntax - for them is now deprecated. diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/booleans.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/booleans.md new file mode 100644 index 00000000000..69826fcd724 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/booleans.md @@ -0,0 +1,31 @@ +--- +title: Booleans +description: + Delve into the Boolean data type in Noir. Understand its methods, practical examples, and best practices for using Booleans in your Noir programs. +keywords: + [ + noir, + boolean type, + methods, + examples, + logical operations, + ] +sidebar_position: 2 +--- + + +The `bool` type in Noir has two possible values: `true` and `false`: + +```rust +fn main() { + let t = true; + let f: bool = false; +} +``` + +> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for +> `false` in _Verifier.toml_. + +The boolean type is most commonly used in conditionals like `if` expressions and `assert` +statements. More about conditionals is covered in the [Control Flow](../control_flow) and +[Assert Function](../assert) sections. diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/field_methods.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/fields.md similarity index 55% rename from noir/docs/versioned_docs/version-v0.7.1/standard_library/field_methods.md rename to noir/docs/versioned_docs/version-v../noir/syntax/data_types/fields.md index 4d1cdc953e9..a1c67945d66 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/field_methods.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/fields.md @@ -1,26 +1,43 @@ --- -title: Field Methods +title: Fields description: - Learn about common methods on Noir Field, including to_le_bits, to_le_bytes, to_le_radix, - to_be_radix, pow_32, etc, and see code examples. + Dive deep into the Field data type in Noir. Understand its methods, practical examples, and best practices to effectively use Fields in your Noir programs. keywords: [ - Noir Field, - to_le_bits, - to_le_bytes, - to_le_radix, - to_be_radix, - pow_32, - Little Endian, - Big Endian, - Vector, - Exponent, + noir, + field type, + methods, + examples, + best practices, ] +sidebar_position: 0 --- +The field type corresponds to the native field type of the proving backend. + +The size of a Noir field depends on the elliptic curve's finite field for the proving backend +adopted. For example, a field would be a 254-bit integer when paired with the default backend that +spans the Grumpkin curve. + +Fields support integer arithmetic and are often used as the default numeric type in Noir: + +```rust +fn main(x : Field, y : Field) { + let z = x + y; +} +``` + +`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new +private value `z` constrained to be equal to `x + y`. + +If proving efficiency is of priority, fields should be used as a default for solving problems. +Smaller integer types (e.g. `u64`) incur extra range constraints. + +## Methods + After declaring a Field, you can use these common methods on it: -## to_le_bits +### to_le_bits Transforms the field into an array of bits, Little Endian. @@ -32,12 +49,12 @@ example: ```rust fn main() { - let field = 2 + let field = 2; let bits = field.to_le_bits(32); } ``` -## to_be_bits +### to_be_bits Transforms the field into an array of bits, Big Endian. @@ -49,12 +66,12 @@ example: ```rust fn main() { - let field = 2 + let field = 2; let bits = field.to_be_bits(32); } ``` -## to_le_bytes +### to_le_bytes Transforms into an array of bytes, Little Endian @@ -66,12 +83,12 @@ example: ```rust fn main() { - let field = 2 + let field = 2; let bytes = field.to_le_bytes(4); } ``` -## to_be_bytes +### to_be_bytes Transforms into an array of bytes, Big Endian @@ -83,12 +100,12 @@ example: ```rust fn main() { - let field = 2 + let field = 2; let bytes = field.to_be_bytes(4); } ``` -## to_le_radix +### to_le_radix Decomposes into a vector over the specified base, Little Endian @@ -100,12 +117,12 @@ example: ```rust fn main() { - let field = 2 + let field = 2; let radix = field.to_le_radix(256, 4); } ``` -## to_be_radix +### to_be_radix Decomposes into a vector over the specified base, Big Endian @@ -117,12 +134,12 @@ example: ```rust fn main() { - let field = 2 + let field = 2; let radix = field.to_be_radix(256, 4); } ``` -## pow_32 +### pow_32 Returns the value to the power of the specified exponent @@ -140,9 +157,9 @@ fn main() { } ``` -## sgn0 +### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/function_types.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/function_types.md new file mode 100644 index 00000000000..61e4076adaf --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/function_types.md @@ -0,0 +1,26 @@ +--- +title: Function types +sidebar_position: 10 +--- + +Noir supports higher-order functions. The syntax for a function type is as follows: + +```rust +fn(arg1_type, arg2_type, ...) -> return_type +``` + +Example: + +```rust +fn assert_returns_100(f: fn() -> Field) { // f takes no args and returns a Field + assert(f() == 100); +} + +fn main() { + assert_returns_100(|| 100); // ok + assert_returns_100(|| 150); // fails +} +``` + +A function type also has an optional capture environment - this is necessary to support closures. +See [Lambdas](@site/docs/noir/syntax/lambdas.md) for more details. diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/index.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/index.md new file mode 100644 index 00000000000..52e568e9b7e --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/index.md @@ -0,0 +1,96 @@ +--- +title: Data Types +description: + Get a clear understanding of the two categories of Noir data types - primitive types and compound + types. Learn about their characteristics, differences, and how to use them in your Noir + programming. +keywords: + [ + noir, + data types, + primitive types, + compound types, + private types, + public types, + ] +--- + +Every value in Noir has a type, which determines which operations are valid for it. + +All values in Noir are fundamentally composed of `Field` elements. For a more approachable +developing experience, abstractions are added on top to introduce different data types in Noir. + +Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound +types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or +public. + +## Private & Public Types + +A **private value** is known only to the Prover, while a **public value** is known by both the +Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All +primitive types (including individual fields of compound types) in Noir are private by default, and +can be marked public when certain values are intended to be revealed to the Verifier. + +> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once +> the proofs are verified on-chain the values can be considered known to everyone that has access to +> that blockchain. + +Public data types are treated no differently to private types apart from the fact that their values +will be revealed in proofs generated. Simply changing the value of a public type will not change the +circuit (where the same goes for changing values of private types as well). + +_Private values_ are also referred to as _witnesses_ sometimes. + +> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different +> meaning than when applied to a function (e.g. `pub fn foo() {}`). +> +> The former is a visibility modifier for the Prover to interpret if a value should be made known to +> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a +> function should be made accessible to external Noir programs like in other languages. + +### pub Modifier + +All data types in Noir are private by default. Types are explicitly declared as public using the +`pub` modifier: + +```rust +fn main(x : Field, y : pub Field) -> pub Field { + x + y +} +``` + +In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note +that visibility is handled **per variable**, so it is perfectly valid to have one input that is +private and another that is public. + +> **Note:** Public types can only be declared through parameters on `main`. + +## Type Aliases + +A type alias is a new name for an existing type. Type aliases are declared with the keyword `type`: + +```rust +type Id = u8; + +fn main() { + let id: Id = 1; + let zero: u8 = 0; + assert(zero + 1 == id); +} +``` + +Type aliases can also be used with [generics](@site/docs/noir/syntax/generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +### BigInt + +You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/integers.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/integers.md new file mode 100644 index 00000000000..7d1e83cf4e9 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/integers.md @@ -0,0 +1,113 @@ +--- +title: Integers +description: Explore the Integer data type in Noir. Learn about its methods, see real-world examples, and grasp how to efficiently use Integers in your Noir code. +keywords: [noir, integer types, methods, examples, arithmetic] +sidebar_position: 1 +--- + +An integer type is a range constrained field type. The Noir frontend supports arbitrarily-sized, both unsigned and signed integer types. + +:::info + +When an integer is defined in Noir without a specific type, it will default to `Field`. + +The one exception is for loop indices which default to `u64` since comparisons on `Field`s are not possible. + +::: + +## Unsigned Integers + +An unsigned integer type is specified first with the letter `u` (indicating its unsigned nature) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: u8 = 1; + let y: u8 = 1; + let z = x + y; + assert (z == 2); +} +``` + +The bit size determines the maximum value the integer type can store. For example, a `u8` variable can store a value in the range of 0 to 255 (i.e. $\\2^{8}-1\\$). + +## Signed Integers + +A signed integer type is specified first with the letter `i` (which stands for integer) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: i8 = -1; + let y: i8 = -1; + let z = x + y; + assert (z == -2); +} +``` + +The bit size determines the maximum and minimum range of value the integer type can store. For example, an `i8` variable can store a value in the range of -128 to 127 (i.e. $\\-2^{7}\\$ to $\\2^{7}-1\\$). + +:::tip + +If you are using the default proving backend with Noir, both even (e.g. _u2_, _i2_) and odd (e.g. _u3_, _i3_) arbitrarily-sized integer types up to 127 bits (i.e. _u127_ and _i127_) are supported. + +::: + +## Overflows + +Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: + +```rust +fn main(x: u8, y: u8) { + let z = x + y; +} +``` + +With: + +```toml +x = "255" +y = "1" +``` + +Would result in: + +``` +$ nargo prove +error: Assertion failed: 'attempt to add with overflow' +┌─ ~/src/main.nr:9:13 +│ +│ let z = x + y; +│ ----- +│ += Call stack: + ... +``` + +A similar error would happen with signed integers: + +```rust +fn main() { + let x: i8 = -118; + let y: i8 = -11; + let z = x + y; +} +``` + +### Wrapping methods + +Although integer overflow is expected to error, some use-cases rely on wrapping. For these use-cases, the standard library provides `wrapping` variants of certain common operations: + +```rust +fn wrapping_add(x: T, y: T) -> T; +fn wrapping_sub(x: T, y: T) -> T; +fn wrapping_mul(x: T, y: T) -> T; +``` + +Example of how it is used: + +```rust +use dep::std; + +fn main(x: u8, y: u8) -> pub u8 { + std::wrapping_add(x + y) +} +``` diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/references.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/references.md new file mode 100644 index 00000000000..a5293d11cfb --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/references.md @@ -0,0 +1,23 @@ +--- +title: References +sidebar_position: 9 +--- + +Noir supports first-class references. References are a bit like pointers: they point to a specific address that can be followed to access the data stored at that address. You can use Rust-like syntax to use pointers in Noir: the `&` operator references the variable, the `*` operator dereferences it. + +Example: + +```rust +fn main() { + let mut x = 2; + + // you can reference x as &mut and pass it to multiplyBy2 + multiplyBy2(&mut x); +} + +// you can access &mut here +fn multiplyBy2(x: &mut Field) { + // and dereference it with * + *x = *x * 2; +} +``` diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/slices.mdx b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/slices.mdx new file mode 100644 index 00000000000..4a6ee816aa2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/slices.mdx @@ -0,0 +1,147 @@ +--- +title: Slices +description: Explore the Slice data type in Noir. Understand its methods, see real-world examples, and learn how to effectively use Slices in your Noir programs. +keywords: [noir, slice type, methods, examples, subarrays] +sidebar_position: 5 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size. + +```rust +use dep::std::slice; + +fn main() -> pub Field { + let mut slice: [Field] = [0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +View the corresponding test file [here][test-file]. + +[test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for slices: + +### push_back + +Pushes a new element to the end of the slice, returning a new slice with a length one greater than the original unmodified slice. + +```rust +fn push_back(_self: [T], _elem: T) -> [T] +``` + +example: + +```rust +fn main() -> pub Field { + let mut slice: [Field] = [0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +View the corresponding test file [here][test-file]. + +### push_front + +Returns a new array with the specified element inserted at index 0. The existing elements indexes are incremented by 1. + +```rust +fn push_front(_self: Self, _elem: T) -> Self +``` + +Example: + +```rust +let mut new_slice: [Field] = []; +new_slice = new_slice.push_front(20); +assert(new_slice[0] == 20); // returns true +``` + +View the corresponding test file [here][test-file]. + +### pop_front + +Returns a tuple of two items, the first element of the array and the rest of the array. + +```rust +fn pop_front(_self: Self) -> (T, Self) +``` + +Example: + +```rust +let (first_elem, rest_of_slice) = slice.pop_front(); +``` + +View the corresponding test file [here][test-file]. + +### pop_back + +Returns a tuple of two items, the beginning of the array with the last element omitted and the last element. + +```rust +fn pop_back(_self: Self) -> (Self, T) +``` + +Example: + +```rust +let (popped_slice, last_elem) = slice.pop_back(); +``` + +View the corresponding test file [here][test-file]. + +### append + +Loops over a slice and adds it to the end of another. + +```rust +fn append(mut self, other: Self) -> Self +``` + +Example: + +```rust +let append = [1, 2].append([3, 4, 5]); +``` + +### insert + +Inserts an element at a specified index and shifts all following elements by 1. + +```rust +fn insert(_self: Self, _index: Field, _elem: T) -> Self +``` + +Example: + +```rust +new_slice = rest_of_slice.insert(2, 100); +assert(new_slice[2] == 100); +``` + +View the corresponding test file [here][test-file]. + +### remove + +Remove an element at a specified index, shifting all elements after it to the left, returning the altered slice and the removed element. + +```rust +fn remove(_self: Self, _index: Field) -> (Self, T) +``` + +Example: + +```rust +let (remove_slice, removed_elem) = slice.remove(3); +``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/03_strings.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/strings.md similarity index 51% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/03_strings.md rename to noir/docs/versioned_docs/version-v../noir/syntax/data_types/strings.md index ee69853bfba..8d76d4ca654 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/03_strings.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/strings.md @@ -10,6 +10,7 @@ keywords: examples, concatenation, ] +sidebar_position: 3 --- @@ -41,3 +42,39 @@ fn main() { assert(message_bytes[0] == message_vec.get(0)); } ``` + +## Escape characters + +You can use escape characters for your strings: + +| Escape Sequence | Description | +|-----------------|-----------------| +| `\r` | Carriage Return | +| `\n` | Newline | +| `\t` | Tab | +| `\0` | Null Character | +| `\"` | Double Quote | +| `\\` | Backslash | + +Example: + +```rust +let s = "Hello \"world" // prints "Hello "world" +let s = "hey \tyou"; // prints "hey you" +``` + +## Raw strings + +A raw string begins with the letter `r` and is optionally delimited by a number of hashes `#`. + +Escape characters are *not* processed within raw strings. All contents are interpreted literally. + +Example: + +```rust +let s = r"Hello world"; +let s = r#"Simon says "hello world""#; + +// Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes +let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; +``` diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/structs.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/structs.md new file mode 100644 index 00000000000..dbf68c99813 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/structs.md @@ -0,0 +1,70 @@ +--- +title: Structs +description: + Explore the Struct data type in Noir. Learn about its methods, see real-world examples, and grasp how to effectively define and use Structs in your Noir programs. +keywords: + [ + noir, + struct type, + methods, + examples, + data structures, + ] +sidebar_position: 8 +--- + +A struct also allows for grouping multiple values of different types. Unlike tuples, we can also +name each field. + +> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the +> field type of Noir. + +Defining a struct requires giving it a name and listing each field within as `: ` pairs: + +```rust +struct Animal { + hands: Field, + legs: Field, + eyes: u8, +} +``` + +An instance of a struct can then be created with actual values in `: ` pairs in any +order. Struct fields are accessible using their given names: + +```rust +fn main() { + let legs = 4; + + let dog = Animal { + eyes: 2, + hands: 0, + legs, + }; + + let zero = dog.hands; +} +``` + +Structs can also be destructured in a pattern, binding each field to a new variable: + +```rust +fn main() { + let Animal { hands, legs: feet, eyes } = get_octopus(); + + let ten = hands + feet + eyes as u8; +} + +fn get_octopus() -> Animal { + let octopus = Animal { + hands: 0, + legs: 8, + eyes: 2, + }; + + octopus +} +``` + +The new variables can be bound with names different from the original struct field names, as +showcased in the `legs --> feet` binding in the example above. diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/tuples.md b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/tuples.md new file mode 100644 index 00000000000..2ec5c9c4113 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/tuples.md @@ -0,0 +1,48 @@ +--- +title: Tuples +description: + Dive into the Tuple data type in Noir. Understand its methods, practical examples, and best practices for efficiently using Tuples in your Noir code. +keywords: + [ + noir, + tuple type, + methods, + examples, + multi-value containers, + ] +sidebar_position: 7 +--- + +A tuple collects multiple values like an array, but with the added ability to collect values of +different types: + +```rust +fn main() { + let tup: (u8, u64, Field) = (255, 500, 1000); +} +``` + +One way to access tuple elements is via destructuring using pattern matching: + +```rust +fn main() { + let tup = (1, 2); + + let (one, two) = tup; + + let three = one + two; +} +``` + +Another way to access tuple elements is via direct member access, using a period (`.`) followed by +the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to +the second and so on: + +```rust +fn main() { + let tup = (5, 6, 7, 8); + + let five = tup.0; + let eight = tup.3; +} +``` diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/data_types/vectors.mdx b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/vectors.mdx new file mode 100644 index 00000000000..10e35711b74 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/data_types/vectors.mdx @@ -0,0 +1,173 @@ +--- +title: Vectors +description: Delve into the Vector data type in Noir. Learn about its methods, practical examples, and best practices for using Vectors in your Noir code. +keywords: [noir, vector type, methods, examples, dynamic arrays] +sidebar_position: 6 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. + +Example: + +```rust +use dep::std::collections::vec::Vec; + +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` + +## Methods + +### new + +Creates a new, empty vector. + +```rust +pub fn new() -> Self { + Self { slice: [] } +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### from_slice + +Creates a vector containing each element from a given slice. Mutations to the resulting vector will not affect the original slice. + +```rust +pub fn from_slice(slice: [T]) -> Self { + Self { slice } +} +``` + +Example: + +```rust +let arr: [Field] = [1, 2, 3]; +let vector_from_slice = Vec::from_slice(arr); +assert(vector_from_slice.len() == 3); +``` + +### get + +Retrieves an element from the vector at a given index. Panics if the index points beyond the vector's end. + +```rust +pub fn get(self, index: Field) -> T { + self.slice[index] +} +``` + +Example: + +```rust +let vector: Vec = Vec::from_slice([10, 20, 30]); +assert(vector.get(1) == 20); +``` + +### push + +Adds a new element to the vector's end, returning a new vector with a length one greater than the original unmodified vector. + +```rust +pub fn push(&mut self, elem: T) { + self.slice = self.slice.push_back(elem); +} +``` + +Example: + +```rust +let mut vector: Vec = Vec::new(); +vector.push(10); +assert(vector.len() == 1); +``` + +### pop + +Removes an element from the vector's end, returning a new vector with a length one less than the original vector, along with the removed element. Panics if the vector's length is zero. + +```rust +pub fn pop(&mut self) -> T { + let (popped_slice, last_elem) = self.slice.pop_back(); + self.slice = popped_slice; + last_elem +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 20]); +let popped_elem = vector.pop(); +assert(popped_elem == 20); +assert(vector.len() == 1); +``` + +### insert + +Inserts an element at a specified index, shifting subsequent elements to the right. + +```rust +pub fn insert(&mut self, index: Field, elem: T) { + self.slice = self.slice.insert(index, elem); +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 30]); +vector.insert(1, 20); +assert(vector.get(1) == 20); +``` + +### remove + +Removes an element at a specified index, shifting subsequent elements to the left, and returns the removed element. + +```rust +pub fn remove(&mut self, index: Field) -> T { + let (new_slice, elem) = self.slice.remove(index); + self.slice = new_slice; + elem +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 20, 30]); +let removed_elem = vector.remove(1); +assert(removed_elem == 20); +assert(vector.len() == 2); +``` + +### len + +Returns the number of elements in the vector. + +```rust +pub fn len(self) -> Field { + self.slice.len() +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/10_distinct.md b/noir/docs/versioned_docs/version-v../noir/syntax/distinct.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/10_distinct.md rename to noir/docs/versioned_docs/version-v../noir/syntax/distinct.md index e7ff7f5017a..b59e0296b23 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/10_distinct.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/distinct.md @@ -1,5 +1,6 @@ --- title: Distinct Witnesses +sidebar_position: 10 --- The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/functions.md b/noir/docs/versioned_docs/version-v../noir/syntax/functions.md new file mode 100644 index 00000000000..48aba9cd058 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/functions.md @@ -0,0 +1,226 @@ +--- +title: Functions +description: + Learn how to declare functions and methods in Noir, a programming language with Rust semantics. + This guide covers parameter declaration, return types, call expressions, and more. +keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] +sidebar_position: 1 +--- + +Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. + +To declare a function the `fn` keyword is used. + +```rust +fn foo() {} +``` + +By default, functions are visible only within the package they are defined. To make them visible outside of that package (for example, as part of a [library](../modules_packages_crates/crates_and_packages.md#libraries)), you should mark them as `pub`: + +```rust +pub fn foo() {} +``` + +You can also restrict the visibility of the function to only the crate it was defined in, by specifying `pub(crate)`: + +```rust +pub(crate) fn foo() {} //foo can only be called within its crate +``` + +All parameters in a function must have a type and all types are known at compile time. The parameter +is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. + +```rust +fn foo(x : Field, y : Field){} +``` + +The return type of a function can be stated by using the `->` arrow notation. The function below +states that the foo function must return a `Field`. If the function returns no value, then the arrow +is omitted. + +```rust +fn foo(x : Field, y : Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## Main function + +If you're writing a binary, the `main` function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time: + +```rust +fn main(x : Field) // this is fine: passing a Field +fn main(x : [Field; 2]) // this is also fine: passing a Field with known size at compile-time +fn main(x : (Field, bool)) // 👌: passing a (Field, bool) tuple means size 2 +fn main(x : str<5>) // this is fine, as long as you pass a string of size 5 + +fn main(x : Vec) // can't compile, has variable size +fn main(x : [Field]) // can't compile, has variable size +fn main(....// i think you got it by now +``` + +Keep in mind [tests](../../getting_started/tooling/testing.md) don't differentiate between `main` and any other function. The following snippet passes tests, but won't compile or prove: + +```rust +fn main(x : [Field]) { + assert(x[0] == 1); +} + +#[test] +fn test_one() { + main([1, 2]); +} +``` + +```bash +$ nargo test +[testing] Running 1 test functions +[testing] Testing test_one... ok +[testing] All tests passed + +$ nargo check +The application panicked (crashed). +Message: Cannot have variable sized arrays as a parameter to main +``` + +## Call Expressions + +Calling a function in Noir is executed by using the function name and passing in the necessary +arguments. + +Below we show how to call the `foo` function from the `main` function using a call expression: + +```rust +fn main(x : Field, y : Field) { + let z = foo(x); +} + +fn foo(x : Field) -> Field { + x + x +} +``` + +## Methods + +You can define methods in Noir on any struct type in scope. + +```rust +struct MyStruct { + foo: Field, + bar: Field, +} + +impl MyStruct { + fn new(foo: Field) -> MyStruct { + MyStruct { + foo, + bar: 2, + } + } + + fn sum(self) -> Field { + self.foo + self.bar + } +} + +fn main() { + let s = MyStruct::new(40); + assert(s.sum() == 42); +} +``` + +Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as +follows: + +```rust +assert(MyStruct::sum(s) == 42); +``` + +It is also possible to specialize which method is chosen depending on the [generic](./generics.md) type that is used. In this example, the `foo` function returns different values depending on its type: + +```rust +struct Foo {} + +impl Foo { + fn foo(self) -> Field { 1 } +} + +impl Foo { + fn foo(self) -> Field { 2 } +} + +fn main() { + let f1: Foo = Foo{}; + let f2: Foo = Foo{}; + assert(f1.foo() + f2.foo() == 3); +} +``` + +Also note that impls with the same method name defined in them cannot overlap. For example, if we already have `foo` defined for `Foo` and `Foo` like we do above, we cannot also define `foo` in an `impl Foo` since it would be ambiguous which version of `foo` to choose. + +```rust +// Including this impl in the same project as the above snippet would +// cause an overlapping impls error +impl Foo { + fn foo(self) -> Field { 3 } +} +``` + +## Lambdas + +Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +See [Lambdas](./lambdas.md) for more details. + +## Attributes + +Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. + +Supported attributes include: + +- **builtin**: the function is implemented by the compiler, for efficiency purposes. +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` +- **field**: Used to enable conditional compilation of code depending on the field size. See below for more details +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./unconstrained.md) and [NoirJS](../../reference/NoirJS/noir_js/index.md) for more details. +- **test**: mark the function as unit tests. See [Tests](../../getting_started/tooling/testing.md) for more details + +### Field Attribute + +The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. +The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. +As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. + +Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + +```rust +#[field(bn254)] +fn foo() -> u32 { + 1 +} + +#[field(23)] +fn foo() -> u32 { + 2 +} + +// This commented code would not compile as foo would be defined twice because it is the same field as bn254 +// #[field(21888242871839275222246405745257275088548364400416034343698204186575808495617)] +// fn foo() -> u32 { +// 2 +// } + +#[field(bls12_381)] +fn foo() -> u32 { + 3 +} +``` + +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v../noir/syntax/generics.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.7.1/language_concepts/06_generics.md rename to noir/docs/versioned_docs/version-v../noir/syntax/generics.md index 66f2e85e16b..443ca2b45a5 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/06_generics.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/generics.md @@ -1,12 +1,10 @@ --- title: Generics -description: - Learn how to use Generics in Noir +description: Learn how to use Generics in Noir keywords: [Noir, Rust, generics, functions, structs] +sidebar_position: 6 --- -# Generics - Generics allow you to use the same functions with multiple different concrete data types. You can read more about the concept of generics in the Rust documentation [here](https://doc.rust-lang.org/book/ch10-01-syntax.html). @@ -28,7 +26,7 @@ struct will be of a certain generic type. In this case `value` is of type `T`. ```rust struct RepeatedValue { value: T, - count: comptime Field, + count: Field, } impl RepeatedValue { diff --git a/noir/docs/versioned_docs/version-v../noir/syntax/lambdas.md b/noir/docs/versioned_docs/version-v../noir/syntax/lambdas.md new file mode 100644 index 00000000000..e0a267adfda --- /dev/null +++ b/noir/docs/versioned_docs/version-v../noir/syntax/lambdas.md @@ -0,0 +1,81 @@ +--- +title: Lambdas +description: Learn how to use anonymous functions in Noir programming language. +keywords: [Noir programming language, lambda, closure, function, anonymous function] +sidebar_position: 8 +--- + +## Introduction + +Lambdas are anonymous functions. The syntax is `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +A block can be used as the body of a lambda, allowing you to declare local variables inside it: + +```rust +let cool = || { + let x = 100; + let y = 100; + x + y +} + +assert(cool() == 200); +``` + +## Closures + +Inside the body of a lambda, you can use variables defined in the enclosing function. Such lambdas are called **closures**. In this example `x` is defined inside `main` and is accessed from within the lambda: + +```rust +fn main() { + let x = 100; + let closure = || x + 150; + assert(closure() == 250); +} +``` + +## Passing closures to higher-order functions + +It may catch you by surprise that the following code fails to compile: + +```rust +fn foo(f: fn () -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // error :( +} +``` + +The reason is that the closure's capture environment affects its type - we have a closure that captures two Fields and `foo` +expects a regular function as an argument - those are incompatible. +:::note + +Variables contained within the `||` are the closure's parameters, and the expression that follows it is the closure's body. The capture environment is comprised of any variables used in the closure's body that are not parameters. + +E.g. in |x| x + y, y would be a captured variable, but x would not be, since it is a parameter of the closure. + +::: +The syntax for the type of a closure is `fn[env](args) -> ret_type`, where `env` is the capture environment of the closure - +in this example that's `(Field, Field)`. + +The best solution in our case is to make `foo` generic over the environment type of its parameter, so that it can be called +with closures with any environment, as well as with regular functions: + +```rust +fn foo(f: fn[Env]() -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // compiles fine + assert(foo(|| 60) == 60); // compiles fine +} +``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v../noir/syntax/mutability.md similarity index 56% rename from noir/docs/versioned_docs/version-v0.6.0/language_concepts/07_mutability.md rename to noir/docs/versioned_docs/version-v../noir/syntax/mutability.md index c8ccb4f8b9f..58e9c1cecfb 100644 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/mutability.md @@ -4,10 +4,9 @@ description: Learn about mutable variables, constants, and globals in Noir programming language. Discover how to declare, modify, and use them in your programs. keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +sidebar_position: 7 --- -# Mutability - Variables in noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned to via an assignment expression. @@ -31,7 +30,7 @@ c = 13; // OK d = 14; // OK // etc. -let MyStruct { x: mut y } = MyStruct { x: a } +let MyStruct { x: mut y } = MyStruct { x: a }; // y is now in scope ``` @@ -39,7 +38,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 @@ -50,53 +49,29 @@ fn helper(mut x: i32) { } ``` -## Comptime values - -Comptime value are values that are known at compile-time. This is different to a witness -which changes per proof. If a comptime value that is being used in your program is changed, then your -circuit will also change. - -Below we show how to declare a comptime value: +## Comptime Values -```rust -fn main() { - let a: comptime Field = 5; +:::warning - // `comptime Field` can also be inferred: - let a = 5; -} -``` +The 'comptime' keyword was removed in version 0.10. The comptime keyword and syntax are currently still kept and parsed for backwards compatibility, but are now deprecated and will issue a warning when used. `comptime` has been removed because it is no longer needed for accessing arrays. -Note that variables declared as mutable may not be comptime: - -```rust -fn main() { - // error: Cannot mark a comptime type as mutable - let mut a: comptime Field = 5; - - // a inferred as a private Field here - let mut a = 5; -} -``` +::: ## Globals -Noir also supports global variables. However, they must be compile-time variables. If `comptime` is -not explicitly written in the type annotation the compiler will implicitly specify the declaration -as compile-time. They can then be used like any other compile-time variable inside functions. The -global type can also be inferred by the compiler entirely. Globals can also be used to specify array +Noir also supports global variables. However, they must be known at compile-time. The global type can also be inferred by the compiler entirely. Globals can also be used to specify array annotations for function parameters and can be imported from submodules. ```rust -global N: Field = 5; // Same as `global N: comptime Field = 5` +global N: Field = 5; // Same as `global N: Field = 5` fn main(x : Field, y : [Field; N]) { let res = x * N; - constrain res == y[0]; + assert(res == y[0]); let res2 = x * mysubmodule::N; - constrain res != res2; + assert(res != res2); } mod mysubmodule { @@ -104,7 +79,7 @@ mod mysubmodule { global N: Field = 10; - fn my_helper() -> comptime Field { + fn my_helper() -> Field { let x = N; x } diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v../noir/syntax/ops.md similarity index 90% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/03_ops.md rename to noir/docs/versioned_docs/version-v../noir/syntax/ops.md index da02b126059..977c8ba1203 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/ops.md @@ -14,6 +14,7 @@ keywords: short-circuiting, backend, ] +sidebar_position: 3 --- # Operations @@ -29,11 +30,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/11_shadowing.md b/noir/docs/versioned_docs/version-v../noir/syntax/shadowing.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/11_shadowing.md rename to noir/docs/versioned_docs/version-v../noir/syntax/shadowing.md index efd743e764f..b5a6b6b38b9 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/11_shadowing.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/shadowing.md @@ -1,5 +1,6 @@ --- title: Shadowing +sidebar_position: 11 --- Noir allows for inheriting variables' values and re-declaring them with the same name similar to Rust, known as shadowing. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/05_unconstrained.md b/noir/docs/versioned_docs/version-v../noir/syntax/unconstrained.md similarity index 97% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/05_unconstrained.md rename to noir/docs/versioned_docs/version-v../noir/syntax/unconstrained.md index 6b621eda3eb..7a61d3953ef 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/05_unconstrained.md +++ b/noir/docs/versioned_docs/version-v../noir/syntax/unconstrained.md @@ -3,10 +3,9 @@ title: Unconstrained Functions description: "Learn about what unconstrained functions in Noir are, how to use them and when you'd want to." keywords: [Noir programming language, unconstrained, open] +sidebar_position: 5 --- - - Unconstrained functions are functions which do not constrain any of the included computation and allow for non-determinisitic computation. ## Why? diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/.nojekyll b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..5cbe9421b92 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,185 @@ +# BarretenbergBackend + +## Implements + +- [`Backend`](../interfaces/Backend.md) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`destroy`](../interfaces/Backend.md#destroy) + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateFinalProof`](../interfaces/Backend.md#generatefinalproof) + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(witness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `witness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProof`](../interfaces/Backend.md#generateintermediateproof) + +#### Example + +```typescript +const intermediateProof = await backend.generateIntermediateProof(witness); +``` + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProofArtifacts`](../interfaces/Backend.md#generateintermediateproofartifacts) + +#### Example + +```typescript +const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyFinalProof`](../interfaces/Backend.md#verifyfinalproof) + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyIntermediateProof`](../interfaces/Backend.md#verifyintermediateproof) + +#### Example + +```typescript +const isValidIntermediate = await backend.verifyIntermediateProof(proof); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/index.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/index.md new file mode 100644 index 00000000000..bfbecb52864 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/index.md @@ -0,0 +1,45 @@ +# backend_barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | + +### Interfaces + +| Interface | Description | +| :------ | :------ | +| [Backend](interfaces/Backend.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | + +## Functions + +### flattenPublicInputs() + +```ts +flattenPublicInputs(publicInputs): string[] +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `WitnessMap` | + +#### Returns + +`string`[] + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/interfaces/Backend.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/interfaces/Backend.md new file mode 100644 index 00000000000..3eb9645c8d2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/interfaces/Backend.md @@ -0,0 +1,132 @@ +# Backend + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates an intermediate proof (meant to be verified in another circuit) + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | +| `numOfPublicInputs` | `number` | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Retrieves the artifacts from a proof in the Field format + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies an intermediate proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..266ade75d17 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,19 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..2aaa55bccf6 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"}]},{"type":"category","label":"Interfaces","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/interfaces/Backend","label":"Backend"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/ProofData","label":"ProofData"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/.nojekyll b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/classes/Noir.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/classes/Noir.md new file mode 100644 index 00000000000..34e20d99684 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/classes/Noir.md @@ -0,0 +1,132 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `backend`? | `Backend` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateFinalProof() + +```ts +generateFinalProof(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateFinalProof(input) +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyFinalProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/and.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/blake2s256.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..0ba5783f0d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,29 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/keccak256.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/sha256.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/xor.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/index.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/index.md new file mode 100644 index 00000000000..8b9e35bc9a1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/index.md @@ -0,0 +1,37 @@ +# noir_js + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [InputMap](type-aliases/InputMap.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/InputMap.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/InputMap.md new file mode 100644 index 00000000000..c714e999d93 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/InputMap.md @@ -0,0 +1,13 @@ +# InputMap + +```ts +type InputMap: object; +``` + +## Index signature + + \[`key`: `string`\]: `InputValue` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..fe2629ddc9f --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/NoirJS/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/InputMap","label":"InputMap"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ProofData","label":"ProofData"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_js/functions/and","label":"and"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v../reference/_category_.json b/noir/docs/versioned_docs/version-v../reference/_category_.json new file mode 100644 index 00000000000..5b6a20a609a --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 4, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v../reference/nargo_commands.md b/noir/docs/versioned_docs/version-v../reference/nargo_commands.md new file mode 100644 index 00000000000..ff3dee8973f --- /dev/null +++ b/noir/docs/versioned_docs/version-v../reference/nargo_commands.md @@ -0,0 +1,250 @@ +--- +title: Nargo +description: + Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, + generate Solidity verifier smart contract and compile into JSON file containing ACIR + representation and ABI of circuit. +keywords: + [ + Nargo, + Noir CLI, + Noir Prover, + Noir Verifier, + generate Solidity verifier, + compile JSON file, + ACIR representation, + ABI of circuit, + TypeScript, + ] +sidebar_position: 0 +--- + +## General options + +| Option | Description | +| -------------------- | -------------------------------------------------- | +| `--show-ssa` | Emit debug information for the intermediate SSA IR | +| `--deny-warnings` | Quit execution when warnings are emitted | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +| Argument | Description | +| -------------- | -------------------------------------------- | +| `` | The subcommand whose help message to display | + +## `nargo backend` + +Installs and selects custom backends used to generate and verify proofs. + +### Commands + +| Command | Description | +| ----------- | --------------------------------------------------------- | +| `current` | Prints the name of the currently active backend | +| `ls` | Prints the list of currently installed backends | +| `use` | Select the backend to use | +| `install` | Install a new backend from a URL | +| `uninstall` | Uninstalls a backend | +| `help` | Print this message or the help of the given subcommand(s) | + +### Options + +| Option | Description | +| ------------ | ----------- | +| `-h, --help` | Print help | + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to check | +| `--workspace` | Check all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +### `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to codegen | +| `--workspace` | Codegen all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo compile` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +You can also use "build" as an alias for compile (e.g. `nargo build`). + +### Options + +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `--package ` | The name of the package to compile | +| `--workspace` | Compile all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo new ` + +Creates a new Noir project in a new folder. + +**Arguments** + +| Argument | Description | +| -------- | -------------------------------- | +| `` | The path to save the new project | + +### Options + +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: package directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | + +## `nargo init` + +Creates a new Noir project in the current directory. + +### Options + +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: current directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | + +## `nargo execute [WITNESS_NAME]` + +Runs the Noir program and prints its return value. + +**Arguments** + +| Argument | Description | +| ---------------- | ----------------------------------------- | +| `[WITNESS_NAME]` | Write the execution witness to named file | + +### Options + +| Option | Description | +| --------------------------------- | ------------------------------------------------------------------------------------ | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `--package ` | The name of the package to execute | +| `--workspace` | Execute all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A +`.tr` file will then be saved in the `./target` folder. + +## `nargo prove` + +Creates a proof for the program. + +### Options + +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--verify` | Verify proof after proving | +| `--package ` | The name of the package to prove | +| `--workspace` | Prove all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid. + +### Options + +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--package ` | The name of the package to verify | +| `--workspace` | Verify all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo test [TEST_NAME]` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. + +Takes an optional `--exact` flag which allows you to select tests based on an exact name. + +See an example on the [testing page](../getting_started/tooling/testing.md). + +### Options + +| Option | Description | +| --------------------- | -------------------------------------- | +| `--show-output` | Display output of `println` statements | +| `--exact` | Only run tests that match exactly | +| `--package ` | The name of the package to test | +| `--workspace` | Test all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo info` + +Prints a table containing the information of the package. + +Currently the table provide + +1. The number of ACIR opcodes +2. The final number gates in the circuit used by a backend + +If the file contains a contract the table will provide the +above information about each function of the contract. + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). + +## `nargo fmt` + +Automatically formats your Noir source code based on the default formatting settings. diff --git a/noir/docs/versioned_docs/version-v../tutorials/noirjs_app.md b/noir/docs/versioned_docs/version-v../tutorials/noirjs_app.md new file mode 100644 index 00000000000..302ee4aeade --- /dev/null +++ b/noir/docs/versioned_docs/version-v../tutorials/noirjs_app.md @@ -0,0 +1,261 @@ +--- +title: Tiny NoirJS app +description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment +keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs] +sidebar_position: 0 +--- + +NoirJS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Before we start + +:::note + +Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.18.x matches `noir_js@0.18.x`, etc. + +In this guide, we will be pinned to 0.17.0. + +::: + +Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). + +First of all, follow the the [Nargo guide](../getting_started/installation/index.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: + +```bash +nargo compile +``` + +Your folder structure should look like: + +```tree +. +└── circuit + ├── Nargo.toml + ├── src + │ └── main.nr + └── target + └── circuit.json +``` + +## Starting a new project + +Go back to the previous folder and start a new project by running run `npm init`. You can configure your project or just leave the defaults, and see a `package.json` appear in your root folder. + +## Installing dependencies + +We'll need two `npm` packages. These packages will provide us the methods we need to run and verify proofs: + +```bash +npm i @noir-lang/backend_barretenberg@^0.17.0 @noir-lang/noir_js@^0.17.0 +``` + +To serve our page, we can use a build tool such as `vite`. Because we're gonna use some `wasm` files, we need to install a plugin as well. Run: + +```bash +npm i --save-dev vite rollup-plugin-copy +``` + +Since we're on the dependency world, we may as well define a nice starting script. Vite makes it easy. Just open `package.json`, find the block "scripts" and add this just below the line with `"test" : "echo......."`: + +```json + "start": "vite --open" +``` + +If you want do build a static website, you can also add some build and preview scripts: + +```json + "build": "vite build", + "preview": "vite preview" +``` + +## Vite plugins + +Vite is great, but support from `wasm` doesn't work out-of-the-box. We're gonna write a quick plugin and use another one. Just copy and paste this into a file named `vite.config.js`. You don't need to understand it, just trust me bro. + +```js +import { defineConfig } from 'vite'; +import copy from 'rollup-plugin-copy'; +import fs from 'fs'; +import path from 'path'; + +const wasmContentTypePlugin = { + name: 'wasm-content-type-plugin', + configureServer(server) { + server.middlewares.use(async (req, res, next) => { + if (req.url.endsWith('.wasm')) { + res.setHeader('Content-Type', 'application/wasm'); + const newPath = req.url.replace('deps', 'dist'); + const targetPath = path.join(__dirname, newPath); + const wasmContent = fs.readFileSync(targetPath); + return res.end(wasmContent); + } + next(); + }); + }, +}; + +export default defineConfig(({ command }) => { + if (command === 'serve') { + return { + plugins: [ + copy({ + targets: [{ src: 'node_modules/**/*.wasm', dest: 'node_modules/.vite/dist' }], + copySync: true, + hook: 'buildStart', + }), + command === 'serve' ? wasmContentTypePlugin : [], + ], + }; + } + + return {}; +}); +``` + +## HTML + +Here's the simplest HTML with some terrible UI. Create a file called `index.html` and paste this: + +```html + + + + + + +

Very basic Noir app

+
+

Logs

+

Proof

+
+ + +``` + +## Some good old vanilla Javascript + +Create a new file `app.js`, which is where our javascript code will live. Let's start with this code inside: + +```js +document.addEventListener('DOMContentLoaded', async () => { + // here's where the magic happens +}); + +function display(container, msg) { + const c = document.getElementById(container); + const p = document.createElement('p'); + p.textContent = msg; + c.appendChild(p); +} +``` + +We can manipulate our website with this little function, so we can see our website working. + +## Adding Noir + +If you come from the previous page, your folder structure should look like this: + +```tree +├── app.js +├── circuit +│ ├── Nargo.toml +│ ├── src +│ │ └── main.nr +│ └── target +│ └── circuit.json +├── index.html +├── package.json +└── vite.config.js +``` + +You'll see other files and folders showing up (like `package-lock.json`, `yarn.lock`, `node_modules`) but you shouldn't have to care about those. + +## Importing our dependencies + +We're starting with the good stuff now. At the top of the new javascript file, import the packages: + +```ts +import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { Noir } from '@noir-lang/noir_js'; +``` + +We also need to import the `circuit` JSON file we created. If you have the suggested folder structure, you can add this line: + +```ts +import circuit from './circuit/target/circuit.json'; +``` + +## Write code + +:::note + +We're gonna be adding code inside the `document.addEventListener...etc` block: + +```js +// forget stuff here +document.addEventListener('DOMContentLoaded', async () => { + // here's where the magic happens +}); +// forget stuff here +``` + +::: + +Our dependencies exported two classes: `BarretenbergBackend` and `Noir`. Let's `init` them and add some logs, just to flex: + +```ts +const backend = new BarretenbergBackend(circuit); +const noir = new Noir(circuit, backend); +``` + +## Proving + +Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: + +```js +const input = { x: 1, y: 2 }; +display('logs', 'Generating proof... ⌛'); +const proof = await noir.generateFinalProof(input); +display('logs', 'Generating proof... ✅'); +display('results', proof.proof); +``` + +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm start` (or `yarn start`). If it doesn't open a browser for you, just visit `localhost:5173`. On a modern laptop, proof will generate in less than 100ms, and you'll see this: + +![Getting Started 0](@site/static/img/noir_getting_started_1.png) + +If you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human. + +In any case, this means your proof was generated! But you shouldn't trust me just yet. Add these lines to see it being verified: + +```js +display('logs', 'Verifying proof... ⌛'); +const verification = await noir.verifyFinalProof(proof); +if (verification) display('logs', 'Verifying proof... ✅'); +``` + +By saving, your app will refresh and here's our complete Tiny Noir App! + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Further Reading + +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. + +You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.10.5/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.10.5/getting_started/00_nargo_installation.md deleted file mode 100644 index de30869732d..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/getting_started/00_nargo_installation.md +++ /dev/null @@ -1,285 +0,0 @@ ---- -title: Nargo Installation -description: - nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, - verifying and more). Learn how to install and use Nargo for your projects with this comprehensive - guide. -keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] ---- - -`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, -verifying and more). - -Alternatively, the interactions can also be performed in [TypeScript](../typescript). - -### UltraPlonk - -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk -version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. - -## Installation - -There are four approaches for installing Nargo: - -- [Option 1: Noirup](#option-1-noirup) -- [Option 2: Binaries](#option-2-binaries) -- [Option 3: Install via Nix](#option-3-install-via-nix) -- [Option 4: Compile from Source](#option-4-compile-from-source) - -Optionally you can also install [Noir VS Code extension] for syntax highlighting. - -### Option 1: Noirup - -If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a -terminal and run: - -```bash -curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash -``` - -Close the terminal, open another one, and run - -```bash -noirup -``` - -Done, you should have the latest version working. You can check with `nargo --version`. - -You can also install nightlies, specific versions -or branches, check out the [noirup repository](https://github.com/noir-lang/noirup) for more -information. - -#### GitHub Actions - -You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as -installing `noirup` and running tests in your GitHub Action `yml` file. - -See the -[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in -this repo containing hash functions in Noir for an example. - -#### Nightly versions - -To install the nightly version of Noir (updated daily) run: - -```bash -noirup -n -``` - -### Option 2: Binaries - -See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous -platform specific binaries. - -#### Step 1 - -Paste and run the following in the terminal to extract and install the binary: - -> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend -> `sudo` and re-run it. - -##### macOS (Apple Silicon) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### macOS (Intel) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### Windows (PowerShell) - -Open PowerShell as Administrator and run: - -```powershell -mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` -Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` -Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` -$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` -$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` -$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` -Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` -$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") -``` - -##### Linux (Bash) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ -echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ -source ~/.bashrc -``` - -#### Step 2 - -Check if the installation was successful by running `nargo --help`. - -> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from -> Finder. Close the new terminal popped up and `nargo` should now be accessible. - -For a successful installation, you should see something similar to the following after running the -command: - -```sh -$ nargo --help - -Noir's package manager - -Usage: nargo - -Commands: - check Checks the constraint system for errors - codegen-verifier Generates a Solidity verifier smart contract for the program - compile Compile the program and its secret execution trace into ACIR format - new Create a new binary project - execute Executes a circuit to calculate its return value - prove Create proof for this program. The proof is returned as a hex encoded string - verify Given a proof and a program, verify whether the proof is valid - test Run the tests for this program - gates Counts the occurrences of different gates in circuit - help Print this message or the help of the given subcommand(s) -``` - -### Option 3: Install via Nix - -Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). - -#### Installing Nix - -For the best experience, please follow these instructions to setup Nix: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -#### Install Nargo into your Nix profile - -1. Use `nix profile` to install Nargo - -```sh -nix profile install github:noir-lang/noir -``` - -### Option 4: Compile from Source - -Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. - -#### Setting up your environment - -For the best experience, please follow these instructions to setup your environment: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -3. Install direnv into your Nix profile by running: - -```sh -nix profile install nixpkgs#direnv -``` - -4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). - 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. -5. Restart your shell. - -#### Shell & editor experience - -Now that your environment is set up, you can get to work on the project. - -1. Clone the repository, such as: - -```sh -git clone git@github.com:noir-lang/noir -``` - -> Replacing `noir` with whichever repository you want to work on. - -2. Navigate to the directory: - -```sh -cd noir -``` - -> Replacing `noir` with whichever repository you cloned. - -3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: - -```sh -direnv allow -``` - -4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. - -5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): - -```sh -code . -``` - -6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. - -#### Building and testing - -Assuming you are using `direnv` to populate your environment, building and testing the project can be done -with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. - -If you want to build the entire project in an isolated sandbox, you can use Nix commands: - -1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. -2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. - -#### Without `direnv` - -If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. - -Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! - -## Uninstalling Nargo - -### Noirup - -If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. - -```bash -rm -r ~/.nargo -rm -r ~/nargo -rm -r ~/noir_cache -``` - -### Nix - -If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. - -```bash -rm ~/.nix-profile/bin/nargo -``` - -[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git -[rust]: https://www.rust-lang.org/tools/install -[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir -[homebrew]: https://brew.sh/ -[cmake]: https://cmake.org/install/ -[llvm]: https://llvm.org/docs/GettingStarted.html -[openmp]: https://openmp.llvm.org/ -[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/noir/docs/versioned_docs/version-v0.10.5/index.md b/noir/docs/versioned_docs/version-v0.10.5/index.md deleted file mode 100644 index e56b24bccd8..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/index.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Introducing Noir -description: - Learn about the public alpha release of Noir, a domain specific language heavily influenced by - Rust that compiles to an intermediate language which can be compiled to an arithmetic circuit or a - rank-1 constraint system. -keywords: - [ - Noir, - Domain Specific Language, - Rust, - Intermediate Language, - Arithmetic Circuit, - Rank-1 Constraint System, - Ethereum Developers, - Protocol Developers, - Blockchain Developers, - Proving System, - Smart Contract Language, - ] -slug: / ---- - -This version of the book is being released with the public alpha. There will be a lot of features -that are missing in this version, however the syntax and the feel of the language will mostly be -completed. - -## What is Noir? - -Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. - -It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. - -## Who is Noir for? - -Noir can be used for a variety of purposes. - -### Solidity Developers - -Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will -be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create -a verifier contract. - -### Protocol Developers - -As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for -your stack, or maybe you simply want to use a different proving system. Since Noir does not compile -to a specific proof system, it is possible for protocol developers to replace the PLONK-based -proving system with a different proving system altogether. - -### Blockchain developers - -As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the -proving system and smart contract language has been pre-defined). In order for you to use Noir in -your blockchain, a proving system backend and a smart contract interface -must be implemented for it. - -## What's new about Noir? - -Noir is simple and flexible in its design, as it does not compile immediately to a fixed -NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled -to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). - -This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. - -## Current Features - -Compiler: - -- Module System -- For expressions -- Arrays -- Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] -- Unsigned integers -- If statements -- Structures and Tuples -- Generics - -ACIR Supported OPCODES: - -- Sha256 -- Blake2s -- Schnorr signature verification -- MerkleMembership -- Pedersen -- HashToField - -## Libraries - -Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). - -Some libraries that are available today include: - -- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library -- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) -- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers -- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address -- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees -- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir -- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers - -See the section on [dependencies](./modules_packages_crates/dependencies) for more information. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.10.5/language_concepts/01_functions.md deleted file mode 100644 index 7cb43c4c5f2..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/01_functions.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: Functions -description: - Learn how to declare functions and methods in Noir, a programming language with Rust semantics. - This guide covers parameter declaration, return types, call expressions, and more. -keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] ---- - -Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. - -To declare a function the `fn` keyword is used. - -```rust -fn foo() {} -``` - -All parameters in a function must have a type and all types are known at compile time. The parameter -is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. - -```rust -fn foo(x : Field, y : pub Field){} -``` - -The return type of a function can be stated by using the `->` arrow notation. The function below -states that the foo function must return a `Field`. If the function returns no value, then the arrow -is omitted. - -```rust -fn foo(x : Field, y : pub Field) -> Field { - x + y -} -``` - -Note that a `return` keyword is unneeded in this case - the last expression in a function's body is -returned. - -## Call Expressions - -Calling a function in Noir is executed by using the function name and passing in the necessary -arguments. - -Below we show how to call the `foo` function from the `main` function using a call expression: - -```rust -fn main(x : Field, y : Field) { - let z = foo(x); -} - -fn foo(x : Field) -> Field { - x + x -} -``` - -## Methods - -You can define methods in Noir on any struct type in scope. - -```rust -struct MyStruct { - foo: Field, - bar: Field, -} - -impl MyStruct { - fn new(foo: Field) -> MyStruct { - MyStruct { - foo, - bar: 2, - } - } - - fn sum(self) -> Field { - self.foo + self.bar - } -} - -fn main() { - let s = MyStruct::new(40); - assert(s.sum() == 42); -} -``` - -Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as -follows: - -```rust -assert(MyStruct::sum(s) == 42); -``` - -## Lambdas - -Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. - -```rust -let add_50 = |val| val + 50; -assert(add_50(100) == 150); -``` - -See [Lambdas](./08_lambdas.md) for more details. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/01_integers.md b/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/01_integers.md deleted file mode 100644 index d9c5e20e795..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/01_integers.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Integers -description: - Explore the Integer data type in Noir. Learn about its methods, see real-world examples, and grasp how to efficiently use Integers in your Noir code. -keywords: - [ - noir, - integer types, - methods, - examples, - arithmetic, - ] ---- - -An integer type is a range constrained field type. The Noir frontend currently supports unsigned, -arbitrary-sized integer types. - -An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by -its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of -$\\([0,2^{32}-1]\\)$: - -```rust -fn main(x : Field, y : u32) { - let z = x as u32 + y; -} -``` - -`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` -are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created -will be rejected by the verifier. - -> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) -> sized integer types. diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/06_vectors.md b/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/06_vectors.md deleted file mode 100644 index c5b74c877f8..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/data_types/06_vectors.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Vectors -description: - Delve into the Vector data type in Noir. Learn about its methods, practical examples, and best practices for using Vectors in your Noir code. -keywords: - [ - noir, - vector type, - methods, - examples, - dynamic arrays, - ] ---- - -:::caution - -This feature is experimental. You should expect it to change in future versions, -cause unexpected behavior, or simply not work at all. - -::: - -A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. - -Example: - -```rust -use dep::std::collections::vec::Vec; - -let mut vector: Vec = Vec::new(); -for i in 0..5 { - vector.push(i); -} -assert(vector.len() == 5); -``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/nargo/01_commands.md b/noir/docs/versioned_docs/version-v0.10.5/nargo/01_commands.md deleted file mode 100644 index 425a73a34c8..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/nargo/01_commands.md +++ /dev/null @@ -1,223 +0,0 @@ ---- -title: Commands -description: - Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, - generate Solidity verifier smart contract and compile into JSON file containing ACIR - representation and ABI of circuit. -keywords: - [ - Nargo, - Noir CLI, - Noir Prover, - Noir Verifier, - generate Solidity verifier, - compile JSON file, - ACIR representation, - ABI of circuit, - TypeScript, - ] ---- - -## General options - -``` -Options: - --show-ssa Emit debug information for the intermediate SSA IR - --deny-warnings Quit execution when warnings are emitted - -h, --help Print help -``` - -## `nargo help [subcommand]` - -Prints the list of available commands or specific information of a subcommand. - -_Arguments_ - -- `` - The subcommand whose help message to display - -## `nargo check` - -Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output -values of the Noir program respectively. - -**Options** - -``` - --package The name of the package to check - --workspace Check all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -## `nargo codegen-verifier` - -Generate a Solidity verifier smart contract for the program. - -**Options** - -``` - --package The name of the package to codegen - --workspace Codegen all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -## `nargo compile` - -Compile the program into a JSON build artifact file containing the ACIR representation and the ABI -of the circuit. This build artifact can then be used to generate and verify proofs. - -You can also use "build" as an alias for compile (e.g. `nargo build`). - -**Options** - -``` - --include-keys Include Proving and Verification keys in the build artifacts - --package The name of the package to compile - --workspace Compile all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -## `nargo new ` - -Creates a new Noir project in a new folder. - -**Arguments** - -``` - The path to save the new project -``` - -**Options** - -``` - --name Name of the package [default: package directory name] - --lib Use a library template - --bin Use a binary template [default] - --contract Use a contract template --h, --help Print help -``` - -## `nargo init` - -Creates a new Noir project in the current directory. - -**Options** - -``` - --name Name of the package [default: current directory name] - --lib Use a library template - --bin Use a binary template [default] - --contract Use a contract template --h, --help Print help -``` - -## `nargo execute [WITNESS_NAME]` - -Runs the Noir program and prints its return value. - -**Arguments** - -``` -[WITNESS_NAME] Write the execution witness to named file -``` - -**Options** - -``` --p, --prover-name The name of the toml file which contains the inputs for the prover [default: Prover] - --package The name of the package to execute - --workspace Execute all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -_Usage_ - -The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which -must be filled in. - -To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A -`.tr` file will then be saved in the `./target` folder. - -> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs -> parsed for your program's ACIR. -> -> This file can be passed along with circuit's ACIR into a TypeScript project for proving and -> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) -> section to learn more. - -## `nargo prove` - -Creates a proof for the program. - -**Options** - -``` --p, --prover-name The name of the toml file which contains the inputs for the prover [default: Prover] --v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] - --verify Verify proof after proving - --package The name of the package to prove - --workspace Prove all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -## `nargo verify` - -Given a proof and a program, verify whether the proof is valid. - -**Options** - -``` --v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] - --package The name of the package verify - --workspace Verify all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -## `nargo test [TEST_NAME]` - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. - -Takes an optional `--exact` flag which allows you to select tests based on an exact name. - -See an example on the [testing page](./testing). - -**Options** - -``` - --show-output Display output of `println` statements - --exact Only run tests that match exactly - --package The name of the package to test - --workspace Test all packages in the workspace - --print-acir Display the ACIR for compiled circuit - --deny-warnings Treat all warnings as errors --h, --help Print help -``` - -## `nargo info` - -Prints a table containing the information of the package. - -Currently the table provide - -1. The number of ACIR opcodes -2. The final number gates in the circuit used by a backend - -If the file contains a contract the table will provide the -above information about each function of the contract. - -## `nargo lsp` - -Start a long-running Language Server process that communicates over stdin/stdout. -Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives.md b/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives.md deleted file mode 100644 index 2df4f929474..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Cryptographic primitives in Noir -description: - Learn about the cryptographic primitives ready to use for any Noir project -keywords: - [ - cryptographic primitives, - Noir project, - ] ---- - -The Noir team is progressively adding new cryptographic primitives to the standard library. Reach out for news or if you would be interested in adding more of these calculations in Noir. - -Some methods are available thanks to the Aztec backend, not being performed using Noir. When using other backends, these methods may or may not be supplied. diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/01_scalar.mdx deleted file mode 100644 index 62265cddb1e..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/01_scalar.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Scalar multiplication -description: - See how you can perform scalar multiplications over a fixed base in Noir -keywords: - [ - cryptographic primitives, - Noir project, - scalar multiplication, - ] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## scalar_mul::fixed_base - -Performs scalar multiplication over the embedded curve whose coordinates are defined by the -configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. - -```rust -fn fixed_base(_input : Field) -> [Field; 2] -``` - -example - -```rust -fn main(x : Field) { - let scal = std::scalar_mul::fixed_base(x); - std::println(scal); -} -``` - - diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx deleted file mode 100644 index 0e219c0e5ff..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Schnorr Signatures -description: Learn how you can verify Schnorr signatures using Noir -keywords: [cryptographic primitives, Noir project, schnorr, signatures] ---- - -import BlackBoxInfo from './common/_blackbox.mdx'; - -## schnorr::verify_signature - -Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). - -```rust -fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool -``` - -where `_signature` can be generated like so using the npm package -[@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) - -```js -const { BarretenbergWasm } = require('@noir-lang/barretenberg/dest/wasm'); -const { Schnorr } = require('@noir-lang/barretenberg/dest/crypto/schnorr'); - -... - -const barretenberg = await BarretenbergWasm.new(); -const schnorr = new Schnorr(barretenberg); -const pubKey = schnorr.computePublicKey(privateKey); -const message = ... -const signature = Array.from( - schnorr.constructSignature(hash, privateKey).toBuffer() -); - -... -``` - - diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx b/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx deleted file mode 100644 index 9fe9b48fbff..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx +++ /dev/null @@ -1,5 +0,0 @@ -:::info - -This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. - -::: \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/logging.md b/noir/docs/versioned_docs/version-v0.10.5/standard_library/logging.md deleted file mode 100644 index 7e2fd9b9aff..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/logging.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Logging -description: - Learn how to use the println statement for debugging in Noir with this tutorial. Understand the - basics of logging in Noir and how to implement it in your code. -keywords: - [ - noir logging, - println statement, - debugging in noir, - noir std library, - logging tutorial, - basic logging in noir, - noir logging implementation, - noir debugging techniques, - rust, - ] ---- - -The standard library provides a familiar `println` statement you can use. Despite being a limited -implementation of rust's `println!` macro, this construct can be useful for debugging. - -You can print the output of println statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are println statements in your tests). - -It is recommended to use `nargo execute` if you want to debug failing constrains with `println` statements. This is due to every input in a test being a constant rather than a witness, so we issue an error during compilation while we only print during execution (which comes after compilation). `println` will not work for failed constraints caught at compile time. - -The `println` statement is unconstrained, so it works for outputting integers, fields, strings, and even structs or expressions. For example: - -```rust -use dep::std; - -struct Person { - age : Field, - height : Field, -} - -fn main(age : Field, height : Field) { - let person = Person { age : age, height : height }; - std::println(person); - std::println(age + height); - std::println("Hello world!"); -} - -``` - -You can print multiple different types in the same statement and string as well as a new "fmtstr" type. A `fmtstr` can be specified in the same way as a normal string it just should be prepended with an "f" character: - -```rust - let fmt_str = f"i: {i}, j: {j}"; - std::println(fmt_str); - - let s = myStruct { y: x, x: y }; - std::println(s); - - std::println(f"i: {i}, s: {s}"); - - std::println(x); - std::println([x, y]); - - let foo = fooStruct { my_struct: s, foo: 15 }; - std::println(f"s: {s}, foo: {foo}"); -``` diff --git a/noir/docs/versioned_docs/version-v0.10.5/typescript.md b/noir/docs/versioned_docs/version-v0.10.5/typescript.md deleted file mode 100644 index 258a2160e92..00000000000 --- a/noir/docs/versioned_docs/version-v0.10.5/typescript.md +++ /dev/null @@ -1,237 +0,0 @@ ---- -title: Working with TypeScript -description: - Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your - program, specify inputs, initialize a prover & verifier, and prove and verify your program. -keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] ---- - -Interactions with Noir programs can also be performed in TypeScript, which can come in handy when -writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). - -You can check the complete code for this tutorial here: [browser with next.js](https://github.com/signorecello/noir-min-browser-example) and [node.js](https://github.com/signorecello/noir-min-nodejs-example). If you want just a browser boilerplate to start with, check out the [noir-starter](https://github.com/noir-lang/noir-starter) for an example implementation. - -:::note - -You may find unexpected errors working with some frameworks such as `vite`. This is due to the -nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using -[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick -start. - -::: - -## Setup - -Make sure you are using Noir version >= 0.10.1. - -You can check your current version by running `nargo --version`. - -See the [Installation page](./getting_started/nargo_installation) for more info. - -We're assuming you're using ES6 and ESM for both browser (for example with React), or nodejs. Install [Node.js](https://nodejs.org/en). Init a new project with `npm init` and add `"type": "module"` to your `package.json`, to let `node` know we're using the new ESM sytem: - -```json -{ - "type": "module" - // the rest of your package.json -} -``` - -Install Noir dependencies in your project by running: - -```bash -npm i @aztec/bb.js@0.3.6 https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42 fflate ethers@5.7.2 -``` - -This will install the `acvm-simulator` that will generate our witness, and the proving backend barretenberg `bb.js`. - -We're also installing `ethers` because we're too lazy to write a function that pads public inputs with 32bytes, and `fflate` to help us decompress our circuit bytecode. - -Since we're with typescript and using `nodejs` types, we also recommend to install the `@types/node` package, otherwise your IDE will scream at you. - -```bash -npm i --save-dev @types/node -``` - -:::note - -While Noir is in rapid development, some packages could interfere with others. For that reason, you -should use these specified versions. Let us know if for some reason you need to use other ones. - -::: - -As for the circuit, run `nargo init` to create a new Noir project. - -We will use a Standard Noir Example and place it in the `src` folder. This program simply multiplies input `x` with input `y` and returns the result `z`. The verifier doesn't know the value of `x`: we're proving that we know it without making it public. - -```rust -// src/main.nr -fn main(x: u32, y: pub u32) -> pub u32 { - let z = x * y; - z -} -``` - -One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` - -## Compiling - -In order to start proving, we need to compile our circuit into the intermediate representation used by our backend. As of today, you have to do that with `nargo`. Just hop to your circuits folder and run `nargo compile`. - -:::info - -At this time, you need to use a nightly version of nargo. Using [noirup](./getting_started/00_nargo_installation.md#option-1-noirup) you can do this simply by running `noirup -n`. - -::: - -You should have a `json` file in `target/` with your circuit's bytecode. The json file is name based on the project name specified in Nargo.toml, so for a project named "test", it will be at `target/test.json`. You can then import that file normally. - -```ts -import circuit from '../target/test.json' assert { type: 'json' }; -``` - -## Decompressing the circuit - -The compiled circuit comes compressed. We need to decompress it, that's where `fflate` comes in. - -```ts -import { decompressSync } from 'fflate'; - -const acirBuffer = Buffer.from(circuit.bytecode, 'base64'); -const acirBufferUncompressed = decompressSync(acirBuffer); -``` - -From here, it's highly recommended you store `acirBuffer` and `acirBufferUncompressed` close by, as they will be used for witness generation and proving. - -## Initializing ACVM and BB.JS - -:::note - -This step will eventually be abstracted away as Noir tooling matures. For now, you should be fine just literally copy-pasting most of this into your own code. - -::: - -Before proving, `bb.js` needs to be initialized. We need to import some functions and use them - -```ts -import { Crs, newBarretenbergApiAsync, RawBuffer } from '@aztec/bb.js/dest/node/index.js'; - -const api = await newBarretenbergApiAsync(4); - -const [exact, circuitSize, subgroup] = await api.acirGetCircuitSizes(acirBufferUncompressed); -const subgroupSize = Math.pow(2, Math.ceil(Math.log2(circuitSize))); -const crs = await Crs.new(subgroupSize + 1); -await api.commonInitSlabAllocator(subgroupSize); -await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); - -const acirComposer = await api.acirNewAcirComposer(subgroupSize); -``` - -We should take two very useful objects from here: `api` and `acirComposer`. Make sure to keep these close by! - -:::info - -On the browser, you also need to init the ACVM. You can do that by importing it and calling it like: - -```ts -import initACVM, { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; - -await initACVM(); -// the rest of your code -``` - -::: - -## Generating witnesses - -Witness generation is what allows us to prove with arbitrary inputs (like user inputs on a form, game, etc). In this example, our input is a simple object with our circuit inputs `x`, `y`, and return `z` (fun fact: the return value in Noir is actually a public input!). We're wrapping it in a function, so it can be conveniently called later on. - -```ts -import { ethers } from 'ethers'; // I'm lazy so I'm using ethers to pad my input -import { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; - -async function generateWitness(input: any, acirBuffer: Buffer): Promise { - const initialWitness = new Map(); - initialWitness.set(1, ethers.utils.hexZeroPad(`0x${input.x.toString(16)}`, 32)); - initialWitness.set(2, ethers.utils.hexZeroPad(`0x${input.y.toString(16)}`, 32)); - - const witnessMap = await executeCircuit(acirBuffer, initialWitness, () => { - throw Error('unexpected oracle'); - }); - - const witnessBuff = compressWitness(witnessMap); - return witnessBuff; -} -``` - -## Proving - -Finally, we're ready to prove with our backend. Just like with the witness generation, could be useful to wrap it in its own function: - -```ts -async function generateProof(witness: Uint8Array) { - const proof = await api.acirCreateProof( - acirComposer, - acirBufferUncompressed, - decompressSync(witness), - false, - ); - return proof; -} -``` - -## Verifying - -Our backend should also be ready to verify our proof: - -```ts -async function verifyProof(proof: Uint8Array) { - await api.acirInitProvingKey(acirComposer, acirBufferUncompressed); - const verified = await api.acirVerifyProof(acirComposer, proof, false); - return verified; -} -``` - -## Now for the fun part - -Let's call our functions, and destroy our API! - -```ts -const input = { x: 3, y: 4 }; -const witness = await generateWitness(input, acirBuffer); -console.log('Witness generated!'); -const proof = await generateProof(witness); -console.log('Proof generated!'); -await verifyProof(proof); -console.log('Proof verified!'); -api.destroy(); -``` - -You can use [this](https://gist.github.com/critesjosh/6f3ba19fdc9298b24e90ba4f736247dc) tsconfig.json. You can see the script [here](https://gist.github.com/critesjosh/4aa36e87a0cc3f09feaf1febb4d11348). - -## Verifying with Smart Contract - -Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in -TypeScript as well. - -This could be useful if the Noir program is designed to be decentrally verified and/or make use of -decentralized states and logics that is handled at the smart contract level. - -This assumes you've already ran `nargo codegen-verifier`, got your smart contract, and deployed it with Hardhat, Foundry, or your tool of choice. You can then verify a Noir proof by simply calling it. - -Currently, `bb.js` appends the public inputs to the proof. However, these inputs need to be fed separately to the verifier contract. A simple solution is to just slice them from the resulting proof, like this: - -```ts -import { ethers } from 'ethers'; // example using ethers v5 -import artifacts from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; // I compiled using Hardhat, so I'm getting my abi from here - -const verifierAddress = '0x123455'; // your verifier address -const provider = new ethers.providers.Web3Provider(window.ethereum); -const signer = this.provider.getSigner(); - -const contract = new ethers.Contract(verifierAddress, artifacts.abi, signer); - -const publicInputs = proof.slice(0, 32); -const slicedProof = proof.slice(32); -await contract.verify(slicedProof, [publicInputs]); -``` diff --git a/noir/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md index 4ff5fc46334..f4ca361d3c4 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md +++ b/noir/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md @@ -14,7 +14,7 @@ Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noi ### UltraPlonk -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +Nargo versions \<0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. ## Installation diff --git a/noir/docs/versioned_docs/version-v0.17.0/index.md b/noir/docs/versioned_docs/version-v0.17.0/index.md index 9ebe1d54944..ddbee58f6e4 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/index.md +++ b/noir/docs/versioned_docs/version-v0.17.0/index.md @@ -67,7 +67,7 @@ Compiler: - For expressions - Arrays - Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Binary operations (\<, \<=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] - Unsigned integers - If statements - Structures and Tuples diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md index 47cdea0cf04..5eb22170e54 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md +++ b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md @@ -30,7 +30,7 @@ All parameters in a function must have a type and all types are known at compile is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. ```rust -fn foo(x : Field, y : pub Field){} +fn foo(x : Field, y : Field){} ``` The return type of a function can be stated by using the `->` arrow notation. The function below @@ -38,7 +38,7 @@ states that the foo function must return a `Field`. If the function returns no v is omitted. ```rust -fn foo(x : Field, y : pub Field) -> Field { +fn foo(x : Field, y : Field) -> Field { x + y } ``` diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md index da02b126059..d5caa463765 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md @@ -29,11 +29,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md index 4641521b1d9..ad902c42c9b 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md @@ -37,7 +37,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md index 658a0441ffb..78d3d2af166 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md +++ b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md @@ -158,7 +158,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v0.17.0/migration_notes.md b/noir/docs/versioned_docs/version-v0.17.0/migration_notes.md index 48a8abcf22e..69782cba388 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/migration_notes.md +++ b/noir/docs/versioned_docs/version-v0.17.0/migration_notes.md @@ -70,7 +70,7 @@ nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/bar This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. -The gzipped filed is running this bash script: , where we need to gzip it as the Nargo currently expect the backend to be zipped up. +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. Then run: diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md b/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md index d9e5a0c6115..11fef2bf8b5 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md +++ b/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md @@ -74,8 +74,8 @@ async execute(inputs) | Return value | Type | Description | | ------------ | --------------------- | --------------------------------------------------- | -| `witness` | Promise | The witness | -| `returnValue` | Promise | The return value | +| `witness` | Promise \ | The witness | +| `returnValue` | Promise \ | The return value | ### Usage @@ -103,7 +103,7 @@ async generateFinalproof(input) | Return value | Type | Description | | ------------ | --------------------- | --------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the proof. | +| `proof` | Promise \ | An array with the byte representation of the proof. | ### Usage @@ -133,7 +133,7 @@ async verifyFinalProof(proof) | Return value | Type | Description | | ------------ | ------------------ | -------------------------------------------- | -| `verified` | Promise | A boolean for whether the proof was verified | +| `verified` | Promise \ | A boolean for whether the proof was verified | ### Usage diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md b/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md index 21c2ff32b57..f444eab1772 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md +++ b/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md @@ -70,7 +70,7 @@ async generateFinalProof(decompressedWitness) | Return value | Type | Description | | ------------ | -------------------- | --------------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the final proof. | +| `proof` | Promise\ | An array with the byte representation of the final proof. | ### Usage @@ -98,7 +98,7 @@ async generateIntermediateProof(witness) | Return value | Type | Description | | ------------ | -------------------- | --------------------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the intermediate proof | +| `proof` | Promise\ | An array with the byte representation of the intermediate proof | ### Usage @@ -127,7 +127,7 @@ async generateProof(decompressedWitness, makeEasyToVerifyInCircuit) | Return value | Type | Description | | ------------ | -------------------- | -------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the proof | +| `proof` | Promise\ | An array with the byte representation of the proof | ### Usage @@ -186,7 +186,7 @@ async verifyFinalProof(proof) | Return value | Type | Description | | ------------ | ------------------ | -------------------------------------------- | -| `verified` | Promise | A boolean for whether the proof was verified | +| `verified` | Promise \ | A boolean for whether the proof was verified | ### Usage @@ -214,7 +214,7 @@ async verifyIntermediateProof(proof) | Return value | Type | Description | | ------------ | ------------------ | -------------------------------------------- | -| `verified` | Promise | A boolean for whether the proof was verified | +| `verified` | Promise \ | A boolean for whether the proof was verified | ### Usage diff --git a/noir/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md index 725c5f4d373..349756d60c0 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md +++ b/noir/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md @@ -14,7 +14,7 @@ Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noi ### UltraPlonk -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +Nargo versions \<0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. ## Installation diff --git a/noir/docs/versioned_docs/version-v0.19.0/index.md b/noir/docs/versioned_docs/version-v0.19.0/index.md index 75e1abf2932..4e2f4043892 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/index.md +++ b/noir/docs/versioned_docs/version-v0.19.0/index.md @@ -67,7 +67,7 @@ Compiler: - For expressions - Arrays - Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Binary operations (\<, \<=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] - Unsigned integers - If statements - Structures and Tuples diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md index 47cdea0cf04..5eb22170e54 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md +++ b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md @@ -30,7 +30,7 @@ All parameters in a function must have a type and all types are known at compile is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. ```rust -fn foo(x : Field, y : pub Field){} +fn foo(x : Field, y : Field){} ``` The return type of a function can be stated by using the `->` arrow notation. The function below @@ -38,7 +38,7 @@ states that the foo function must return a `Field`. If the function returns no v is omitted. ```rust -fn foo(x : Field, y : pub Field) -> Field { +fn foo(x : Field, y : Field) -> Field { x + y } ``` diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md index da02b126059..d5caa463765 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md @@ -29,11 +29,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md index 4641521b1d9..ad902c42c9b 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md @@ -37,7 +37,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md index 658a0441ffb..78d3d2af166 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md +++ b/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md @@ -158,7 +158,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v0.19.0/migration_notes.md b/noir/docs/versioned_docs/version-v0.19.0/migration_notes.md index e87eb1feaba..0d7e0af0efd 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/migration_notes.md +++ b/noir/docs/versioned_docs/version-v0.19.0/migration_notes.md @@ -78,7 +78,7 @@ nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/bar This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. -The gzipped filed is running this bash script: , where we need to gzip it as the Nargo currently expect the backend to be zipped up. +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. Then run: diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md b/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md index 0d6d5abbbff..ccdd53f2bcc 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md +++ b/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md @@ -77,8 +77,8 @@ async execute(inputs, foreignCallHandler) | Return value | Type | Description | | ------------ | --------------------- | --------------------------------------------------- | -| `witness` | Promise | The witness | -| `returnValue` | Promise | The return value | +| `witness` | Promise \ | The witness | +| `returnValue` | Promise \ | The return value | ### Usage @@ -107,7 +107,7 @@ async generateFinalproof(input) | Return value | Type | Description | | ------------ | --------------------- | --------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the proof. | +| `proof` | Promise \ | An array with the byte representation of the proof. | ### Usage @@ -137,7 +137,7 @@ async verifyFinalProof(proof) | Return value | Type | Description | | ------------ | ------------------ | -------------------------------------------- | -| `verified` | Promise | A boolean for whether the proof was verified | +| `verified` | Promise \ | A boolean for whether the proof was verified | ### Usage diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md b/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md index 21c2ff32b57..f444eab1772 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md +++ b/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md @@ -70,7 +70,7 @@ async generateFinalProof(decompressedWitness) | Return value | Type | Description | | ------------ | -------------------- | --------------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the final proof. | +| `proof` | Promise\ | An array with the byte representation of the final proof. | ### Usage @@ -98,7 +98,7 @@ async generateIntermediateProof(witness) | Return value | Type | Description | | ------------ | -------------------- | --------------------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the intermediate proof | +| `proof` | Promise\ | An array with the byte representation of the intermediate proof | ### Usage @@ -127,7 +127,7 @@ async generateProof(decompressedWitness, makeEasyToVerifyInCircuit) | Return value | Type | Description | | ------------ | -------------------- | -------------------------------------------------- | -| `proof` | Promise | An array with the byte representation of the proof | +| `proof` | Promise\ | An array with the byte representation of the proof | ### Usage @@ -186,7 +186,7 @@ async verifyFinalProof(proof) | Return value | Type | Description | | ------------ | ------------------ | -------------------------------------------- | -| `verified` | Promise | A boolean for whether the proof was verified | +| `verified` | Promise \ | A boolean for whether the proof was verified | ### Usage @@ -214,7 +214,7 @@ async verifyIntermediateProof(proof) | Return value | Type | Description | | ------------ | ------------------ | -------------------------------------------- | -| `verified` | Promise | A boolean for whether the proof was verified | +| `verified` | Promise \ | A boolean for whether the proof was verified | ### Usage diff --git a/noir/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md index 725c5f4d373..349756d60c0 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md +++ b/noir/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md @@ -14,7 +14,7 @@ Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noi ### UltraPlonk -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +Nargo versions \<0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. ## Installation diff --git a/noir/docs/versioned_docs/version-v0.19.1/index.md b/noir/docs/versioned_docs/version-v0.19.1/index.md index 75e1abf2932..4e2f4043892 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/index.md +++ b/noir/docs/versioned_docs/version-v0.19.1/index.md @@ -67,7 +67,7 @@ Compiler: - For expressions - Arrays - Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Binary operations (\<, \<=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] - Unsigned integers - If statements - Structures and Tuples diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md index 47cdea0cf04..5eb22170e54 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md +++ b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md @@ -30,7 +30,7 @@ All parameters in a function must have a type and all types are known at compile is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. ```rust -fn foo(x : Field, y : pub Field){} +fn foo(x : Field, y : Field){} ``` The return type of a function can be stated by using the `->` arrow notation. The function below @@ -38,7 +38,7 @@ states that the foo function must return a `Field`. If the function returns no v is omitted. ```rust -fn foo(x : Field, y : pub Field) -> Field { +fn foo(x : Field, y : Field) -> Field { x + y } ``` diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md index da02b126059..d5caa463765 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md @@ -29,11 +29,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md index 4641521b1d9..ad902c42c9b 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md @@ -37,7 +37,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md index 658a0441ffb..78d3d2af166 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md +++ b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md @@ -158,7 +158,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v0.19.1/migration_notes.md b/noir/docs/versioned_docs/version-v0.19.1/migration_notes.md index e87eb1feaba..0d7e0af0efd 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/migration_notes.md +++ b/noir/docs/versioned_docs/version-v0.19.1/migration_notes.md @@ -78,7 +78,7 @@ nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/bar This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. -The gzipped filed is running this bash script: , where we need to gzip it as the Nargo currently expect the backend to be zipped up. +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. Then run: diff --git a/noir/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md index 725c5f4d373..349756d60c0 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md +++ b/noir/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md @@ -14,7 +14,7 @@ Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noi ### UltraPlonk -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +Nargo versions \<0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. ## Installation diff --git a/noir/docs/versioned_docs/version-v0.19.2/index.md b/noir/docs/versioned_docs/version-v0.19.2/index.md index 75e1abf2932..4e2f4043892 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/index.md +++ b/noir/docs/versioned_docs/version-v0.19.2/index.md @@ -67,7 +67,7 @@ Compiler: - For expressions - Arrays - Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Binary operations (\<, \<=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] - Unsigned integers - If statements - Structures and Tuples diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md index 47cdea0cf04..5eb22170e54 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md +++ b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md @@ -30,7 +30,7 @@ All parameters in a function must have a type and all types are known at compile is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. ```rust -fn foo(x : Field, y : pub Field){} +fn foo(x : Field, y : Field){} ``` The return type of a function can be stated by using the `->` arrow notation. The function below @@ -38,7 +38,7 @@ states that the foo function must return a `Field`. If the function returns no v is omitted. ```rust -fn foo(x : Field, y : pub Field) -> Field { +fn foo(x : Field, y : Field) -> Field { x + y } ``` diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md index da02b126059..d5caa463765 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md @@ -29,11 +29,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md index 4641521b1d9..ad902c42c9b 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md @@ -37,7 +37,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md index 658a0441ffb..78d3d2af166 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md +++ b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md @@ -158,7 +158,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v0.19.2/migration_notes.md b/noir/docs/versioned_docs/version-v0.19.2/migration_notes.md index e87eb1feaba..0d7e0af0efd 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/migration_notes.md +++ b/noir/docs/versioned_docs/version-v0.19.2/migration_notes.md @@ -78,7 +78,7 @@ nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/bar This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. -The gzipped filed is running this bash script: , where we need to gzip it as the Nargo currently expect the backend to be zipped up. +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. Then run: diff --git a/noir/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md index 725c5f4d373..349756d60c0 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md +++ b/noir/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md @@ -14,7 +14,7 @@ Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noi ### UltraPlonk -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +Nargo versions \<0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. ## Installation diff --git a/noir/docs/versioned_docs/version-v0.19.3/index.md b/noir/docs/versioned_docs/version-v0.19.3/index.md index 75e1abf2932..4e2f4043892 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/index.md +++ b/noir/docs/versioned_docs/version-v0.19.3/index.md @@ -67,7 +67,7 @@ Compiler: - For expressions - Arrays - Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Binary operations (\<, \<=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] - Unsigned integers - If statements - Structures and Tuples diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md index 47cdea0cf04..5eb22170e54 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md +++ b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md @@ -30,7 +30,7 @@ All parameters in a function must have a type and all types are known at compile is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. ```rust -fn foo(x : Field, y : pub Field){} +fn foo(x : Field, y : Field){} ``` The return type of a function can be stated by using the `->` arrow notation. The function below @@ -38,7 +38,7 @@ states that the foo function must return a `Field`. If the function returns no v is omitted. ```rust -fn foo(x : Field, y : pub Field) -> Field { +fn foo(x : Field, y : Field) -> Field { x + y } ``` diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md index da02b126059..d5caa463765 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md @@ -29,11 +29,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md index 4641521b1d9..ad902c42c9b 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md @@ -37,7 +37,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md index 658a0441ffb..78d3d2af166 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md +++ b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md @@ -158,7 +158,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/versioned_docs/version-v0.19.3/migration_notes.md b/noir/docs/versioned_docs/version-v0.19.3/migration_notes.md index e87eb1feaba..0d7e0af0efd 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/migration_notes.md +++ b/noir/docs/versioned_docs/version-v0.19.3/migration_notes.md @@ -78,7 +78,7 @@ nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/bar This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. -The gzipped filed is running this bash script: , where we need to gzip it as the Nargo currently expect the backend to be zipped up. +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. Then run: diff --git a/noir/docs/docs/examples/merkle-proof.mdx b/noir/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/docs/examples/merkle-proof.mdx rename to noir/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx diff --git a/noir/docs/docs/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md similarity index 99% rename from noir/docs/docs/getting_started/00_nargo_installation.md rename to noir/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md index 725c5f4d373..349756d60c0 100644 --- a/noir/docs/docs/getting_started/00_nargo_installation.md +++ b/noir/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md @@ -14,7 +14,7 @@ Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noi ### UltraPlonk -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +Nargo versions \<0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. ## Installation diff --git a/noir/docs/docs/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/docs/getting_started/01_hello_world.md rename to noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md diff --git a/noir/docs/docs/getting_started/02_breakdown.md b/noir/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/docs/getting_started/02_breakdown.md rename to noir/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.7.1/index.md b/noir/docs/versioned_docs/version-v0.19.4/index.md similarity index 93% rename from noir/docs/versioned_docs/version-v0.7.1/index.md rename to noir/docs/versioned_docs/version-v0.19.4/index.md index e56b24bccd8..4e2f4043892 100644 --- a/noir/docs/versioned_docs/version-v0.7.1/index.md +++ b/noir/docs/versioned_docs/version-v0.19.4/index.md @@ -21,10 +21,6 @@ keywords: slug: / --- -This version of the book is being released with the public alpha. There will be a lot of features -that are missing in this version, however the syntax and the feel of the language will mostly be -completed. - ## What is Noir? Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. @@ -71,7 +67,7 @@ Compiler: - For expressions - Arrays - Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Binary operations (\<, \<=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] - Unsigned integers - If statements - Structures and Tuples @@ -83,7 +79,8 @@ ACIR Supported OPCODES: - Blake2s - Schnorr signature verification - MerkleMembership -- Pedersen +- Pedersen Commitment +- Pedersen Hash - HashToField ## Libraries diff --git a/noir/docs/docs/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md similarity index 98% rename from noir/docs/docs/language_concepts/01_functions.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md index 47cdea0cf04..5eb22170e54 100644 --- a/noir/docs/docs/language_concepts/01_functions.md +++ b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md @@ -30,7 +30,7 @@ All parameters in a function must have a type and all types are known at compile is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. ```rust -fn foo(x : Field, y : pub Field){} +fn foo(x : Field, y : Field){} ``` The return type of a function can be stated by using the `->` arrow notation. The function below @@ -38,7 +38,7 @@ states that the foo function must return a `Field`. If the function returns no v is omitted. ```rust -fn foo(x : Field, y : pub Field) -> Field { +fn foo(x : Field, y : Field) -> Field { x + y } ``` diff --git a/noir/docs/docs/language_concepts/02_control_flow.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/docs/language_concepts/02_control_flow.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md diff --git a/noir/docs/docs/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md similarity index 90% rename from noir/docs/docs/language_concepts/03_ops.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md index da02b126059..d5caa463765 100644 --- a/noir/docs/docs/language_concepts/03_ops.md +++ b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md @@ -29,11 +29,11 @@ keywords: | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | | >> | Right shift an integer by another integer amount | Types must be integer | | ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | | > | returns a bool if one value is more than the other | Upper bound must have a known bit size | | >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | | == | returns a bool if one value is equal to the other | Both types must not be constants | diff --git a/noir/docs/docs/language_concepts/04_assert.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md similarity index 100% rename from noir/docs/docs/language_concepts/04_assert.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md diff --git a/noir/docs/docs/language_concepts/05_unconstrained.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/docs/language_concepts/05_unconstrained.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md diff --git a/noir/docs/docs/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md similarity index 100% rename from noir/docs/docs/language_concepts/06_generics.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md similarity index 98% rename from noir/docs/versioned_docs/version-v0.10.5/language_concepts/07_mutability.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md index 4641521b1d9..ad902c42c9b 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/language_concepts/07_mutability.md +++ b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md @@ -37,7 +37,7 @@ Note that mutability in noir is local and everything is passed by value, so if a mutates its parameters then the parent function will keep the old value of the parameters. ```rust -fn main() -> Field { +fn main() -> pub Field { let x = 3; helper(x); x // x is still 3 diff --git a/noir/docs/docs/language_concepts/08_lambdas.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/docs/language_concepts/08_lambdas.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md diff --git a/noir/docs/docs/language_concepts/09_comments.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md similarity index 100% rename from noir/docs/docs/language_concepts/09_comments.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md diff --git a/noir/docs/docs/language_concepts/10_distinct.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/docs/language_concepts/10_distinct.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md diff --git a/noir/docs/docs/language_concepts/11_shadowing.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/docs/language_concepts/11_shadowing.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md diff --git a/noir/docs/docs/language_concepts/data_types.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md diff --git a/noir/docs/docs/language_concepts/data_types/00_fields.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md similarity index 98% rename from noir/docs/docs/language_concepts/data_types/00_fields.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md index 658a0441ffb..78d3d2af166 100644 --- a/noir/docs/docs/language_concepts/data_types/00_fields.md +++ b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md @@ -158,7 +158,7 @@ fn main() { ### sgn0 -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. ```rust fn sgn0(self) -> u1 diff --git a/noir/docs/docs/language_concepts/data_types/01_integers.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/01_integers.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md diff --git a/noir/docs/docs/language_concepts/data_types/02_booleans.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/02_booleans.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md new file mode 100644 index 00000000000..b4c75942bb8 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md @@ -0,0 +1,88 @@ +--- +title: Strings +description: + Discover the String data type in Noir. Learn about its methods, see real-world examples, and understand how to effectively manipulate and use Strings in Noir. +keywords: + [ + noir, + string type, + methods, + examples, + concatenation, + ] +--- + + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with `std::println()`. See more about [Logging](../../standard_library/logging). + +```rust +use dep::std; + +fn main(message : pub str<11>, hex_as_string : str<4>) { + std::println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +You can convert a `str` to a byte array by calling `as_bytes()` +or a vector by calling `as_bytes_vec()`. + +```rust +fn main() { + let message = "hello world"; + let message_bytes = message.as_bytes(); + let mut message_vec = message.as_bytes_vec(); + assert(message_bytes.len() == 11); + assert(message_bytes[0] == 104); + assert(message_bytes[0] == message_vec.get(0)); +} +``` + +## Escape Characters + +You can use escape characters for your strings: + +| Escape Sequence | Description | +|-----------------|-----------------| +| `\r` | Carriage Return | +| `\n` | Newline | +| `\t` | Tab | +| `\0` | Null Character | +| `\"` | Double Quote | +| `\\` | Backslash | + +Example: + +```rust +let s = "Hello \"world"; // prints "Hello "world" +let s = "hey \tyou"; // prints "hey you" +``` + +## Formatted Strings + +You can prepend a string with the singular `f` token to create a formatted string. This is useful when logging, as it allows injection of local variables: + +```rust +let var = 15; +std::println(f"var {var}") // prints "var 0x0F" + +let var = -1 as u8; +std::println(f"var {var}") // prints "var 255" + +let var : i8 = -1; +std::println(f"var {var}") // prints "var -1" + +// prints "Hello +//world" +std::println(f"Hello +world"); + +std::println(f"hey \tyou"); // prints "hey \tyou" +``` + +A type can be specified to print numbers either as hex via `Field`, unsigned via `u*` types and signed via `i*` types. + +Note that escaped characters in formatted strings `fmtstr` will be outputted as defined, i.e. "\n" will be printed `\n`, not as a new line. You can add a newline or other whitespace by creating a multiline string as in the example above. diff --git a/noir/docs/docs/language_concepts/data_types/04_arrays.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/04_arrays.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/docs/language_concepts/data_types/05_slices.mdx b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/docs/language_concepts/data_types/05_slices.mdx rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/docs/language_concepts/data_types/06_vectors.mdx b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/docs/language_concepts/data_types/06_vectors.mdx rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/docs/language_concepts/data_types/07_tuples.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/07_tuples.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/docs/language_concepts/data_types/08_structs.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/08_structs.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md diff --git a/noir/docs/docs/language_concepts/data_types/09_references.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/09_references.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md diff --git a/noir/docs/docs/language_concepts/data_types/10_function_types.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/docs/language_concepts/data_types/10_function_types.md rename to noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/migration_notes.md b/noir/docs/versioned_docs/version-v0.19.4/migration_notes.md new file mode 100644 index 00000000000..0d7e0af0efd --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/migration_notes.md @@ -0,0 +1,91 @@ +--- +title: Migration notes +description: Read about migration notes from previous versions, which could solve problems while updating +keywords: [Noir, notes, migration, updating, upgrading] +--- + +Noir is in full-speed development. Things break fast, wild, and often. This page attempts to leave some notes on errors you might encounter when upgrading and how to resolve them until proper patches are built. + +## ≥0.19 + +### Enforcing `compiler_version` + +From this version on, the compiler will check for the `compiler_version` field in `Nargo.toml`, and will error if it doesn't match the current Nargo version in use. + +To update, please make sure this field in `Nargo.toml` matches the output of `nargo --version`. + +## ≥0.14 + +The index of the [for loops](./language_concepts/02_control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: + +```rust +for i in 0..10 { + let i = i as Field; +} +``` + +## ≥v0.11.0 and Nargo backend + +From this version onwards, Nargo starts managing backends through the `nargo backend` command. Upgrading to the versions per usual steps might lead to: + +### `backend encountered an error` + +This is likely due to the existing locally installed version of proving backend (e.g. barretenberg) is incompatible with the version of Nargo in use. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo prove +``` + +with you Noir program. + +This will trigger the download and installation of the latest version of barretenberg compatible with your Nargo in use. + +### `backend encountered an error: illegal instruction` + +On certain Intel-based systems, an `illegal instruction` error may arise due to incompatibility of barretenberg with certain CPU instructions. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/barretenberg-js-binary/raw/master/run-bb.tar.gz +``` + +This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. + +The gzipped filed is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. + +Then run: + +``` +DESIRED_BINARY_VERSION=0.8.1 nargo info +``` + +This overrides the bb native binary with a bb.js node application instead, which should be compatible with most if not all hardware. This does come with the drawback of being generally slower than native binary. + +0.8.1 indicates bb.js version 0.8.1, so if you change that it will update to a different version or the default version in the script if none was supplied. diff --git a/noir/docs/docs/modules_packages_crates/crates_and_packages.md b/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/docs/modules_packages_crates/crates_and_packages.md rename to noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/docs/modules_packages_crates/dependencies.md b/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/docs/modules_packages_crates/dependencies.md rename to noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md diff --git a/noir/docs/docs/modules_packages_crates/modules.md b/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/docs/modules_packages_crates/modules.md rename to noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md diff --git a/noir/docs/docs/modules_packages_crates/workspaces.md b/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/docs/modules_packages_crates/workspaces.md rename to noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md diff --git a/noir/docs/docs/nargo/01_commands.md b/noir/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md similarity index 100% rename from noir/docs/docs/nargo/01_commands.md rename to noir/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md diff --git a/noir/docs/docs/nargo/02_testing.md b/noir/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md similarity index 100% rename from noir/docs/docs/nargo/02_testing.md rename to noir/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md diff --git a/noir/docs/docs/nargo/03_solidity_verifier.md b/noir/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/docs/nargo/03_solidity_verifier.md rename to noir/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md diff --git a/noir/docs/docs/nargo/04_language_server.md b/noir/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md similarity index 100% rename from noir/docs/docs/nargo/04_language_server.md rename to noir/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md diff --git a/noir/docs/docs/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/docs/noir_js/getting_started/01_tiny_noir_app.md rename to noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/docs/noir_js/noir_js.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md similarity index 100% rename from noir/docs/docs/noir_js/noir_js.md rename to noir/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..5cbe9421b92 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,185 @@ +# BarretenbergBackend + +## Implements + +- [`Backend`](../interfaces/Backend.md) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`destroy`](../interfaces/Backend.md#destroy) + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateFinalProof`](../interfaces/Backend.md#generatefinalproof) + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(witness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `witness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProof`](../interfaces/Backend.md#generateintermediateproof) + +#### Example + +```typescript +const intermediateProof = await backend.generateIntermediateProof(witness); +``` + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProofArtifacts`](../interfaces/Backend.md#generateintermediateproofartifacts) + +#### Example + +```typescript +const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyFinalProof`](../interfaces/Backend.md#verifyfinalproof) + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyIntermediateProof`](../interfaces/Backend.md#verifyintermediateproof) + +#### Example + +```typescript +const isValidIntermediate = await backend.verifyIntermediateProof(proof); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md new file mode 100644 index 00000000000..93b248b0f65 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md @@ -0,0 +1,45 @@ +# Backend Barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | + +### Interfaces + +| Interface | Description | +| :------ | :------ | +| [Backend](interfaces/Backend.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | + +## Functions + +### flattenPublicInputs() + +```ts +flattenPublicInputs(publicInputs): string[] +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `WitnessMap` | + +#### Returns + +`string`[] + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md new file mode 100644 index 00000000000..3eb9645c8d2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md @@ -0,0 +1,132 @@ +# Backend + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates an intermediate proof (meant to be verified in another circuit) + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | +| `numOfPublicInputs` | `number` | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Retrieves the artifacts from a proof in the Field format + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies an intermediate proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..266ade75d17 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,19 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..04e662c845f --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"noir_js/reference/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"}]},{"type":"category","label":"Interfaces","items":[{"type":"doc","id":"noir_js/reference/backend_barretenberg/interfaces/Backend","label":"Backend"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"noir_js/reference/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"},{"type":"doc","id":"noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"noir_js/reference/backend_barretenberg/type-aliases/ProofData","label":"ProofData"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md new file mode 100644 index 00000000000..e54116fb1d8 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md @@ -0,0 +1,131 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `backend`? | `Backend` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateFinalProof() + +```ts +generateFinalProof(inputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateFinalproof(input) +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyFinalProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..0ba5783f0d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,29 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md new file mode 100644 index 00000000000..348453c0059 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md @@ -0,0 +1,37 @@ +# Noir JS + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [InputMap](type-aliases/InputMap.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md new file mode 100644 index 00000000000..c714e999d93 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md @@ -0,0 +1,13 @@ +# InputMap + +```ts +type InputMap: object; +``` + +## Index signature + + \[`key`: `string`\]: `InputValue` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..077ebeb133e --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"noir_js/reference/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/InputMap","label":"InputMap"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ProofData","label":"ProofData"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"noir_js/reference/noir_js/functions/and","label":"and"},{"type":"doc","id":"noir_js/reference/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"noir_js/reference/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"noir_js/reference/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"noir_js/reference/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/black_box_fns.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md similarity index 94% rename from noir/docs/versioned_docs/version-v0.9.0/standard_library/black_box_fns.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md index c758846b688..1dfabfe8f22 100644 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/black_box_fns.md +++ b/noir/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md @@ -29,7 +29,8 @@ Here is a list of the current black box functions that are supported by UltraPlo - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) - [Fixed base scalar multiplication](./cryptographic_primitives/scalar) diff --git a/noir/docs/docs/standard_library/cryptographic_primitives.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/docs/standard_library/cryptographic_primitives.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 83% rename from noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx index 1d9b1c7f09c..76745196681 100644 --- a/noir/docs/versioned_docs/version-v0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx +++ b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx @@ -7,7 +7,7 @@ keywords: [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] --- -import BlackBoxInfo from './common/_blackbox.mdx'; +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## sha256 @@ -47,12 +47,12 @@ fn main() { -## pedersen +## pedersen_hash Given an array of Fields, returns the Pedersen hash. ```rust -fn pedersen(_input : [Field]) -> [Field; 2] +fn pedersen_hash(_input : [Field]) -> Field ``` example: @@ -60,7 +60,28 @@ example: ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::pedersen(x); + let hash = std::hash::pedersen_hash(x); +} +``` + + + + + +## pedersen_commitment + +Given an array of Fields, returns the Pedersen commitment. + +```rust +fn pedersen_commitment(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let commitment = std::hash::pedersen_commitment(x); } ``` @@ -130,7 +151,7 @@ example: fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::mimc_bn254(x); + let hash = std::hash::mimc::mimc_bn254(x); } ``` diff --git a/noir/docs/docs/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/docs/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/docs/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/docs/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/docs/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/docs/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/docs/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/docs/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/docs/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/docs/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/docs/standard_library/logging.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/logging.md similarity index 100% rename from noir/docs/docs/standard_library/logging.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/logging.md diff --git a/noir/docs/docs/standard_library/merkle_trees.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/docs/standard_library/merkle_trees.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/options.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/options.md new file mode 100644 index 00000000000..3d3139fb98b --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.19.4/standard_library/options.md @@ -0,0 +1,99 @@ +--- +title: Option Type +--- + +The `Option` type is a way to express that a value might be present (`Some(T))` or absent (`None`). It's a safer way to handle potential absence of values, compared to using nulls in many other languages. + +```rust +struct Option { + None, + Some(T), +} +``` + +You can import the Option type into your Noir program like so: + +```rust +use dep::std::option::Option; + +fn main() { + let none = Option::none(); + let some = Option::some(3); +} +``` + +See [this test](https://github.com/noir-lang/noir/blob/5cbfb9c4a06c8865c98ff2b594464b037d821a5c/crates/nargo_cli/tests/test_data/option/src/main.nr) for a more comprehensive set of examples of each of the methods described below. + +## Methods + +### none + +Constructs a none value. + +### some + +Constructs a some wrapper around a given value. + +### is_none + +Returns true if the Option is None. + +### is_some + +Returns true of the Option is Some. + +### unwrap + +Asserts `self.is_some()` and returns the wrapped value. + +### unwrap_unchecked + +Returns the inner value without asserting `self.is_some()`. This method can be useful within an if condition when we already know that `option.is_some()`. If the option is None, there is no guarantee what value will be returned, only that it will be of type T for an `Option`. + +### unwrap_or + +Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value. + +### unwrap_or_else + +Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return a default value. + +### map + +If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`. + +### map_or + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value. + +### map_or_else + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`. + +### and + +Returns None if self is None. Otherwise, this returns `other`. + +### and_then + +If self is None, this returns None. Otherwise, this calls the given function with the Some value contained within self, and returns the result of that call. In some languages this function is called `flat_map` or `bind`. + +### or + +If self is Some, return self. Otherwise, return `other`. + +### or_else + +If self is Some, return self. Otherwise, return `default()`. + +### xor + +If only one of the two Options is Some, return that option. Otherwise, if both options are Some or both are None, None is returned. + +### filter + +Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true. Otherwise, this returns `None`. + +### flatten + +Flattens an `Option>` into a `Option`. This returns `None` if the outer Option is None. Otherwise, this returns the inner Option. diff --git a/noir/docs/docs/standard_library/recursion.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md similarity index 100% rename from noir/docs/docs/standard_library/recursion.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/zeroed.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.6.0/standard_library/zeroed.md rename to noir/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.6.0/examples/merkle-proof.md b/noir/docs/versioned_docs/version-v0.6.0/examples/merkle-proof.md deleted file mode 100644 index 4696b4a1426..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/examples/merkle-proof.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Merkle Proof Membership -description: - Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a - merkle tree with a specified root, at a given index. -keywords: - [merkle proof, merkle membership proof, Noir, rust, hash function, Pedersen, sha256, merkle tree] ---- - -Let's walk through an example of a merkle membership proof in Noir that proves that a given leaf is -in a merkle tree. - -```rust -use dep::std; - -fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Field) { - let leaf = std::hash::hash_to_field(message); - let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); - assert(merkle_root == root); -} - -``` - -The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen -by the backend. The only requirement is that this hash function can heuristically be used as a -random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen` -instead. - -```rust -let leaf = std::hash::hash_to_field(message); -``` - -The leaf is then passed to a compute_merkle_root function with the root, index and hashpath. The returned root can then be asserted to be the same as the provided root. - -```rust -let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); -assert (merkle_root == root); -``` - -> **Note:** It is possible to re-implement the merkle tree implementation without standard library. -> However, for most usecases, it is enough. In general, the standard library will always opt to be -> as conservative as possible, while striking a balance with efficiency. - -An example, the merkle membership proof, only requires a hash function that has collision -resistance, hence a hash function like Pedersen is allowed, which in most cases is more efficient -than the even more conservative sha256. - -[view an example on the starter repo](https://github.com/noir-lang/noir-examples/blob/3ea09545cabfa464124ec2f3ea8e60c608abe6df/stealthdrop/circuits/src/main.nr#L20) diff --git a/noir/docs/versioned_docs/version-v0.6.0/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.6.0/getting_started/00_nargo_installation.md deleted file mode 100644 index 432884b709e..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/getting_started/00_nargo_installation.md +++ /dev/null @@ -1,283 +0,0 @@ ---- -title: Nargo Installation -description: - nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, - verifying and more). Learn how to install and use Nargo for your projects with this comprehensive - guide. -keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] ---- - -`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, -verifying and more). - -Alternatively, the interactions can also be performed in [TypeScript](../typescript). - -### UltraPlonk - -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk -version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. - -## Installation - -There are four approaches for installing Nargo: - -- [Option 1: Noirup](#option-1-noirup) -- [Option 2: Binaries](#option-2-binaries) -- [Option 3: Install via Nix](#option-3-install-via-nix) -- [Option 4: Compile from Source](#option-4-compile-from-source) - -Optionally you can also install [Noir VS Code extension] for syntax highlighting. - -### Option 1: Noirup - -If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a -terminal and run: - -```bash -curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash -``` - -Close the terminal, open another one, and run - -```bash -noirup -v 0.6.0 -``` - -Done, you should have the latest version working. You can check with `nargo --version`. - -You can also install nightlies, specific versions -or branches, check out the [noirup repository](https://github.com/noir-lang/noirup) for more -information. - -#### GitHub Actions - -You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as -installing `noirup` and running tests in your GitHub Action `yml` file. - -See the -[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in -this repo containing hash functions in Noir for an example. - -#### Nightly versions - -To install the nightly version of Noir (updated daily) run: - -```bash -noirup -n -``` - -### Option 2: Binaries - -See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous -platform specific binaries. - -#### Step 1 - -Paste and run the following in the terminal to extract and install the binary: - -> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend -> `sudo` and re-run it. - -##### macOS (Apple Silicon) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### macOS (Intel) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### Windows (PowerShell) - -Open PowerShell as Administrator and run: - -```powershell -mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` -Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` -Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` -$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` -$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` -$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` -Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` -$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") -``` - -##### Linux (Bash) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ -echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ -source ~/.bashrc -``` - -#### Step 2 - -Check if the installation was successful by running `nargo --help`. - -> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from -> Finder. Close the new terminal popped up and `nargo` should now be accessible. - -For a successful installation, you should see something similar to the following after running the -command: - -```sh -$ nargo --help - -Noir's package manager - -Usage: nargo - -Commands: - check Checks the constraint system for errors - codegen-verifier Generates a Solidity verifier smart contract for the program - compile Compile the program and its secret execution trace into ACIR format - new Create a new binary project - execute Executes a circuit to calculate its return value - prove Create proof for this program. The proof is returned as a hex encoded string - verify Given a proof and a program, verify whether the proof is valid - test Run the tests for this program - gates Counts the occurrences of different gates in circuit - help Print this message or the help of the given subcommand(s) -``` - -### Option 3: Install via Nix - -Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). - -#### Installing Nix - -For the best experience, please follow these instructions to setup Nix: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -#### Install Nargo into your Nix profile - -1. Use `nix profile` to install Nargo - -```sh -nix profile install github:noir-lang/noir -``` - -### Option 4: Compile from Source - -Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. - -#### Setting up your environment - -For the best experience, please follow these instructions to setup your environment: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -3. Install direnv into your Nix profile by running: - -```sh -nix profile install nixpkgs#direnv -``` - -4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). -5. Restart your shell. - -#### Shell & editor experience - -Now that your environment is set up, you can get to work on the project. - -1. Clone the repository, such as: - -```sh -git clone git@github.com:noir-lang/noir -``` -> Replacing `noir` with whichever repository you want to work on. - -2. Navigate to the directory: - -```sh -cd noir -``` -> Replacing `noir` with whichever repository you cloned. - -3. You should see a __direnv error__ because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: - -```sh -direnv allow -``` - -4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. - -5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): - -```sh -code . -``` - -6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. - -#### Building and testing - -Assuming you are using `direnv` to populate your environment, building and testing the project can be done -with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. - -If you want to build the entire project in an isolated sandbox, you can use Nix commands: - -1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. -2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. - -#### Without `direnv` - -If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. - -Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! - -## Uninstalling Nargo - -### Noirup - -If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. - -```bash -rm -r ~/.nargo -rm -r ~/nargo -rm -r ~/noir_cache -``` - -### Nix - -If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. - -```bash -rm ~/.nix-profile/bin/nargo -``` - -[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git -[rust]: https://www.rust-lang.org/tools/install -[noir vs code extension]: - https://marketplace.visualstudio.com/items?itemName=noir-lang.noir-programming-language-syntax-highlighter -[homebrew]: https://brew.sh/ -[cmake]: https://cmake.org/install/ -[llvm]: https://llvm.org/docs/GettingStarted.html -[openmp]: https://openmp.llvm.org/ -[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/noir/docs/versioned_docs/version-v0.6.0/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.6.0/getting_started/01_hello_world.md deleted file mode 100644 index 0f21ad45569..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/getting_started/01_hello_world.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: Create A Project -description: - Learn how to create and verify your first Noir program using Nargo, a programming language for - zero-knowledge proofs. -keywords: - [ - Nargo, - Noir, - zero-knowledge proofs, - programming language, - create Noir program, - verify Noir program, - step-by-step guide, - ] ---- - -Now that we have installed Nargo, it is time to make our first hello world program! - -## Create a Project Directory - -Noir code can live anywhere on your computer. Let us create a _projects_ folder in the home -directory to house our Noir programs. - -For Linux, macOS, and Windows PowerShell, create the directory and change directory into it by -running: - -```sh -mkdir ~/projects -cd ~/projects -``` - -For Windows CMD, run: - -```sh -> mkdir "%USERPROFILE%\projects" -> cd /d "%USERPROFILE%\projects" -``` - -## Create Our First Nargo Project - -Now that we are in the projects directory, create a new Nargo project by running: - -```sh -nargo new hello_world -``` - -> **Note:** `hello_world` can be any arbitrary project name, we are simply using `hello_world` for -> demonstration. -> -> In production, the common practice is to name the project folder as `circuits` for better -> identifiability when sitting alongside other folders in the codebase (e.g. `contracts`, `scripts`, -> `test`). - -A `hello_world` folder would be created. Similar to Rust, the folder houses _src/main.nr_ and -_Nargo.toml_ that contains the source code and environmental options of your Noir program -respectively. - -### Intro to Noir Syntax - -Let us take a closer look at _main.nr_. The default _main.nr_ generated should look like this: - -```rust -fn main(x : Field, y : pub Field) { - assert(x != y); -} -``` - -The first line of the program specifies the program's inputs: - -```rust -x : Field, y : pub Field -``` - -Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the -keyword `pub` (e.g. `y`). To learn more about private and public values, check the -[Data Types](../language_concepts/data_types) section. - -The next line of the program specifies its body: - -```rust -assert(x != y); -``` - -The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. - -For more Noir syntax, check the [Language Concepts](../language_concepts/comments) chapter. - -## Build In/Output Files - -Change directory into _hello_world_ and build in/output files for your Noir program by running: - -```sh -cd hello_world -nargo check -``` - -Two additional files would be generated in your project directory: - -_Prover.toml_ houses input values, and _Verifier.toml_ houses public values. - -## Prove Our Noir Program - -Now that the project is set up, we can create a proof of correct execution on our Noir program. - -Fill in input values for execution in the _Prover.toml_ file. For example: - -```toml -x = "1" -y = "2" -``` - -Prove the valid execution of your Noir program with your preferred proof name, for example `p`: - -```sh -nargo prove p -``` - -A new folder _proofs_ would then be generated in your project directory, containing the proof file -`p.proof`. - -The _Verifier.toml_ file would also be updated with the public values computed from program -execution (in this case the value of `y`): - -```toml -y = "0x0000000000000000000000000000000000000000000000000000000000000002" -``` - -> **Note:** Values in _Verifier.toml_ are computed as 32-byte hex values. - -## Verify Our Noir Program - -Once a proof is generated, we can verify correct execution of our Noir program by verifying the -proof file. - -Verify your proof of name `p` by running: - -```sh -nargo verify p -``` - -The verification will complete in silence if it is successful. If it fails, it will log the -corresponding error instead. - -Congratulations, you have now created and verified a proof for your very first Noir program! - -In the [next section](breakdown), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.6.0/getting_started/02_breakdown.md b/noir/docs/versioned_docs/version-v0.6.0/getting_started/02_breakdown.md deleted file mode 100644 index 5f4f00a3f36..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/getting_started/02_breakdown.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Project Breakdown -description: - Learn about the anatomy of a Nargo project, including the purpose of the Prover and Verifier TOML - files, and how to prove and verify your program. -keywords: - [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] ---- - -This section breaks down our hello world program in section _1.2_. We elaborate on the project -structure and what the `prove` and `verify` commands did in the previous section. - -## Anatomy of a Nargo Project - -Upon creating a new project with `nargo new` and building the in/output files with `nargo check` -commands, you would get a minimal Nargo project of the following structure: - - - src - - Prover.toml - - Verifier.toml - - Nargo.toml - -The source directory _src_ holds the source code for your Noir program. By default only a _main.nr_ -file will be generated within it. - -_Prover.toml_ is used for specifying the input values for executing and proving the program. -Optionally you may specify expected output values for prove-time checking as well. - -_Verifier.toml_ contains public in/output values computed when executing the Noir program. - -_Nargo.toml_ contains the environmental options of your project. - -_proofs_ and _contract_ directories will not be immediately visible until you create a proof or -verifier contract respectively. - -### main.nr - -The _main.nr_ file contains a `main` method, this method is the entry point into your Noir program. - -In our sample program, _main.nr_ looks like this: - -```rust -fn main(x : Field, y : Field) { - constrain x != y; -} -``` - -The parameters `x` and `y` can be seen as the API for the program and must be supplied by the -prover. Since neither `x` nor `y` is marked as public, the verifier does not supply any inputs, when -verifying the proof. - -The prover supplies the values for `x` and `y` in the _Prover.toml_ file. - -As for the program body, `constrain` ensures the satisfaction of the condition (e.g. `x != y`) is -constrained by the proof of the execution of said program (i.e. if the condition was not met, the -verifier would reject the proof as an invalid proof). - -### Prover.toml - -The _Prover.toml_ file is a file which the prover uses to supply his witness values(both private and -public). - -In our hello world program the _Prover.toml_ file looks like this: - -```toml -x = "1" -y = "2" -``` - -When the command `nargo prove my_proof` is executed, two processes happen: - -1. Noir creates a proof that `x` which holds the value of `1` and `y` which holds the value of `2` - is not equal. This not equal constraint is due to the line `constrain x != y`. - -2. Noir creates and stores the proof of this statement in the _proofs_ directory and names the proof - file _my_proof_. Opening this file will display the proof in hex format. - -## Verifying a Proof - -When the command `nargo verify my_proof` is executed, two processes happen: - -1. Noir checks in the _proofs_ directory for a file called _my_proof_ - -2. If that file is found, the proof's validity is checked - -> **Note:** The validity of the proof is linked to the current Noir program; if the program is -> changed and the verifier verifies the proof, it will fail because the proof is not valid for the -> _modified_ Noir program. - -In production, the prover and the verifier are usually two separate entities. A prover would -retrieve the necessary inputs, execute the Noir program, generate a proof and pass it to the -verifier. The verifier would then retrieve the public inputs from usually external sources and -verifies the validity of the proof against it. - -Take a private asset transfer as an example: - -A user on browser as the prover would retrieve private inputs (e.g. the user's private key) and -public inputs (e.g. the user's encrypted balance on-chain), compute the transfer, generate a proof -and submit it to the verifier smart contract. - -The verifier contract would then draw the user's encrypted balance directly from the blockchain and -verify the proof submitted against it. If the verification passes, additional functions in the -verifier contract could trigger (e.g. approve the asset transfer). diff --git a/noir/docs/versioned_docs/version-v0.6.0/index.md b/noir/docs/versioned_docs/version-v0.6.0/index.md deleted file mode 100644 index f4706182ffa..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/index.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Introducing Noir -description: - Learn about the public alpha release of Noir, a domain specific language heavily influenced by - Rust that compiles to an intermediate language which can be compiled to an arithmetic circuit or a - rank-1 constraint system. -keywords: - [ - Noir, - Domain Specific Language, - Rust, - Intermediate Language, - Arithmetic Circuit, - Rank-1 Constraint System, - Ethereum Developers, - Protocol Developers, - Blockchain Developers, - Proving System, - Smart Contract Language, - ] -slug: / ---- - -This version of the book is being released with the public alpha. There will be a lot of features -that are missing in this version, however the syntax and the feel of the language will mostly be -completed. - -## What is Noir? - -Noir is a domain specific language for creating and verifying proofs. It's design choices are -influenced heavily by Rust. - -## What's new about Noir? - -Noir is simple and flexible in its design, as it does not compile immediately to a fixed -NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled -to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). - -This in itself brings up a few challenges -within the design process, but allows one to decouple the programming language completely from the -backend. This is similar in theory to LLVM. - -## Who is Noir for? - -Noir can be used for a variety of purposes. - -### Ethereum Developers - -Noir currently includes a command to publish a contract which verifies your Noir program. This will -be modularised in the future; however, as of the alpha, you can use the `contract` command to create -a verifier contract. - -### Protocol Developers - -As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for -your stack, or maybe you simply want to use a different proving system. Since Noir does not compile -to a specific proof system, it is possible for protocol developers to replace the PLONK-based -proving system with a different proving system altogether. - -### Blockchain developers - -As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the -proving system and smart contract language has been pre-defined). In order for you to use Noir in -your blockchain, a proving system backend and a smart contract interface -must be implemented for it. diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/00_data_types.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/00_data_types.md deleted file mode 100644 index 3a711fc8922..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/00_data_types.md +++ /dev/null @@ -1,301 +0,0 @@ ---- -title: Data Types -description: - Get a clear understanding of the two categories of Noir data types - primitive types and compound - types. Learn about their characteristics, differences, and how to use them in your Noir - programming. -keywords: - [ - noir, - data types, - primitive types, - compound types, - private types, - public types, - field type, - integer types, - boolean type, - array type, - tuple type, - struct type, - ] ---- - -Every value in Noir has a type, which determines which operations are valid for it. - -All values in Noir are fundamentally composed of `Field` elements. For a more approachable -developing experience, abstractions are added on top to introduce different data types in Noir. - -Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound -types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or -public. - -## Private & Public Types - -A **private value** is known only to the Prover, while a **public value** is known by both the -Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All -primitive types (including individual fields of compound types) in Noir are private by default, and -can be marked public when certain values are intended to be revealed to the Verifier. - -> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once -> the proofs are verified on-chain the values can be considered known to everyone that has access to -> that blockchain. - -Public data types are treated no differently to private types apart from the fact that their values -will be revealed in proofs generated. Simply changing the value of a public type will not change the -circuit (where the same goes for changing values of private types as well). - -_Private values_ are also referred to as _witnesses_ sometimes. - -> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different -> meaning than when applied to a function (e.g. `pub fn foo() {}`). -> -> The former is a visibility modifier for the Prover to interpret if a value should be made known to -> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a -> function should be made accessible to external Noir programs like in other languages. - -### pub Modifier - -All data types in Noir are private by default. Types are explicitly declared as public using the -`pub` modifier: - -```rust -fn main(x : Field, y : pub Field) -> pub Field { - x + y -} -``` - -In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note -that visibility is handled **per variable**, so it is perfectly valid to have one input that is -private and another that is public. - -> **Note:** Public types can only be declared through parameters on `main`. - -## Primitive Types - -A primitive type represents a single value. They can be private or public. - -### Fields - -The field type corresponds to the native field type of the proving backend. - -The size of a Noir field depends on the elliptic curve's finite field for the proving backend -adopted. For example, a field would be a 254-bit integer when paired with the default backend that -spans the Grumpkin curve. - -Fields support integer arithmetic and are often used as the default numeric type in Noir: - -```rust -fn main(x : Field, y : Field) { - let z = x + y; -} -``` - -`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new -private value `z` constrained to be equal to `x + y`. - -If proving efficiency is of priority, fields should be used as a default for solving problems. -Smaller integer types (e.g. `u64`) incur extra range constraints. - -### Integers - -An integer type is a range constrained field type. The Noir frontend currently supports unsigned, -arbitrary-sized integer types. - -An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by -its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of -$\\([0,2^{32}-1]\\)$: - -```rust -fn main(x : Field, y : u32) { - let z = x as u32 + y; -} -``` - -`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` -are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created -will be rejected by the verifier. - -> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) -> sized integer types. - -### Booleans - -The `bool` type in Noir has two possible values: `true` and `false`: - -```rust -fn main() { - let t = true; - let f: bool = false; -} -``` - -> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for -> `false` in _Verifier.toml_. - -The boolean type is most commonly used in conditionals like `if` expressions and `constrain` -statements. More about conditionals is covered in the [Control Flow](./control_flow) and -[Constrain Statement](./constrain) sections. - -### Strings - -The string type is a fixed length value defined with `str`. - -You can use strings in `constrain` statements, `assert()` functions or print them with -`std::println()`. - -```rust -fn main(message : pub str<11>, hex_as_string : str<4>) { - std::println(message); - assert(message == "hello world"); - assert(hex_as_string == "0x41"); -} -``` - -## Compound Types - -A compound type groups together multiple values into one type. Elements within a compound type can -be private or public. - -### Arrays - -An array is one way of grouping together values into one compound type. Array types can be inferred -or explicitly specified via the syntax `[; ]`: - -```rust -fn main(x : Field, y : Field) { - let my_arr = [x, y]; - let your_arr: [Field; 2] = [x, y]; -} -``` - -Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. - -Array elements can be accessed using indexing: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - let first = a[0]; - let second = a[1]; -} -``` - -All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group -a `Field` value and a `u8` value together for example. - -You can write mutable arrays, like: - -```rust -fn main() { - let mut arr = [1, 2, 3, 4, 5]; - assert(arr[0] == 1); - - arr[0] = 42; - assert(arr[0] == 42); -} -``` - -#### Types - -You can create arrays of primitive types or structs. There is not yet support for nested arrays -(arrays of arrays) or arrays of structs that contain arrays. - -### Tuples - -A tuple collects multiple values like an array, but with the added ability to collect values of -different types: - -```rust -fn main() { - let tup: (u8, u64, Field) = (255, 500, 1000); -} -``` - -One way to access tuple elements is via destructuring using pattern matching: - -```rust -fn main() { - let tup = (1, 2); - - let (one, two) = tup; - - let three = one + two; -} -``` - -Another way to access tuple elements is via direct member access, using a period (`.`) followed by -the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to -the second and so on: - -```rust -fn main() { - let tup = (5, 6, 7, 8); - - let five = tup.0; - let eight = tup.3; -} -``` - -### Structs - -A struct also allows for grouping multiple values of different types. Unlike tuples, we can also -name each field. - -> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the -> field type of Noir. - -Defining a struct requires giving it a name and listing each field within as `: ` pairs: - -```rust -struct Animal { - hands: Field, - legs: Field, - eyes: u8, -} -``` - -An instance of a struct can then be created with actual values in `: ` pairs in any -order. Struct fields are accessible using their given names: - -```rust -fn main() { - let legs = 4; - - let dog = Animal { - eyes: 2, - hands: 0, - legs, - }; - - let zero = dog.hands; -} -``` - -Structs can also be destructured in a pattern, binding each field to a new variable: - -```rust -fn main() { - let Animal { hands, legs: feet, eyes } = get_octopus(); - - let ten = hands + feet + eyes as u8; -} - -fn get_octopus() -> Animal { - let octopus = Animal { - hands: 0, - legs: 8, - eyes: 2, - }; - - octopus -} -``` - -The new variables can be bound with names different from the original struct field names, as -showcased in the `legs --> feet` binding in the example above. - -:::note -You can use Structs as inputs to the `main` function, but you can't output them -::: diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/01_functions.md deleted file mode 100644 index c4bc0545a1c..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/01_functions.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Functions -description: - Learn how to declare functions and methods in Noir, a programming language with Rust semantics. - This guide covers parameter declaration, return types, call expressions, and more. -keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] ---- - -Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. - -To declare a function the `fn` keyword is used. - -```rust -fn foo() {} -``` - -All parameters in a function must have a type and all types are known at compile time. The parameter -is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. - -```rust -fn foo(x : Field, y : pub Field){} -``` - -The return type of a function can be stated by using the `->` arrow notation. The function below -states that the foo function must return a `Field`. If the function returns no value, then the arrow -is omitted. - -```rust -fn foo(x : Field, y : pub Field) -> Field { - x + y -} -``` - -Note that a `return` keyword is unneeded in this case - the last expression in a function's body is -returned. - -## Call Expressions - -Calling a function in Noir is executed by using the function name and passing in the necessary -arguments. - -Below we show how to call the `foo` function from the `main` function using a call expression: - -```rust -fn main(x : Field, y : Field) { - let z = foo(x); -} - -fn foo(x : Field) -> Field { - x + x -} -``` - -## Methods - -You can define methods in Noir on any struct type in scope. - -```rust -struct MyStruct { - foo: Field, - bar: Field, -} - -impl MyStruct { - fn new(foo: Field) -> MyStruct { - MyStruct { - foo, - bar: 2, - } - } - - fn sum(self) -> Field { - self.foo + self.bar - } -} - -fn main() { - let s = MyStruct::new(40); - constrain s.sum() == 42; -} -``` - -Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as -follows: - -```rust -constrain MyStruct::sum(s) == 42 -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/02_control_flow.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/02_control_flow.md deleted file mode 100644 index 29108dd2634..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/02_control_flow.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Control Flow -description: - Learn how to use loops and if expressions in the Noir programming language. Discover the syntax - and examples for for loops and if-else statements. -keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] ---- - -## Loops - -Noir has one kind of loop: the `for` loop. `for` loops allow you to repeat a block of code multiple -times. - -The following block of code between the braces is run 10 times. - -```rust -for i in 0..10 { - // do something -}; -``` - -## If Expressions - -Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required -for the statement's conditonal to be surrounded by parentheses. - -```rust -let a = 0; -let mut x: u32 = 0; - -if a == 0 { - if a != 0 { - x = 6; - } else { - x = 2; - } -} else { - x = 5; - constrain x == 5; -} -constrain x == 2; -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/03_ops.md deleted file mode 100644 index d08df2094a5..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/03_ops.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Logical Operations -description: - Learn about the supported arithmetic and logical operations in the Noir programming language. - Discover how to perform operations on private input types, integers, and booleans. -keywords: - [ - Noir programming language, - supported operations, - arithmetic operations, - logical operations, - predicate operators, - bitwise operations, - short-circuiting, - backend, - ] ---- - -# Operations - -## Table of Supported Operations - -| Operation | Description | Requirements | -| :-------- | :------------------------------------------------------------: | -------------------------------------: | -| + | Adds two private input types together | Types must be private input | -| - | Subtracts two private input types together | Types must be private input | -| \* | Multiplies two private input types together | Types must be private input | -| / | Divides two private input types together | Types must be private input | -| ^ | XOR two private input types together | Types must be integer | -| & | AND two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | -| >> | Right shift an integer by another integer amount | Types must be integer | -| ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | -| > | returns a bool if one value is more than the other | Upper bound must have a known bit size | -| >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | -| == | returns a bool if one value is equal to the other | Both types must not be constants | -| != | returns a bool if one value is not equal to the other | Both types must not be constants | - -### Predicate Operators - -`<,<=, !=, == , >, >=` are known as predicate/comparison operations because they compare two values. -This differs from the operations such as `+` where the operands are used in _computation_. - -### Bitwise Operations Example - -```rust -fn main(x : Field) { - let y = x as u32; - let z = y & y; -} -``` - -`z` is implicitly constrained to be the result of `y & y`. The `&` operand is used to denote bitwise -`&`. - -> `x & x` would not compile as `x` is a `Field` and not an integer type. - -### Logical Operators - -Noir has no support for the logical operators `||` and `&&`. This is because encoding the -short-circuiting that these operators require can be inefficient for Noir's backend. Instead you can -use the bitwise operators `|` and `&` which operate indentically for booleans, just without the -short-circuiting. - -```rust -let my_val = 5; - -let mut flag = 1; -if (my_val > 6) | (my_val == 0) { - flag = 0; -} -constrain flag == 1; - -if (my_val != 10) & (my_val < 50) { - flag = 0; -} -constrain flag == 0; -``` - -### Shorthand operators - -Noir shorthand operators for most of the above operators, namely `+=, -=, *=, /=, %=, &=, |=, ^=, <<=`, and `>>=`. These allow for more concise syntax. For example: - -```rust -let mut i = 0; -i = i + 1; -``` - -could be written as: - -```rust -let mut i = 0; -i += 1; -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/05_constrain.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/05_constrain.md deleted file mode 100644 index 9ba1e260e8c..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/05_constrain.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Constrain Statements -description: - Learn about the constrain keyword in Noir, which can be used to explicitly constrain the predicate - or comparison expression that follows to be true, and what happens if the expression is false at - runtime. -keywords: - [Noir programming language, constrain statement, predicate expression, comparison expression] ---- - -:::danger - -In versions >=0.5.0 use the [`assert`](./04_assert.md) syntax. The `constrain` statement will be -maintained for some time for backwards compatibility but will be deprecated in the future. - -::: - -Noir includes a special keyword `constrain` which will explicitly constrain the predicate/comparison -expression that follows to be true. If this expression is false at runtime, the program will fail to -be proven. - -### Constrain statement example - -```rust -fn main(x : Field, y : Field) { - constrain x == y; -} -``` - -The above snippet compiles because `==` is a predicate operation. Conversely, the following will not -compile: - -```rust -fn main(x : Field, y : Field) { - constrain x + y; -} -``` - -> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should -> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/06_generics.md deleted file mode 100644 index 4d6c01fd797..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/06_generics.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Generics -description: - Learn how to use Generics in Noir -keywords: [Noir, Rust, generics, functions, structs] ---- - -# Generics - -Generics allow you to use the same functions with multiple different concrete data types. You can -read more about the concept of generics in the Rust documentation -[here](https://doc.rust-lang.org/book/ch10-01-syntax.html). - -Here is a trivial example showing the identity function that supports any type. In Rust, it is -common to refer to the most general type as `T`. We follow the same convention in Noir. - -```rust -fn id(x: T) -> T { - x -} -``` - -## In Structs - -Generics are useful for specifying types in structs. For example, we can specify that a field in a -struct will be of a certain generic type. In this case `value` is of type `T`. - -```rust -struct RepeatedValue { - value: T, - count: comptime Field, -} - -impl RepeatedValue { - fn new(value: T) -> Self { - Self { value, count: 1 } - } - - fn increment(mut repeated: Self) -> Self { - repeated.count += 1; - repeated - } - - fn print(self) { - for _i in 0 .. self.count { - dep::std::println(self.value); - } - } -} - -fn main() { - let mut repeated = RepeatedValue::new("Hello!"); - repeated = repeated.increment(); - repeated.print(); -} -``` - -The `print` function will print `Hello!` an arbitrary number of times, twice in this case. - -If we want to be generic over array lengths (which are type-level integers), we can use numeric -generics. Using these looks just like using regular generics, but these generics can resolve to -integers at compile-time, rather than resolving to types. Here's an example of a struct that is -generic over the size of the array it contains internally: - -```rust -struct BigInt { - limbs: [u32; N], -} - -impl BigInt { - // `N` is in scope of all methods in the impl - fn first(first: BigInt, second: BigInt) -> Self { - constrain first.limbs != second.limbs; - first - - fn second(first: BigInt, second: Self) -> Self { - constrain first.limbs != second.limbs; - second - } -} -``` - -## Calling functions on generic parameters - -Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in -Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also -requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? - -The answer is that we can translate this by passing in the function manually. Here's an example of -implementing array equality in Noir: - -```rust -fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { - if array1.len() != array2.len() { - false - } else { - let mut result = true; - for i in 0 .. array1.len() { - result &= elem_eq(array1[i], array2[i]); - } - result - } -} - -fn main() { - constrain array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b); - - // We can use array_eq even for arrays of structs, as long as we have - // an equality function for these structs we can pass in - let array = [MyStruct::new(), MyStruct::new()]; - constrain array_eq(array, array, MyStruct::eq); -} -``` - -You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/08_comments.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/08_comments.md deleted file mode 100644 index 5b1d9fa38f2..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/08_comments.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Comments -description: - Learn how to write comments in Noir programming language. A comment is a line of code that is - ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments - are supported in Noir. -keywords: [Noir programming language, comments, single-line comments, multi-line comments] ---- - -A comment is a line in your codebase which the compiler ignores, however it can be read by -programmers. - -Here is a single line comment: - -```rust -// This is a comment and is ignored -``` - -`//` is used to tell the compiler to ignore the rest of the line. - -Noir doesn't have multi-line comments, but you can emulate them via using `//` on each line - -```rust -// This is a multi line -// comment, that is ignored by -// the compiler -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/09_distinct.md b/noir/docs/versioned_docs/version-v0.6.0/language_concepts/09_distinct.md deleted file mode 100644 index 03759d4bb4a..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/language_concepts/09_distinct.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Distinct Witnesses ---- - -The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures -that the witnesses being returned as public inputs are all unique. - -The `distinct` keyword is only used for return values on program entry points (usually the `main()` -function). - -When using `disctinct` and `pub` simultaneously, `distinct` comes first. See the example below. - -You can read more about the problem this solves -[here](https://github.com/noir-lang/noir/issues/1183). - -## Example - -Without the `distinct` keyword, the following program - -```rust -fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { - let a = 1; - let b = 1; - [x + 1, y, a, b] -} -``` - -compiles to - -```json -{ - //... - "abi": { - //... - "param_witnesses": { "x": [1], "y": [2] }, - "return_witnesses": [3, 2, 4, 4] - } -} -``` - -Whereas (with the `distinct` keyword) - -```rust -fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { - let a = 1; - let b = 1; - [x + 1, y, a, b] -} -``` - -compiles to - -```json -{ - //... - "abi": { - //... - "param_witnesses": { "x": [1], "y": [2] }, - //... - "return_witnesses": [3, 4, 5, 6] - } -} -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/crates_and_packages.md b/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/crates_and_packages.md deleted file mode 100644 index 34f28a71148..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/crates_and_packages.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Crates and Packages -description: - Learn how to use Crates and Packages in your Noir project -keywords: [Nargo, dependencies, package management, crates, package] ---- - -## Crates - -A crate is the smallest amount of code that the Noir compiler considers at a time. -Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as we’ll see in the coming sections. - -### Crate Types - -A Noir crate can come in one of two forms: a binary crate or a library crate. - -_Binary crates_ are programs which you can compile to an ACIR circuit which you can then create proofs against. Each must have a function called `main` that defines the ACIR circuit which is to be proved. - -_Library crates_ don't have a `main` function and they don't compile down to ACIR. Instead they define functionality intended to be shared with multiple projects, and eventually included in a binary crate. - -### Crate Root - -Every crate has a root, which is the source file that the compiler starts, this is also known as the root module. The Noir compiler does not enforce any conditions on the name of the file which is the crate root, however if you are compiling via Nargo the crate root must be called `lib.nr` or `main.nr` for library or binary crates respectively. - -## Packages - -A Nargo _package_ is a collection of one of more crates that provides a set of functionality. A package must include a Nargo.toml file. - -A package _must_ contain either a library or a binary crate, but not both. - -### Differences from Cargo Packages - -One notable difference between Rust's Cargo and Noir's Nargo is that while Cargo allows a package to contain an unlimited number of binary crates and a single library crate, Nargo currently only allows a package to contain a single crate. - -In future this restriction may be lifted to allow a Nargo package to contain both a binary and library crate or multiple binary crates. diff --git a/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/dependencies.md b/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/dependencies.md deleted file mode 100644 index f3b40eb849b..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/modules_packages_crates/dependencies.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: Managing Dependencies -description: - Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub - and use them easily in your project. -keywords: [Nargo, dependencies, GitHub, package management, versioning] ---- - -Nargo allows you to upload packages to GitHub and use them as dependencies. - -## Specifying a dependency - -Specifying a dependency requires a tag to a specific commit and the git url to the url containing -the package. - -Currently, there are no requirements on the tag contents. If requirements are added, it would follow -semver 2.0 guidelines. - -> Note: Without a `tag` , there would be no versioning and dependencies would change each time you -> compile your project. - -For example, to add the [ecrecover-noir library](https://github.com/colinnielsen/ecrecover-noir) to your project, add it to `Nargo.toml`: - -```toml -# Nargo.toml - -[dependencies] -ecrecover = {tag = "v0.2.0", git = "https://github.com/colinnielsen/ecrecover-noir"} -``` - -## Specifying a local dependency - -You can also specify dependencies that are local to your machine. - -For example, this file structure has a library and binary crate - -``` -├── binary_crate -│   ├── Nargo.toml -│   └── src -│   └── main.nr -└── liba - ├── Nargo.toml - └── src - └── lib.nr -``` - -Inside of the binary crate, you can specify: - -```toml -# Nargo.toml - -[dependencies] -libA = { path = "../liba" } -``` - -## Importing dependencies - -You can import a dependency to a Noir file using the following syntax. For example, to import the -ecrecover-noir library and local liba referenced above: - -```rust -use dep::ecrecover; -use dep::libA; -``` - -You can also import only the specific parts of dependency that you want to use. For example, -demonstrated in the -[elliptic curve example](../standard_library/cryptographic_primitives/ec_primitives#examples), you -can import just the `Point` and the `Curve` that you want to use. - -```rust -use dep::std::ec::tecurve::affine::Curve; -use dep::std::ec::tecurve::affine::Point; -``` - -## Available Libraries - -Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). - -Some libraries that are available today include: - -- BigInt -- "`ecrecover`" -- sparse merkle tree verifier diff --git a/noir/docs/versioned_docs/version-v0.6.0/nargo/01_commands.md b/noir/docs/versioned_docs/version-v0.6.0/nargo/01_commands.md deleted file mode 100644 index f9d9ddb77ff..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/nargo/01_commands.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Commands -description: - Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, - generate Solidity verifier smart contract and compile into JSON file containing ACIR - representation and ABI of circuit. -keywords: - [ - Nargo, - Noir CLI, - Noir Prover, - Noir Verifier, - generate Solidity verifier, - compile JSON file, - ACIR representation, - ABI of circuit, - TypeScript, - ] ---- - -## General options - -``` -Options: - -s, --show-ssa Emit debug information for the intermediate SSA IR - -d, --deny-warnings Quit execution when warnings are emitted - --show-output Display output of `println` statements during tests - -h, --help Print help -``` - -## `nargo help [subcommand]` - -Prints the list of available commands or specific information of a subcommand. - -_Arguments_ - -- `` - The subcommand whose help message to display - -## `nargo check` - -Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output -values of the Noir program respectively. - -## `nargo codegen-verifier` - -Generate a Solidity verifier smart contract for the program. - -## `nargo compile ` - -Compile the program into a JSON build artifact file containing the ACIR representation and the ABI -of the circuit. This build artifact can then be used to generate and verify proofs. - -_Arguments_ - -- `` - The name of the circuit file - -_Options_ - -- `-c, --contracts` - Compile each contract function used within the program - -## `nargo new [path]` - -Creates a new Noir project. - -_Arguments_ - -- `` - Name of the package -- `[path]` - The path to save the new project - -## `nargo execute [witness_name]` - -Runs the Noir program and prints its return value. - -_Arguments_ - -- `[witness_name]` - The name of the witness - -_Usage_ - -The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which -must be filled in. - -To save the witness to file, run the command with a value for the `witness-name` argument. A -`.tr` file will then be saved in the `build` folder. - -> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs -> parsed for your program's ACIR. -> -> This file can be passed along with circuit's ACIR into a TypeScript project for proving and -> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) -> section to learn more. - -## `nargo prove ` - -Creates a proof for the program. - -_Arguments_ - -- `` - The name of the proof - -_Options_ - -- `-v, --verify` - Verify proof after proving - -## `nargo verify ` - -Given a proof and a program, verify whether the proof is valid. - -_Arguments_ - -- `` - The proof to verify - -## `nargo test ` - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. - -See an example on the [testing page](./testing). - -_Arguments_ - -- `` - a pattern to indicate to only run tests with names containing the pattern - -## `nargo gates` - -Counts the occurrences of different gates in circuit - -## `nargo print-acir` - -Print a compiled circuit to stdout such that the ACIR can be inspected. diff --git a/noir/docs/versioned_docs/version-v0.6.0/nargo/02_testing.md b/noir/docs/versioned_docs/version-v0.6.0/nargo/02_testing.md deleted file mode 100644 index 73f91c72bfd..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/nargo/02_testing.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: Testing in Noir -description: Learn how to use Nargo to test your Noir program in a quick and easy way -keywords: [Nargo, testing, Noir, compile, test] ---- - -You can test your Noir programs using Noir circuits. - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. - -For example if you have a program like: - -```rust -fn add(x: u64, y: u64) -> u64 { - x + y -} -#[test] -fn test_add() { - constrain add(2,2) == 4; - constrain add(0,1) == 1; - constrain add(1,0) == 1; -} -``` - -Running `nargo test` will test that the `test_add` function can be executed while satisfying the all -the contraints which allows you to test that add returns the expected values. Test functions can't -have any arguments currently. - -This is much faster compared to testing in Typescript but the only downside is that you can't -explicitly test that a certain set of inputs are invalid. i.e. you can't say that you want -add(2^64-1, 2^64-1) to fail. diff --git a/noir/docs/versioned_docs/version-v0.6.0/nargo/03_solidity_verifier.md b/noir/docs/versioned_docs/version-v0.6.0/nargo/03_solidity_verifier.md deleted file mode 100644 index 69a5607f1b2..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/nargo/03_solidity_verifier.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Solidity Verifier -description: - Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier - contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart - contract. Read more to find out! -keywords: - [ - solidity verifier, - smart contract, - blockchain, - compiler, - plonk_vk.sol, - EVM blockchain, - verifying Noir programs, - proving backend, - Barretenberg, - ] ---- - -For certain applications, it may be desirable to run the verifier as a smart contract instead of on -a local machine. - -Compile a Solidity verifier contract for your Noir program by running: - -```sh -nargo codegen-verifier -``` - -A new `contract` folder would then be generated in your project directory, containing the Solidity -file `plonk_vk.sol`. It can be deployed on any EVM blockchain acting as a verifier smart contract. - -> **Note:** It is possible to compile verifier contracts of Noir programs for other smart contract -> platforms as long as the proving backend supplies an implementation. -> -> Barretenberg, the default proving backend for Nargo, supports compilation of verifier contracts in -> Solidity only for the time being. - -## Verify - -To verify a proof using the Solidity verifier contract, call the `verify` function with the -following signature: - -```solidity -function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) -``` - -### Public Inputs - -:::tip - -A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in -Noir. - -Under the hood, the return value is passed as an input to the circuit and is checked at the end of -the circuit program. - -::: - -The verifier contract uses the output (return) value of a Noir program as a public input. So if you -have the following function - -```rust -fn main( - // Public inputs - pubkey_x: pub Field, - pubkey_y: pub Field, - // Private inputs - priv_key: Field, -) -> pub Field -``` - -then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an -error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. - -In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. - -#### Struct inputs - -Consider the following program: - -```rust -struct Type1 { - val1: Field, - val2: Field, -} - -struct Nested { - t1: Type1, - is_true: bool, -} - -fn main(x: pub Field, nested: pub Nested, y: pub Field) { - //... -} -``` - -Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` - -## Noir for EVM chains - -You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: - -- Optimism -- Arbitrum -- Polygon PoS -- Scroll -- Celo - -Other EVM chains should work, but have not been tested directly by our team. If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. - -### Unsupported chains - -Unfortunately not all "EVM" chains are supported. - -**zkSync** and the **Polygon zkEVM** do *not* currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/array_methods.md b/noir/docs/versioned_docs/version-v0.6.0/standard_library/array_methods.md deleted file mode 100644 index 701590ccf54..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/array_methods.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: Array Methods -description: - Learn about the commonly used methods available for arrays in Noir, including len, sort, fold, - reduce, all, and any. -keywords: [rust, array, methods, len, sort, fold, reduce, all, any] ---- - -# Array - -For convenience, the STD provides some ready-to-use, common methods for arrays[^migrationnote]: - -## len - -Returns the length of an array - -```rust -fn len(_array: [T; N]) -> comptime Field -``` - -example - -```rust -fn main() { - let array = [42, 42]; - constrain array.len() == 2; -} -``` - -## sort - -Returns a new sorted array. The original array remains untouched. Notice that this function will -only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting -logic it uses internally is optimized specifically for these values. If you need a sort function to -sort any type, you should use the function `sort_via` described below. - -```rust -fn sort(_array: [T; N]) -> [T; N] -``` - -example - -```rust -fn main() { - let arr = [42, 32] - let sorted = arr.sort(); - constrain sorted == [32, 42]; -} -``` - -## sort_via - -Sorts the array with a custom comparison function - -```rust -fn sort_via(mut a: [T; N], ordering: fn(T, T) -> bool) -> [T; N] -``` - -example - -```rust -fn main() { - let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); - constrain sorted_ascending == [32, 42]; // verifies - - let sorted_descending = arr.sort_via(|a, b| a > b); - constrain sorted_descending == [32, 42]; // does not verify -} -``` - -## map - -Applies a function to each element of the array, returning a new array containing the mapped elements. - -```rust -fn map(f: fn(T) -> U) -> [U; N] -``` - -example - -```rust -let a = [1, 2, 3]; -let b = a.map(|a| a * 2) // b is now [2, 4, 6] -``` - -## fold - -Applies a function to each element of the array, returning the final accumulated value. The first -parameter is the initial value. - -```rust -fn fold(mut accumulator: U, f: fn(U, T) -> U) -> U -``` - -This is a left fold, so the given function will be applied to the accumulator and first element of -the array, then the second, and so on. For a given call the expected result would be equivalent to: - -```rust -let a1 = [1]; -let a2 = [1, 2]; -let a3 = [1, 2, 3]; - -let f = |a, b| a - b; -a1.fold(10, f) //=> f(10, 1) -a2.fold(10, f) //=> f(f(10, 1), 2) -a3.fold(10, f) //=> f(f(f(10, 1), 2), 3) -``` - -example: - -```rust - -fn main() { - let arr = [2,2,2,2,2] - let folded = arr.fold(0, |a, b| a + b); - constrain folded == 10; -} - -``` - -## reduce - -Same as fold, but uses the first element as starting element. - -```rust -fn reduce(f: fn(T, T) -> T) -> T -``` - -example: - -```rust -fn main() { - let arr = [2,2,2,2,2] - let reduced = arr.reduce(|a, b| a + b); - constrain reduced == 10; -} -``` - -## all - -Returns true if all the elements satisfy the given predicate - -```rust -fn all(predicate: fn(T) -> bool) -> bool -``` - -example: - -```rust -fn main() { - let arr = [2,2,2,2,2] - let all = arr.all(|a| a == 2); - constrain all; -} -``` - -## any - -Returns true if any of the elements satisfy the given predicate - -```rust -fn any(predicate: fn(T) -> bool) -> bool -``` - -example: - -```rust -fn main() { - let arr = [2,2,2,2,5] - let any = arr.any(|a| a == 5); - constrain any; -} - -``` - -[^migrationnote]: - Migration Note: These methods were previously free functions, called via `std::array::len()`. - For the sake of ease of use and readability, these functions are now methods and the old syntax - for them is now deprecated. diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/black_box_fns.md b/noir/docs/versioned_docs/version-v0.6.0/standard_library/black_box_fns.md deleted file mode 100644 index 3063e71c147..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/black_box_fns.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Black Box Functions -description: Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. -keywords: [noir, black box functions] ---- - -Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. - -:::warning - -It is likely that not all backends will support a particular black box function. - -::: - -Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. - -Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: - -```rust -#[foreign(sha256)] -fn sha256(_input : [u8; N]) -> [u8; 32] {} -``` - -## Function list - -Here is a list of the current black box functions that are supported by UltraPlonk: - -- AES -- [SHA256](./cryptographic_primitives/hashes#sha256) -- [Schnorr signature verification](./cryptographic_primitives/schnorr) -- [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Pedersen](./cryptographic_primitives/hashes#pedersen) -- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) -- [ECDSA signature verification](./cryptographic_primitives/ecdsa_secp256k1) -- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) -- [Compute merkle root](./merkle_trees#compute_merkle_root) -- AND -- XOR -- RANGE -- [Keccak256](./cryptographic_primitives/hashes#keccak256) - -Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. - -You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx deleted file mode 100644 index c373f10ca6a..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx +++ /dev/null @@ -1,149 +0,0 @@ ---- -title: Hash methods -description: - Learn about the cryptographic primitives ready to use for any Noir project, including sha256, blake2s, pedersen, mimc_bn254 and mimc -keywords: - [ - cryptographic primitives, - Noir project, - sha256, - blake2s, - pedersen, - mimc_bn254, - mimc, - hash - ] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## sha256 - -Given an array of bytes, returns the resulting sha256 hash. - -```rust -fn sha256(_input : [u8]) -> [u8; 32] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::sha256(x); -} -``` - - - -## blake2s - -Given an array of bytes, returns an array with the Blake2 hash - -```rust -fn blake2s(_input : [u8]) -> [u8; 32] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::blake2s(x); -} -``` - - - -## pedersen - -Given an array of Fields, returns the Pedersen hash. - -```rust -fn pedersen(_input : [Field]) -> [Field; 2] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::pedersen(x); -} -``` - - - -## keccak256 - -Given an array of bytes (`u8`), returns the resulting keccak hash as an array of 32 bytes (`[u8; 32]`). - -```rust -fn keccak256(_input : [u8; N]) -> [u8; 32] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::keccak256(x); -} -``` - - - -## poseidon - -Given an array of Fields, returns a new Field with the Poseidon Hash. Mind that you need to specify how many inputs are there to your Poseidon function. - -```rust -// example for hash_1, hash_2 accepts an array of length 2, etc -fn hash_1(input: [Field; 1]) -> Field -``` - -example: - -```rust -fn main() -{ - let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); - constrain hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a; -} -``` - -## mimc_bn254 and mimc - -`mimc_bn254` is `mimc`, but with hardcoded parameters for the BN254 curve. You can use it by -providing an array of Fields, and it returns a Field with the hash. You can use the `mimc` method if -you're willing to input your own constants: - -```rust -fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field -``` - -otherwise, use the `mimc_bn254` method: - -```rust -fn mimc_bn254(array: [Field; N]) -> Field -``` - -example: - -```rust - -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::mimc_bn254(x); -} -``` - -## hash_to_field - -```rust -fn hash_to_field(_input : [Field; N]) -> Field {} -``` - -Calculates the `blake2s` hash of the inputs and returns the hash modulo the field modulus to return a value which can be represented as a `Field`. - - diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/01_scalar.mdx deleted file mode 100644 index 62265cddb1e..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/01_scalar.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Scalar multiplication -description: - See how you can perform scalar multiplications over a fixed base in Noir -keywords: - [ - cryptographic primitives, - Noir project, - scalar multiplication, - ] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## scalar_mul::fixed_base - -Performs scalar multiplication over the embedded curve whose coordinates are defined by the -configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. - -```rust -fn fixed_base(_input : Field) -> [Field; 2] -``` - -example - -```rust -fn main(x : Field) { - let scal = std::scalar_mul::fixed_base(x); - std::println(scal); -} -``` - - diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx deleted file mode 100644 index c2c6f3ae19a..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Schnorr Signatures -description: Learn how you can verify Schnorr signatures using Noir -keywords: [cryptographic primitives, Noir project, schnorr, signatures] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## schnorr::verify_signature - -Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). - -```rust -fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> Field -``` - -where `_signature` can be generated like so using the npm package -[@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) - -```js -const { BarretenbergWasm } = require('@noir-lang/barretenberg/dest/wasm'); -const { Schnorr } = require('@noir-lang/barretenberg/dest/crypto/schnorr'); - -... - -const barretenberg = await BarretenbergWasm.new(); -const schnorr = new Schnorr(barretenberg); -const pubKey = schnorr.computePublicKey(privateKey); -const message = ... -const signature = Array.from( - schnorr.constructSignature(hash, privateKey).toBuffer() -); - -... -``` - - diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx b/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx deleted file mode 100644 index 88892712fb6..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: ECDSA Verification -description: - Learn about the cryptographic primitives regarding ECDSA over the secp256k1 curve -keywords: - [ - cryptographic primitives, - Noir project, - ecdsa, - secp256k1, - signatures, - ] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## ecdsa_secp256k1::verify_signature - -Verifier for ECDSA Secp256k1 signatures - -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> Field -``` - - diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md deleted file mode 100644 index 2d4ed0f8fae..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: Elliptic Curve Primitives -keywords: [cryptographic primitives, Noir project] ---- - -Data structures and methods on them that allow you to carry out computations involving elliptic -curves over the (mathematical) field corresponding to `Field`. For the field currently at our -disposal, applications would involve a curve embedded in BN254, e.g. the -[Baby Jubjub curve](https://eips.ethereum.org/EIPS/eip-2494). - -## Data structures - -### Elliptic curve configurations - -(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Curve`), i.e. the specific elliptic -curve you want to use, which would be specified using any one of the methods -`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::new` which take the coefficients in the -defining equation together with a generator point as parameters. You can find more detail in the -comments in -[`noir_stdlib/src/ec.nr`](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr), but -the gist of it is that the elliptic curves of interest are usually expressed in one of the standard -forms implemented here (Twisted Edwards, Montgomery and Short Weierstraß), and in addition to that, -you could choose to use `affine` coordinates (Cartesian coordinates - the usual (x,y) - possibly -together with a point at infinity) or `curvegroup` coordinates (some form of projective coordinates -requiring more coordinates but allowing for more efficient implementations of elliptic curve -operations). Conversions between all of these forms are provided, and under the hood these -conversions are done whenever an operation is more efficient in a different representation (or a -mixed coordinate representation is employed). - -### Points - -(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Point`), i.e. points lying on the -elliptic curve. For a curve configuration `c` and a point `p`, it may be checked checked that `p` -does indeed lie on `c` by calling `c.contains(p1)`. - -## Methods - -(given a choice of curve representation, e.g. use `std::ec::tecurve::affine::Curve` and use -`std::ec::tecurve::affine::Point`) - -- The **zero element** is given by `Point::zero()`, and we can verify whether a point `p: Point` is - zero by calling `p.is_zero()`. -- **Equality**: Points `p1: Point` and `p2: Point` may be checked for equality by calling - `p1.eq(p2)`. -- **Addition**: For `c: Curve` and points `p1: Point` and `p2: Point` on the curve, adding these two - points is accomplished by calling `c.add(p1,p2)`. -- **Negation**: For a point `p: Point`, `p.negate()` is its negation. -- **Subtraction**: For `c` and `p1`, `p2` as above, subtracting `p2` from `p1` is accomplished by - calling `c.subtract(p1,p2)`. -- **Scalar multiplication**: For `c` as above, `p: Point` a point on the curve and `n: Field`, - scalar multiplication is given by `c.mul(n,p)`. If instead `n :: [u1; N]`, i.e. `n` is a bit - array, the `bit_mul` method may be used instead: `c.bit_mul(n,p)` -- **Multi-scalar multiplication**: For `c` as above and arrays `n: [Field; N]` and `p: [Point; N]`, - multi-scalar multiplication is given by `c.msm(n,p)`. -- **Coordinate representation conversions**: The `into_group` method converts a point or curve - configuration in the affine representation to one in the CurveGroup representation, and - `into_affine` goes in the other direction. -- **Curve representation conversions**: `tecurve` and `montcurve` curves and points are equivalent - and may be converted between one another by calling `into_montcurve` or `into_tecurve` on their - configurations or points. `swcurve` is more general and a curve c of one of the other two types - may be converted to this representation by calling `c.into_swcurve()`, whereas a point `p` lying - on the curve given by `c` may be mapped to its corresponding `swcurve` point by calling - `c.map_into_swcurve(p)`. -- **Map-to-curve methods**: The Elligator 2 method of mapping a field element `n: Field` into a - `tecurve` or `montcurve` with configuration `c` may be called as `c.elligator2_map(n)`. For all of - the curve configurations, the SWU map-to-curve method may be called as `c.swu_map(z,n)`, where - `z: Field` depends on `Field` and `c` and must be chosen by the user (the conditions it needs to - satisfy are specified in the comments - [here](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr)). - -## Examples - -The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) -illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more -interesting examples in Noir would be: - -Public-key cryptography: Given an elliptic curve and a 'base point' on it, determine the public key -from the private key. This is a matter of using scalar multiplication. In the case of Baby Jubjub, -for example, this code would do: - -```rust -use dep::std::ec::tecurve::affine::Curve; -use dep::std::ec::tecurve::affine::Point; - -fn bjj_pub_key(priv_key: Field) -> Point -{ - - let bjj = Curve::new(168700, 168696, G::new(995203441582195749578291179787384436505546430278305826713579947235728471134,5472060717959818805561601436314318772137091100104008585924551046643952123905)); - - let base_pt = Point::new(5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203); - - bjj.mul(priv_key,base_pt) -} -``` - -This would come in handy in a Merkle proof. - -- EdDSA signature verification: This is a matter of combining these primitives with a suitable hash - function. See - [feat(stdlib): EdDSA sig verification noir#1136](https://github.com/noir-lang/noir/pull/1136) for - the case of Baby Jubjub and the Poseidon hash function. diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx b/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx deleted file mode 100644 index 9fe9b48fbff..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx +++ /dev/null @@ -1,5 +0,0 @@ -:::info - -This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. - -::: \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/field_methods.md b/noir/docs/versioned_docs/version-v0.6.0/standard_library/field_methods.md deleted file mode 100644 index 7cea9846102..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/field_methods.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -title: Field Methods -description: - Learn about common methods on Noir Field, including to_le_bits, to_le_bytes, to_le_radix, - to_be_radix, pow_32, etc, and see code examples. -keywords: - [ - Noir Field, - to_le_bits, - to_le_bytes, - to_le_radix, - to_be_radix, - pow_32, - Little Endian, - Big Endian, - Vector, - Exponent, - ] ---- - -After declaring a Field, you can use these common methods on it: - -## to_le_bits - -Transforms the field into an array of bits, Little Endian. - -```rust -fn to_le_bits(_x : Field, _bit_size: u32) -> [u1; N] -``` - -example: - -```rust -fn main() { - let field = 2 - let bits = field.to_le_bits(32); -} -``` - -## to_be_bits - -Transforms the field into an array of bits, Big Endian. - -```rust -fn to_be_bits(_x : Field, _bit_size: u32) -> [u1; N] -``` - -example: - -```rust -fn main() { - let field = 2 - let bits = field.to_be_bits(32); -} -``` - -## to_le_bytes - -Transforms into an array of bytes, Little Endian - -```rust -fn to_le_bytes(_x : Field, byte_size: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let bytes = field.to_le_bytes(4); -} -``` - -## to_be_bytes - -Transforms into an array of bytes, Big Endian - -```rust -fn to_be_bytes(_x : Field, byte_size: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let bytes = field.to_be_bytes(4); -} -``` - -## to_le_radix - -Decomposes into a vector over the specified base, Little Endian - -```rust -fn to_le_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let radix = field.to_le_radix(256, 4); -} -``` - -## to_be_radix - -Decomposes into a vector over the specified base, Big Endian - -```rust -fn to_be_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let radix = field.to_be_radix(256, 4); -} -``` - -## pow_32 - -Returns the value to the power of the specified exponent - -```rust -fn pow_32(self, exponent: Field) -> Field -``` - -example: - -```rust -fn main() { - let field = 2 - let pow = field.pow_32(4); - constrain pow == 16; -} -``` - -## sgn0 - -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. - -```rust -fn sgn0(self) -> u1 -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/logging.md b/noir/docs/versioned_docs/version-v0.6.0/standard_library/logging.md deleted file mode 100644 index 649d35a3f0b..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/logging.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Logging -description: - Learn how to use the println statement for debugging in Noir with this tutorial. Understand the - basics of logging in Noir and how to implement it in your code. -keywords: - [ - noir logging, - println statement, - debugging in noir, - noir std library, - logging tutorial, - basic logging in noir, - noir logging implementation, - noir debugging techniques, - rust, - ] ---- - -# Logging - -The standard library provides a familiar `println` statement you can use. Despite being a limited -implementation of rust's `println!` macro, this construct can be useful for debugging. - -The `println` statement only works for fields, integers and arrays (including strings). - -```rust -use dep::std; - -fn main(string: pub str<5>) { - let x = 5; - std::println(x) -} - -``` - -To view the output of the `println` statement you need to set the `--show-output` flag. - -``` -$ nargo prove --help -Create proof for this program. The proof is returned as a hex encoded string - -Usage: nargo prove [OPTIONS] [PROOF_NAME] [CIRCUIT_NAME] - -Arguments: - [PROOF_NAME] The name of the proof - [CIRCUIT_NAME] The name of the circuit build files (ACIR, proving and verification keys) - -Options: - -v, --verify Verify proof after proving - -s, --show-ssa Emit debug information for the intermediate SSA IR - -d, --deny-warnings Quit execution when warnings are emitted - --show-output Display output of `println` statements during tests - -h, --help Print help -``` diff --git a/noir/docs/versioned_docs/version-v0.6.0/standard_library/merkle_trees.md b/noir/docs/versioned_docs/version-v0.6.0/standard_library/merkle_trees.md deleted file mode 100644 index fc8909a4795..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/standard_library/merkle_trees.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Merkle Trees -description: - Learn about Merkle Trees in Noir with this tutorial. Explore the basics of computing a merkle root using a proof, with examples. -keywords: - [ - Merkle trees in Noir, - Noir programming language, - check membership, - computing root from leaf, - Noir Merkle tree implementation, - Merkle tree tutorial, - Merkle tree code examples, - Noir libraries, - pedersen hash., - ] ---- - -## compute_merkle_root - -Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](cryptographic_primitives/00_hashes.mdx#pedersen). - -```rust -fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field -``` - -example: - -```rust -/** - // these values are for this example only - index = "0" - priv_key = "0x000000000000000000000000000000000000000000000000000000616c696365" - secret = "0x1929ea3ab8d9106a899386883d9428f8256cfedb3c4f6b66bf4aa4d28a79988f" - note_hash_path = [ - "0x1e61bdae0f027b1b2159e1f9d3f8d00fa668a952dddd822fda80dc745d6f65cc", - "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", - "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" - ] - */ -fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { - - let pubkey = std::scalar_mul::fixed_base(priv_key); - let pubkey_x = pubkey[0]; - let pubkey_y = pubkey[1]; - let note_commitment = std::hash::pedersen([pubkey_x, pubkey_y, secret]); - - let root = std::merkle::compute_merkle_root(note_commitment[0], index, note_hash_path); - std::println(root); -} -``` - -To check merkle tree membership: - -1. Include a merkle root as a program input. -2. Compute the merkle root of a given leaf, index and hash path. -3. Assert the merkle roots are equal. - -For more info about merkle trees, see the Wikipedia [page](https://en.wikipedia.org/wiki/Merkle_tree). \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.6.0/typescript.md b/noir/docs/versioned_docs/version-v0.6.0/typescript.md deleted file mode 100644 index fae002dfd28..00000000000 --- a/noir/docs/versioned_docs/version-v0.6.0/typescript.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -title: Working with TypeScript -description: - Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your - program, specify inputs, initialize a prover & verifier, and prove and verify your program. -keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] ---- - -Interactions with Noir programs can also be performed in TypeScript, which can come in handy when -writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). - -This guide is based on the [noir-starter](https://github.com/signorecello/noir-starter) example. -Please refer to it for an example implementation. - -:::note - -You may find unexpected errors working with some frameworks such as `vite`. This is due to the -nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using -[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick -start. - -::: - -## Setup - -We're assuming you're using ES6 for both browser (for example with React), or nodejs. - -Install [Yarn](https://yarnpkg.com/) or [Node.js](https://nodejs.org/en). Init a new project with -`npm init`. Install Noir dependencies in your project by running: - -```bash -npm i @noir-lang/noir_wasm@0.3.2-fa0e9cff github:noir-lang/barretenberg#39a1547875f941ef6640217a42d8f34972425c97 @noir-lang/aztec_backend@0.1.0-0c3b2f2 -``` - -:::note - -While Noir is in rapid development, some packages could interfere with others. For that reason, you -should use these specified versions. Let us know if for some reason you need to use other ones. - -::: - -As for the circuit, we will use the _Standard Noir Example_ and place it in the `src` folder. Feel -free to use any other, as long as you refactor the below examples accordingly. - -This standard example is a program that multiplies input `x` with input `y` and returns the result: - -```rust -// src/main.nr -fn main(x: u32, y: pub u32) -> pub u32 { - let z = x * y; - z -} -``` - -One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` - -## Imports - -We need some imports, for both the `noir_wasm` library (which will compile the circuit into `wasm` -executables) and `aztec_backend` which is the actual proving backend we will be using. - -We also need to tell the compiler where to find the `.nr` files, so we need to import -`initialiseResolver`. - -```ts -import initNoirWasm, { acir_read_bytes, compile } from '@noir-lang/noir_wasm'; -import initialiseAztecBackend from '@noir-lang/aztec_backend'; -import { initialiseResolver } from '@noir-lang/noir-source-resolver'; -``` - -## Compiling - -We'll go over the code line-by-line later: - -```ts -export const compileCircuit = async () => { - await initNoirWasm(); - - return await fetch(new URL('../src/main.nr', import.meta.url)) - .then(r => r.text()) - .then(code => { - initialiseResolver((id: any) => { - return code; - }); - }) - .then(() => { - try { - const compiled_noir = compile({}); - return compiled_noir; - } catch (e) { - console.log('Error while compiling:', e); - } - }); -}; -``` - -1. First we're calling `initNoirWasm`. This is required on the browser only. -2. We then pass an URL that points to our `main.nr` file, and call `.then` on it so we can get the - actual text of the source code -3. We call `initialiseResolver` returning the source code -4. Finally, we can call the `compile` function - -This function should return us the compiled circuit. - -:::note - -You can use as many files as you need, -[importing them as you would do with Nargo](./modules_packages_crates/dependencies), and you don't -need to set them up in the `src` folder. Just mind the following particularities about -`initialiseResolver`: - -1. The `compile` function expects a `main.nr` file as an entry point. If you need another one, just - pass it as a `entry_point` parameter to `compile`. Check the - [noir starter](https://github.com/signorecello/noir-starter) for an example on multiple files and - a non-default entry point. -2. `initialiseResolver` needs to be synchronous -3. Different frameworks use different ways of fetching files. It's beyond the scope of this guide to - explain why and how, but for reference, - [noir starter](https://github.com/signorecello/noir-starter) uses both Next.js and node.js for - testing. - -Quick tip: an easy way to deal with `initialiseResolver` is just to prepare a -`{fileName: "literally_the_code"}` object beforehand - -::: - -## ACIR - -Noir compiles to two properties: - -1. The ACIR, which is the intermediate language used by backends such as Barretenberg -2. The ABI, which tells you which inputs are to be read - -Let's write a little function that gets us both, initializes the backend, and returns the ACIR as -bytes: - -```ts -export const getAcir = async () => { - const { circuit, abi } = await compileCircuit(); - await initialiseAztecBackend(); - - let acir_bytes = new Uint8Array(Buffer.from(circuit, 'hex')); - return acir_read_bytes(acir_bytes); -}; -``` - -Calling `getAcir()` now should return us the ACIR of the circuit, ready to be used in proofs. - -## Initializing Prover & Verifier - -Prior to proving and verifying, the prover and verifier have to first be initialized by calling -`barretenberg`'s `setup_generic_prover_and_verifier` with your Noir program's ACIR: - -```ts -let [prover, verifier] = await setup_generic_prover_and_verifier(acir); -``` - -This is probably a good time to store this prover and verifier into your state like React Context, -Redux, or others. - -## Proving - -The Noir program can then be executed and proved by calling `barretenberg`'s `create_proof` -function: - -```ts -const proof = await create_proof(prover, acir, abi); -``` - -On the browser, this proof can fail as it requires heavy loads to be run on worker threads. Here's a -quick example of a worker: - -```ts -// worker.ts -onmessage = async event => { - try { - await initializeAztecBackend(); - const { acir, input } = event.data; - const [prover, verifier] = await setup_generic_prover_and_verifier(acir); - const proof = await create_proof(prover, acir, input); - postMessage(proof); - } catch (er) { - postMessage(er); - } finally { - close(); - } -}; -``` - -Which would be called like this, for example: - -```ts -// index.ts -const worker = new Worker(new URL('./worker.ts', import.meta.url)); -worker.onmessage = e => { - if (e.data instanceof Error) { - // oh no! - } else { - // yey! - } -}; -worker.postMessage({ acir, input: { x: 3, y: 4 } }); -``` - -## Verifying - -The `proof` obtained can be verified by calling `barretenberg`'s `verify_proof` function: - -```ts -// 1_mul.ts -const verified = await verify_proof(verifier, proof); -``` - -The function should return `true` if the entire process is working as intended, which can be -asserted if you are writing a test script: - -```ts -expect(verified).eq(true); -``` - -## Verifying with Smart Contract - -Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in -TypeScript as well. - -This could be useful if the Noir program is designed to be decentrally verified and/or make use of -decentralized states and logics that is handled at the smart contract level. - -To generate the verifier smart contract using typescript: - -```ts -// generator.ts -import { writeFileSync } from 'fs'; - -const sc = verifier.SmartContract(); -syncWriteFile('../contracts/plonk_vk.sol', sc); - -function syncWriteFile(filename: string, data: any) { - writeFileSync(join(__dirname, filename), data, { - flag: 'w', - }); -} -``` - -You can then verify a Noir proof using the verifier contract, for example using Hardhat: - -```ts -// verifier.ts -import { ethers } from 'hardhat'; -import { Contract, ContractFactory, utils } from 'ethers'; - -let Verifier: ContractFactory; -let verifierContract: Contract; - -before(async () => { - Verifier = await ethers.getContractFactory('TurboVerifier'); - verifierContract = await Verifier.deploy(); -}); - -// Verify proof -const sc_verified = await verifierContract.verify(proof); -``` diff --git a/noir/docs/versioned_docs/version-v0.7.1/examples/merkle-proof.md b/noir/docs/versioned_docs/version-v0.7.1/examples/merkle-proof.md deleted file mode 100644 index 4696b4a1426..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/examples/merkle-proof.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Merkle Proof Membership -description: - Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a - merkle tree with a specified root, at a given index. -keywords: - [merkle proof, merkle membership proof, Noir, rust, hash function, Pedersen, sha256, merkle tree] ---- - -Let's walk through an example of a merkle membership proof in Noir that proves that a given leaf is -in a merkle tree. - -```rust -use dep::std; - -fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Field) { - let leaf = std::hash::hash_to_field(message); - let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); - assert(merkle_root == root); -} - -``` - -The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen -by the backend. The only requirement is that this hash function can heuristically be used as a -random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen` -instead. - -```rust -let leaf = std::hash::hash_to_field(message); -``` - -The leaf is then passed to a compute_merkle_root function with the root, index and hashpath. The returned root can then be asserted to be the same as the provided root. - -```rust -let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); -assert (merkle_root == root); -``` - -> **Note:** It is possible to re-implement the merkle tree implementation without standard library. -> However, for most usecases, it is enough. In general, the standard library will always opt to be -> as conservative as possible, while striking a balance with efficiency. - -An example, the merkle membership proof, only requires a hash function that has collision -resistance, hence a hash function like Pedersen is allowed, which in most cases is more efficient -than the even more conservative sha256. - -[view an example on the starter repo](https://github.com/noir-lang/noir-examples/blob/3ea09545cabfa464124ec2f3ea8e60c608abe6df/stealthdrop/circuits/src/main.nr#L20) diff --git a/noir/docs/versioned_docs/version-v0.7.1/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.7.1/getting_started/00_nargo_installation.md deleted file mode 100644 index fb86a966e75..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/getting_started/00_nargo_installation.md +++ /dev/null @@ -1,284 +0,0 @@ ---- -title: Nargo Installation -description: - nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, - verifying and more). Learn how to install and use Nargo for your projects with this comprehensive - guide. -keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] ---- - -`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, -verifying and more). - -Alternatively, the interactions can also be performed in [TypeScript](../typescript). - -### UltraPlonk - -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk -version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. - -## Installation - -There are four approaches for installing Nargo: - -- [Option 1: Noirup](#option-1-noirup) -- [Option 2: Binaries](#option-2-binaries) -- [Option 3: Install via Nix](#option-3-install-via-nix) -- [Option 4: Compile from Source](#option-4-compile-from-source) - -Optionally you can also install [Noir VS Code extension] for syntax highlighting. - -### Option 1: Noirup - -If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a -terminal and run: - -```bash -curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash -``` - -Close the terminal, open another one, and run - -```bash -noirup -``` - -Done, you should have the latest version working. You can check with `nargo --version`. - -You can also install nightlies, specific versions -or branches, check out the [noirup repository](https://github.com/noir-lang/noirup) for more -information. - -#### GitHub Actions - -You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as -installing `noirup` and running tests in your GitHub Action `yml` file. - -See the -[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in -this repo containing hash functions in Noir for an example. - -#### Nightly versions - -To install the nightly version of Noir (updated daily) run: - -```bash -noirup -n -``` - -### Option 2: Binaries - -See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous -platform specific binaries. - -#### Step 1 - -Paste and run the following in the terminal to extract and install the binary: - -> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend -> `sudo` and re-run it. - -##### macOS (Apple Silicon) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### macOS (Intel) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### Windows (PowerShell) - -Open PowerShell as Administrator and run: - -```powershell -mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` -Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` -Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` -$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` -$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` -$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` -Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` -$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") -``` - -##### Linux (Bash) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ -echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ -source ~/.bashrc -``` - -#### Step 2 - -Check if the installation was successful by running `nargo --help`. - -> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from -> Finder. Close the new terminal popped up and `nargo` should now be accessible. - -For a successful installation, you should see something similar to the following after running the -command: - -```sh -$ nargo --help - -Noir's package manager - -Usage: nargo - -Commands: - check Checks the constraint system for errors - codegen-verifier Generates a Solidity verifier smart contract for the program - compile Compile the program and its secret execution trace into ACIR format - new Create a new binary project - execute Executes a circuit to calculate its return value - prove Create proof for this program. The proof is returned as a hex encoded string - verify Given a proof and a program, verify whether the proof is valid - test Run the tests for this program - gates Counts the occurrences of different gates in circuit - help Print this message or the help of the given subcommand(s) -``` - -### Option 3: Install via Nix - -Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). - -#### Installing Nix - -For the best experience, please follow these instructions to setup Nix: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -#### Install Nargo into your Nix profile - -1. Use `nix profile` to install Nargo - -```sh -nix profile install github:noir-lang/noir -``` - -### Option 4: Compile from Source - -Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. - -#### Setting up your environment - -For the best experience, please follow these instructions to setup your environment: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -3. Install direnv into your Nix profile by running: - -```sh -nix profile install nixpkgs#direnv -``` - -4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). -5. Restart your shell. - -#### Shell & editor experience - -Now that your environment is set up, you can get to work on the project. - -1. Clone the repository, such as: - -```sh -git clone git@github.com:noir-lang/noir -``` - -> Replacing `noir` with whichever repository you want to work on. - -2. Navigate to the directory: - -```sh -cd noir -``` - -> Replacing `noir` with whichever repository you cloned. - -3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: - -```sh -direnv allow -``` - -4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. - -5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): - -```sh -code . -``` - -6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. - -#### Building and testing - -Assuming you are using `direnv` to populate your environment, building and testing the project can be done -with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. - -If you want to build the entire project in an isolated sandbox, you can use Nix commands: - -1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. -2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. - -#### Without `direnv` - -If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. - -Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! - -## Uninstalling Nargo - -### Noirup - -If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. - -```bash -rm -r ~/.nargo -rm -r ~/nargo -rm -r ~/noir_cache -``` - -### Nix - -If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. - -```bash -rm ~/.nix-profile/bin/nargo -``` - -[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git -[rust]: https://www.rust-lang.org/tools/install -[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir -[homebrew]: https://brew.sh/ -[cmake]: https://cmake.org/install/ -[llvm]: https://llvm.org/docs/GettingStarted.html -[openmp]: https://openmp.llvm.org/ -[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/noir/docs/versioned_docs/version-v0.7.1/getting_started/02_breakdown.md b/noir/docs/versioned_docs/version-v0.7.1/getting_started/02_breakdown.md deleted file mode 100644 index 64d04c4e062..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/getting_started/02_breakdown.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Project Breakdown -description: - Learn about the anatomy of a Nargo project, including the purpose of the Prover and Verifier TOML - files, and how to prove and verify your program. -keywords: - [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] ---- - -This section breaks down our hello world program in section _1.2_. We elaborate on the project -structure and what the `prove` and `verify` commands did in the previous section. - -## Anatomy of a Nargo Project - -Upon creating a new project with `nargo new` and building the in/output files with `nargo check` -commands, you would get a minimal Nargo project of the following structure: - - - src - - Prover.toml - - Verifier.toml - - Nargo.toml - -The source directory _src_ holds the source code for your Noir program. By default only a _main.nr_ -file will be generated within it. - -_Prover.toml_ is used for specifying the input values for executing and proving the program. You can specify `toml` files with different names by using the `--prover-name` or `-p` flags, see the [Prover](#provertoml) section below. Optionally you may specify expected output values for prove-time checking as well. - -_Verifier.toml_ contains public in/output values computed when executing the Noir program. - -_Nargo.toml_ contains the environmental options of your project. - -_proofs_ and _contract_ directories will not be immediately visible until you create a proof or -verifier contract respectively. - -### main.nr - -The _main.nr_ file contains a `main` method, this method is the entry point into your Noir program. - -In our sample program, _main.nr_ looks like this: - -```rust -fn main(x : Field, y : Field) { - assert(x != y); -} -``` - -The parameters `x` and `y` can be seen as the API for the program and must be supplied by the -prover. Since neither `x` nor `y` is marked as public, the verifier does not supply any inputs, when -verifying the proof. - -The prover supplies the values for `x` and `y` in the _Prover.toml_ file. - -As for the program body, `assert` ensures the satisfaction of the condition (e.g. `x != y`) is -constrained by the proof of the execution of said program (i.e. if the condition was not met, the -verifier would reject the proof as an invalid proof). - -### Prover.toml - -The _Prover.toml_ file is a file which the prover uses to supply his witness values(both private and -public). - -In our hello world program the _Prover.toml_ file looks like this: - -```toml -x = "1" -y = "2" -``` - -When the command `nargo prove my_proof` is executed, two processes happen: - -1. Noir creates a proof that `x` which holds the value of `1` and `y` which holds the value of `2` - is not equal. This not equal constraint is due to the line `assert(x != y)`. - -2. Noir creates and stores the proof of this statement in the _proofs_ directory and names the proof - file _my_proof_. Opening this file will display the proof in hex format. - -#### Custom toml files - -You can specify a `toml` file with a different name to use for proving by using the `--prover-name` or `-p` flags. - -This command looks for proof inputs in the default **Prover.toml** and generates proof `p`: - -```bash -nargo prove p -``` - -This command looks for proof inputs in the custom **OtherProver.toml** and generates proof `pp`: - -```bash -nargo prove -p OtherProver pp -``` - -## Verifying a Proof - -When the command `nargo verify my_proof` is executed, two processes happen: - -1. Noir checks in the _proofs_ directory for a file called _my_proof_ - -2. If that file is found, the proof's validity is checked - -> **Note:** The validity of the proof is linked to the current Noir program; if the program is -> changed and the verifier verifies the proof, it will fail because the proof is not valid for the -> _modified_ Noir program. - -In production, the prover and the verifier are usually two separate entities. A prover would -retrieve the necessary inputs, execute the Noir program, generate a proof and pass it to the -verifier. The verifier would then retrieve the public inputs from usually external sources and -verifies the validity of the proof against it. - -Take a private asset transfer as an example: - -A user on browser as the prover would retrieve private inputs (e.g. the user's private key) and -public inputs (e.g. the user's encrypted balance on-chain), compute the transfer, generate a proof -and submit it to the verifier smart contract. - -The verifier contract would then draw the user's encrypted balance directly from the blockchain and -verify the proof submitted against it. If the verification passes, additional functions in the -verifier contract could trigger (e.g. approve the asset transfer). - -Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code. - -In the [next section](language_server), we will explain how to utilize the Noir Language Server. diff --git a/noir/docs/versioned_docs/version-v0.7.1/getting_started/03_language_server.md b/noir/docs/versioned_docs/version-v0.7.1/getting_started/03_language_server.md deleted file mode 100644 index e6f5dfc2faa..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/getting_started/03_language_server.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Language Server -description: - Learn about the Noir Language Server, how to install the components, and configuration that may be required. -keywords: - [Nargo, Language Server, LSP, VSCode, Visual Studio Code] ---- - -This section helps you install and configure the Noir Language Server. - -The Language Server Protocol (LSP) has two components, the [Server](#language-server) and the [Client](#language-client). Below we describe each in the context of Noir. - -## Language Server - -The Server component is provided by the Nargo command line tool that you installed at the beginning of this guide. -As long as Nargo is installed and you've used it to run other commands in this guide, it should be good to go! - -If you'd like to verify that the `nargo lsp` command is available, you can run `nargo --help` and look for `lsp` in the list of commands. If you see it, you're using a version of Noir with LSP support. - -## Language Client - -The Client component is usually an editor plugin that launches the Server. It communicates LSP messages between the editor and the Server. For example, when you save a file, the Client will alert the Server, so it can try to compile the project and report any errors. - -Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). - -### Configuration - -* __Noir: Enable LSP__ - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. -* __Noir: Nargo Flags__ - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. -* __Noir: Nargo Path__ - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. -* __Noir > Trace: Server__ - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/00_data_types.md b/noir/docs/versioned_docs/version-v0.7.1/language_concepts/00_data_types.md deleted file mode 100644 index 6ac494ad404..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/00_data_types.md +++ /dev/null @@ -1,305 +0,0 @@ ---- -title: Data Types -description: - Get a clear understanding of the two categories of Noir data types - primitive types and compound - types. Learn about their characteristics, differences, and how to use them in your Noir - programming. -keywords: - [ - noir, - data types, - primitive types, - compound types, - private types, - public types, - field type, - integer types, - boolean type, - array type, - tuple type, - struct type, - ] ---- - -Every value in Noir has a type, which determines which operations are valid for it. - -All values in Noir are fundamentally composed of `Field` elements. For a more approachable -developing experience, abstractions are added on top to introduce different data types in Noir. - -Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound -types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or -public. - -## Private & Public Types - -A **private value** is known only to the Prover, while a **public value** is known by both the -Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All -primitive types (including individual fields of compound types) in Noir are private by default, and -can be marked public when certain values are intended to be revealed to the Verifier. - -> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once -> the proofs are verified on-chain the values can be considered known to everyone that has access to -> that blockchain. - -Public data types are treated no differently to private types apart from the fact that their values -will be revealed in proofs generated. Simply changing the value of a public type will not change the -circuit (where the same goes for changing values of private types as well). - -_Private values_ are also referred to as _witnesses_ sometimes. - -> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different -> meaning than when applied to a function (e.g. `pub fn foo() {}`). -> -> The former is a visibility modifier for the Prover to interpret if a value should be made known to -> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a -> function should be made accessible to external Noir programs like in other languages. - -### pub Modifier - -All data types in Noir are private by default. Types are explicitly declared as public using the -`pub` modifier: - -```rust -fn main(x : Field, y : pub Field) -> pub Field { - x + y -} -``` - -In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note -that visibility is handled **per variable**, so it is perfectly valid to have one input that is -private and another that is public. - -> **Note:** Public types can only be declared through parameters on `main`. - -## Primitive Types - -A primitive type represents a single value. They can be private or public. - -### Fields - -The field type corresponds to the native field type of the proving backend. - -The size of a Noir field depends on the elliptic curve's finite field for the proving backend -adopted. For example, a field would be a 254-bit integer when paired with the default backend that -spans the Grumpkin curve. - -Fields support integer arithmetic and are often used as the default numeric type in Noir: - -```rust -fn main(x : Field, y : Field) { - let z = x + y; -} -``` - -`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new -private value `z` constrained to be equal to `x + y`. - -If proving efficiency is of priority, fields should be used as a default for solving problems. -Smaller integer types (e.g. `u64`) incur extra range constraints. - -### Integers - -An integer type is a range constrained field type. The Noir frontend currently supports unsigned, -arbitrary-sized integer types. - -An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by -its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of -$\\([0,2^{32}-1]\\)$: - -```rust -fn main(x : Field, y : u32) { - let z = x as u32 + y; -} -``` - -`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` -are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created -will be rejected by the verifier. - -> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) -> sized integer types. - -### Booleans - -The `bool` type in Noir has two possible values: `true` and `false`: - -```rust -fn main() { - let t = true; - let f: bool = false; -} -``` - -> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for -> `false` in _Verifier.toml_. - -The boolean type is most commonly used in conditionals like `if` expressions and `assert` -statements. More about conditionals is covered in the [Control Flow](./control_flow) and -[Assert Function](./assert) sections. - -### Strings - -The string type is a fixed length value defined with `str`. - -You can use strings in `assert()` functions or print them with -`std::println()`. - -```rust -fn main(message : pub str<11>, hex_as_string : str<4>) { - std::println(message); - assert(message == "hello world"); - assert(hex_as_string == "0x41"); -} -``` - -## Compound Types - -A compound type groups together multiple values into one type. Elements within a compound type can -be private or public. - -### Arrays - -An array is one way of grouping together values into one compound type. Array types can be inferred -or explicitly specified via the syntax `[; ]`: - -```rust -fn main(x : Field, y : Field) { - let my_arr = [x, y]; - let your_arr: [Field; 2] = [x, y]; -} -``` - -Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. - -Array elements can be accessed using indexing: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - let first = a[0]; - let second = a[1]; -} -``` - -All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group -a `Field` value and a `u8` value together for example. - -You can write mutable arrays, like: - -```rust -fn main() { - let mut arr = [1, 2, 3, 4, 5]; - assert(arr[0] == 1); - - arr[0] = 42; - assert(arr[0] == 42); -} -``` - -#### Types - -You can create arrays of primitive types or structs. There is not yet support for nested arrays -(arrays of arrays) or arrays of structs that contain arrays. - -### Tuples - -A tuple collects multiple values like an array, but with the added ability to collect values of -different types: - -```rust -fn main() { - let tup: (u8, u64, Field) = (255, 500, 1000); -} -``` - -One way to access tuple elements is via destructuring using pattern matching: - -```rust -fn main() { - let tup = (1, 2); - - let (one, two) = tup; - - let three = one + two; -} -``` - -Another way to access tuple elements is via direct member access, using a period (`.`) followed by -the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to -the second and so on: - -```rust -fn main() { - let tup = (5, 6, 7, 8); - - let five = tup.0; - let eight = tup.3; -} -``` - -### Structs - -A struct also allows for grouping multiple values of different types. Unlike tuples, we can also -name each field. - -> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the -> field type of Noir. - -Defining a struct requires giving it a name and listing each field within as `: ` pairs: - -```rust -struct Animal { - hands: Field, - legs: Field, - eyes: u8, -} -``` - -An instance of a struct can then be created with actual values in `: ` pairs in any -order. Struct fields are accessible using their given names: - -```rust -fn main() { - let legs = 4; - - let dog = Animal { - eyes: 2, - hands: 0, - legs, - }; - - let zero = dog.hands; -} -``` - -Structs can also be destructured in a pattern, binding each field to a new variable: - -```rust -fn main() { - let Animal { hands, legs: feet, eyes } = get_octopus(); - - let ten = hands + feet + eyes as u8; -} - -fn get_octopus() -> Animal { - let octopus = Animal { - hands: 0, - legs: 8, - eyes: 2, - }; - - octopus -} -``` - -The new variables can be bound with names different from the original struct field names, as -showcased in the `legs --> feet` binding in the example above. - -:::note -You can use Structs as inputs to the `main` function, but you can't output them -::: - -### BigInt - -You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.7.1/language_concepts/01_functions.md deleted file mode 100644 index 54c618599d2..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/01_functions.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Functions -description: - Learn how to declare functions and methods in Noir, a programming language with Rust semantics. - This guide covers parameter declaration, return types, call expressions, and more. -keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] ---- - -Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. - -To declare a function the `fn` keyword is used. - -```rust -fn foo() {} -``` - -All parameters in a function must have a type and all types are known at compile time. The parameter -is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. - -```rust -fn foo(x : Field, y : pub Field){} -``` - -The return type of a function can be stated by using the `->` arrow notation. The function below -states that the foo function must return a `Field`. If the function returns no value, then the arrow -is omitted. - -```rust -fn foo(x : Field, y : pub Field) -> Field { - x + y -} -``` - -Note that a `return` keyword is unneeded in this case - the last expression in a function's body is -returned. - -## Call Expressions - -Calling a function in Noir is executed by using the function name and passing in the necessary -arguments. - -Below we show how to call the `foo` function from the `main` function using a call expression: - -```rust -fn main(x : Field, y : Field) { - let z = foo(x); -} - -fn foo(x : Field) -> Field { - x + x -} -``` - -## Methods - -You can define methods in Noir on any struct type in scope. - -```rust -struct MyStruct { - foo: Field, - bar: Field, -} - -impl MyStruct { - fn new(foo: Field) -> MyStruct { - MyStruct { - foo, - bar: 2, - } - } - - fn sum(self) -> Field { - self.foo + self.bar - } -} - -fn main() { - let s = MyStruct::new(40); - assert(s.sum() == 42); -} -``` - -Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as -follows: - -```rust -assert(MyStruct::sum(s) == 42); -``` diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/04_assert.md b/noir/docs/versioned_docs/version-v0.7.1/language_concepts/04_assert.md deleted file mode 100644 index a25a946123d..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/04_assert.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Assert Function -description: - Learn about the assert function in Noir, which can be used to explicitly constrain the predicate or - comparison expression that follows to be true, and what happens if the expression is false at - runtime. -keywords: [Noir programming language, assert statement, predicate expression, comparison expression] ---- - -Noir includes a special `assert` function which will explicitly constrain the predicate/comparison -expression that follows to be true. If this expression is false at runtime, the program will fail to -be proven. - -### Example - -```rust -fn main(x : Field, y : Field) { - assert(x == y); -} -``` - -The above snippet compiles because `==` is a predicate operation. Conversely, the following will not -compile: - -```rust -// INCORRECT - -fn main(x : Field, y : Field) { - assert(x + y); -} -``` - -> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should -> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.7.1/language_concepts/07_mutability.md deleted file mode 100644 index 5631a322659..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/07_mutability.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: Mutability -description: - Learn about mutable variables, constants, and globals in Noir programming language. Discover how - to declare, modify, and use them in your programs. -keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] ---- - -Variables in Noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned -to via an assignment expression. - -```rust -let x = 2; -x = 3; // error: x must be mutable to be assigned to - -let mut y = 3; -let y = 4; // OK -``` - -The `mut` modifier can also apply to patterns: - -```rust -let (a, mut b) = (1, 2); -a = 11; // error: a must be mutable to be assigned to -b = 12; // OK - -let mut (c, d) = (3, 4); -c = 13; // OK -d = 14; // OK - -// etc. -let MyStruct { x: mut y } = MyStruct { x: a } -// y is now in scope -``` - -Note that mutability in noir is local and everything is passed by value, so if a called function -mutates its parameters then the parent function will keep the old value of the parameters. - -```rust -fn main() -> Field { - let x = 3; - helper(x); - x // x is still 3 -} - -fn helper(mut x: i32) { - x = 4; -} -``` - -## Comptime Values - -Comptime values are values that are known at compile-time. This is different to a witness -which changes per proof. If a comptime value that is being used in your program is changed, then your -circuit will also change. - -Comptime is slightly different from Rust's `const`. Namely, it is a bit more flexible in that normal functions can accept comptime parameters. For example, this is used to verify an array index is known at compile-time. Note that the "known at compile-time" here means "known after function inlining is performed while optimizing the program" and not "known during type-checking." - -Below we show how to declare a comptime value: - -```rust -fn main() { - let a: comptime Field = 5; - - // `comptime Field` can also be inferred: - let a = 5; -} -``` - -Note that variables declared as mutable may not be comptime: - -```rust -fn main() { - // error: Cannot mark a comptime type as mutable - let mut a: comptime Field = 5; - - // a inferred as a private Field here - let mut a = 5; -} -``` - -## Globals - -Noir also supports global variables. However, they must be compile-time variables. If `comptime` is -not explicitly written in the type annotation the compiler will implicitly specify the declaration -as compile-time. They can then be used like any other compile-time variable inside functions. The -global type can also be inferred by the compiler entirely. Globals can also be used to specify array -annotations for function parameters and can be imported from submodules. - -```rust -global N: Field = 5; // Same as `global N: comptime Field = 5` - -fn main(x : Field, y : [Field; N]) { - let res = x * N; - - assert(res == y[0]); - - let res2 = x * mysubmodule::N; - assert(res != res2); -} - -mod mysubmodule { - use dep::std; - - global N: Field = 10; - - fn my_helper() -> comptime Field { - let x = N; - x - } -} -``` - -## Why only local mutability? - -Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting -without applying additional overhead to the user. Modeling a mutable reference is not as -straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/08_comments.md b/noir/docs/versioned_docs/version-v0.7.1/language_concepts/08_comments.md deleted file mode 100644 index 5b1d9fa38f2..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/08_comments.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Comments -description: - Learn how to write comments in Noir programming language. A comment is a line of code that is - ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments - are supported in Noir. -keywords: [Noir programming language, comments, single-line comments, multi-line comments] ---- - -A comment is a line in your codebase which the compiler ignores, however it can be read by -programmers. - -Here is a single line comment: - -```rust -// This is a comment and is ignored -``` - -`//` is used to tell the compiler to ignore the rest of the line. - -Noir doesn't have multi-line comments, but you can emulate them via using `//` on each line - -```rust -// This is a multi line -// comment, that is ignored by -// the compiler -``` diff --git a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/09_distinct.md b/noir/docs/versioned_docs/version-v0.7.1/language_concepts/09_distinct.md deleted file mode 100644 index 03759d4bb4a..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/language_concepts/09_distinct.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Distinct Witnesses ---- - -The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures -that the witnesses being returned as public inputs are all unique. - -The `distinct` keyword is only used for return values on program entry points (usually the `main()` -function). - -When using `disctinct` and `pub` simultaneously, `distinct` comes first. See the example below. - -You can read more about the problem this solves -[here](https://github.com/noir-lang/noir/issues/1183). - -## Example - -Without the `distinct` keyword, the following program - -```rust -fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { - let a = 1; - let b = 1; - [x + 1, y, a, b] -} -``` - -compiles to - -```json -{ - //... - "abi": { - //... - "param_witnesses": { "x": [1], "y": [2] }, - "return_witnesses": [3, 2, 4, 4] - } -} -``` - -Whereas (with the `distinct` keyword) - -```rust -fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { - let a = 1; - let b = 1; - [x + 1, y, a, b] -} -``` - -compiles to - -```json -{ - //... - "abi": { - //... - "param_witnesses": { "x": [1], "y": [2] }, - //... - "return_witnesses": [3, 4, 5, 6] - } -} -``` diff --git a/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/modules.md b/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/modules.md deleted file mode 100644 index e429b336511..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/modules_packages_crates/modules.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Understanding Modules -description: - Learn how to organize your files using modules in Noir, following the same convention as Rust's - module system. Examples included. -keywords: [Noir, Rust, modules, organizing files, sub-modules] ---- - -# Modules - -Noir's module system follows the same convention as the _newer_ version of Rust's module system. - -## Purpose of Modules - -Modules are used to organise files. Without modules all of your code would need to live in a single -file. In Noir, the compiler does not automatically scan all of your files to detect modules. This -must be done explicitly by the developer. - -## Examples - -### Importing a module in the crate root - -Filename : `src/main.nr` - -```rust -mod foo; - -fn main() { - foo::hello_world(); -} -``` - -Filename : `src/foo.nr` - -```rust -fn from_foo() {} -``` - -In the above snippet, the crate root is the `src/main.nr` file. The compiler sees the module -declaration `mod foo` which prompts it to look for a foo.nr file. - -Visually this module hierarchy looks like the following : - -``` -crate - ├── main - │ - └── foo - └── from_foo - -``` - -### Importing a module throughout the tree -All modules are accessible from the ``crate::`` namespace. - -``` -crate - ├── bar - ├── foo - └── main - -``` -In the above snippet, if ``bar`` would like to use functions in ``foo``, it can do so by ``use crate::foo::function_name``. - -### Sub-modules - -Filename : `src/main.nr` - -```rust -mod foo; - -fn main() { - foo::from_foo(); -} -``` - -Filename : `src/foo.nr` - -```rust -mod bar; -fn from_foo() {} -``` - -Filename : `src/foo/bar.nr` - -```rust -fn from_bar() {} -``` - -In the above snippet, we have added an extra module to the module tree; `bar`. `bar` is a submodule -of `foo` hence we declare bar in `foo.nr` with `mod bar`. Since `foo` is not the crate root, the -compiler looks for the file associated with the `bar` module in `src/foo/bar.nr` - -Visually the module hierarchy looks as follows: - -``` -crate - ├── main - │ - └── foo - ├── from_foo - └── bar - └── from_bar -``` diff --git a/noir/docs/versioned_docs/version-v0.7.1/nargo/01_commands.md b/noir/docs/versioned_docs/version-v0.7.1/nargo/01_commands.md deleted file mode 100644 index 8efa286b5f0..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/nargo/01_commands.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Commands -description: - Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, - generate Solidity verifier smart contract and compile into JSON file containing ACIR - representation and ABI of circuit. -keywords: - [ - Nargo, - Noir CLI, - Noir Prover, - Noir Verifier, - generate Solidity verifier, - compile JSON file, - ACIR representation, - ABI of circuit, - TypeScript, - ] ---- - -## General options - -``` -Options: - -s, --show-ssa Emit debug information for the intermediate SSA IR - -d, --deny-warnings Quit execution when warnings are emitted - --show-output Display output of `println` statements during tests - -h, --help Print help -``` - -## `nargo help [subcommand]` - -Prints the list of available commands or specific information of a subcommand. - -_Arguments_ - -- `` - The subcommand whose help message to display - -## `nargo check` - -Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output -values of the Noir program respectively. - -## `nargo codegen-verifier` - -Generate a Solidity verifier smart contract for the program. - -## `nargo compile ` - -Compile the program into a JSON build artifact file containing the ACIR representation and the ABI -of the circuit. This build artifact can then be used to generate and verify proofs. - -_Arguments_ - -- `` - The name of the circuit file - -_Options_ - -- `-c, --contracts` - Compile each contract function used within the program -- `--print-acir` - Displays the ACIR for the compiled circuit - -## `nargo new [path]` - -Creates a new Noir project. - -_Arguments_ - -- `` - Name of the package -- `[path]` - The path to save the new project - -## `nargo execute [witness_name]` - -Runs the Noir program and prints its return value. - -_Arguments_ - -- `[witness_name]` - The name of the witness - -_Usage_ - -The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which -must be filled in. - -To save the witness to file, run the command with a value for the `witness-name` argument. A -`.tr` file will then be saved in the `build` folder. - -> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs -> parsed for your program's ACIR. -> -> This file can be passed along with circuit's ACIR into a TypeScript project for proving and -> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) -> section to learn more. - -## `nargo prove ` - -Creates a proof for the program. - -_Arguments_ - -- `` - The name of the proof - -_Options_ - -- `-v, --verify` - Verify proof after proving - -## `nargo verify ` - -Given a proof and a program, verify whether the proof is valid. - -_Arguments_ - -- `` - The proof to verify - -## `nargo test ` - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. - -See an example on the [testing page](./testing). - -_Arguments_ - -- `` - a pattern to indicate to only run tests with names containing the pattern - -## `nargo gates` - -Counts the occurrences of different gates in circuit - -## `nargo lsp` - -Start a long-running Language Server process that communicates over stdin/stdout. -Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/black_box_fns.md b/noir/docs/versioned_docs/version-v0.7.1/standard_library/black_box_fns.md deleted file mode 100644 index 3063e71c147..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/black_box_fns.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Black Box Functions -description: Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. -keywords: [noir, black box functions] ---- - -Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. - -:::warning - -It is likely that not all backends will support a particular black box function. - -::: - -Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. - -Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: - -```rust -#[foreign(sha256)] -fn sha256(_input : [u8; N]) -> [u8; 32] {} -``` - -## Function list - -Here is a list of the current black box functions that are supported by UltraPlonk: - -- AES -- [SHA256](./cryptographic_primitives/hashes#sha256) -- [Schnorr signature verification](./cryptographic_primitives/schnorr) -- [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Pedersen](./cryptographic_primitives/hashes#pedersen) -- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) -- [ECDSA signature verification](./cryptographic_primitives/ecdsa_secp256k1) -- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) -- [Compute merkle root](./merkle_trees#compute_merkle_root) -- AND -- XOR -- RANGE -- [Keccak256](./cryptographic_primitives/hashes#keccak256) - -Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. - -You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives.md b/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives.md deleted file mode 100644 index 2df4f929474..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Cryptographic primitives in Noir -description: - Learn about the cryptographic primitives ready to use for any Noir project -keywords: - [ - cryptographic primitives, - Noir project, - ] ---- - -The Noir team is progressively adding new cryptographic primitives to the standard library. Reach out for news or if you would be interested in adding more of these calculations in Noir. - -Some methods are available thanks to the Aztec backend, not being performed using Noir. When using other backends, these methods may or may not be supplied. diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx deleted file mode 100644 index 31a84cdb753..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx +++ /dev/null @@ -1,146 +0,0 @@ ---- -title: Hash methods -description: - Learn about the cryptographic primitives ready to use for any Noir project, including sha256, - blake2s, pedersen, mimc_bn254 and mimc -keywords: - [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] ---- - -import BlackBoxInfo from './common/_blackbox.mdx'; - -## sha256 - -Given an array of bytes, returns the resulting sha256 hash. - -```rust -fn sha256(_input : [u8]) -> [u8; 32] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::sha256(x); -} -``` - - - -## blake2s - -Given an array of bytes, returns an array with the Blake2 hash - -```rust -fn blake2s(_input : [u8]) -> [u8; 32] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::blake2s(x); -} -``` - - - -## pedersen - -Given an array of Fields, returns the Pedersen hash. - -```rust -fn pedersen(_input : [Field]) -> [Field; 2] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::pedersen(x); -} -``` - - - -## keccak256 - -Given an array of bytes (`u8`), returns the resulting keccak hash as an array of 32 bytes -(`[u8; 32]`). Specify a message_size to hash only the first `message_size` bytes -of the input. - -```rust -fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] -``` - -example: - -```rust -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let message_size = 4; - let hash = std::hash::keccak256(x, message_size); -} -``` - - - -## poseidon - -Given an array of Fields, returns a new Field with the Poseidon Hash. Mind that you need to specify -how many inputs are there to your Poseidon function. - -```rust -// example for hash_1, hash_2 accepts an array of length 2, etc -fn hash_1(input: [Field; 1]) -> Field -``` - -example: - -```rust -fn main() -{ - let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); - assert(hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); -} -``` - -## mimc_bn254 and mimc - -`mimc_bn254` is `mimc`, but with hardcoded parameters for the BN254 curve. You can use it by -providing an array of Fields, and it returns a Field with the hash. You can use the `mimc` method if -you're willing to input your own constants: - -```rust -fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field -``` - -otherwise, use the `mimc_bn254` method: - -```rust -fn mimc_bn254(array: [Field; N]) -> Field -``` - -example: - -```rust - -fn main() { - let x = [163, 117, 178, 149] // some random bytes - let hash = std::hash::mimc_bn254(x); -} -``` - -## hash_to_field - -```rust -fn hash_to_field(_input : [Field; N]) -> Field {} -``` - -Calculates the `blake2s` hash of the inputs and returns the hash modulo the field modulus to return -a value which can be represented as a `Field`. - - diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/01_scalar.mdx deleted file mode 100644 index 62265cddb1e..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/01_scalar.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Scalar multiplication -description: - See how you can perform scalar multiplications over a fixed base in Noir -keywords: - [ - cryptographic primitives, - Noir project, - scalar multiplication, - ] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## scalar_mul::fixed_base - -Performs scalar multiplication over the embedded curve whose coordinates are defined by the -configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. - -```rust -fn fixed_base(_input : Field) -> [Field; 2] -``` - -example - -```rust -fn main(x : Field) { - let scal = std::scalar_mul::fixed_base(x); - std::println(scal); -} -``` - - diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx b/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx deleted file mode 100644 index 0b800fdbc5f..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: ECDSA Verification -description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 curve -keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, signatures] ---- - -import BlackBoxInfo from './common/_blackbox.mdx'; - -## ecdsa_secp256k1::verify_signature - -Verifier for ECDSA Secp256k1 signatures - -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool -``` - - diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md deleted file mode 100644 index 26fb4c09e88..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Elliptic Curve Primitives -keywords: [cryptographic primitives, Noir project] ---- - -Data structures and methods on them that allow you to carry out computations involving elliptic -curves over the (mathematical) field corresponding to `Field`. For the field currently at our -disposal, applications would involve a curve embedded in BN254, e.g. the -[Baby Jubjub curve](https://eips.ethereum.org/EIPS/eip-2494). - -## Data structures - -### Elliptic curve configurations - -(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Curve`), i.e. the specific elliptic -curve you want to use, which would be specified using any one of the methods -`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::new` which take the coefficients in the -defining equation together with a generator point as parameters. You can find more detail in the -comments in -[`noir_stdlib/src/ec.nr`](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr), but -the gist of it is that the elliptic curves of interest are usually expressed in one of the standard -forms implemented here (Twisted Edwards, Montgomery and Short Weierstraß), and in addition to that, -you could choose to use `affine` coordinates (Cartesian coordinates - the usual (x,y) - possibly -together with a point at infinity) or `curvegroup` coordinates (some form of projective coordinates -requiring more coordinates but allowing for more efficient implementations of elliptic curve -operations). Conversions between all of these forms are provided, and under the hood these -conversions are done whenever an operation is more efficient in a different representation (or a -mixed coordinate representation is employed). - -### Points - -(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Point`), i.e. points lying on the -elliptic curve. For a curve configuration `c` and a point `p`, it may be checked checked that `p` -does indeed lie on `c` by calling `c.contains(p1)`. - -## Methods - -(given a choice of curve representation, e.g. use `std::ec::tecurve::affine::Curve` and use -`std::ec::tecurve::affine::Point`) - -- The **zero element** is given by `Point::zero()`, and we can verify whether a point `p: Point` is - zero by calling `p.is_zero()`. -- **Equality**: Points `p1: Point` and `p2: Point` may be checked for equality by calling - `p1.eq(p2)`. -- **Addition**: For `c: Curve` and points `p1: Point` and `p2: Point` on the curve, adding these two - points is accomplished by calling `c.add(p1,p2)`. -- **Negation**: For a point `p: Point`, `p.negate()` is its negation. -- **Subtraction**: For `c` and `p1`, `p2` as above, subtracting `p2` from `p1` is accomplished by - calling `c.subtract(p1,p2)`. -- **Scalar multiplication**: For `c` as above, `p: Point` a point on the curve and `n: Field`, - scalar multiplication is given by `c.mul(n,p)`. If instead `n :: [u1; N]`, i.e. `n` is a bit - array, the `bit_mul` method may be used instead: `c.bit_mul(n,p)` -- **Multi-scalar multiplication**: For `c` as above and arrays `n: [Field; N]` and `p: [Point; N]`, - multi-scalar multiplication is given by `c.msm(n,p)`. -- **Coordinate representation conversions**: The `into_group` method converts a point or curve - configuration in the affine representation to one in the CurveGroup representation, and - `into_affine` goes in the other direction. -- **Curve representation conversions**: `tecurve` and `montcurve` curves and points are equivalent - and may be converted between one another by calling `into_montcurve` or `into_tecurve` on their - configurations or points. `swcurve` is more general and a curve c of one of the other two types - may be converted to this representation by calling `c.into_swcurve()`, whereas a point `p` lying - on the curve given by `c` may be mapped to its corresponding `swcurve` point by calling - `c.map_into_swcurve(p)`. -- **Map-to-curve methods**: The Elligator 2 method of mapping a field element `n: Field` into a - `tecurve` or `montcurve` with configuration `c` may be called as `c.elligator2_map(n)`. For all of - the curve configurations, the SWU map-to-curve method may be called as `c.swu_map(z,n)`, where - `z: Field` depends on `Field` and `c` and must be chosen by the user (the conditions it needs to - satisfy are specified in the comments - [here](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr)). - -## Examples - -The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) -illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more -interesting examples in Noir would be: - -Public-key cryptography: Given an elliptic curve and a 'base point' on it, determine the public key -from the private key. This is a matter of using scalar multiplication. In the case of Baby Jubjub, -for example, this code would do: - -```rust -use dep::std::ec::tecurve::affine::{Curve, Point}; - -fn bjj_pub_key(priv_key: Field) -> Point -{ - - let bjj = Curve::new(168700, 168696, G::new(995203441582195749578291179787384436505546430278305826713579947235728471134,5472060717959818805561601436314318772137091100104008585924551046643952123905)); - - let base_pt = Point::new(5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203); - - bjj.mul(priv_key,base_pt) -} -``` - -This would come in handy in a Merkle proof. - -- EdDSA signature verification: This is a matter of combining these primitives with a suitable hash - function. See - [feat(stdlib): EdDSA sig verification noir#1136](https://github.com/noir-lang/noir/pull/1136) for - the case of Baby Jubjub and the Poseidon hash function. diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx b/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx deleted file mode 100644 index 9fe9b48fbff..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx +++ /dev/null @@ -1,5 +0,0 @@ -:::info - -This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. - -::: \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/logging.md b/noir/docs/versioned_docs/version-v0.7.1/standard_library/logging.md deleted file mode 100644 index 649d35a3f0b..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/logging.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Logging -description: - Learn how to use the println statement for debugging in Noir with this tutorial. Understand the - basics of logging in Noir and how to implement it in your code. -keywords: - [ - noir logging, - println statement, - debugging in noir, - noir std library, - logging tutorial, - basic logging in noir, - noir logging implementation, - noir debugging techniques, - rust, - ] ---- - -# Logging - -The standard library provides a familiar `println` statement you can use. Despite being a limited -implementation of rust's `println!` macro, this construct can be useful for debugging. - -The `println` statement only works for fields, integers and arrays (including strings). - -```rust -use dep::std; - -fn main(string: pub str<5>) { - let x = 5; - std::println(x) -} - -``` - -To view the output of the `println` statement you need to set the `--show-output` flag. - -``` -$ nargo prove --help -Create proof for this program. The proof is returned as a hex encoded string - -Usage: nargo prove [OPTIONS] [PROOF_NAME] [CIRCUIT_NAME] - -Arguments: - [PROOF_NAME] The name of the proof - [CIRCUIT_NAME] The name of the circuit build files (ACIR, proving and verification keys) - -Options: - -v, --verify Verify proof after proving - -s, --show-ssa Emit debug information for the intermediate SSA IR - -d, --deny-warnings Quit execution when warnings are emitted - --show-output Display output of `println` statements during tests - -h, --help Print help -``` diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/merkle_trees.md b/noir/docs/versioned_docs/version-v0.7.1/standard_library/merkle_trees.md deleted file mode 100644 index fc8909a4795..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/merkle_trees.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Merkle Trees -description: - Learn about Merkle Trees in Noir with this tutorial. Explore the basics of computing a merkle root using a proof, with examples. -keywords: - [ - Merkle trees in Noir, - Noir programming language, - check membership, - computing root from leaf, - Noir Merkle tree implementation, - Merkle tree tutorial, - Merkle tree code examples, - Noir libraries, - pedersen hash., - ] ---- - -## compute_merkle_root - -Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](cryptographic_primitives/00_hashes.mdx#pedersen). - -```rust -fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field -``` - -example: - -```rust -/** - // these values are for this example only - index = "0" - priv_key = "0x000000000000000000000000000000000000000000000000000000616c696365" - secret = "0x1929ea3ab8d9106a899386883d9428f8256cfedb3c4f6b66bf4aa4d28a79988f" - note_hash_path = [ - "0x1e61bdae0f027b1b2159e1f9d3f8d00fa668a952dddd822fda80dc745d6f65cc", - "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", - "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" - ] - */ -fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { - - let pubkey = std::scalar_mul::fixed_base(priv_key); - let pubkey_x = pubkey[0]; - let pubkey_y = pubkey[1]; - let note_commitment = std::hash::pedersen([pubkey_x, pubkey_y, secret]); - - let root = std::merkle::compute_merkle_root(note_commitment[0], index, note_hash_path); - std::println(root); -} -``` - -To check merkle tree membership: - -1. Include a merkle root as a program input. -2. Compute the merkle root of a given leaf, index and hash path. -3. Assert the merkle roots are equal. - -For more info about merkle trees, see the Wikipedia [page](https://en.wikipedia.org/wiki/Merkle_tree). \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.7.1/standard_library/zeroed.md b/noir/docs/versioned_docs/version-v0.7.1/standard_library/zeroed.md deleted file mode 100644 index 97dab02dac2..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/standard_library/zeroed.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Zeroed Function -description: - The zeroed function returns a zeroed value of any type. -keywords: - [ - zeroed - ] ---- - -Implements `fn zeroed() -> T` to return a zeroed value of any type. This function is generally unsafe to use as the zeroed bit pattern is not guaranteed to be valid for all types. It can however, be useful in cases when the value is guaranteed not to be used such as in a BoundedVec library implementing a growable vector, up to a certain length, backed by an array. The array can be initialized with zeroed values which are guaranteed to be inaccessible until the vector is pushed to. Similarly, enumerations in noir can be implemented using this method by providing zeroed values for the unused variants. - -You can access the function at `std::unsafe::zeroed`. - -This function currently supports the following types: - -- Field -- Bool -- Uint -- Array -- String -- Tuple -- Function - -Using it on other types could result in unexpected behavior. diff --git a/noir/docs/versioned_docs/version-v0.7.1/typescript.md b/noir/docs/versioned_docs/version-v0.7.1/typescript.md deleted file mode 100644 index fae002dfd28..00000000000 --- a/noir/docs/versioned_docs/version-v0.7.1/typescript.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -title: Working with TypeScript -description: - Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your - program, specify inputs, initialize a prover & verifier, and prove and verify your program. -keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] ---- - -Interactions with Noir programs can also be performed in TypeScript, which can come in handy when -writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). - -This guide is based on the [noir-starter](https://github.com/signorecello/noir-starter) example. -Please refer to it for an example implementation. - -:::note - -You may find unexpected errors working with some frameworks such as `vite`. This is due to the -nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using -[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick -start. - -::: - -## Setup - -We're assuming you're using ES6 for both browser (for example with React), or nodejs. - -Install [Yarn](https://yarnpkg.com/) or [Node.js](https://nodejs.org/en). Init a new project with -`npm init`. Install Noir dependencies in your project by running: - -```bash -npm i @noir-lang/noir_wasm@0.3.2-fa0e9cff github:noir-lang/barretenberg#39a1547875f941ef6640217a42d8f34972425c97 @noir-lang/aztec_backend@0.1.0-0c3b2f2 -``` - -:::note - -While Noir is in rapid development, some packages could interfere with others. For that reason, you -should use these specified versions. Let us know if for some reason you need to use other ones. - -::: - -As for the circuit, we will use the _Standard Noir Example_ and place it in the `src` folder. Feel -free to use any other, as long as you refactor the below examples accordingly. - -This standard example is a program that multiplies input `x` with input `y` and returns the result: - -```rust -// src/main.nr -fn main(x: u32, y: pub u32) -> pub u32 { - let z = x * y; - z -} -``` - -One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` - -## Imports - -We need some imports, for both the `noir_wasm` library (which will compile the circuit into `wasm` -executables) and `aztec_backend` which is the actual proving backend we will be using. - -We also need to tell the compiler where to find the `.nr` files, so we need to import -`initialiseResolver`. - -```ts -import initNoirWasm, { acir_read_bytes, compile } from '@noir-lang/noir_wasm'; -import initialiseAztecBackend from '@noir-lang/aztec_backend'; -import { initialiseResolver } from '@noir-lang/noir-source-resolver'; -``` - -## Compiling - -We'll go over the code line-by-line later: - -```ts -export const compileCircuit = async () => { - await initNoirWasm(); - - return await fetch(new URL('../src/main.nr', import.meta.url)) - .then(r => r.text()) - .then(code => { - initialiseResolver((id: any) => { - return code; - }); - }) - .then(() => { - try { - const compiled_noir = compile({}); - return compiled_noir; - } catch (e) { - console.log('Error while compiling:', e); - } - }); -}; -``` - -1. First we're calling `initNoirWasm`. This is required on the browser only. -2. We then pass an URL that points to our `main.nr` file, and call `.then` on it so we can get the - actual text of the source code -3. We call `initialiseResolver` returning the source code -4. Finally, we can call the `compile` function - -This function should return us the compiled circuit. - -:::note - -You can use as many files as you need, -[importing them as you would do with Nargo](./modules_packages_crates/dependencies), and you don't -need to set them up in the `src` folder. Just mind the following particularities about -`initialiseResolver`: - -1. The `compile` function expects a `main.nr` file as an entry point. If you need another one, just - pass it as a `entry_point` parameter to `compile`. Check the - [noir starter](https://github.com/signorecello/noir-starter) for an example on multiple files and - a non-default entry point. -2. `initialiseResolver` needs to be synchronous -3. Different frameworks use different ways of fetching files. It's beyond the scope of this guide to - explain why and how, but for reference, - [noir starter](https://github.com/signorecello/noir-starter) uses both Next.js and node.js for - testing. - -Quick tip: an easy way to deal with `initialiseResolver` is just to prepare a -`{fileName: "literally_the_code"}` object beforehand - -::: - -## ACIR - -Noir compiles to two properties: - -1. The ACIR, which is the intermediate language used by backends such as Barretenberg -2. The ABI, which tells you which inputs are to be read - -Let's write a little function that gets us both, initializes the backend, and returns the ACIR as -bytes: - -```ts -export const getAcir = async () => { - const { circuit, abi } = await compileCircuit(); - await initialiseAztecBackend(); - - let acir_bytes = new Uint8Array(Buffer.from(circuit, 'hex')); - return acir_read_bytes(acir_bytes); -}; -``` - -Calling `getAcir()` now should return us the ACIR of the circuit, ready to be used in proofs. - -## Initializing Prover & Verifier - -Prior to proving and verifying, the prover and verifier have to first be initialized by calling -`barretenberg`'s `setup_generic_prover_and_verifier` with your Noir program's ACIR: - -```ts -let [prover, verifier] = await setup_generic_prover_and_verifier(acir); -``` - -This is probably a good time to store this prover and verifier into your state like React Context, -Redux, or others. - -## Proving - -The Noir program can then be executed and proved by calling `barretenberg`'s `create_proof` -function: - -```ts -const proof = await create_proof(prover, acir, abi); -``` - -On the browser, this proof can fail as it requires heavy loads to be run on worker threads. Here's a -quick example of a worker: - -```ts -// worker.ts -onmessage = async event => { - try { - await initializeAztecBackend(); - const { acir, input } = event.data; - const [prover, verifier] = await setup_generic_prover_and_verifier(acir); - const proof = await create_proof(prover, acir, input); - postMessage(proof); - } catch (er) { - postMessage(er); - } finally { - close(); - } -}; -``` - -Which would be called like this, for example: - -```ts -// index.ts -const worker = new Worker(new URL('./worker.ts', import.meta.url)); -worker.onmessage = e => { - if (e.data instanceof Error) { - // oh no! - } else { - // yey! - } -}; -worker.postMessage({ acir, input: { x: 3, y: 4 } }); -``` - -## Verifying - -The `proof` obtained can be verified by calling `barretenberg`'s `verify_proof` function: - -```ts -// 1_mul.ts -const verified = await verify_proof(verifier, proof); -``` - -The function should return `true` if the entire process is working as intended, which can be -asserted if you are writing a test script: - -```ts -expect(verified).eq(true); -``` - -## Verifying with Smart Contract - -Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in -TypeScript as well. - -This could be useful if the Noir program is designed to be decentrally verified and/or make use of -decentralized states and logics that is handled at the smart contract level. - -To generate the verifier smart contract using typescript: - -```ts -// generator.ts -import { writeFileSync } from 'fs'; - -const sc = verifier.SmartContract(); -syncWriteFile('../contracts/plonk_vk.sol', sc); - -function syncWriteFile(filename: string, data: any) { - writeFileSync(join(__dirname, filename), data, { - flag: 'w', - }); -} -``` - -You can then verify a Noir proof using the verifier contract, for example using Hardhat: - -```ts -// verifier.ts -import { ethers } from 'hardhat'; -import { Contract, ContractFactory, utils } from 'ethers'; - -let Verifier: ContractFactory; -let verifierContract: Contract; - -before(async () => { - Verifier = await ethers.getContractFactory('TurboVerifier'); - verifierContract = await Verifier.deploy(); -}); - -// Verify proof -const sc_verified = await verifierContract.verify(proof); -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/getting_started/00_nargo_installation.md b/noir/docs/versioned_docs/version-v0.9.0/getting_started/00_nargo_installation.md deleted file mode 100644 index de30869732d..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/getting_started/00_nargo_installation.md +++ /dev/null @@ -1,285 +0,0 @@ ---- -title: Nargo Installation -description: - nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, - verifying and more). Learn how to install and use Nargo for your projects with this comprehensive - guide. -keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] ---- - -`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, -verifying and more). - -Alternatively, the interactions can also be performed in [TypeScript](../typescript). - -### UltraPlonk - -Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk -version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. - -## Installation - -There are four approaches for installing Nargo: - -- [Option 1: Noirup](#option-1-noirup) -- [Option 2: Binaries](#option-2-binaries) -- [Option 3: Install via Nix](#option-3-install-via-nix) -- [Option 4: Compile from Source](#option-4-compile-from-source) - -Optionally you can also install [Noir VS Code extension] for syntax highlighting. - -### Option 1: Noirup - -If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a -terminal and run: - -```bash -curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash -``` - -Close the terminal, open another one, and run - -```bash -noirup -``` - -Done, you should have the latest version working. You can check with `nargo --version`. - -You can also install nightlies, specific versions -or branches, check out the [noirup repository](https://github.com/noir-lang/noirup) for more -information. - -#### GitHub Actions - -You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as -installing `noirup` and running tests in your GitHub Action `yml` file. - -See the -[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in -this repo containing hash functions in Noir for an example. - -#### Nightly versions - -To install the nightly version of Noir (updated daily) run: - -```bash -noirup -n -``` - -### Option 2: Binaries - -See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous -platform specific binaries. - -#### Step 1 - -Paste and run the following in the terminal to extract and install the binary: - -> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend -> `sudo` and re-run it. - -##### macOS (Apple Silicon) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### macOS (Intel) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ -echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ -source ~/.zshrc -``` - -##### Windows (PowerShell) - -Open PowerShell as Administrator and run: - -```powershell -mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` -Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` -Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` -$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` -$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` -$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` -Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` -$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") -``` - -##### Linux (Bash) - -```bash -mkdir -p $HOME/.nargo/bin && \ -curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ -tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ -echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ -source ~/.bashrc -``` - -#### Step 2 - -Check if the installation was successful by running `nargo --help`. - -> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from -> Finder. Close the new terminal popped up and `nargo` should now be accessible. - -For a successful installation, you should see something similar to the following after running the -command: - -```sh -$ nargo --help - -Noir's package manager - -Usage: nargo - -Commands: - check Checks the constraint system for errors - codegen-verifier Generates a Solidity verifier smart contract for the program - compile Compile the program and its secret execution trace into ACIR format - new Create a new binary project - execute Executes a circuit to calculate its return value - prove Create proof for this program. The proof is returned as a hex encoded string - verify Given a proof and a program, verify whether the proof is valid - test Run the tests for this program - gates Counts the occurrences of different gates in circuit - help Print this message or the help of the given subcommand(s) -``` - -### Option 3: Install via Nix - -Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). - -#### Installing Nix - -For the best experience, please follow these instructions to setup Nix: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -#### Install Nargo into your Nix profile - -1. Use `nix profile` to install Nargo - -```sh -nix profile install github:noir-lang/noir -``` - -### Option 4: Compile from Source - -Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. - -#### Setting up your environment - -For the best experience, please follow these instructions to setup your environment: - -1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. -2. Create the file `~/.config/nix/nix.conf` with the contents: - -```ini -experimental-features = nix-command -extra-experimental-features = flakes -``` - -3. Install direnv into your Nix profile by running: - -```sh -nix profile install nixpkgs#direnv -``` - -4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). - 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. -5. Restart your shell. - -#### Shell & editor experience - -Now that your environment is set up, you can get to work on the project. - -1. Clone the repository, such as: - -```sh -git clone git@github.com:noir-lang/noir -``` - -> Replacing `noir` with whichever repository you want to work on. - -2. Navigate to the directory: - -```sh -cd noir -``` - -> Replacing `noir` with whichever repository you cloned. - -3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: - -```sh -direnv allow -``` - -4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. - -5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): - -```sh -code . -``` - -6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. - -#### Building and testing - -Assuming you are using `direnv` to populate your environment, building and testing the project can be done -with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. - -If you want to build the entire project in an isolated sandbox, you can use Nix commands: - -1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. -2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. - -#### Without `direnv` - -If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. - -Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! - -## Uninstalling Nargo - -### Noirup - -If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. - -```bash -rm -r ~/.nargo -rm -r ~/nargo -rm -r ~/noir_cache -``` - -### Nix - -If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. - -```bash -rm ~/.nix-profile/bin/nargo -``` - -[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git -[rust]: https://www.rust-lang.org/tools/install -[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir -[homebrew]: https://brew.sh/ -[cmake]: https://cmake.org/install/ -[llvm]: https://llvm.org/docs/GettingStarted.html -[openmp]: https://openmp.llvm.org/ -[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/noir/docs/versioned_docs/version-v0.9.0/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.9.0/getting_started/01_hello_world.md deleted file mode 100644 index 0f21ad45569..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/getting_started/01_hello_world.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: Create A Project -description: - Learn how to create and verify your first Noir program using Nargo, a programming language for - zero-knowledge proofs. -keywords: - [ - Nargo, - Noir, - zero-knowledge proofs, - programming language, - create Noir program, - verify Noir program, - step-by-step guide, - ] ---- - -Now that we have installed Nargo, it is time to make our first hello world program! - -## Create a Project Directory - -Noir code can live anywhere on your computer. Let us create a _projects_ folder in the home -directory to house our Noir programs. - -For Linux, macOS, and Windows PowerShell, create the directory and change directory into it by -running: - -```sh -mkdir ~/projects -cd ~/projects -``` - -For Windows CMD, run: - -```sh -> mkdir "%USERPROFILE%\projects" -> cd /d "%USERPROFILE%\projects" -``` - -## Create Our First Nargo Project - -Now that we are in the projects directory, create a new Nargo project by running: - -```sh -nargo new hello_world -``` - -> **Note:** `hello_world` can be any arbitrary project name, we are simply using `hello_world` for -> demonstration. -> -> In production, the common practice is to name the project folder as `circuits` for better -> identifiability when sitting alongside other folders in the codebase (e.g. `contracts`, `scripts`, -> `test`). - -A `hello_world` folder would be created. Similar to Rust, the folder houses _src/main.nr_ and -_Nargo.toml_ that contains the source code and environmental options of your Noir program -respectively. - -### Intro to Noir Syntax - -Let us take a closer look at _main.nr_. The default _main.nr_ generated should look like this: - -```rust -fn main(x : Field, y : pub Field) { - assert(x != y); -} -``` - -The first line of the program specifies the program's inputs: - -```rust -x : Field, y : pub Field -``` - -Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the -keyword `pub` (e.g. `y`). To learn more about private and public values, check the -[Data Types](../language_concepts/data_types) section. - -The next line of the program specifies its body: - -```rust -assert(x != y); -``` - -The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. - -For more Noir syntax, check the [Language Concepts](../language_concepts/comments) chapter. - -## Build In/Output Files - -Change directory into _hello_world_ and build in/output files for your Noir program by running: - -```sh -cd hello_world -nargo check -``` - -Two additional files would be generated in your project directory: - -_Prover.toml_ houses input values, and _Verifier.toml_ houses public values. - -## Prove Our Noir Program - -Now that the project is set up, we can create a proof of correct execution on our Noir program. - -Fill in input values for execution in the _Prover.toml_ file. For example: - -```toml -x = "1" -y = "2" -``` - -Prove the valid execution of your Noir program with your preferred proof name, for example `p`: - -```sh -nargo prove p -``` - -A new folder _proofs_ would then be generated in your project directory, containing the proof file -`p.proof`. - -The _Verifier.toml_ file would also be updated with the public values computed from program -execution (in this case the value of `y`): - -```toml -y = "0x0000000000000000000000000000000000000000000000000000000000000002" -``` - -> **Note:** Values in _Verifier.toml_ are computed as 32-byte hex values. - -## Verify Our Noir Program - -Once a proof is generated, we can verify correct execution of our Noir program by verifying the -proof file. - -Verify your proof of name `p` by running: - -```sh -nargo verify p -``` - -The verification will complete in silence if it is successful. If it fails, it will log the -corresponding error instead. - -Congratulations, you have now created and verified a proof for your very first Noir program! - -In the [next section](breakdown), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.9.0/index.md b/noir/docs/versioned_docs/version-v0.9.0/index.md deleted file mode 100644 index e56b24bccd8..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/index.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Introducing Noir -description: - Learn about the public alpha release of Noir, a domain specific language heavily influenced by - Rust that compiles to an intermediate language which can be compiled to an arithmetic circuit or a - rank-1 constraint system. -keywords: - [ - Noir, - Domain Specific Language, - Rust, - Intermediate Language, - Arithmetic Circuit, - Rank-1 Constraint System, - Ethereum Developers, - Protocol Developers, - Blockchain Developers, - Proving System, - Smart Contract Language, - ] -slug: / ---- - -This version of the book is being released with the public alpha. There will be a lot of features -that are missing in this version, however the syntax and the feel of the language will mostly be -completed. - -## What is Noir? - -Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. - -It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. - -## Who is Noir for? - -Noir can be used for a variety of purposes. - -### Solidity Developers - -Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will -be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create -a verifier contract. - -### Protocol Developers - -As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for -your stack, or maybe you simply want to use a different proving system. Since Noir does not compile -to a specific proof system, it is possible for protocol developers to replace the PLONK-based -proving system with a different proving system altogether. - -### Blockchain developers - -As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the -proving system and smart contract language has been pre-defined). In order for you to use Noir in -your blockchain, a proving system backend and a smart contract interface -must be implemented for it. - -## What's new about Noir? - -Noir is simple and flexible in its design, as it does not compile immediately to a fixed -NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled -to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). - -This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. - -## Current Features - -Compiler: - -- Module System -- For expressions -- Arrays -- Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] -- Unsigned integers -- If statements -- Structures and Tuples -- Generics - -ACIR Supported OPCODES: - -- Sha256 -- Blake2s -- Schnorr signature verification -- MerkleMembership -- Pedersen -- HashToField - -## Libraries - -Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). - -Some libraries that are available today include: - -- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library -- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) -- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers -- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address -- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees -- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir -- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers - -See the section on [dependencies](./modules_packages_crates/dependencies) for more information. diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/00_data_types.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/00_data_types.md deleted file mode 100644 index abbadca86be..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/00_data_types.md +++ /dev/null @@ -1,405 +0,0 @@ ---- -title: Data Types -description: - Get a clear understanding of the two categories of Noir data types - primitive types and compound - types. Learn about their characteristics, differences, and how to use them in your Noir - programming. -keywords: - [ - noir, - data types, - primitive types, - compound types, - private types, - public types, - field type, - integer types, - boolean type, - array type, - tuple type, - struct type, - ] ---- - -Every value in Noir has a type, which determines which operations are valid for it. - -All values in Noir are fundamentally composed of `Field` elements. For a more approachable -developing experience, abstractions are added on top to introduce different data types in Noir. - -Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound -types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or -public. - -## Private & Public Types - -A **private value** is known only to the Prover, while a **public value** is known by both the -Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All -primitive types (including individual fields of compound types) in Noir are private by default, and -can be marked public when certain values are intended to be revealed to the Verifier. - -> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once -> the proofs are verified on-chain the values can be considered known to everyone that has access to -> that blockchain. - -Public data types are treated no differently to private types apart from the fact that their values -will be revealed in proofs generated. Simply changing the value of a public type will not change the -circuit (where the same goes for changing values of private types as well). - -_Private values_ are also referred to as _witnesses_ sometimes. - -> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different -> meaning than when applied to a function (e.g. `pub fn foo() {}`). -> -> The former is a visibility modifier for the Prover to interpret if a value should be made known to -> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a -> function should be made accessible to external Noir programs like in other languages. - -### pub Modifier - -All data types in Noir are private by default. Types are explicitly declared as public using the -`pub` modifier: - -```rust -fn main(x : Field, y : pub Field) -> pub Field { - x + y -} -``` - -In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note -that visibility is handled **per variable**, so it is perfectly valid to have one input that is -private and another that is public. - -> **Note:** Public types can only be declared through parameters on `main`. - -## Primitive Types - -A primitive type represents a single value. They can be private or public. - -### Fields - -The field type corresponds to the native field type of the proving backend. - -The size of a Noir field depends on the elliptic curve's finite field for the proving backend -adopted. For example, a field would be a 254-bit integer when paired with the default backend that -spans the Grumpkin curve. - -Fields support integer arithmetic and are often used as the default numeric type in Noir: - -```rust -fn main(x : Field, y : Field) { - let z = x + y; -} -``` - -`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new -private value `z` constrained to be equal to `x + y`. - -If proving efficiency is of priority, fields should be used as a default for solving problems. -Smaller integer types (e.g. `u64`) incur extra range constraints. - -### Integers - -An integer type is a range constrained field type. The Noir frontend currently supports unsigned, -arbitrary-sized integer types. - -An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by -its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of -$\\([0,2^{32}-1]\\)$: - -```rust -fn main(x : Field, y : u32) { - let z = x as u32 + y; -} -``` - -`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` -are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created -will be rejected by the verifier. - -> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) -> sized integer types. - -### Booleans - -The `bool` type in Noir has two possible values: `true` and `false`: - -```rust -fn main() { - let t = true; - let f: bool = false; -} -``` - -> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for -> `false` in _Verifier.toml_. - -The boolean type is most commonly used in conditionals like `if` expressions and `assert` -statements. More about conditionals is covered in the [Control Flow](./control_flow) and -[Assert Function](./assert) sections. - -### Strings - -The string type is a fixed length value defined with `str`. - -You can use strings in `assert()` functions or print them with -`std::println()`. - -```rust -fn main(message : pub str<11>, hex_as_string : str<4>) { - std::println(message); - assert(message == "hello world"); - assert(hex_as_string == "0x41"); -} -``` - -## Compound Types - -A compound type groups together multiple values into one type. Elements within a compound type can -be private or public. - -### Arrays - -An array is one way of grouping together values into one compound type. Array types can be inferred -or explicitly specified via the syntax `[; ]`: - -```rust -fn main(x : Field, y : Field) { - let my_arr = [x, y]; - let your_arr: [Field; 2] = [x, y]; -} -``` - -Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. - -Array elements can be accessed using indexing: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - let first = a[0]; - let second = a[1]; -} -``` - -All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group -a `Field` value and a `u8` value together for example. - -You can write mutable arrays, like: - -```rust -fn main() { - let mut arr = [1, 2, 3, 4, 5]; - assert(arr[0] == 1); - - arr[0] = 42; - assert(arr[0] == 42); -} -``` - -You can instantiate a new array of a fixed size with the same value repeated for each element. The following example instantiates an array of length 32 where each element is of type Field and has the value 0. - -```rust -let array: [Field; 32] = [0; 32]; -``` - -#### Types - -You can create arrays of primitive types or structs. There is not yet support for nested arrays -(arrays of arrays) or arrays of structs that contain arrays. - -### Slices - -:::caution - -This feature is experimental. You should expect it to change in future versions, -cause unexpected behavior, or simply not work at all. - -::: - -A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size. - -Slices are part of the [noir standard library](../standard_library/slice_methods) so you need to import the respective module in order to work with it. For example: - -```rust -use dep::std::slice; - -fn main() -> pub Field { - let mut slice: [Field] = [0; 2]; - - let mut new_slice = slice.push_back(6); - new_slice.len() -} -``` - -### Vectors - -:::caution - -This feature is experimental. You should expect it to change in future versions, -cause unexpected behavior, or simply not work at all. - -::: - -A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. - -Example: - -```rust -use std::collections::vec::Vec; - -let mut vector: Vec = Vec::new(); -for i in 0..5 { - vector.push(i); -} -assert(vector.len() == 5); -``` - -### Tuples - -A tuple collects multiple values like an array, but with the added ability to collect values of -different types: - -```rust -fn main() { - let tup: (u8, u64, Field) = (255, 500, 1000); -} -``` - -One way to access tuple elements is via destructuring using pattern matching: - -```rust -fn main() { - let tup = (1, 2); - - let (one, two) = tup; - - let three = one + two; -} -``` - -Another way to access tuple elements is via direct member access, using a period (`.`) followed by -the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to -the second and so on: - -```rust -fn main() { - let tup = (5, 6, 7, 8); - - let five = tup.0; - let eight = tup.3; -} -``` - -### Structs - -A struct also allows for grouping multiple values of different types. Unlike tuples, we can also -name each field. - -> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the -> field type of Noir. - -Defining a struct requires giving it a name and listing each field within as `: ` pairs: - -```rust -struct Animal { - hands: Field, - legs: Field, - eyes: u8, -} -``` - -An instance of a struct can then be created with actual values in `: ` pairs in any -order. Struct fields are accessible using their given names: - -```rust -fn main() { - let legs = 4; - - let dog = Animal { - eyes: 2, - hands: 0, - legs, - }; - - let zero = dog.hands; -} -``` - -Structs can also be destructured in a pattern, binding each field to a new variable: - -```rust -fn main() { - let Animal { hands, legs: feet, eyes } = get_octopus(); - - let ten = hands + feet + eyes as u8; -} - -fn get_octopus() -> Animal { - let octopus = Animal { - hands: 0, - legs: 8, - eyes: 2, - }; - - octopus -} -``` - -The new variables can be bound with names different from the original struct field names, as -showcased in the `legs --> feet` binding in the example above. - -:::note -You can use Structs as inputs to the `main` function, but you can't output them -::: - -### Type Aliases - -A type alias is a new name for an existing type. Type aliases are declared with the keyword `type`: - -```rust -type Id = u8; - -fn main() { - let id: Id = 1; - let zero: u8 = 0; - assert(zero + 1 == id); -} -``` - -Type aliases can also be used with [generics](./06_generics.md): - -```rust -type Id = Size; - -fn main() { - let id: Id = 1; - let zero: u32 = 0; - assert(zero + 1 == id); -} -``` - -### BigInt - -You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. - -## References - -Noir supports first-class references. References are a bit like pointers: they point to a specific address that can be followed to access the data stored at that address. You can use Rust-like syntax to use pointers in Noir: the `&` operator references the variable, the `*` operator dereferences it. - -Example: - -```rust -fn main() { - let mut x = 2; - - // you can reference x as &mut and pass it to multiplyBy2 - multiplyBy2(&mut x); -} - -// you can access &mut here -fn multiplyBy2(x: &mut Field) { - // and dereference it with * - *x = *x * 2; -} -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/01_functions.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/01_functions.md deleted file mode 100644 index 54c618599d2..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/01_functions.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Functions -description: - Learn how to declare functions and methods in Noir, a programming language with Rust semantics. - This guide covers parameter declaration, return types, call expressions, and more. -keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] ---- - -Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. - -To declare a function the `fn` keyword is used. - -```rust -fn foo() {} -``` - -All parameters in a function must have a type and all types are known at compile time. The parameter -is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. - -```rust -fn foo(x : Field, y : pub Field){} -``` - -The return type of a function can be stated by using the `->` arrow notation. The function below -states that the foo function must return a `Field`. If the function returns no value, then the arrow -is omitted. - -```rust -fn foo(x : Field, y : pub Field) -> Field { - x + y -} -``` - -Note that a `return` keyword is unneeded in this case - the last expression in a function's body is -returned. - -## Call Expressions - -Calling a function in Noir is executed by using the function name and passing in the necessary -arguments. - -Below we show how to call the `foo` function from the `main` function using a call expression: - -```rust -fn main(x : Field, y : Field) { - let z = foo(x); -} - -fn foo(x : Field) -> Field { - x + x -} -``` - -## Methods - -You can define methods in Noir on any struct type in scope. - -```rust -struct MyStruct { - foo: Field, - bar: Field, -} - -impl MyStruct { - fn new(foo: Field) -> MyStruct { - MyStruct { - foo, - bar: 2, - } - } - - fn sum(self) -> Field { - self.foo + self.bar - } -} - -fn main() { - let s = MyStruct::new(40); - assert(s.sum() == 42); -} -``` - -Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as -follows: - -```rust -assert(MyStruct::sum(s) == 42); -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/02_control_flow.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/02_control_flow.md deleted file mode 100644 index 691c514d9a8..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/02_control_flow.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Control Flow -description: - Learn how to use loops and if expressions in the Noir programming language. Discover the syntax - and examples for for loops and if-else statements. -keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] ---- - -## Loops - -Noir has one kind of loop: the `for` loop. `for` loops allow you to repeat a block of code multiple -times. - -The following block of code between the braces is run 10 times. - -```rust -for i in 0..10 { - // do something -}; -``` - -## If Expressions - -Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required -for the statement's conditional to be surrounded by parentheses. - -```rust -let a = 0; -let mut x: u32 = 0; - -if a == 0 { - if a != 0 { - x = 6; - } else { - x = 2; - } -} else { - x = 5; - assert(x == 5); -} -assert(x == 2); -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/03_ops.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/03_ops.md deleted file mode 100644 index da02b126059..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/03_ops.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Logical Operations -description: - Learn about the supported arithmetic and logical operations in the Noir programming language. - Discover how to perform operations on private input types, integers, and booleans. -keywords: - [ - Noir programming language, - supported operations, - arithmetic operations, - logical operations, - predicate operators, - bitwise operations, - short-circuiting, - backend, - ] ---- - -# Operations - -## Table of Supported Operations - -| Operation | Description | Requirements | -| :-------- | :------------------------------------------------------------: | -------------------------------------: | -| + | Adds two private input types together | Types must be private input | -| - | Subtracts two private input types together | Types must be private input | -| \* | Multiplies two private input types together | Types must be private input | -| / | Divides two private input types together | Types must be private input | -| ^ | XOR two private input types together | Types must be integer | -| & | AND two private input types together | Types must be integer | -| \| | OR two private input types together | Types must be integer | -| << | Left shift an integer by another integer amount | Types must be integer | -| >> | Right shift an integer by another integer amount | Types must be integer | -| ! | Bitwise not of a value | Type must be integer or boolean | -| < | returns a bool if one value is less than the other | Upper bound must have a known bit size | -| <= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | -| > | returns a bool if one value is more than the other | Upper bound must have a known bit size | -| >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | -| == | returns a bool if one value is equal to the other | Both types must not be constants | -| != | returns a bool if one value is not equal to the other | Both types must not be constants | - -### Predicate Operators - -`<,<=, !=, == , >, >=` are known as predicate/comparison operations because they compare two values. -This differs from the operations such as `+` where the operands are used in _computation_. - -### Bitwise Operations Example - -```rust -fn main(x : Field) { - let y = x as u32; - let z = y & y; -} -``` - -`z` is implicitly constrained to be the result of `y & y`. The `&` operand is used to denote bitwise -`&`. - -> `x & x` would not compile as `x` is a `Field` and not an integer type. - -### Logical Operators - -Noir has no support for the logical operators `||` and `&&`. This is because encoding the -short-circuiting that these operators require can be inefficient for Noir's backend. Instead you can -use the bitwise operators `|` and `&` which operate indentically for booleans, just without the -short-circuiting. - -```rust -let my_val = 5; - -let mut flag = 1; -if (my_val > 6) | (my_val == 0) { - flag = 0; -} -assert(flag == 1); - -if (my_val != 10) & (my_val < 50) { - flag = 0; -} -assert(flag == 0); -``` - -### Shorthand operators - -Noir shorthand operators for most of the above operators, namely `+=, -=, *=, /=, %=, &=, |=, ^=, <<=`, and `>>=`. These allow for more concise syntax. For example: - -```rust -let mut i = 0; -i = i + 1; -``` - -could be written as: - -```rust -let mut i = 0; -i += 1; -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/04_assert.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/04_assert.md deleted file mode 100644 index a25a946123d..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/04_assert.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Assert Function -description: - Learn about the assert function in Noir, which can be used to explicitly constrain the predicate or - comparison expression that follows to be true, and what happens if the expression is false at - runtime. -keywords: [Noir programming language, assert statement, predicate expression, comparison expression] ---- - -Noir includes a special `assert` function which will explicitly constrain the predicate/comparison -expression that follows to be true. If this expression is false at runtime, the program will fail to -be proven. - -### Example - -```rust -fn main(x : Field, y : Field) { - assert(x == y); -} -``` - -The above snippet compiles because `==` is a predicate operation. Conversely, the following will not -compile: - -```rust -// INCORRECT - -fn main(x : Field, y : Field) { - assert(x + y); -} -``` - -> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should -> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/06_generics.md deleted file mode 100644 index 66f2e85e16b..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/06_generics.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Generics -description: - Learn how to use Generics in Noir -keywords: [Noir, Rust, generics, functions, structs] ---- - -# Generics - -Generics allow you to use the same functions with multiple different concrete data types. You can -read more about the concept of generics in the Rust documentation -[here](https://doc.rust-lang.org/book/ch10-01-syntax.html). - -Here is a trivial example showing the identity function that supports any type. In Rust, it is -common to refer to the most general type as `T`. We follow the same convention in Noir. - -```rust -fn id(x: T) -> T { - x -} -``` - -## In Structs - -Generics are useful for specifying types in structs. For example, we can specify that a field in a -struct will be of a certain generic type. In this case `value` is of type `T`. - -```rust -struct RepeatedValue { - value: T, - count: comptime Field, -} - -impl RepeatedValue { - fn new(value: T) -> Self { - Self { value, count: 1 } - } - - fn increment(mut repeated: Self) -> Self { - repeated.count += 1; - repeated - } - - fn print(self) { - for _i in 0 .. self.count { - dep::std::println(self.value); - } - } -} - -fn main() { - let mut repeated = RepeatedValue::new("Hello!"); - repeated = repeated.increment(); - repeated.print(); -} -``` - -The `print` function will print `Hello!` an arbitrary number of times, twice in this case. - -If we want to be generic over array lengths (which are type-level integers), we can use numeric -generics. Using these looks just like using regular generics, but these generics can resolve to -integers at compile-time, rather than resolving to types. Here's an example of a struct that is -generic over the size of the array it contains internally: - -```rust -struct BigInt { - limbs: [u32; N], -} - -impl BigInt { - // `N` is in scope of all methods in the impl - fn first(first: BigInt, second: BigInt) -> Self { - assert(first.limbs != second.limbs); - first - - fn second(first: BigInt, second: Self) -> Self { - assert(first.limbs != second.limbs); - second - } -} -``` - -## Calling functions on generic parameters - -Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in -Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also -requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? - -The answer is that we can translate this by passing in the function manually. Here's an example of -implementing array equality in Noir: - -```rust -fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { - if array1.len() != array2.len() { - false - } else { - let mut result = true; - for i in 0 .. array1.len() { - result &= elem_eq(array1[i], array2[i]); - } - result - } -} - -fn main() { - assert(array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b)); - - // We can use array_eq even for arrays of structs, as long as we have - // an equality function for these structs we can pass in - let array = [MyStruct::new(), MyStruct::new()]; - assert(array_eq(array, array, MyStruct::eq)); -} -``` - -You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/07_mutability.md b/noir/docs/versioned_docs/version-v0.9.0/language_concepts/07_mutability.md deleted file mode 100644 index 69798c7a276..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/language_concepts/07_mutability.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: Mutability -description: - Learn about mutable variables, constants, and globals in Noir programming language. Discover how - to declare, modify, and use them in your programs. -keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] ---- - -Variables in noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned -to via an assignment expression. - -```rust -let x = 2; -x = 3; // error: x must be mutable to be assigned to - -let mut y = 3; -let y = 4; // OK -``` - -The `mut` modifier can also apply to patterns: - -```rust -let (a, mut b) = (1, 2); -a = 11; // error: a must be mutable to be assigned to -b = 12; // OK - -let mut (c, d) = (3, 4); -c = 13; // OK -d = 14; // OK - -// etc. -let MyStruct { x: mut y } = MyStruct { x: a } -// y is now in scope -``` - -Note that mutability in noir is local and everything is passed by value, so if a called function -mutates its parameters then the parent function will keep the old value of the parameters. - -```rust -fn main() -> Field { - let x = 3; - helper(x); - x // x is still 3 -} - -fn helper(mut x: i32) { - x = 4; -} -``` - -## Comptime Values - -Comptime values are values that are known at compile-time. This is different to a witness -which changes per proof. If a comptime value that is being used in your program is changed, then your -circuit will also change. - -Comptime is slightly different from Rust's `const`. Namely, it is a bit more flexible in that normal functions can accept comptime parameters. For example, this is used to verify an array index is known at compile-time. Note that the "known at compile-time" here means "known after function inlining is performed while optimizing the program" and not "known during type-checking." - -Below we show how to declare a comptime value: - -```rust -fn main() { - let a: comptime Field = 5; - - // `comptime Field` can also be inferred: - let a = 5; -} -``` - -Comptime variables can be mutuable, but must be known at compile time: - -```rust -fn main(runtime_var: Field) -> pub Field { - let known_at_compile_time: comptime Field = 1; - - // The next line will cause an error - let bad_var: comptime Field = runtime_var; - -} -``` - -As `runtime_var` is a argument to the circuit it cannot be known at compile time and so assigning it to a comptime variable should fail. A circuit's arguments is the only way in which non-comptime variables can enter the circuit (excluding [brillig](./unconstrained) foreign calls). - -## Globals - -Noir also supports global variables. However, they must be compile-time variables. If `comptime` is -not explicitly written in the type annotation the compiler will implicitly specify the declaration -as compile-time. They can then be used like any other compile-time variable inside functions. The -global type can also be inferred by the compiler entirely. Globals can also be used to specify array -annotations for function parameters and can be imported from submodules. - -```rust -global N: Field = 5; // Same as `global N: comptime Field = 5` - -fn main(x : Field, y : [Field; N]) { - let res = x * N; - - assert(res == y[0]); - - let res2 = x * mysubmodule::N; - assert(res != res2); -} - -mod mysubmodule { - use dep::std; - - global N: Field = 10; - - fn my_helper() -> comptime Field { - let x = N; - x - } -} -``` - -## Why only local mutability? - -Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting -without applying additional overhead to the user. Modeling a mutable reference is not as -straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/crates_and_packages.md b/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/crates_and_packages.md deleted file mode 100644 index 34f28a71148..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/crates_and_packages.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Crates and Packages -description: - Learn how to use Crates and Packages in your Noir project -keywords: [Nargo, dependencies, package management, crates, package] ---- - -## Crates - -A crate is the smallest amount of code that the Noir compiler considers at a time. -Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as we’ll see in the coming sections. - -### Crate Types - -A Noir crate can come in one of two forms: a binary crate or a library crate. - -_Binary crates_ are programs which you can compile to an ACIR circuit which you can then create proofs against. Each must have a function called `main` that defines the ACIR circuit which is to be proved. - -_Library crates_ don't have a `main` function and they don't compile down to ACIR. Instead they define functionality intended to be shared with multiple projects, and eventually included in a binary crate. - -### Crate Root - -Every crate has a root, which is the source file that the compiler starts, this is also known as the root module. The Noir compiler does not enforce any conditions on the name of the file which is the crate root, however if you are compiling via Nargo the crate root must be called `lib.nr` or `main.nr` for library or binary crates respectively. - -## Packages - -A Nargo _package_ is a collection of one of more crates that provides a set of functionality. A package must include a Nargo.toml file. - -A package _must_ contain either a library or a binary crate, but not both. - -### Differences from Cargo Packages - -One notable difference between Rust's Cargo and Noir's Nargo is that while Cargo allows a package to contain an unlimited number of binary crates and a single library crate, Nargo currently only allows a package to contain a single crate. - -In future this restriction may be lifted to allow a Nargo package to contain both a binary and library crate or multiple binary crates. diff --git a/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/dependencies.md b/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/dependencies.md deleted file mode 100644 index 2807ad52046..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/dependencies.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Managing Dependencies -description: - Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub - and use them easily in your project. -keywords: [Nargo, dependencies, GitHub, package management, versioning] ---- - -Nargo allows you to upload packages to GitHub and use them as dependencies. - -## Specifying a dependency - -Specifying a dependency requires a tag to a specific commit and the git url to the url containing -the package. - -Currently, there are no requirements on the tag contents. If requirements are added, it would follow -semver 2.0 guidelines. - -> Note: Without a `tag` , there would be no versioning and dependencies would change each time you -> compile your project. - -For example, to add the [ecrecover-noir library](https://github.com/colinnielsen/ecrecover-noir) to your project, add it to `Nargo.toml`: - -```toml -# Nargo.toml - -[dependencies] -ecrecover = {tag = "v0.8.0", git = "https://github.com/colinnielsen/ecrecover-noir"} -``` - -## Specifying a local dependency - -You can also specify dependencies that are local to your machine. - -For example, this file structure has a library and binary crate - -``` -├── binary_crate -│   ├── Nargo.toml -│   └── src -│   └── main.nr -└── liba - ├── Nargo.toml - └── src - └── lib.nr -``` - -Inside of the binary crate, you can specify: - -```toml -# Nargo.toml - -[dependencies] -libA = { path = "../liba" } -``` - -## Importing dependencies - -You can import a dependency to a Noir file using the following syntax. For example, to import the -ecrecover-noir library and local liba referenced above: - -```rust -use dep::ecrecover; -use dep::libA; -``` - -You can also import only the specific parts of dependency that you want to use, like so: - -```rust -use dep::std::hash::sha256; -use dep::std::scalar_mul::fixed_base; -``` - -Lastly, as demonstrated in the -[elliptic curve example](../standard_library/cryptographic_primitives/ec_primitives#examples), you -can import multiple items in the same line by enclosing them in curly braces: - -```rust -use dep::std::ec::tecurve::affine::{Curve, Point}; -``` - -## Dependencies of Dependencies - -Note that when you import a dependency, you also get access to all of the dependencies of that package. - -For example, the [phy_vector](https://github.com/resurgencelabs/phy_vector) library imports an [fraction](https://github.com/resurgencelabs/fraction) library. If you're importing the phy_vector library, then you can access the functions in fractions library like so: - -```rust -use dep::phy_vector; - -fn main(x : Field, y : pub Field) { - //... - let f = phy_vector::fraction::toFraction(true, 2, 1); - //... -} -``` - -## Available Libraries - -Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). - -Some libraries that are available today include: - -- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library -- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) -- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers -- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address -- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees -- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir -- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers diff --git a/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/modules.md b/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/modules.md deleted file mode 100644 index e429b336511..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/modules_packages_crates/modules.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Understanding Modules -description: - Learn how to organize your files using modules in Noir, following the same convention as Rust's - module system. Examples included. -keywords: [Noir, Rust, modules, organizing files, sub-modules] ---- - -# Modules - -Noir's module system follows the same convention as the _newer_ version of Rust's module system. - -## Purpose of Modules - -Modules are used to organise files. Without modules all of your code would need to live in a single -file. In Noir, the compiler does not automatically scan all of your files to detect modules. This -must be done explicitly by the developer. - -## Examples - -### Importing a module in the crate root - -Filename : `src/main.nr` - -```rust -mod foo; - -fn main() { - foo::hello_world(); -} -``` - -Filename : `src/foo.nr` - -```rust -fn from_foo() {} -``` - -In the above snippet, the crate root is the `src/main.nr` file. The compiler sees the module -declaration `mod foo` which prompts it to look for a foo.nr file. - -Visually this module hierarchy looks like the following : - -``` -crate - ├── main - │ - └── foo - └── from_foo - -``` - -### Importing a module throughout the tree -All modules are accessible from the ``crate::`` namespace. - -``` -crate - ├── bar - ├── foo - └── main - -``` -In the above snippet, if ``bar`` would like to use functions in ``foo``, it can do so by ``use crate::foo::function_name``. - -### Sub-modules - -Filename : `src/main.nr` - -```rust -mod foo; - -fn main() { - foo::from_foo(); -} -``` - -Filename : `src/foo.nr` - -```rust -mod bar; -fn from_foo() {} -``` - -Filename : `src/foo/bar.nr` - -```rust -fn from_bar() {} -``` - -In the above snippet, we have added an extra module to the module tree; `bar`. `bar` is a submodule -of `foo` hence we declare bar in `foo.nr` with `mod bar`. Since `foo` is not the crate root, the -compiler looks for the file associated with the `bar` module in `src/foo/bar.nr` - -Visually the module hierarchy looks as follows: - -``` -crate - ├── main - │ - └── foo - ├── from_foo - └── bar - └── from_bar -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/nargo/01_commands.md b/noir/docs/versioned_docs/version-v0.9.0/nargo/01_commands.md deleted file mode 100644 index d550e137258..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/nargo/01_commands.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: Commands -description: - Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, - generate Solidity verifier smart contract and compile into JSON file containing ACIR - representation and ABI of circuit. -keywords: - [ - Nargo, - Noir CLI, - Noir Prover, - Noir Verifier, - generate Solidity verifier, - compile JSON file, - ACIR representation, - ABI of circuit, - TypeScript, - ] ---- - -## General options - -``` -Options: - -s, --show-ssa Emit debug information for the intermediate SSA IR - -d, --deny-warnings Quit execution when warnings are emitted - -h, --help Print help -``` - -## `nargo help [subcommand]` - -Prints the list of available commands or specific information of a subcommand. - -_Arguments_ - -- `` - The subcommand whose help message to display - -## `nargo check` - -Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output -values of the Noir program respectively. - -## `nargo codegen-verifier` - -Generate a Solidity verifier smart contract for the program. - -## `nargo compile ` - -Compile the program into a JSON build artifact file containing the ACIR representation and the ABI -of the circuit. This build artifact can then be used to generate and verify proofs. - -You can also use "build" as an alias for compile. - -For example, `nargo build `. - -_Arguments_ - -- `` - The name of the circuit file - -_Options_ - -- `-c, --contracts` - Compile each contract function used within the program -- `--print-acir` - Displays the ACIR for the compiled circuit - -## `nargo new [path]` - -Creates a new Noir project in a new folder called `` - Name of the package -- `[path]` - The path to save the new project - -## `nargo init` - -Creates a new Noir project in the current directory. - -## `nargo execute [witness_name]` - -Runs the Noir program and prints its return value. - -_Arguments_ - -- `[witness_name]` - The name of the witness - -_Usage_ - -The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which -must be filled in. - -To save the witness to file, run the command with a value for the `witness-name` argument. A -`.tr` file will then be saved in the `build` folder. - -> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs -> parsed for your program's ACIR. -> -> This file can be passed along with circuit's ACIR into a TypeScript project for proving and -> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) -> section to learn more. - -## `nargo prove ` - -Creates a proof for the program. - -_Arguments_ - -- `` - The name of the proof - -_Options_ - -- `-v, --verify` - Verify proof after proving - -## `nargo verify ` - -Given a proof and a program, verify whether the proof is valid. - -_Arguments_ - -- `` - The proof to verify - -## `nargo test ` - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. - -See an example on the [testing page](./testing). - -_Arguments_ - -- `` - a pattern to indicate to only run tests with names containing the pattern - -## `nargo gates` - -Counts the occurrences of different gates in circuit - -## `nargo lsp` - -Start a long-running Language Server process that communicates over stdin/stdout. -Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/noir/docs/versioned_docs/version-v0.9.0/nargo/02_testing.md b/noir/docs/versioned_docs/version-v0.9.0/nargo/02_testing.md deleted file mode 100644 index ba0bebd658b..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/nargo/02_testing.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: Testing in Noir -description: Learn how to use Nargo to test your Noir program in a quick and easy way -keywords: [Nargo, testing, Noir, compile, test] ---- - -You can test your Noir programs using Noir circuits. - -Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if -you run `nargo test`. - -For example if you have a program like: - -```rust -fn add(x: u64, y: u64) -> u64 { - x + y -} -#[test] -fn test_add() { - assert(add(2,2) == 4); - assert(add(0,1) == 1); - assert(add(1,0) == 1); -} -``` - -Running `nargo test` will test that the `test_add` function can be executed while satisfying the all -the contraints which allows you to test that add returns the expected values. Test functions can't -have any arguments currently. - -This is much faster compared to testing in Typescript but the only downside is that you can't -explicitly test that a certain set of inputs are invalid. i.e. you can't say that you want -add(2^64-1, 2^64-1) to fail. diff --git a/noir/docs/versioned_docs/version-v0.9.0/nargo/03_solidity_verifier.md b/noir/docs/versioned_docs/version-v0.9.0/nargo/03_solidity_verifier.md deleted file mode 100644 index 9ac60cb0ba7..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/nargo/03_solidity_verifier.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: Solidity Verifier -description: - Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier - contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart - contract. Read more to find out! -keywords: - [ - solidity verifier, - smart contract, - blockchain, - compiler, - plonk_vk.sol, - EVM blockchain, - verifying Noir programs, - proving backend, - Barretenberg, - ] ---- - -For certain applications, it may be desirable to run the verifier as a smart contract instead of on -a local machine. - -Compile a Solidity verifier contract for your Noir program by running: - -```sh -nargo codegen-verifier -``` - -A new `contract` folder would then be generated in your project directory, containing the Solidity -file `plonk_vk.sol`. It can be deployed on any EVM blockchain acting as a verifier smart contract. - -> **Note:** It is possible to compile verifier contracts of Noir programs for other smart contract -> platforms as long as the proving backend supplies an implementation. -> -> Barretenberg, the default proving backend for Nargo, supports compilation of verifier contracts in -> Solidity only for the time being. - -## Verify - -To verify a proof using the Solidity verifier contract, call the `verify` function with the -following signature: - -```solidity -function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) -``` - -You can see an example of how the `verify` function is called in the example zk voting application [here](https://github.com/noir-lang/noir-examples/blob/33e598c257e2402ea3a6b68dd4c5ad492bce1b0a/foundry-voting/src/zkVote.sol#L35): - -```solidity -function castVote(bytes calldata proof, uint proposalId, uint vote, bytes32 nullifierHash) public returns (bool) { - // ... - bytes32[] memory publicInputs = new bytes32[](4); - publicInputs[0] = merkleRoot; - publicInputs[1] = bytes32(proposalId); - publicInputs[2] = bytes32(vote); - publicInputs[3] = nullifierHash; - require(verifier.verify(proof, publicInputs), "Invalid proof"); -``` - -### Public Inputs - -:::tip - -A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in -Noir. - -Under the hood, the return value is passed as an input to the circuit and is checked at the end of -the circuit program. - -::: - -The verifier contract uses the output (return) value of a Noir program as a public input. So if you -have the following function - -```rust -fn main( - // Public inputs - pubkey_x: pub Field, - pubkey_y: pub Field, - // Private inputs - priv_key: Field, -) -> pub Field -``` - -then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an -error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. - -In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. - -#### Struct inputs - -Consider the following program: - -```rust -struct Type1 { - val1: Field, - val2: Field, -} - -struct Nested { - t1: Type1, - is_true: bool, -} - -fn main(x: pub Field, nested: pub Nested, y: pub Field) { - //... -} -``` - -Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` - -## Noir for EVM chains - -You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: - -- Optimism -- Arbitrum -- Polygon PoS -- Scroll -- Celo - -Other EVM chains should work, but have not been tested directly by our team. If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. - -### Unsupported chains - -Unfortunately not all "EVM" chains are supported. - -**zkSync** and the **Polygon zkEVM** do _not_ currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/01_scalar.mdx deleted file mode 100644 index 62265cddb1e..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/01_scalar.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Scalar multiplication -description: - See how you can perform scalar multiplications over a fixed base in Noir -keywords: - [ - cryptographic primitives, - Noir project, - scalar multiplication, - ] ---- - -import BlackBoxInfo from './common/\_blackbox.mdx'; - -## scalar_mul::fixed_base - -Performs scalar multiplication over the embedded curve whose coordinates are defined by the -configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. - -```rust -fn fixed_base(_input : Field) -> [Field; 2] -``` - -example - -```rust -fn main(x : Field) { - let scal = std::scalar_mul::fixed_base(x); - std::println(scal); -} -``` - - diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx deleted file mode 100644 index 8f060ed3316..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: EdDSA Verification -description: Learn about the cryptographic primitives regarding EdDSA -keywords: [cryptographic primitives, Noir project, eddsa, signatures] ---- - -import BlackBoxInfo from './common/_blackbox.mdx'; - -## eddsa::eddsa_poseidon_verify - -Verifier for EdDSA signatures - -```rust -fn eddsa_poseidon_verify(public_key_x : Field, public_key_y : Field, signature_s: Field, signature_r8_x: Field, signature_r8_y: Field, message: Field) -> bool -``` - - diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx b/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx deleted file mode 100644 index 9fe9b48fbff..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx +++ /dev/null @@ -1,5 +0,0 @@ -:::info - -This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. - -::: \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/field_methods.md b/noir/docs/versioned_docs/version-v0.9.0/standard_library/field_methods.md deleted file mode 100644 index 4d1cdc953e9..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/field_methods.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -title: Field Methods -description: - Learn about common methods on Noir Field, including to_le_bits, to_le_bytes, to_le_radix, - to_be_radix, pow_32, etc, and see code examples. -keywords: - [ - Noir Field, - to_le_bits, - to_le_bytes, - to_le_radix, - to_be_radix, - pow_32, - Little Endian, - Big Endian, - Vector, - Exponent, - ] ---- - -After declaring a Field, you can use these common methods on it: - -## to_le_bits - -Transforms the field into an array of bits, Little Endian. - -```rust -fn to_le_bits(_x : Field, _bit_size: u32) -> [u1; N] -``` - -example: - -```rust -fn main() { - let field = 2 - let bits = field.to_le_bits(32); -} -``` - -## to_be_bits - -Transforms the field into an array of bits, Big Endian. - -```rust -fn to_be_bits(_x : Field, _bit_size: u32) -> [u1; N] -``` - -example: - -```rust -fn main() { - let field = 2 - let bits = field.to_be_bits(32); -} -``` - -## to_le_bytes - -Transforms into an array of bytes, Little Endian - -```rust -fn to_le_bytes(_x : Field, byte_size: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let bytes = field.to_le_bytes(4); -} -``` - -## to_be_bytes - -Transforms into an array of bytes, Big Endian - -```rust -fn to_be_bytes(_x : Field, byte_size: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let bytes = field.to_be_bytes(4); -} -``` - -## to_le_radix - -Decomposes into a vector over the specified base, Little Endian - -```rust -fn to_le_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let radix = field.to_le_radix(256, 4); -} -``` - -## to_be_radix - -Decomposes into a vector over the specified base, Big Endian - -```rust -fn to_be_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] -``` - -example: - -```rust -fn main() { - let field = 2 - let radix = field.to_be_radix(256, 4); -} -``` - -## pow_32 - -Returns the value to the power of the specified exponent - -```rust -fn pow_32(self, exponent: Field) -> Field -``` - -example: - -```rust -fn main() { - let field = 2 - let pow = field.pow_32(4); - assert(pow == 16); -} -``` - -## sgn0 - -Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1. - -```rust -fn sgn0(self) -> u1 -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/logging.md b/noir/docs/versioned_docs/version-v0.9.0/standard_library/logging.md deleted file mode 100644 index 42a84be1992..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/logging.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Logging -description: - Learn how to use the println statement for debugging in Noir with this tutorial. Understand the - basics of logging in Noir and how to implement it in your code. -keywords: - [ - noir logging, - println statement, - debugging in noir, - noir std library, - logging tutorial, - basic logging in noir, - noir logging implementation, - noir debugging techniques, - rust, - ] ---- - -# Logging - -The standard library provides a familiar `println` statement you can use. Despite being a limited -implementation of rust's `println!` macro, this construct can be useful for debugging. - -The `println` statement is unconstrained, so it works for outputting integers, fields, strings, and even structs or expressions. For example: - -```rust -use dep::std; - -struct Person { - age : Field, - height : Field, -} - -fn main(age : Field, height : Field) { - let person = Person { age : age, height : height }; - std::println(person); - std::println(age + height); - std::println("Hello world!"); -} - -``` diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/slice_methods.md b/noir/docs/versioned_docs/version-v0.9.0/standard_library/slice_methods.md deleted file mode 100644 index 8b93d8ea427..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/slice_methods.md +++ /dev/null @@ -1,279 +0,0 @@ ---- -title: Slice Methods -description: - Learn about the commonly used methods available for slices in Noir, including push_back, len, srt, map, fold, reduce, all, and any. -keywords: [rust, slice, methods, push_back, len, sort, fold, reduce, all, any] ---- - -For convenience, the STD provides some ready-to-use, common methods for slices: - -## push_back - -Pushes a new element to the end of the slice, returning a new slice with a length one greater than the original unmodified slice. - -```rust -fn push_back(_self: [T], _elem: T) -> [T] -``` - -example: - -```rust -fn main() -> pub Field { - let mut slice: [Field] = [0; 2]; - - let mut new_slice = slice.push_back(6); - new_slice.len() -} -``` - -View the corresponding test file [here][test-file]. - -## push_front - -Returns a new array with the specified element inserted at index 0. The existing elements indexes are incremented by 1. - -```rust -fn push_front(_self: Self, _elem: T) -> Self -``` - -Example: - -```rust -let mut new_slice: [Field] = []; -new_slice = new_slice.push_front(20); -assert(new_slice[0] == 20); // returns true -``` - -View the corresponding test file [here][test-file]. - -## pop_front - -Returns a tuple of two items, the first element of the array and the rest of the array. - -```rust -fn pop_front(_self: Self) -> (T, Self) -``` - -Example: - -```rust -let (first_elem, rest_of_slice) = slice.pop_front(); -``` - -View the corresponding test file [here][test-file]. - -## pop_back - -Returns a tuple of two items, the beginning of the array with the last element omitted and the last element. - -```rust -fn pop_back(_self: Self) -> (Self, T) -``` - -Example: - -```rust -let (popped_slice, last_elem) = slice.pop_back(); -``` - -View the corresponding test file [here][test-file]. - -## insert - -Inserts an element at a specified index and shifts all following elements by 1. - -```rust -fn insert(_self: Self, _index: Field, _elem: T) -> Self -``` - -Example: - -```rust - new_slice = rest_of_slice.insert(2, 100); -assert(new_slice[2] == 100); -``` - -View the corresponding test file [here][test-file]. - -## remove - -Remove an element at a specified index, shifting all elements after it to the left, returning the altered slice and the removed element. - -```rust -fn remove(_self: Self, _index: Field) -> (Self, T) -``` - -Example: - -```rust -let (remove_slice, removed_elem) = slice.remove(3); -``` - -View the corresponding test file [here]([test-file]. - -## len - -Returns the length of a slice - -```rust -fn len(_slice: [T]) -> comptime Field -``` - -Example: - -```rust -fn main() { - let slic = [42, 42] - assert(slic.len() == 2); -} -``` - -## sort - -Returns a new sorted slice. The original slice remains untouched. Notice that this function will -only work for slices of fields or integers, not for any arbitrary type. This is because the sorting -logic the function uses internally is optimized specifically for these values. If you need a sort function to -sort any type, you should use the function `sort_via` described below. - -```rust -fn sort(_slice: [T]) -> [T] -``` - -Example: - -```rust -fn main() { - let slic = [42, 32] - let sorted = slic.sort(); - assert(sorted == [32, 42]); -} -``` - -## sort_via - -Sorts the slice with a custom comparison function - -```rust -fn sort_via(mut a: [T], ordering: fn(T, T) -> bool) -> [T] -``` - -Example: - -```rust -fn main() { - let slic = [42, 32] - let sorted_ascending = slic.sort_via(|a, b| a < b); - assert(sorted_ascending == [32, 42]); // verifies - - let sorted_descending = slic.sort_via(|a, b| a > b); - assert(sorted_descending == [32, 42]); // does not verify -} -``` - -## map - -Applies a function to each element of the slice, returning a new slice containing the mapped elements. - -```rust -fn map(f: fn(T) -> U) -> [U] -``` - -Example: - -```rust -let a = [1, 2, 3]; -let b = a.map(|a| a * 2) // b is now [2, 4, 6] -``` - -## fold - -Applies a function to each element of the slice, returning the final accumulated value. The first -parameter is the initial value. - -```rust -fn fold(mut accumulator: U, f: fn(U, T) -> U) -> U -``` - -This is a left fold, so the given function will be applied to the accumulator and first element of -the slice, then the second, and so on. For a given call the expected result would be equivalent to: - -```rust -let a1 = [1]; -let a2 = [1, 2]; -let a3 = [1, 2, 3]; - -let f = |a, b| a - b; -a1.fold(10, f) //=> f(10, 1) -a2.fold(10, f) //=> f(f(10, 1), 2) -a3.fold(10, f) //=> f(f(f(10, 1), 2), 3) -``` - -Example: - -```rust - -fn main() { - let slic = [2,2,2,2,2] - let folded = slic.fold(0, |a, b| a + b); - assert(folded == 10); -} - -``` - -## reduce - -Same as fold, but uses the first element as starting element. - -```rust -fn reduce(f: fn(T, T) -> T) -> T -``` - -Example: - -```rust -fn main() { - let slic = [2,2,2,2,2] - let reduced = slic.reduce(|a, b| a + b); - assert(reduced == 10); -} -``` - -## all - -Returns true if all the elements satisfy the given predicate - -```rust -fn all(predicate: fn(T) -> bool) -> bool -``` - -Example: - -```rust -fn main() { - let slic = [2,2,2,2,2] - let all = slic.all(|a| a == 2); - assert(all); -} -``` - -## any - -Returns true if any of the elements satisfy the given predicate - -```rust -fn any(predicate: fn(T) -> bool) -> bool -``` - -Example: - -```rust -fn main() { - let slic = [2,2,2,2,5] - let any = slic.any(|a| a == 5); - assert(any); -} - -``` - -[test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr - diff --git a/noir/docs/versioned_docs/version-v0.9.0/standard_library/zeroed.md b/noir/docs/versioned_docs/version-v0.9.0/standard_library/zeroed.md deleted file mode 100644 index 97dab02dac2..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/standard_library/zeroed.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Zeroed Function -description: - The zeroed function returns a zeroed value of any type. -keywords: - [ - zeroed - ] ---- - -Implements `fn zeroed() -> T` to return a zeroed value of any type. This function is generally unsafe to use as the zeroed bit pattern is not guaranteed to be valid for all types. It can however, be useful in cases when the value is guaranteed not to be used such as in a BoundedVec library implementing a growable vector, up to a certain length, backed by an array. The array can be initialized with zeroed values which are guaranteed to be inaccessible until the vector is pushed to. Similarly, enumerations in noir can be implemented using this method by providing zeroed values for the unused variants. - -You can access the function at `std::unsafe::zeroed`. - -This function currently supports the following types: - -- Field -- Bool -- Uint -- Array -- String -- Tuple -- Function - -Using it on other types could result in unexpected behavior. diff --git a/noir/docs/versioned_docs/version-v0.9.0/typescript.md b/noir/docs/versioned_docs/version-v0.9.0/typescript.md deleted file mode 100644 index 8608783784c..00000000000 --- a/noir/docs/versioned_docs/version-v0.9.0/typescript.md +++ /dev/null @@ -1,243 +0,0 @@ ---- -title: Working with TypeScript -description: - Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your - program, specify inputs, initialize a prover & verifier, and prove and verify your program. -keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] ---- - -Interactions with Noir programs can also be performed in TypeScript, which can come in handy when -writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). - -You can check the complete code for this tutorial here: [browser with next.js](https://github.com/signorecello/noir-min-browser-example) and [node.js](https://github.com/signorecello/noir-min-nodejs-example). If you want just a browser boilerplate to start with, check out the [noir-starter](https://github.com/noir-lang/noir-starter) for an example implementation. - -:::note - -You may find unexpected errors working with some frameworks such as `vite`. This is due to the -nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using -[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick -start. - -::: - -## Setup - -Make sure you are using Noir version >= 0.10.1. - -You can check your current version by running `nargo --version`. - -You can install version 0.10.1 with noirup with - -```bash -noirup -v 0.10.1 -``` - -See the [Installation page](./getting_started/nargo_installation) for more info. - -We're assuming you're using ES6 and ESM for both browser (for example with React), or nodejs. Install [Node.js](https://nodejs.org/en). Init a new project with `npm init` and add `"type": "module"` to your `package.json`, to let `node` know we're using the new ESM sytem: - -```json -{ - "type": "module" - // the rest of your package.json -} -``` - -Install Noir dependencies in your project by running: - -```bash -npm i @aztec/bb.js@0.3.6 https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42 fflate ethers@5.7.2 -``` - -This will install the `acvm-simulator` that will generate our witness, and the proving backend barretenberg `bb.js`. - -We're also installing `ethers` because we're too lazy to write a function that pads public inputs with 32bytes, and `fflate` to help us decompress our circuit bytecode. - -Since we're with typescript and using `nodejs` types, we also recommend to install the `@types/node` package, otherwise your IDE will scream at you. - -```bash -npm i --save-dev @types/node -``` - -:::note - -While Noir is in rapid development, some packages could interfere with others. For that reason, you -should use these specified versions. Let us know if for some reason you need to use other ones. - -::: - -As for the circuit, run `nargo init` to create a new Noir project. - -We will use a Standard Noir Example and place it in the `src` folder. This program simply multiplies input `x` with input `y` and returns the result `z`. The verifier doesn't know the value of `x`: we're proving that we know it without making it public. - -```rust -// src/main.nr -fn main(x: u32, y: pub u32) -> pub u32 { - let z = x * y; - z -} -``` - -One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` - -## Compiling - -In order to start proving, we need to compile our circuit into the intermediate representation used by our backend. As of today, you have to do that with `nargo`. Just hop to your circuits folder and run `nargo compile`. - -:::info - -At this time, you need to use a nightly version of nargo. Using [noirup](./getting_started/00_nargo_installation.md#option-1-noirup) you can do this simply by running `noirup -n`. - -::: - -You should have a `json` file in `target/` with your circuit's bytecode. The json file is name based on the project name specified in Nargo.toml, so for a project named "test", it will be at `target/test.json`. You can then import that file normally. - -```ts -import circuit from '../target/test.json' assert { type: 'json' }; -``` - -## Decompressing the circuit - -The compiled circuit comes compressed. We need to decompress it, that's where `fflate` comes in. - -```ts -import { decompressSync } from 'fflate'; - -const acirBuffer = Buffer.from(circuit.bytecode, 'base64'); -const acirBufferUncompressed = decompressSync(acirBuffer); -``` - -From here, it's highly recommended you store `acirBuffer` and `acirBufferUncompressed` close by, as they will be used for witness generation and proving. - -## Initializing ACVM and BB.JS - -:::note - -This step will eventually be abstracted away as Noir tooling matures. For now, you should be fine just literally copy-pasting most of this into your own code. - -::: - -Before proving, `bb.js` needs to be initialized. We need to import some functions and use them - -```ts -import { Crs, newBarretenbergApiAsync, RawBuffer } from '@aztec/bb.js/dest/node/index.js'; - -const api = await newBarretenbergApiAsync(4); - -const [exact, circuitSize, subgroup] = await api.acirGetCircuitSizes(acirBufferUncompressed); -const subgroupSize = Math.pow(2, Math.ceil(Math.log2(circuitSize))); -const crs = await Crs.new(subgroupSize + 1); -await api.commonInitSlabAllocator(subgroupSize); -await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); - -const acirComposer = await api.acirNewAcirComposer(subgroupSize); -``` - -We should take two very useful objects from here: `api` and `acirComposer`. Make sure to keep these close by! - -:::info - -On the browser, you also need to init the ACVM. You can do that by importing it and calling it like: - -```ts -import initACVM, { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; - -await initACVM(); -// the rest of your code -``` - -::: - -## Generating witnesses - -Witness generation is what allows us to prove with arbitrary inputs (like user inputs on a form, game, etc). In this example, our input is a simple object with our circuit inputs `x`, `y`, and return `z` (fun fact: the return value in Noir is actually a public input!). We're wrapping it in a function, so it can be conveniently called later on. - -```ts -import { ethers } from 'ethers'; // I'm lazy so I'm using ethers to pad my input -import { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; - -async function generateWitness(input: any, acirBuffer: Buffer): Promise { - const initialWitness = new Map(); - initialWitness.set(1, ethers.utils.hexZeroPad(`0x${input.x.toString(16)}`, 32)); - initialWitness.set(2, ethers.utils.hexZeroPad(`0x${input.y.toString(16)}`, 32)); - - const witnessMap = await executeCircuit(acirBuffer, initialWitness, () => { - throw Error('unexpected oracle'); - }); - - const witnessBuff = compressWitness(witnessMap); - return witnessBuff; -} -``` - -## Proving - -Finally, we're ready to prove with our backend. Just like with the witness generation, could be useful to wrap it in its own function: - -```ts -async function generateProof(witness: Uint8Array) { - const proof = await api.acirCreateProof( - acirComposer, - acirBufferUncompressed, - decompressSync(witness), - false, - ); - return proof; -} -``` - -## Verifying - -Our backend should also be ready to verify our proof: - -```ts -async function verifyProof(proof: Uint8Array) { - await api.acirInitProvingKey(acirComposer, acirBufferUncompressed); - const verified = await api.acirVerifyProof(acirComposer, proof, false); - return verified; -} -``` - -## Now for the fun part - -Let's call our functions, and destroy our API! - -```ts -const input = { x: 3, y: 4 }; -const witness = await generateWitness(input, acirBuffer); -console.log('Witness generated!'); -const proof = await generateProof(witness); -console.log('Proof generated!'); -await verifyProof(proof); -console.log('Proof verified!'); -api.destroy(); -``` - -You can use [this](https://gist.github.com/critesjosh/6f3ba19fdc9298b24e90ba4f736247dc) tsconfig.json. You can see the script [here](https://gist.github.com/critesjosh/4aa36e87a0cc3f09feaf1febb4d11348). - -## Verifying with Smart Contract - -Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in -TypeScript as well. - -This could be useful if the Noir program is designed to be decentrally verified and/or make use of -decentralized states and logics that is handled at the smart contract level. - -This assumes you've already ran `nargo codegen-verifier`, got your smart contract, and deployed it with Hardhat, Foundry, or your tool of choice. You can then verify a Noir proof by simply calling it. - -Currently, `bb.js` appends the public inputs to the proof. However, these inputs need to be fed separately to the verifier contract. A simple solution is to just slice them from the resulting proof, like this: - -```ts -import { ethers } from 'ethers'; // example using ethers v5 -import artifacts from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; // I compiled using Hardhat, so I'm getting my abi from here - -const verifierAddress = '0x123455'; // your verifier address -const provider = new ethers.providers.Web3Provider(window.ethereum); -const signer = this.provider.getSigner(); - -const contract = new ethers.Contract(verifierAddress, artifacts.abi, signer); - -const publicInputs = proof.slice(0, 32); -const slicedProof = proof.slice(32); -await contract.verify(slicedProof, [publicInputs]); -``` diff --git a/noir/docs/versioned_sidebars/version-v..-sidebars.json b/noir/docs/versioned_sidebars/version-v..-sidebars.json new file mode 100644 index 00000000000..b16f79cc176 --- /dev/null +++ b/noir/docs/versioned_sidebars/version-v..-sidebars.json @@ -0,0 +1,83 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "The Noir Language", + "items": [ + { + "type": "autogenerated", + "dirName": "noir" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "category", + "label": "How To Guides", + "items": [ + { + "type": "autogenerated", + "dirName": "how_to" + } + ] + }, + { + "type": "category", + "label": "Explainers", + "items": [ + { + "type": "autogenerated", + "dirName": "explainers" + } + ] + }, + { + "type": "category", + "label": "Tutorials", + "items": [ + { + "type": "autogenerated", + "dirName": "tutorials" + } + ] + }, + { + "type": "category", + "label": "Reference", + "items": [ + { + "type": "autogenerated", + "dirName": "reference" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "doc", + "id": "migration_notes", + "label": "Migration notes" + } + ] +} diff --git a/noir/docs/versioned_sidebars/version-v0.10.5-sidebars.json b/noir/docs/versioned_sidebars/version-v0.10.5-sidebars.json deleted file mode 100644 index a51ebf87643..00000000000 --- a/noir/docs/versioned_sidebars/version-v0.10.5-sidebars.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "sidebar": [ - { - "type": "doc", - "id": "index", - "label": "Noir" - }, - { - "type": "category", - "label": "Getting Started", - "items": [ - { - "type": "autogenerated", - "dirName": "getting_started" - } - ] - }, - { - "type": "category", - "label": "Examples", - "items": [ - { - "type": "autogenerated", - "dirName": "examples" - } - ] - }, - { - "type": "category", - "label": "Nargo", - "items": [ - { - "type": "autogenerated", - "dirName": "nargo" - } - ] - }, - { - "type": "category", - "label": "Language Concepts", - "items": [ - { - "type": "category", - "label": "Data Types", - "link": { - "type": "doc", - "id": "language_concepts/data_types" - }, - "items": [ - { - "type": "autogenerated", - "dirName": "language_concepts/data_types" - } - ] - }, - "language_concepts/functions", - "language_concepts/control_flow", - "language_concepts/ops", - "language_concepts/assert", - "language_concepts/unconstrained", - "language_concepts/generics", - "language_concepts/mutability", - "language_concepts/lambdas", - "language_concepts/comments", - "language_concepts/distinct", - "language_concepts/shadowing" - ] - }, - { - "type": "category", - "label": "Noir Standard Library", - "items": [ - { - "type": "category", - "label": "Cryptographic Primitives", - "link": { - "type": "doc", - "id": "standard_library/cryptographic_primitives" - }, - "items": [ - { - "type": "autogenerated", - "dirName": "standard_library/cryptographic_primitives" - } - ] - }, - "standard_library/recursion", - "standard_library/logging", - "standard_library/merkle_trees", - "standard_library/zeroed", - "standard_library/black_box_fns", - "standard_library/options" - ] - }, - { - "type": "category", - "label": "Modules, Packages and Crates", - "items": [ - { - "type": "autogenerated", - "dirName": "modules_packages_crates" - } - ] - }, - { - "type": "doc", - "id": "typescript", - "label": "Working with Typescript" - } - ] -} diff --git a/noir/docs/versioned_sidebars/version-v0.19.4-sidebars.json b/noir/docs/versioned_sidebars/version-v0.19.4-sidebars.json new file mode 100644 index 00000000000..a1675eca18d --- /dev/null +++ b/noir/docs/versioned_sidebars/version-v0.19.4-sidebars.json @@ -0,0 +1,293 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index", + "label": "Noir" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "Examples", + "items": [ + { + "type": "autogenerated", + "dirName": "examples" + } + ] + }, + { + "type": "category", + "label": "Nargo", + "items": [ + { + "type": "autogenerated", + "dirName": "nargo" + } + ] + }, + { + "type": "category", + "label": "Language Concepts", + "items": [ + { + "type": "category", + "label": "Data Types", + "link": { + "type": "doc", + "id": "language_concepts/data_types" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "language_concepts/data_types" + } + ] + }, + "language_concepts/functions", + "language_concepts/control_flow", + "language_concepts/ops", + "language_concepts/assert", + "language_concepts/unconstrained", + "language_concepts/generics", + "language_concepts/mutability", + "language_concepts/lambdas", + "language_concepts/comments", + "language_concepts/distinct", + "language_concepts/shadowing" + ] + }, + { + "type": "category", + "label": "Noir Standard Library", + "items": [ + { + "type": "category", + "label": "Cryptographic Primitives", + "link": { + "type": "doc", + "id": "standard_library/cryptographic_primitives" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "standard_library/cryptographic_primitives" + } + ] + }, + "standard_library/recursion", + "standard_library/logging", + "standard_library/merkle_trees", + "standard_library/zeroed", + "standard_library/black_box_fns", + "standard_library/options" + ] + }, + { + "type": "category", + "label": "Modules, Packages and Crates", + "items": [ + { + "type": "autogenerated", + "dirName": "modules_packages_crates" + } + ] + }, + { + "type": "category", + "label": "NoirJS", + "link": { + "type": "doc", + "id": "noir_js/noir_js" + }, + "items": [ + { + "type": "category", + "label": "Guides", + "items": [ + { + "type": "autogenerated", + "dirName": "noir_js/getting_started" + } + ] + }, + { + "type": "category", + "label": "Reference", + "items": [ + { + "type": "category", + "label": "Noir JS", + "link": { + "type": "doc", + "id": "noir_js/reference/noir_js/index" + }, + "items": [ + { + "type": "category", + "label": "Classes", + "items": [ + { + "type": "doc", + "id": "noir_js/reference/noir_js/classes/Noir", + "label": "Noir" + } + ] + }, + { + "type": "category", + "label": "Type Aliases", + "items": [ + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/CompiledCircuit", + "label": "CompiledCircuit" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/ForeignCallHandler", + "label": "ForeignCallHandler" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/ForeignCallInput", + "label": "ForeignCallInput" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/ForeignCallOutput", + "label": "ForeignCallOutput" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/InputMap", + "label": "InputMap" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/ProofData", + "label": "ProofData" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/type-aliases/WitnessMap", + "label": "WitnessMap" + } + ] + }, + { + "type": "category", + "label": "Functions", + "items": [ + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/and", + "label": "and" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/blake2s256", + "label": "blake2s256" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify", + "label": "ecdsa_secp256k1_verify" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify", + "label": "ecdsa_secp256r1_verify" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/keccak256", + "label": "keccak256" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/sha256", + "label": "sha256" + }, + { + "type": "doc", + "id": "noir_js/reference/noir_js/functions/xor", + "label": "xor" + } + ] + } + ] + }, + { + "type": "category", + "label": "Backend Barretenberg", + "link": { + "type": "doc", + "id": "noir_js/reference/backend_barretenberg/index" + }, + "items": [ + { + "type": "category", + "label": "Classes", + "items": [ + { + "type": "doc", + "id": "noir_js/reference/backend_barretenberg/classes/BarretenbergBackend", + "label": "BarretenbergBackend" + } + ] + }, + { + "type": "category", + "label": "Interfaces", + "items": [ + { + "type": "doc", + "id": "noir_js/reference/backend_barretenberg/interfaces/Backend", + "label": "Backend" + } + ] + }, + { + "type": "category", + "label": "Type Aliases", + "items": [ + { + "type": "doc", + "id": "noir_js/reference/backend_barretenberg/type-aliases/BackendOptions", + "label": "BackendOptions" + }, + { + "type": "doc", + "id": "noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit", + "label": "CompiledCircuit" + }, + { + "type": "doc", + "id": "noir_js/reference/backend_barretenberg/type-aliases/ProofData", + "label": "ProofData" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "doc", + "id": "migration_notes", + "label": "Migration notes" + } + ] +} diff --git a/noir/docs/versioned_sidebars/version-v0.6.0-sidebars.json b/noir/docs/versioned_sidebars/version-v0.6.0-sidebars.json deleted file mode 100644 index 7323ae1c504..00000000000 --- a/noir/docs/versioned_sidebars/version-v0.6.0-sidebars.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "sidebar": [ - { - "type": "doc", - "id": "index", - "label": "Noir" - }, - { - "type": "category", - "label": "Getting Started", - "items": [ - { - "type": "autogenerated", - "dirName": "getting_started" - } - ] - }, - { - "type": "category", - "label": "Examples", - "items": [ - { - "type": "autogenerated", - "dirName": "examples" - } - ] - }, - { - "type": "category", - "label": "Nargo", - "items": [ - { - "type": "autogenerated", - "dirName": "nargo" - } - ] - }, - { - "type": "category", - "label": "Language Concepts", - "items": [ - { - "type": "autogenerated", - "dirName": "language_concepts" - } - ] - }, - { - "type": "category", - "label": "Noir Standard Library", - "items": [ - { - "type": "category", - "label": "Cryptographic Primitives", - "link": { - "type": "doc", - "id": "standard_library/cryptographic_primitives" - }, - "items": [ - { - "type": "autogenerated", - "dirName": "standard_library/cryptographic_primitives" - } - ] - }, - "standard_library/array_methods", - "standard_library/field_methods", - "standard_library/logging", - "standard_library/merkle_trees", - "standard_library/zeroed", - "standard_library/black_box_fns" - ] - }, - { - "type": "category", - "label": "Modules, Packages and Crates", - "items": [ - { - "type": "autogenerated", - "dirName": "modules_packages_crates" - } - ] - }, - { - "type": "doc", - "id": "typescript", - "label": "Working with Typescript" - } - ] -} diff --git a/noir/docs/versioned_sidebars/version-v0.7.1-sidebars.json b/noir/docs/versioned_sidebars/version-v0.7.1-sidebars.json deleted file mode 100644 index 7323ae1c504..00000000000 --- a/noir/docs/versioned_sidebars/version-v0.7.1-sidebars.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "sidebar": [ - { - "type": "doc", - "id": "index", - "label": "Noir" - }, - { - "type": "category", - "label": "Getting Started", - "items": [ - { - "type": "autogenerated", - "dirName": "getting_started" - } - ] - }, - { - "type": "category", - "label": "Examples", - "items": [ - { - "type": "autogenerated", - "dirName": "examples" - } - ] - }, - { - "type": "category", - "label": "Nargo", - "items": [ - { - "type": "autogenerated", - "dirName": "nargo" - } - ] - }, - { - "type": "category", - "label": "Language Concepts", - "items": [ - { - "type": "autogenerated", - "dirName": "language_concepts" - } - ] - }, - { - "type": "category", - "label": "Noir Standard Library", - "items": [ - { - "type": "category", - "label": "Cryptographic Primitives", - "link": { - "type": "doc", - "id": "standard_library/cryptographic_primitives" - }, - "items": [ - { - "type": "autogenerated", - "dirName": "standard_library/cryptographic_primitives" - } - ] - }, - "standard_library/array_methods", - "standard_library/field_methods", - "standard_library/logging", - "standard_library/merkle_trees", - "standard_library/zeroed", - "standard_library/black_box_fns" - ] - }, - { - "type": "category", - "label": "Modules, Packages and Crates", - "items": [ - { - "type": "autogenerated", - "dirName": "modules_packages_crates" - } - ] - }, - { - "type": "doc", - "id": "typescript", - "label": "Working with Typescript" - } - ] -} diff --git a/noir/docs/versioned_sidebars/version-v0.9.0-sidebars.json b/noir/docs/versioned_sidebars/version-v0.9.0-sidebars.json deleted file mode 100644 index 190363917e0..00000000000 --- a/noir/docs/versioned_sidebars/version-v0.9.0-sidebars.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "sidebar": [ - { - "type": "doc", - "id": "index", - "label": "Noir" - }, - { - "type": "category", - "label": "Getting Started", - "items": [ - { - "type": "autogenerated", - "dirName": "getting_started" - } - ] - }, - { - "type": "category", - "label": "Examples", - "items": [ - { - "type": "autogenerated", - "dirName": "examples" - } - ] - }, - { - "type": "category", - "label": "Nargo", - "items": [ - { - "type": "autogenerated", - "dirName": "nargo" - } - ] - }, - { - "type": "category", - "label": "Language Concepts", - "items": [ - { - "type": "autogenerated", - "dirName": "language_concepts" - } - ] - }, - { - "type": "category", - "label": "Noir Standard Library", - "items": [ - { - "type": "category", - "label": "Cryptographic Primitives", - "link": { - "type": "doc", - "id": "standard_library/cryptographic_primitives" - }, - "items": [ - { - "type": "autogenerated", - "dirName": "standard_library/cryptographic_primitives" - } - ] - }, - "standard_library/slice_methods", - "standard_library/field_methods", - "standard_library/recursion", - "standard_library/logging", - "standard_library/merkle_trees", - "standard_library/zeroed", - "standard_library/black_box_fns" - ] - }, - { - "type": "category", - "label": "Modules, Packages and Crates", - "items": [ - { - "type": "autogenerated", - "dirName": "modules_packages_crates" - } - ] - }, - { - "type": "doc", - "id": "typescript", - "label": "Working with Typescript" - } - ] -} diff --git a/noir/docs/versions.json b/noir/docs/versions.json deleted file mode 100644 index 7391f71ae5b..00000000000 --- a/noir/docs/versions.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - "v0.19.3", - "v0.19.2", - "v0.17.0", - "v0.10.5" -] diff --git a/noir/flake.nix b/noir/flake.nix index ac858c1714f..6a146becbb8 100644 --- a/noir/flake.nix +++ b/noir/flake.nix @@ -73,7 +73,7 @@ # Configuration shared between builds config = { # x-release-please-start-version - version = "0.19.4"; + version = "0.22.0"; # x-release-please-end src = pkgs.lib.cleanSourceWith { diff --git a/noir/noir_stdlib/src/default.nr b/noir/noir_stdlib/src/default.nr new file mode 100644 index 00000000000..232be74489c --- /dev/null +++ b/noir/noir_stdlib/src/default.nr @@ -0,0 +1,48 @@ +trait Default { + fn default() -> Self; +} + +impl Default for Field { fn default() -> Field { 0 } } + +impl Default for u8 { fn default() -> u8 { 0 } } +impl Default for u16 { fn default() -> u16 { 0 } } +impl Default for u32 { fn default() -> u32 { 0 } } +impl Default for u64 { fn default() -> u64 { 0 } } + +impl Default for i8 { fn default() -> i8 { 0 } } +impl Default for i16 { fn default() -> i16 { 0 } } +impl Default for i32 { fn default() -> i32 { 0 } } +impl Default for i64 { fn default() -> i64 { 0 } } + +impl Default for () { fn default() -> () { () } } +impl Default for bool { fn default() -> bool { false } } + +impl Default for [T; N] where T: Default { + fn default() -> [T; N] { + [T::default(); N] + } +} + +impl Default for (A, B) where A: Default, B: Default { + fn default() -> (A, B) { + (A::default(), B::default()) + } +} + +impl Default for (A, B, C) where A: Default, B: Default, C: Default { + fn default() -> (A, B, C) { + (A::default(), B::default(), C::default()) + } +} + +impl Default for (A, B, C, D) where A: Default, B: Default, C: Default, D: Default { + fn default() -> (A, B, C, D) { + (A::default(), B::default(), C::default(), D::default()) + } +} + +impl Default for (A, B, C, D, E) where A: Default, B: Default, C: Default, D: Default, E: Default { + fn default() -> (A, B, C, D, E) { + (A::default(), B::default(), C::default(), D::default(), E::default()) + } +} diff --git a/noir/noir_stdlib/src/hash.nr b/noir/noir_stdlib/src/hash.nr index 157d6518367..ad7e4f2e28f 100644 --- a/noir/noir_stdlib/src/hash.nr +++ b/noir/noir_stdlib/src/hash.nr @@ -16,7 +16,7 @@ pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint { pedersen_commitment_with_separator(input, 0) } -#[foreign(pedersen)] +#[foreign(pedersen_commitment)] pub fn __pedersen_commitment_with_separator(_input: [Field; N], _separator: u32) -> [Field; 2] {} pub fn pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> PedersenPoint { diff --git a/noir/noir_stdlib/src/lib.nr b/noir/noir_stdlib/src/lib.nr index 8d878eecbb3..70b4681b54d 100644 --- a/noir/noir_stdlib/src/lib.nr +++ b/noir/noir_stdlib/src/lib.nr @@ -19,13 +19,21 @@ mod compat; mod option; mod string; mod test; +mod ops; +mod default; +mod prelude; + // Oracle calls are required to be wrapped in an unconstrained function -// Thus, the only argument to the `println` oracle is expected to always be an ident -#[oracle(println)] -unconstrained fn println_oracle(_input: T) {} +// Thus, the only argument to the `println` oracle is expected to always be an ident +#[oracle(print)] +unconstrained fn print_oracle(_with_newline: bool, _input: T) {} + +unconstrained pub fn print(input: T) { + print_oracle(false, input); +} unconstrained pub fn println(input: T) { - println_oracle(input); + print_oracle(true, input); } #[foreign(recursive_aggregation)] diff --git a/noir/noir_stdlib/src/ops.nr b/noir/noir_stdlib/src/ops.nr new file mode 100644 index 00000000000..23acc2f0e5d --- /dev/null +++ b/noir/noir_stdlib/src/ops.nr @@ -0,0 +1,117 @@ + +trait Add { + fn add(self, other: Self) -> Self; +} + +impl Add for Field { fn add(self, other: Field) -> Field { self + other } } + +impl Add for u8 { fn add(self, other: u8) -> u8 { self + other } } +impl Add for u16 { fn add(self, other: u16) -> u16 { self + other } } +impl Add for u32 { fn add(self, other: u32) -> u32 { self + other } } +impl Add for u64 { fn add(self, other: u64) -> u64 { self + other } } + +impl Add for i8 { fn add(self, other: i8) -> i8 { self + other } } +impl Add for i16 { fn add(self, other: i16) -> i16 { self + other } } +impl Add for i32 { fn add(self, other: i32) -> i32 { self + other } } +impl Add for i64 { fn add(self, other: i64) -> i64 { self + other } } + +trait Sub { + fn sub(self, other: Self) -> Self; +} + +impl Sub for Field { fn sub(self, other: Field) -> Field { self - other } } + +impl Sub for u8 { fn sub(self, other: u8) -> u8 { self - other } } +impl Sub for u16 { fn sub(self, other: u16) -> u16 { self - other } } +impl Sub for u32 { fn sub(self, other: u32) -> u32 { self - other } } +impl Sub for u64 { fn sub(self, other: u64) -> u64 { self - other } } + +impl Sub for i8 { fn sub(self, other: i8) -> i8 { self - other } } +impl Sub for i16 { fn sub(self, other: i16) -> i16 { self - other } } +impl Sub for i32 { fn sub(self, other: i32) -> i32 { self - other } } +impl Sub for i64 { fn sub(self, other: i64) -> i64 { self - other } } + +trait Mul { + fn mul(self, other: Self) -> Self; +} + +impl Mul for Field { fn mul(self, other: Field) -> Field { self * other } } + +impl Mul for u8 { fn mul(self, other: u8) -> u8 { self * other } } +impl Mul for u16 { fn mul(self, other: u16) -> u16 { self * other } } +impl Mul for u32 { fn mul(self, other: u32) -> u32 { self * other } } +impl Mul for u64 { fn mul(self, other: u64) -> u64 { self * other } } + +impl Mul for i8 { fn mul(self, other: i8) -> i8 { self * other } } +impl Mul for i16 { fn mul(self, other: i16) -> i16 { self * other } } +impl Mul for i32 { fn mul(self, other: i32) -> i32 { self * other } } +impl Mul for i64 { fn mul(self, other: i64) -> i64 { self * other } } + +trait Div { + fn div(self, other: Self) -> Self; +} + +impl Div for Field { fn div(self, other: Field) -> Field { self / other } } + +impl Div for u8 { fn div(self, other: u8) -> u8 { self / other } } +impl Div for u16 { fn div(self, other: u16) -> u16 { self / other } } +impl Div for u32 { fn div(self, other: u32) -> u32 { self / other } } +impl Div for u64 { fn div(self, other: u64) -> u64 { self / other } } + +impl Div for i8 { fn div(self, other: i8) -> i8 { self / other } } +impl Div for i16 { fn div(self, other: i16) -> i16 { self / other } } +impl Div for i32 { fn div(self, other: i32) -> i32 { self / other } } +impl Div for i64 { fn div(self, other: i64) -> i64 { self / other } } + +trait Eq { + fn eq(self, other: Self) -> bool; +} + +impl Eq for Field { fn eq(self, other: Field) -> bool { self == other } } + +impl Eq for u8 { fn eq(self, other: u8) -> bool { self == other } } +impl Eq for u16 { fn eq(self, other: u16) -> bool { self == other } } +impl Eq for u32 { fn eq(self, other: u32) -> bool { self == other } } +impl Eq for u64 { fn eq(self, other: u64) -> bool { self == other } } + +impl Eq for i8 { fn eq(self, other: i8) -> bool { self == other } } +impl Eq for i16 { fn eq(self, other: i16) -> bool { self == other } } +impl Eq for i32 { fn eq(self, other: i32) -> bool { self == other } } +impl Eq for i64 { fn eq(self, other: i64) -> bool { self == other } } + +impl Eq for () { fn eq(_self: Self, _other: ()) -> bool { true } } +impl Eq for bool { fn eq(self, other: bool) -> bool { self == other } } + +impl Eq for [T; N] where T: Eq { + fn eq(self, other: [T; N]) -> bool { + let mut result = true; + for i in 0 .. self.len() { + result &= self[i].eq(other[i]); + } + result + } +} + +impl Eq for (A, B) where A: Eq, B: Eq { + fn eq(self, other: (A, B)) -> bool { + self.0.eq(other.0) & self.1.eq(other.1) + } +} + +impl Eq for (A, B, C) where A: Eq, B: Eq, C: Eq { + fn eq(self, other: (A, B, C)) -> bool { + self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) + } +} + +impl Eq for (A, B, C, D) where A: Eq, B: Eq, C: Eq, D: Eq { + fn eq(self, other: (A, B, C, D)) -> bool { + self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3) + } +} + +impl Eq for (A, B, C, D, E) where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { + fn eq(self, other: (A, B, C, D, E)) -> bool { + self.0.eq(other.0) & self.1.eq(other.1) & self.2.eq(other.2) & self.3.eq(other.3) & self.4.eq(other.4) + } +} diff --git a/noir/noir_stdlib/src/prelude.nr b/noir/noir_stdlib/src/prelude.nr new file mode 100644 index 00000000000..f33a1f7e7f1 --- /dev/null +++ b/noir/noir_stdlib/src/prelude.nr @@ -0,0 +1,3 @@ +use crate::collections::vec::Vec; +use crate::option::Option; +use crate::{print, println, assert_constant}; diff --git a/noir/noir_stdlib/src/slice.nr b/noir/noir_stdlib/src/slice.nr index ca06e2aae44..a5a9a38ed53 100644 --- a/noir/noir_stdlib/src/slice.nr +++ b/noir/noir_stdlib/src/slice.nr @@ -21,28 +21,16 @@ impl [T] { #[builtin(slice_pop_front)] pub fn pop_front(_self: Self) -> (T, Self) { } - pub fn insert(self, _index: Field, _elem: T) -> Self { - // TODO(#2462): Slice insert with a dynamic index - crate::assert_constant(_index); - self.__slice_insert(_index, _elem) - } - /// Insert an element at a specified index, shifting all elements /// after it to the right #[builtin(slice_insert)] - fn __slice_insert(_self: Self, _index: Field, _elem: T) -> Self { } - - pub fn remove(self, _index: Field) -> (Self, T) { - // TODO(#2462): Slice remove with a dynamic index - crate::assert_constant(_index); - self.__slice_remove(_index) - } + pub fn insert(_self: Self, _index: Field, _elem: T) -> Self { } /// Remove an element at a specified index, shifting all elements /// after it to the left, returning the altered slice and /// the removed element #[builtin(slice_remove)] - fn __slice_remove(_self: Self, _index: Field) -> (Self, T) { } + pub fn remove(_self: Self, _index: Field) -> (Self, T) { } // Append each element of the `other` slice to the end of `self`. // This returns a new slice and leaves both input slices unchanged. diff --git a/noir/package.json b/noir/package.json index bced1fb21e8..20a5b87cfd8 100644 --- a/noir/package.json +++ b/noir/package.json @@ -3,7 +3,6 @@ "private": true, "workspaces": [ "compiler/wasm", - "compiler/source-resolver", "compiler/integration-tests", "tooling/noir_js_types", "tooling/noirc_abi_wasm", @@ -27,10 +26,9 @@ "install:noirc_abi_wasm": "yarn workspace @noir-lang/noirc_abi run install:from:nix", "install:from:nix": "yarn install:acvm_js && yarn install:noir_wasm && yarn install:noirc_abi_wasm", "build:types": "yarn workspace @noir-lang/types run build", - "build:source-resolver": "yarn workspace @noir-lang/source-resolver run build", "build:backend_barretenberg": "yarn workspace @noir-lang/backend_barretenberg run build", "build:noir_js": "yarn workspace @noir-lang/noir_js run build", - "build:js:only": "yarn build:types && yarn build:source-resolver && yarn build:backend_barretenberg && yarn build:noir_js", + "build:js:only": "yarn build:types && yarn build:backend_barretenberg && yarn build:noir_js", "prepare:publish": "yarn clean && yarn install:from:nix && yarn build:js:only", "nightly:version": "yarn workspaces foreach run nightly:version", "publish:all": "yarn install && yarn workspaces foreach run publish" diff --git a/noir/release-please-config.json b/noir/release-please-config.json index afc0bfd420d..e73993ca974 100644 --- a/noir/release-please-config.json +++ b/noir/release-please-config.json @@ -14,11 +14,6 @@ "extra-files": [ "Cargo.toml", "flake.nix", - { - "type": "json", - "path": "compiler/source-resolver/package.json", - "jsonpath": "$.version" - }, { "type": "json", "path": "compiler/wasm/package.json", @@ -48,6 +43,11 @@ "type": "json", "path": "tooling/noirc_abi_wasm/package.json", "jsonpath": "$.version" + }, + { + "type": "json", + "path": "docs/docs/package.json", + "jsonpath": "$.version" } ] }, @@ -65,8 +65,11 @@ "blackbox_solver/Cargo.toml", "brillig/Cargo.toml", "brillig_vm/Cargo.toml", - "stdlib/Cargo.toml", - "flake.nix", + { + "type": "json", + "path": "acvm_js/package.json", + "jsonpath": "$.version" + }, { "type": "json", "path": "acvm_js/package.json", @@ -77,5 +80,6 @@ }, "plugins": [ "sentence-case" - ] -} + ], + "bootstrap-sha": "690cfc0468de0b9aee53ccfe832c71c16e61e5fc" +} \ No newline at end of file diff --git a/noir/scripts/bootstrap_native.sh b/noir/scripts/bootstrap_native.sh index fb361c96f57..3e0e2ed853a 100755 --- a/noir/scripts/bootstrap_native.sh +++ b/noir/scripts/bootstrap_native.sh @@ -14,7 +14,7 @@ fi # Build native. if [ -n "${DEBUG:-}" ]; then - cargo build --features="noirc_driver/aztec" + cargo build else - cargo build --features="noirc_driver/aztec" --release + cargo build --release fi diff --git a/noir/scripts/bootstrap_packages.sh b/noir/scripts/bootstrap_packages.sh index 1363acf51a6..df4ee5b3aed 100755 --- a/noir/scripts/bootstrap_packages.sh +++ b/noir/scripts/bootstrap_packages.sh @@ -14,8 +14,6 @@ else export GIT_COMMIT=$(git rev-parse --verify HEAD) fi -export cargoExtraArgs="--features noirc_driver/aztec" - yarn yarn build @@ -25,10 +23,9 @@ yarn workspaces foreach pack rm -rf packages && mkdir -p packages tar zxfv acvm-repo/acvm_js/package.tgz -C packages && mv packages/package packages/acvm_js -tar zxfv compiler/source-resolver/package.tgz -C packages && mv packages/package packages/source-resolver tar zxfv compiler/wasm/package.tgz -C packages && mv packages/package packages/noir_wasm tar zxfv tooling/noir_codegen/package.tgz -C packages && mv packages/package packages/noir_codegen tar zxfv tooling/noir_js/package.tgz -C packages && mv packages/package packages/noir_js tar zxfv tooling/noir_js_backend_barretenberg/package.tgz -C packages && mv packages/package packages/backend_barretenberg tar zxfv tooling/noir_js_types/package.tgz -C packages && mv packages/package packages/types -tar zxfv tooling/noirc_abi_wasm/package.tgz -C packages && mv packages/package packages/noirc_abi \ No newline at end of file +tar zxfv tooling/noirc_abi_wasm/package.tgz -C packages && mv packages/package packages/noirc_abi diff --git a/noir/scripts/nargo_compile_noir_codegen_assert_lt.sh b/noir/scripts/nargo_compile_noir_codegen_assert_lt.sh new file mode 100755 index 00000000000..858a16cf517 --- /dev/null +++ b/noir/scripts/nargo_compile_noir_codegen_assert_lt.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +cd ./tooling/noir_codegen/test/assert_lt +nargo compile \ No newline at end of file diff --git a/noir/scripts/nargo_compile_noir_js_assert_lt.sh b/noir/scripts/nargo_compile_noir_js_assert_lt.sh new file mode 100755 index 00000000000..636ae59b996 --- /dev/null +++ b/noir/scripts/nargo_compile_noir_js_assert_lt.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +cd ./tooling/noir_js/test/noir_compiled_examples/assert_lt +nargo compile \ No newline at end of file diff --git a/noir/scripts/nargo_compile_wasm_fixtures.sh b/noir/scripts/nargo_compile_wasm_fixtures.sh new file mode 100755 index 00000000000..c047888e405 --- /dev/null +++ b/noir/scripts/nargo_compile_wasm_fixtures.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd ./compiler/wasm/fixtures +for dir in $(ls -d */); do + pushd $dir/noir-script + nargo compile + popd +done diff --git a/noir/scripts/test_js_packages.sh b/noir/scripts/test_js_packages.sh new file mode 100755 index 00000000000..a5ec5b92a70 --- /dev/null +++ b/noir/scripts/test_js_packages.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -eu + +cd $(dirname "$0")/.. + +./scripts/install_wasm-bindgen.sh + +# If this project has been subrepod into another project, set build data manually. +export SOURCE_DATE_EPOCH=$(date +%s) +export GIT_DIRTY=false +if [ -f ".gitrepo" ]; then + export GIT_COMMIT=$(awk '/commit =/ {print $3}' .gitrepo) +else + export GIT_COMMIT=$(git rev-parse --verify HEAD) +fi + +cargo build --release +export PATH="${PATH}:/usr/src/noir/target/release/" + +yarn +yarn build +npx playwright install +npx playwright install-deps + +./scripts/test.sh +yarn test \ No newline at end of file diff --git a/noir/scripts/test_native.sh b/noir/scripts/test_native.sh new file mode 100755 index 00000000000..bc1c47ecf12 --- /dev/null +++ b/noir/scripts/test_native.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -eu + +cd $(dirname "$0")/.. + +# If this project has been subrepod into another project, set build data manually. +export SOURCE_DATE_EPOCH=$(date +%s) +export GIT_DIRTY=false +if [ -f ".gitrepo" ]; then + export GIT_COMMIT=$(awk '/commit =/ {print $3}' .gitrepo) +else + export GIT_COMMIT=$(git rev-parse --verify HEAD) +fi + +cargo test --workspace --locked --release \ No newline at end of file diff --git a/noir/scripts/update-acvm-workspace-versions.sh b/noir/scripts/update-acvm-workspace-versions.sh new file mode 100755 index 00000000000..3478333f05a --- /dev/null +++ b/noir/scripts/update-acvm-workspace-versions.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Path to the top-level Cargo.toml +TOP_LEVEL_CARGO_TOML="Cargo.toml" + +# Temporary file to store paths +TEMP_PATHS_FILE="temp_paths.txt" + +# Extract local dependencies paths that start with "acvm-repo" +grep 'path = "acvm-repo' "$TOP_LEVEL_CARGO_TOML" | sed -E 's/.*path = "([^"]+)".*/\1/' > "$TEMP_PATHS_FILE" + +# Read each path and update the version in the top level workspace Cargo.toml file +# to match the version in the component's Cargo.toml +while IFS= read -r component_path; do + # Extract the component name + # This is acir_field for example or stdlib + component_name=$(basename "$component_path") + + # Extract the version from the component's Cargo.toml + # This is acvm-repo/acir_field for example + component_version=$(grep '^version =' "$component_path/Cargo.toml" | sed -E 's/version = "([^"]+)"/\1/') + + if [ -z "$component_version" ]; then + echo "Error: Unable to extract version for $component_name from $component_path/Cargo.toml" + continue + fi + + # Update the version in the top-level Cargo.toml + sed -i.bak -E "s|($component_name[[:space:]]*=[[:space:]]*\{[[:space:]]*version[[:space:]]*=[[:space:]]*\")([^\"]+)(\".*)|\1$component_version\3|" "$TOP_LEVEL_CARGO_TOML" + + if [ $? -ne 0 ]; then + echo "Error: Unable to update version for $component_name in $TOP_LEVEL_CARGO_TOML" + else + echo "Version for $component_name updated successfully to $component_version in $TOP_LEVEL_CARGO_TOML" + fi +done < "$TEMP_PATHS_FILE" + +# Remove temporary file and backup file +rm "$TEMP_PATHS_FILE" +rm "${TOP_LEVEL_CARGO_TOML}.bak" diff --git a/noir/test_programs/.gitignore b/noir/test_programs/.gitignore new file mode 100644 index 00000000000..01a3426160c --- /dev/null +++ b/noir/test_programs/.gitignore @@ -0,0 +1 @@ +acir_artifacts diff --git a/noir/test_programs/acir_artifacts/1327_concrete_in_generic/target/acir.gz b/noir/test_programs/acir_artifacts/1327_concrete_in_generic/target/acir.gz deleted file mode 100644 index cc92863a4a8..00000000000 Binary files a/noir/test_programs/acir_artifacts/1327_concrete_in_generic/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/1327_concrete_in_generic/target/witness.gz b/noir/test_programs/acir_artifacts/1327_concrete_in_generic/target/witness.gz deleted file mode 100644 index 454a9b75e04..00000000000 Binary files a/noir/test_programs/acir_artifacts/1327_concrete_in_generic/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/1_mul/target/acir.gz b/noir/test_programs/acir_artifacts/1_mul/target/acir.gz deleted file mode 100644 index 7572c9ac2cf..00000000000 Binary files a/noir/test_programs/acir_artifacts/1_mul/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/1_mul/target/witness.gz b/noir/test_programs/acir_artifacts/1_mul/target/witness.gz deleted file mode 100644 index 76f5c8a2fe2..00000000000 Binary files a/noir/test_programs/acir_artifacts/1_mul/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/2_div/target/acir.gz b/noir/test_programs/acir_artifacts/2_div/target/acir.gz deleted file mode 100644 index 46405fc2029..00000000000 Binary files a/noir/test_programs/acir_artifacts/2_div/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/2_div/target/witness.gz b/noir/test_programs/acir_artifacts/2_div/target/witness.gz deleted file mode 100644 index 3145b77d957..00000000000 Binary files a/noir/test_programs/acir_artifacts/2_div/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/3_add/target/acir.gz b/noir/test_programs/acir_artifacts/3_add/target/acir.gz deleted file mode 100644 index 42e66d90f73..00000000000 Binary files a/noir/test_programs/acir_artifacts/3_add/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/3_add/target/witness.gz b/noir/test_programs/acir_artifacts/3_add/target/witness.gz deleted file mode 100644 index 0cfc48c525e..00000000000 Binary files a/noir/test_programs/acir_artifacts/3_add/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/4_sub/target/acir.gz b/noir/test_programs/acir_artifacts/4_sub/target/acir.gz deleted file mode 100644 index 633bec13563..00000000000 Binary files a/noir/test_programs/acir_artifacts/4_sub/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/4_sub/target/witness.gz b/noir/test_programs/acir_artifacts/4_sub/target/witness.gz deleted file mode 100644 index 68e9df80789..00000000000 Binary files a/noir/test_programs/acir_artifacts/4_sub/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/5_over/target/acir.gz b/noir/test_programs/acir_artifacts/5_over/target/acir.gz deleted file mode 100644 index 681a0290f75..00000000000 Binary files a/noir/test_programs/acir_artifacts/5_over/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/5_over/target/witness.gz b/noir/test_programs/acir_artifacts/5_over/target/witness.gz deleted file mode 100644 index b0a38188cab..00000000000 Binary files a/noir/test_programs/acir_artifacts/5_over/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/6/target/acir.gz b/noir/test_programs/acir_artifacts/6/target/acir.gz deleted file mode 100644 index 0cc489d8932..00000000000 Binary files a/noir/test_programs/acir_artifacts/6/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/6/target/witness.gz b/noir/test_programs/acir_artifacts/6/target/witness.gz deleted file mode 100644 index 5c060e1b469..00000000000 Binary files a/noir/test_programs/acir_artifacts/6/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/6_array/target/acir.gz b/noir/test_programs/acir_artifacts/6_array/target/acir.gz deleted file mode 100644 index 787db190b49..00000000000 Binary files a/noir/test_programs/acir_artifacts/6_array/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/6_array/target/witness.gz b/noir/test_programs/acir_artifacts/6_array/target/witness.gz deleted file mode 100644 index cc96fd18e00..00000000000 Binary files a/noir/test_programs/acir_artifacts/6_array/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/7/target/acir.gz b/noir/test_programs/acir_artifacts/7/target/acir.gz deleted file mode 100644 index 7f14d2a932c..00000000000 Binary files a/noir/test_programs/acir_artifacts/7/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/7/target/witness.gz b/noir/test_programs/acir_artifacts/7/target/witness.gz deleted file mode 100644 index d51356eb6c1..00000000000 Binary files a/noir/test_programs/acir_artifacts/7/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/7_function/target/acir.gz b/noir/test_programs/acir_artifacts/7_function/target/acir.gz deleted file mode 100644 index 5ddc1ba38e6..00000000000 Binary files a/noir/test_programs/acir_artifacts/7_function/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/7_function/target/witness.gz b/noir/test_programs/acir_artifacts/7_function/target/witness.gz deleted file mode 100644 index 0bb522d210e..00000000000 Binary files a/noir/test_programs/acir_artifacts/7_function/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/arithmetic_binary_operations/target/acir.gz b/noir/test_programs/acir_artifacts/arithmetic_binary_operations/target/acir.gz deleted file mode 100644 index fd31cc3bfa6..00000000000 Binary files a/noir/test_programs/acir_artifacts/arithmetic_binary_operations/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/arithmetic_binary_operations/target/witness.gz b/noir/test_programs/acir_artifacts/arithmetic_binary_operations/target/witness.gz deleted file mode 100644 index 450a83edc9c..00000000000 Binary files a/noir/test_programs/acir_artifacts/arithmetic_binary_operations/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_dynamic/target/acir.gz b/noir/test_programs/acir_artifacts/array_dynamic/target/acir.gz deleted file mode 100644 index e6111539302..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_dynamic/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_dynamic/target/witness.gz b/noir/test_programs/acir_artifacts/array_dynamic/target/witness.gz deleted file mode 100644 index 102bb7ad178..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_dynamic/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_eq/target/acir.gz b/noir/test_programs/acir_artifacts/array_eq/target/acir.gz deleted file mode 100644 index b274cd72649..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_eq/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_eq/target/witness.gz b/noir/test_programs/acir_artifacts/array_eq/target/witness.gz deleted file mode 100644 index f000e986c3d..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_eq/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_len/target/acir.gz b/noir/test_programs/acir_artifacts/array_len/target/acir.gz deleted file mode 100644 index 795d22712b2..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_len/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_len/target/witness.gz b/noir/test_programs/acir_artifacts/array_len/target/witness.gz deleted file mode 100644 index c3763958eeb..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_len/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_neq/target/acir.gz b/noir/test_programs/acir_artifacts/array_neq/target/acir.gz deleted file mode 100644 index 8d87f8bc575..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_neq/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_neq/target/witness.gz b/noir/test_programs/acir_artifacts/array_neq/target/witness.gz deleted file mode 100644 index c56b373217d..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_neq/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_sort/target/acir.gz b/noir/test_programs/acir_artifacts/array_sort/target/acir.gz deleted file mode 100644 index 42d701ede8a..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_sort/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/array_sort/target/witness.gz b/noir/test_programs/acir_artifacts/array_sort/target/witness.gz deleted file mode 100644 index 8229809cc95..00000000000 Binary files a/noir/test_programs/acir_artifacts/array_sort/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/assert/target/acir.gz b/noir/test_programs/acir_artifacts/assert/target/acir.gz deleted file mode 100644 index c4e7f86f219..00000000000 Binary files a/noir/test_programs/acir_artifacts/assert/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/assert/target/witness.gz b/noir/test_programs/acir_artifacts/assert/target/witness.gz deleted file mode 100644 index 16880cedea2..00000000000 Binary files a/noir/test_programs/acir_artifacts/assert/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/assert_statement/target/acir.gz b/noir/test_programs/acir_artifacts/assert_statement/target/acir.gz deleted file mode 100644 index d71ac1b6b0e..00000000000 Binary files a/noir/test_programs/acir_artifacts/assert_statement/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/assert_statement/target/witness.gz b/noir/test_programs/acir_artifacts/assert_statement/target/witness.gz deleted file mode 100644 index 3e073aac635..00000000000 Binary files a/noir/test_programs/acir_artifacts/assert_statement/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/assign_ex/target/acir.gz b/noir/test_programs/acir_artifacts/assign_ex/target/acir.gz deleted file mode 100644 index a682df0b963..00000000000 Binary files a/noir/test_programs/acir_artifacts/assign_ex/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/assign_ex/target/witness.gz b/noir/test_programs/acir_artifacts/assign_ex/target/witness.gz deleted file mode 100644 index 35e05b7622b..00000000000 Binary files a/noir/test_programs/acir_artifacts/assign_ex/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bit_and/target/acir.gz b/noir/test_programs/acir_artifacts/bit_and/target/acir.gz deleted file mode 100644 index 5fb7041cdf1..00000000000 Binary files a/noir/test_programs/acir_artifacts/bit_and/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bit_and/target/witness.gz b/noir/test_programs/acir_artifacts/bit_and/target/witness.gz deleted file mode 100644 index 0c5dc12cf1c..00000000000 Binary files a/noir/test_programs/acir_artifacts/bit_and/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bit_shifts_comptime/target/acir.gz b/noir/test_programs/acir_artifacts/bit_shifts_comptime/target/acir.gz deleted file mode 100644 index d6c006fd102..00000000000 Binary files a/noir/test_programs/acir_artifacts/bit_shifts_comptime/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bit_shifts_comptime/target/witness.gz b/noir/test_programs/acir_artifacts/bit_shifts_comptime/target/witness.gz deleted file mode 100644 index 81bae695da1..00000000000 Binary files a/noir/test_programs/acir_artifacts/bit_shifts_comptime/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bit_shifts_runtime/target/acir.gz b/noir/test_programs/acir_artifacts/bit_shifts_runtime/target/acir.gz deleted file mode 100644 index 1a800a63a57..00000000000 Binary files a/noir/test_programs/acir_artifacts/bit_shifts_runtime/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bit_shifts_runtime/target/witness.gz b/noir/test_programs/acir_artifacts/bit_shifts_runtime/target/witness.gz deleted file mode 100644 index 2af844993dd..00000000000 Binary files a/noir/test_programs/acir_artifacts/bit_shifts_runtime/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bool_not/target/acir.gz b/noir/test_programs/acir_artifacts/bool_not/target/acir.gz deleted file mode 100644 index 233a1e25f33..00000000000 Binary files a/noir/test_programs/acir_artifacts/bool_not/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bool_not/target/witness.gz b/noir/test_programs/acir_artifacts/bool_not/target/witness.gz deleted file mode 100644 index 16880cedea2..00000000000 Binary files a/noir/test_programs/acir_artifacts/bool_not/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bool_or/target/acir.gz b/noir/test_programs/acir_artifacts/bool_or/target/acir.gz deleted file mode 100644 index 697832be207..00000000000 Binary files a/noir/test_programs/acir_artifacts/bool_or/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/bool_or/target/witness.gz b/noir/test_programs/acir_artifacts/bool_or/target/witness.gz deleted file mode 100644 index 10cffba7141..00000000000 Binary files a/noir/test_programs/acir_artifacts/bool_or/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_acir_as_brillig/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_acir_as_brillig/target/acir.gz deleted file mode 100644 index dfcbcfe2d5b..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_acir_as_brillig/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_acir_as_brillig/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_acir_as_brillig/target/witness.gz deleted file mode 100644 index 844178f0430..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_acir_as_brillig/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_arrays/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_arrays/target/acir.gz deleted file mode 100644 index afadfe0d7c8..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_arrays/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_arrays/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_arrays/target/witness.gz deleted file mode 100644 index 2d9b4cf245b..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_arrays/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_assert/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_assert/target/acir.gz deleted file mode 100644 index 10c49ba04e3..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_assert/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_assert/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_assert/target/witness.gz deleted file mode 100644 index 628e5fbc6d8..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_assert/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_blake2s/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_blake2s/target/acir.gz deleted file mode 100644 index 5511eedede9..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_blake2s/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_blake2s/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_blake2s/target/witness.gz deleted file mode 100644 index d51356eb6c1..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_blake2s/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_calls/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_calls/target/acir.gz deleted file mode 100644 index 71a5956d1f4..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_calls/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_calls/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_calls/target/witness.gz deleted file mode 100644 index 844178f0430..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_calls/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_calls_array/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_calls_array/target/acir.gz deleted file mode 100644 index 970c95756c7..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_calls_array/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_calls_array/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_calls_array/target/witness.gz deleted file mode 100644 index 266c94d043a..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_calls_array/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_calls_conditionals/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_calls_conditionals/target/acir.gz deleted file mode 100644 index 1c06691acfe..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_calls_conditionals/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_calls_conditionals/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_calls_conditionals/target/witness.gz deleted file mode 100644 index 3e7c051ffc4..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_calls_conditionals/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_conditional/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_conditional/target/acir.gz deleted file mode 100644 index 09f123508f7..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_conditional/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_conditional/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_conditional/target/witness.gz deleted file mode 100644 index 162d33a5fd3..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_conditional/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_ecdsa/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_ecdsa/target/acir.gz deleted file mode 100644 index 5514ad75442..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_ecdsa/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_ecdsa/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_ecdsa/target/witness.gz deleted file mode 100644 index 5fe202b72f0..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_ecdsa/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_fns_as_values/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_fns_as_values/target/acir.gz deleted file mode 100644 index db2717ae656..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_fns_as_values/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_fns_as_values/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_fns_as_values/target/witness.gz deleted file mode 100644 index f4a9c9f6dda..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_fns_as_values/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_hash_to_field/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_hash_to_field/target/acir.gz deleted file mode 100644 index 4ef5ef5d1cb..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_hash_to_field/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_hash_to_field/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_hash_to_field/target/witness.gz deleted file mode 100644 index 1529254d597..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_hash_to_field/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_identity_function/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_identity_function/target/acir.gz deleted file mode 100644 index 080769c4fe7..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_identity_function/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_identity_function/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_identity_function/target/witness.gz deleted file mode 100644 index 9a911d62512..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_identity_function/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_keccak/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_keccak/target/acir.gz deleted file mode 100644 index 6f22b23625c..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_keccak/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_keccak/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_keccak/target/witness.gz deleted file mode 100644 index 95b5064a5a7..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_keccak/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_loop/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_loop/target/acir.gz deleted file mode 100644 index 04baae8d290..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_loop/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_loop/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_loop/target/witness.gz deleted file mode 100644 index 6e9e8ecd1d0..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_loop/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_nested_arrays/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_nested_arrays/target/acir.gz deleted file mode 100644 index 2fe7430584b..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_nested_arrays/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_nested_arrays/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_nested_arrays/target/witness.gz deleted file mode 100644 index 87cf83430f7..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_nested_arrays/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_nested_slices/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_nested_slices/target/acir.gz deleted file mode 100644 index 2247d8a8baa..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_nested_slices/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_nested_slices/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_nested_slices/target/witness.gz deleted file mode 100644 index 3530c6f59c1..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_nested_slices/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_not/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_not/target/acir.gz deleted file mode 100644 index f97dbde95da..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_not/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_not/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_not/target/witness.gz deleted file mode 100644 index 3fbf07be37e..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_not/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_oracle/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_oracle/target/acir.gz deleted file mode 100644 index a1854cf090a..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_oracle/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_oracle/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_oracle/target/witness.gz deleted file mode 100644 index bd1fe47aade..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_oracle/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_pedersen/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_pedersen/target/acir.gz deleted file mode 100644 index a8971591478..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_pedersen/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_pedersen/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_pedersen/target/witness.gz deleted file mode 100644 index b26110156a0..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_pedersen/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_recursion/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_recursion/target/acir.gz deleted file mode 100644 index 88daa302398..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_recursion/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_recursion/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_recursion/target/witness.gz deleted file mode 100644 index 46e192995f3..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_recursion/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_references/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_references/target/acir.gz deleted file mode 100644 index d28e62ff67e..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_references/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_references/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_references/target/witness.gz deleted file mode 100644 index bf62ea672eb..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_references/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_scalar_mul/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_scalar_mul/target/acir.gz deleted file mode 100644 index 51c25758d37..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_scalar_mul/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_scalar_mul/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_scalar_mul/target/witness.gz deleted file mode 100644 index 3204207ec63..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_scalar_mul/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_schnorr/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_schnorr/target/acir.gz deleted file mode 100644 index 95af8d0743f..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_schnorr/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_schnorr/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_schnorr/target/witness.gz deleted file mode 100644 index 17d93cc4d19..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_schnorr/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_sha256/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_sha256/target/acir.gz deleted file mode 100644 index f497023135a..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_sha256/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_sha256/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_sha256/target/witness.gz deleted file mode 100644 index 118042d5841..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_sha256/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_slices/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_slices/target/acir.gz deleted file mode 100644 index c58474d160c..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_slices/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_slices/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_slices/target/witness.gz deleted file mode 100644 index 3530c6f59c1..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_slices/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_to_be_bytes/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_to_be_bytes/target/acir.gz deleted file mode 100644 index 011371d0bf5..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_to_be_bytes/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_to_be_bytes/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_to_be_bytes/target/witness.gz deleted file mode 100644 index 0d48d549824..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_to_be_bytes/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_to_bytes_integration/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_to_bytes_integration/target/acir.gz deleted file mode 100644 index e235e8e3134..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_to_bytes_integration/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_to_bytes_integration/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_to_bytes_integration/target/witness.gz deleted file mode 100644 index b3813a1f976..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_to_bytes_integration/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_to_le_bytes/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_to_le_bytes/target/acir.gz deleted file mode 100644 index b2a486c7176..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_to_le_bytes/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_to_le_bytes/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_to_le_bytes/target/witness.gz deleted file mode 100644 index d12168c557b..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_to_le_bytes/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_top_level/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_top_level/target/acir.gz deleted file mode 100644 index c200de2ac0e..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_top_level/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_top_level/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_top_level/target/witness.gz deleted file mode 100644 index 38bdf1f7263..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_top_level/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_unitialised_arrays/target/acir.gz b/noir/test_programs/acir_artifacts/brillig_unitialised_arrays/target/acir.gz deleted file mode 100644 index 3b1f545133d..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_unitialised_arrays/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/brillig_unitialised_arrays/target/witness.gz b/noir/test_programs/acir_artifacts/brillig_unitialised_arrays/target/witness.gz deleted file mode 100644 index 9724de0f1d9..00000000000 Binary files a/noir/test_programs/acir_artifacts/brillig_unitialised_arrays/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/cast_bool/target/acir.gz b/noir/test_programs/acir_artifacts/cast_bool/target/acir.gz deleted file mode 100644 index 032b36d1629..00000000000 Binary files a/noir/test_programs/acir_artifacts/cast_bool/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/cast_bool/target/witness.gz b/noir/test_programs/acir_artifacts/cast_bool/target/witness.gz deleted file mode 100644 index fa79236ad55..00000000000 Binary files a/noir/test_programs/acir_artifacts/cast_bool/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/closures_mut_ref/target/acir.gz b/noir/test_programs/acir_artifacts/closures_mut_ref/target/acir.gz deleted file mode 100644 index 271b0ddd649..00000000000 Binary files a/noir/test_programs/acir_artifacts/closures_mut_ref/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/closures_mut_ref/target/witness.gz b/noir/test_programs/acir_artifacts/closures_mut_ref/target/witness.gz deleted file mode 100644 index 37c6d67fada..00000000000 Binary files a/noir/test_programs/acir_artifacts/closures_mut_ref/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_1/target/acir.gz b/noir/test_programs/acir_artifacts/conditional_1/target/acir.gz deleted file mode 100644 index 16ec8f28b53..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_1/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_1/target/witness.gz b/noir/test_programs/acir_artifacts/conditional_1/target/witness.gz deleted file mode 100644 index 30cc2834841..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_1/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_2/target/acir.gz b/noir/test_programs/acir_artifacts/conditional_2/target/acir.gz deleted file mode 100644 index 8b56f25b2cf..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_2/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_2/target/witness.gz b/noir/test_programs/acir_artifacts/conditional_2/target/witness.gz deleted file mode 100644 index 310c2cba8c4..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_2/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_421/target/acir.gz b/noir/test_programs/acir_artifacts/conditional_regression_421/target/acir.gz deleted file mode 100644 index bb060b5ebcc..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_421/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_421/target/witness.gz b/noir/test_programs/acir_artifacts/conditional_regression_421/target/witness.gz deleted file mode 100644 index 025b2d9ea44..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_421/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_661/target/acir.gz b/noir/test_programs/acir_artifacts/conditional_regression_661/target/acir.gz deleted file mode 100644 index 51e30b8bbc1..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_661/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_661/target/witness.gz b/noir/test_programs/acir_artifacts/conditional_regression_661/target/witness.gz deleted file mode 100644 index 2683a9ba4ae..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_661/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_short_circuit/target/acir.gz b/noir/test_programs/acir_artifacts/conditional_regression_short_circuit/target/acir.gz deleted file mode 100644 index 75f2bcfdb0b..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_short_circuit/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_short_circuit/target/witness.gz b/noir/test_programs/acir_artifacts/conditional_regression_short_circuit/target/witness.gz deleted file mode 100644 index b2aa4a0b23f..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_short_circuit/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_underflow/target/acir.gz b/noir/test_programs/acir_artifacts/conditional_regression_underflow/target/acir.gz deleted file mode 100644 index df762d9205e..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_underflow/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/conditional_regression_underflow/target/witness.gz b/noir/test_programs/acir_artifacts/conditional_regression_underflow/target/witness.gz deleted file mode 100644 index 939eb503b6f..00000000000 Binary files a/noir/test_programs/acir_artifacts/conditional_regression_underflow/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/custom_entry/target/acir.gz b/noir/test_programs/acir_artifacts/custom_entry/target/acir.gz deleted file mode 100644 index c4e7f86f219..00000000000 Binary files a/noir/test_programs/acir_artifacts/custom_entry/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/custom_entry/target/witness.gz b/noir/test_programs/acir_artifacts/custom_entry/target/witness.gz deleted file mode 100644 index 16880cedea2..00000000000 Binary files a/noir/test_programs/acir_artifacts/custom_entry/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/debug_logs/target/acir.gz b/noir/test_programs/acir_artifacts/debug_logs/target/acir.gz deleted file mode 100644 index 49568a14320..00000000000 Binary files a/noir/test_programs/acir_artifacts/debug_logs/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/debug_logs/target/witness.gz b/noir/test_programs/acir_artifacts/debug_logs/target/witness.gz deleted file mode 100644 index 3199dac0924..00000000000 Binary files a/noir/test_programs/acir_artifacts/debug_logs/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/diamond_deps_0/target/acir.gz b/noir/test_programs/acir_artifacts/diamond_deps_0/target/acir.gz deleted file mode 100644 index e73668fd86c..00000000000 Binary files a/noir/test_programs/acir_artifacts/diamond_deps_0/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/diamond_deps_0/target/witness.gz b/noir/test_programs/acir_artifacts/diamond_deps_0/target/witness.gz deleted file mode 100644 index d2a6bdba5c8..00000000000 Binary files a/noir/test_programs/acir_artifacts/diamond_deps_0/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/distinct_keyword/target/acir.gz b/noir/test_programs/acir_artifacts/distinct_keyword/target/acir.gz deleted file mode 100644 index b3411dc96a7..00000000000 Binary files a/noir/test_programs/acir_artifacts/distinct_keyword/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/distinct_keyword/target/witness.gz b/noir/test_programs/acir_artifacts/distinct_keyword/target/witness.gz deleted file mode 100644 index d79dfba9359..00000000000 Binary files a/noir/test_programs/acir_artifacts/distinct_keyword/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/double_verify_proof/target/acir.gz b/noir/test_programs/acir_artifacts/double_verify_proof/target/acir.gz deleted file mode 100644 index a2faad65143..00000000000 Binary files a/noir/test_programs/acir_artifacts/double_verify_proof/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/double_verify_proof/target/witness.gz b/noir/test_programs/acir_artifacts/double_verify_proof/target/witness.gz deleted file mode 100644 index 251984d6292..00000000000 Binary files a/noir/test_programs/acir_artifacts/double_verify_proof/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/ecdsa_secp256k1/target/acir.gz b/noir/test_programs/acir_artifacts/ecdsa_secp256k1/target/acir.gz deleted file mode 100644 index 9108d663e86..00000000000 Binary files a/noir/test_programs/acir_artifacts/ecdsa_secp256k1/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/ecdsa_secp256k1/target/witness.gz b/noir/test_programs/acir_artifacts/ecdsa_secp256k1/target/witness.gz deleted file mode 100644 index a094ba3246b..00000000000 Binary files a/noir/test_programs/acir_artifacts/ecdsa_secp256k1/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/ecdsa_secp256r1/target/acir.gz b/noir/test_programs/acir_artifacts/ecdsa_secp256r1/target/acir.gz deleted file mode 100644 index ec6bc2c73a0..00000000000 Binary files a/noir/test_programs/acir_artifacts/ecdsa_secp256r1/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/ecdsa_secp256r1/target/witness.gz b/noir/test_programs/acir_artifacts/ecdsa_secp256r1/target/witness.gz deleted file mode 100644 index 79d009caea4..00000000000 Binary files a/noir/test_programs/acir_artifacts/ecdsa_secp256r1/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/eddsa/target/acir.gz b/noir/test_programs/acir_artifacts/eddsa/target/acir.gz deleted file mode 100644 index b8577dbd3ac..00000000000 Binary files a/noir/test_programs/acir_artifacts/eddsa/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/eddsa/target/witness.gz b/noir/test_programs/acir_artifacts/eddsa/target/witness.gz deleted file mode 100644 index 7c125021d96..00000000000 Binary files a/noir/test_programs/acir_artifacts/eddsa/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/field_attribute/target/acir.gz b/noir/test_programs/acir_artifacts/field_attribute/target/acir.gz deleted file mode 100644 index 9401237fd8c..00000000000 Binary files a/noir/test_programs/acir_artifacts/field_attribute/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/field_attribute/target/witness.gz b/noir/test_programs/acir_artifacts/field_attribute/target/witness.gz deleted file mode 100644 index 5f3c241de56..00000000000 Binary files a/noir/test_programs/acir_artifacts/field_attribute/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/generics/target/acir.gz b/noir/test_programs/acir_artifacts/generics/target/acir.gz deleted file mode 100644 index c9462cfa87f..00000000000 Binary files a/noir/test_programs/acir_artifacts/generics/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/generics/target/witness.gz b/noir/test_programs/acir_artifacts/generics/target/witness.gz deleted file mode 100644 index 4d120219b14..00000000000 Binary files a/noir/test_programs/acir_artifacts/generics/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/global_consts/target/acir.gz b/noir/test_programs/acir_artifacts/global_consts/target/acir.gz deleted file mode 100644 index 8b6a0d9db65..00000000000 Binary files a/noir/test_programs/acir_artifacts/global_consts/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/global_consts/target/witness.gz b/noir/test_programs/acir_artifacts/global_consts/target/witness.gz deleted file mode 100644 index 41fe927e809..00000000000 Binary files a/noir/test_programs/acir_artifacts/global_consts/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/hash_to_field/target/acir.gz b/noir/test_programs/acir_artifacts/hash_to_field/target/acir.gz deleted file mode 100644 index 9be98aef491..00000000000 Binary files a/noir/test_programs/acir_artifacts/hash_to_field/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/hash_to_field/target/witness.gz b/noir/test_programs/acir_artifacts/hash_to_field/target/witness.gz deleted file mode 100644 index 743d797096b..00000000000 Binary files a/noir/test_programs/acir_artifacts/hash_to_field/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/higher_order_functions/target/acir.gz b/noir/test_programs/acir_artifacts/higher_order_functions/target/acir.gz deleted file mode 100644 index eab354be13d..00000000000 Binary files a/noir/test_programs/acir_artifacts/higher_order_functions/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/higher_order_functions/target/witness.gz b/noir/test_programs/acir_artifacts/higher_order_functions/target/witness.gz deleted file mode 100644 index 329d15dfb17..00000000000 Binary files a/noir/test_programs/acir_artifacts/higher_order_functions/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/if_else_chain/target/acir.gz b/noir/test_programs/acir_artifacts/if_else_chain/target/acir.gz deleted file mode 100644 index 21cb3898a2d..00000000000 Binary files a/noir/test_programs/acir_artifacts/if_else_chain/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/if_else_chain/target/witness.gz b/noir/test_programs/acir_artifacts/if_else_chain/target/witness.gz deleted file mode 100644 index 4ab0b124e70..00000000000 Binary files a/noir/test_programs/acir_artifacts/if_else_chain/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/import/target/acir.gz b/noir/test_programs/acir_artifacts/import/target/acir.gz deleted file mode 100644 index ff6e6f6c394..00000000000 Binary files a/noir/test_programs/acir_artifacts/import/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/import/target/witness.gz b/noir/test_programs/acir_artifacts/import/target/witness.gz deleted file mode 100644 index 93c5b96bdf3..00000000000 Binary files a/noir/test_programs/acir_artifacts/import/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/integer_array_indexing/target/acir.gz b/noir/test_programs/acir_artifacts/integer_array_indexing/target/acir.gz deleted file mode 100644 index 1c4c50039eb..00000000000 Binary files a/noir/test_programs/acir_artifacts/integer_array_indexing/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/integer_array_indexing/target/witness.gz b/noir/test_programs/acir_artifacts/integer_array_indexing/target/witness.gz deleted file mode 100644 index b3d60e315ec..00000000000 Binary files a/noir/test_programs/acir_artifacts/integer_array_indexing/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/keccak256/target/acir.gz b/noir/test_programs/acir_artifacts/keccak256/target/acir.gz deleted file mode 100644 index cb74273e4d7..00000000000 Binary files a/noir/test_programs/acir_artifacts/keccak256/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/keccak256/target/witness.gz b/noir/test_programs/acir_artifacts/keccak256/target/witness.gz deleted file mode 100644 index 42bcc0ccbd1..00000000000 Binary files a/noir/test_programs/acir_artifacts/keccak256/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/main_bool_arg/target/acir.gz b/noir/test_programs/acir_artifacts/main_bool_arg/target/acir.gz deleted file mode 100644 index d054abe1df0..00000000000 Binary files a/noir/test_programs/acir_artifacts/main_bool_arg/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/main_bool_arg/target/witness.gz b/noir/test_programs/acir_artifacts/main_bool_arg/target/witness.gz deleted file mode 100644 index 80a779d4464..00000000000 Binary files a/noir/test_programs/acir_artifacts/main_bool_arg/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/merkle_insert/target/acir.gz b/noir/test_programs/acir_artifacts/merkle_insert/target/acir.gz deleted file mode 100644 index 5468d947456..00000000000 Binary files a/noir/test_programs/acir_artifacts/merkle_insert/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/merkle_insert/target/witness.gz b/noir/test_programs/acir_artifacts/merkle_insert/target/witness.gz deleted file mode 100644 index 6351d29dd11..00000000000 Binary files a/noir/test_programs/acir_artifacts/merkle_insert/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/mock_oracle/target/acir.gz b/noir/test_programs/acir_artifacts/mock_oracle/target/acir.gz deleted file mode 100644 index 618e9cc8ad1..00000000000 Binary files a/noir/test_programs/acir_artifacts/mock_oracle/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/mock_oracle/target/witness.gz b/noir/test_programs/acir_artifacts/mock_oracle/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/noir/test_programs/acir_artifacts/mock_oracle/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/modules/target/acir.gz b/noir/test_programs/acir_artifacts/modules/target/acir.gz deleted file mode 100644 index 05b5e23ae3e..00000000000 Binary files a/noir/test_programs/acir_artifacts/modules/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/modules/target/witness.gz b/noir/test_programs/acir_artifacts/modules/target/witness.gz deleted file mode 100644 index 58c7b52ef85..00000000000 Binary files a/noir/test_programs/acir_artifacts/modules/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/modules_more/target/acir.gz b/noir/test_programs/acir_artifacts/modules_more/target/acir.gz deleted file mode 100644 index ff6e6f6c394..00000000000 Binary files a/noir/test_programs/acir_artifacts/modules_more/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/modules_more/target/witness.gz b/noir/test_programs/acir_artifacts/modules_more/target/witness.gz deleted file mode 100644 index 6f12eac202f..00000000000 Binary files a/noir/test_programs/acir_artifacts/modules_more/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/modulus/target/acir.gz b/noir/test_programs/acir_artifacts/modulus/target/acir.gz deleted file mode 100644 index a99124a5e3a..00000000000 Binary files a/noir/test_programs/acir_artifacts/modulus/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/modulus/target/witness.gz b/noir/test_programs/acir_artifacts/modulus/target/witness.gz deleted file mode 100644 index 02931c632ff..00000000000 Binary files a/noir/test_programs/acir_artifacts/modulus/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/nested_array_dynamic/target/acir.gz b/noir/test_programs/acir_artifacts/nested_array_dynamic/target/acir.gz deleted file mode 100644 index 762ace26416..00000000000 Binary files a/noir/test_programs/acir_artifacts/nested_array_dynamic/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/nested_array_dynamic/target/witness.gz b/noir/test_programs/acir_artifacts/nested_array_dynamic/target/witness.gz deleted file mode 100644 index e469a0ee7a7..00000000000 Binary files a/noir/test_programs/acir_artifacts/nested_array_dynamic/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/nested_arrays_from_brillig/target/acir.gz b/noir/test_programs/acir_artifacts/nested_arrays_from_brillig/target/acir.gz deleted file mode 100644 index 1fba277a1f8..00000000000 Binary files a/noir/test_programs/acir_artifacts/nested_arrays_from_brillig/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/nested_arrays_from_brillig/target/witness.gz b/noir/test_programs/acir_artifacts/nested_arrays_from_brillig/target/witness.gz deleted file mode 100644 index a3161ac44f9..00000000000 Binary files a/noir/test_programs/acir_artifacts/nested_arrays_from_brillig/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/nested_slice_dynamic/target/acir.gz b/noir/test_programs/acir_artifacts/nested_slice_dynamic/target/acir.gz deleted file mode 100644 index 3db0a495a9d..00000000000 Binary files a/noir/test_programs/acir_artifacts/nested_slice_dynamic/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/nested_slice_dynamic/target/witness.gz b/noir/test_programs/acir_artifacts/nested_slice_dynamic/target/witness.gz deleted file mode 100644 index 9c9e80efe8f..00000000000 Binary files a/noir/test_programs/acir_artifacts/nested_slice_dynamic/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/pedersen_check/target/acir.gz b/noir/test_programs/acir_artifacts/pedersen_check/target/acir.gz deleted file mode 100644 index 02c9f32e3c5..00000000000 Binary files a/noir/test_programs/acir_artifacts/pedersen_check/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/pedersen_check/target/witness.gz b/noir/test_programs/acir_artifacts/pedersen_check/target/witness.gz deleted file mode 100644 index caf34e2b734..00000000000 Binary files a/noir/test_programs/acir_artifacts/pedersen_check/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/poseidon_bn254_hash/target/acir.gz b/noir/test_programs/acir_artifacts/poseidon_bn254_hash/target/acir.gz deleted file mode 100644 index 0327f600884..00000000000 Binary files a/noir/test_programs/acir_artifacts/poseidon_bn254_hash/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/poseidon_bn254_hash/target/witness.gz b/noir/test_programs/acir_artifacts/poseidon_bn254_hash/target/witness.gz deleted file mode 100644 index b3f3f1a3b24..00000000000 Binary files a/noir/test_programs/acir_artifacts/poseidon_bn254_hash/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/poseidonsponge_x5_254/target/acir.gz b/noir/test_programs/acir_artifacts/poseidonsponge_x5_254/target/acir.gz deleted file mode 100644 index dc260ce2aa7..00000000000 Binary files a/noir/test_programs/acir_artifacts/poseidonsponge_x5_254/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/poseidonsponge_x5_254/target/witness.gz b/noir/test_programs/acir_artifacts/poseidonsponge_x5_254/target/witness.gz deleted file mode 100644 index f61ba4ec0cf..00000000000 Binary files a/noir/test_programs/acir_artifacts/poseidonsponge_x5_254/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/pred_eq/target/acir.gz b/noir/test_programs/acir_artifacts/pred_eq/target/acir.gz deleted file mode 100644 index 032b36d1629..00000000000 Binary files a/noir/test_programs/acir_artifacts/pred_eq/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/pred_eq/target/witness.gz b/noir/test_programs/acir_artifacts/pred_eq/target/witness.gz deleted file mode 100644 index f1ea0249fe9..00000000000 Binary files a/noir/test_programs/acir_artifacts/pred_eq/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/references/target/acir.gz b/noir/test_programs/acir_artifacts/references/target/acir.gz deleted file mode 100644 index 0668e2eca25..00000000000 Binary files a/noir/test_programs/acir_artifacts/references/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/references/target/witness.gz b/noir/test_programs/acir_artifacts/references/target/witness.gz deleted file mode 100644 index bf62ea672eb..00000000000 Binary files a/noir/test_programs/acir_artifacts/references/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression/target/acir.gz b/noir/test_programs/acir_artifacts/regression/target/acir.gz deleted file mode 100644 index f92aa2603b4..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression/target/witness.gz b/noir/test_programs/acir_artifacts/regression/target/witness.gz deleted file mode 100644 index dc1f8e0e3f7..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression_2854/target/acir.gz b/noir/test_programs/acir_artifacts/regression_2854/target/acir.gz deleted file mode 100644 index 6f4ffaa488f..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression_2854/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression_2854/target/witness.gz b/noir/test_programs/acir_artifacts/regression_2854/target/witness.gz deleted file mode 100644 index c0b900e8119..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression_2854/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression_mem_op_predicate/target/acir.gz b/noir/test_programs/acir_artifacts/regression_mem_op_predicate/target/acir.gz deleted file mode 100644 index a408771e244..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression_mem_op_predicate/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression_mem_op_predicate/target/witness.gz b/noir/test_programs/acir_artifacts/regression_mem_op_predicate/target/witness.gz deleted file mode 100644 index 2d0e8a4f685..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression_mem_op_predicate/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression_method_cannot_be_found/target/acir.gz b/noir/test_programs/acir_artifacts/regression_method_cannot_be_found/target/acir.gz deleted file mode 100644 index dd4d7ea5f45..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression_method_cannot_be_found/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/regression_method_cannot_be_found/target/witness.gz b/noir/test_programs/acir_artifacts/regression_method_cannot_be_found/target/witness.gz deleted file mode 100644 index 4e90289d5e1..00000000000 Binary files a/noir/test_programs/acir_artifacts/regression_method_cannot_be_found/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/scalar_mul/target/acir.gz b/noir/test_programs/acir_artifacts/scalar_mul/target/acir.gz deleted file mode 100644 index 0bf8db7df70..00000000000 Binary files a/noir/test_programs/acir_artifacts/scalar_mul/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/scalar_mul/target/witness.gz b/noir/test_programs/acir_artifacts/scalar_mul/target/witness.gz deleted file mode 100644 index 637e61f60de..00000000000 Binary files a/noir/test_programs/acir_artifacts/scalar_mul/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/schnorr/target/acir.gz b/noir/test_programs/acir_artifacts/schnorr/target/acir.gz deleted file mode 100644 index 047e59422ee..00000000000 Binary files a/noir/test_programs/acir_artifacts/schnorr/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/schnorr/target/witness.gz b/noir/test_programs/acir_artifacts/schnorr/target/witness.gz deleted file mode 100644 index 91bf1aeb7ad..00000000000 Binary files a/noir/test_programs/acir_artifacts/schnorr/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/sha256/target/acir.gz b/noir/test_programs/acir_artifacts/sha256/target/acir.gz deleted file mode 100644 index a2de8064bb5..00000000000 Binary files a/noir/test_programs/acir_artifacts/sha256/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/sha256/target/witness.gz b/noir/test_programs/acir_artifacts/sha256/target/witness.gz deleted file mode 100644 index d5762dfc7d5..00000000000 Binary files a/noir/test_programs/acir_artifacts/sha256/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/sha2_byte/target/acir.gz b/noir/test_programs/acir_artifacts/sha2_byte/target/acir.gz deleted file mode 100644 index 571fde25f2b..00000000000 Binary files a/noir/test_programs/acir_artifacts/sha2_byte/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/sha2_byte/target/witness.gz b/noir/test_programs/acir_artifacts/sha2_byte/target/witness.gz deleted file mode 100644 index 08ca373be7e..00000000000 Binary files a/noir/test_programs/acir_artifacts/sha2_byte/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/signed_arithmetic/target/acir.gz b/noir/test_programs/acir_artifacts/signed_arithmetic/target/acir.gz deleted file mode 100644 index 82747c17417..00000000000 Binary files a/noir/test_programs/acir_artifacts/signed_arithmetic/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/signed_arithmetic/target/witness.gz b/noir/test_programs/acir_artifacts/signed_arithmetic/target/witness.gz deleted file mode 100644 index 6627fd7d53f..00000000000 Binary files a/noir/test_programs/acir_artifacts/signed_arithmetic/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/signed_division/target/acir.gz b/noir/test_programs/acir_artifacts/signed_division/target/acir.gz deleted file mode 100644 index 39a17a5a529..00000000000 Binary files a/noir/test_programs/acir_artifacts/signed_division/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/signed_division/target/witness.gz b/noir/test_programs/acir_artifacts/signed_division/target/witness.gz deleted file mode 100644 index a35e3011ee6..00000000000 Binary files a/noir/test_programs/acir_artifacts/signed_division/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_2d_array/target/acir.gz b/noir/test_programs/acir_artifacts/simple_2d_array/target/acir.gz deleted file mode 100644 index 59b62b9c99d..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_2d_array/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_2d_array/target/witness.gz b/noir/test_programs/acir_artifacts/simple_2d_array/target/witness.gz deleted file mode 100644 index 321a76492da..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_2d_array/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_add_and_ret_arr/target/acir.gz b/noir/test_programs/acir_artifacts/simple_add_and_ret_arr/target/acir.gz deleted file mode 100644 index d7ec1ebc477..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_add_and_ret_arr/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_add_and_ret_arr/target/witness.gz b/noir/test_programs/acir_artifacts/simple_add_and_ret_arr/target/witness.gz deleted file mode 100644 index 35e05b7622b..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_add_and_ret_arr/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_bitwise/target/acir.gz b/noir/test_programs/acir_artifacts/simple_bitwise/target/acir.gz deleted file mode 100644 index 84fc5cc5de2..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_bitwise/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_bitwise/target/witness.gz b/noir/test_programs/acir_artifacts/simple_bitwise/target/witness.gz deleted file mode 100644 index 2afa317a120..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_bitwise/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_comparison/target/acir.gz b/noir/test_programs/acir_artifacts/simple_comparison/target/acir.gz deleted file mode 100644 index 452780c4d30..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_comparison/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_comparison/target/witness.gz b/noir/test_programs/acir_artifacts/simple_comparison/target/witness.gz deleted file mode 100644 index 5896584fa8a..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_comparison/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_mut/target/acir.gz b/noir/test_programs/acir_artifacts/simple_mut/target/acir.gz deleted file mode 100644 index 9338b74aabd..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_mut/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_mut/target/witness.gz b/noir/test_programs/acir_artifacts/simple_mut/target/witness.gz deleted file mode 100644 index 9e7641cea1e..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_mut/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_not/target/acir.gz b/noir/test_programs/acir_artifacts/simple_not/target/acir.gz deleted file mode 100644 index a47defb9fe6..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_not/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_not/target/witness.gz b/noir/test_programs/acir_artifacts/simple_not/target/witness.gz deleted file mode 100644 index a8e277ea795..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_not/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_print/target/acir.gz b/noir/test_programs/acir_artifacts/simple_print/target/acir.gz deleted file mode 100644 index 9640753adfe..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_print/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_print/target/witness.gz b/noir/test_programs/acir_artifacts/simple_print/target/witness.gz deleted file mode 100644 index 35e05b7622b..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_print/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_program_addition/target/acir.gz b/noir/test_programs/acir_artifacts/simple_program_addition/target/acir.gz deleted file mode 100644 index d7ec1ebc477..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_program_addition/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_program_addition/target/witness.gz b/noir/test_programs/acir_artifacts/simple_program_addition/target/witness.gz deleted file mode 100644 index 94ea8c8f2b1..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_program_addition/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_radix/target/acir.gz b/noir/test_programs/acir_artifacts/simple_radix/target/acir.gz deleted file mode 100644 index 8c5fd3c0bd4..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_radix/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_radix/target/witness.gz b/noir/test_programs/acir_artifacts/simple_radix/target/witness.gz deleted file mode 100644 index 4b051d62ee2..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_radix/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_shield/target/acir.gz b/noir/test_programs/acir_artifacts/simple_shield/target/acir.gz deleted file mode 100644 index 1916c475919..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_shield/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_shield/target/witness.gz b/noir/test_programs/acir_artifacts/simple_shield/target/witness.gz deleted file mode 100644 index 171330f5142..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_shield/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_shift_left_right/target/acir.gz b/noir/test_programs/acir_artifacts/simple_shift_left_right/target/acir.gz deleted file mode 100644 index bae747f46c6..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_shift_left_right/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/simple_shift_left_right/target/witness.gz b/noir/test_programs/acir_artifacts/simple_shift_left_right/target/witness.gz deleted file mode 100644 index 6bc0b91e147..00000000000 Binary files a/noir/test_programs/acir_artifacts/simple_shift_left_right/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/slice_dynamic_index/target/acir.gz b/noir/test_programs/acir_artifacts/slice_dynamic_index/target/acir.gz deleted file mode 100644 index 1bbc8ea075c..00000000000 Binary files a/noir/test_programs/acir_artifacts/slice_dynamic_index/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/slice_dynamic_index/target/witness.gz b/noir/test_programs/acir_artifacts/slice_dynamic_index/target/witness.gz deleted file mode 100644 index 8c7e5f4fb95..00000000000 Binary files a/noir/test_programs/acir_artifacts/slice_dynamic_index/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/slice_struct_field/target/acir.gz b/noir/test_programs/acir_artifacts/slice_struct_field/target/acir.gz deleted file mode 100644 index 6b1f189a331..00000000000 Binary files a/noir/test_programs/acir_artifacts/slice_struct_field/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/slice_struct_field/target/witness.gz b/noir/test_programs/acir_artifacts/slice_struct_field/target/witness.gz deleted file mode 100644 index f404e58ade3..00000000000 Binary files a/noir/test_programs/acir_artifacts/slice_struct_field/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/slices/target/acir.gz b/noir/test_programs/acir_artifacts/slices/target/acir.gz deleted file mode 100644 index 7a053fcb196..00000000000 Binary files a/noir/test_programs/acir_artifacts/slices/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/slices/target/witness.gz b/noir/test_programs/acir_artifacts/slices/target/witness.gz deleted file mode 100644 index 359b2f75601..00000000000 Binary files a/noir/test_programs/acir_artifacts/slices/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/strings/target/acir.gz b/noir/test_programs/acir_artifacts/strings/target/acir.gz deleted file mode 100644 index c489121a9b1..00000000000 Binary files a/noir/test_programs/acir_artifacts/strings/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/strings/target/witness.gz b/noir/test_programs/acir_artifacts/strings/target/witness.gz deleted file mode 100644 index 72a93aabbfe..00000000000 Binary files a/noir/test_programs/acir_artifacts/strings/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct/target/acir.gz b/noir/test_programs/acir_artifacts/struct/target/acir.gz deleted file mode 100644 index e9de8adcb38..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct/target/witness.gz b/noir/test_programs/acir_artifacts/struct/target/witness.gz deleted file mode 100644 index a8e277ea795..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct_array_inputs/target/acir.gz b/noir/test_programs/acir_artifacts/struct_array_inputs/target/acir.gz deleted file mode 100644 index f66ed17a0cf..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct_array_inputs/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct_array_inputs/target/witness.gz b/noir/test_programs/acir_artifacts/struct_array_inputs/target/witness.gz deleted file mode 100644 index 82307dcb96e..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct_array_inputs/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct_fields_ordering/target/acir.gz b/noir/test_programs/acir_artifacts/struct_fields_ordering/target/acir.gz deleted file mode 100644 index 8ddb62e8799..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct_fields_ordering/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct_fields_ordering/target/witness.gz b/noir/test_programs/acir_artifacts/struct_fields_ordering/target/witness.gz deleted file mode 100644 index e2eb3145306..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct_fields_ordering/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct_inputs/target/acir.gz b/noir/test_programs/acir_artifacts/struct_inputs/target/acir.gz deleted file mode 100644 index b658b4111f6..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct_inputs/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/struct_inputs/target/witness.gz b/noir/test_programs/acir_artifacts/struct_inputs/target/witness.gz deleted file mode 100644 index b52a8644265..00000000000 Binary files a/noir/test_programs/acir_artifacts/struct_inputs/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/submodules/target/acir.gz b/noir/test_programs/acir_artifacts/submodules/target/acir.gz deleted file mode 100644 index 697832be207..00000000000 Binary files a/noir/test_programs/acir_artifacts/submodules/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/submodules/target/witness.gz b/noir/test_programs/acir_artifacts/submodules/target/witness.gz deleted file mode 100644 index 10cffba7141..00000000000 Binary files a/noir/test_programs/acir_artifacts/submodules/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_be_bytes/target/acir.gz b/noir/test_programs/acir_artifacts/to_be_bytes/target/acir.gz deleted file mode 100644 index df6294bc970..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_be_bytes/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_be_bytes/target/witness.gz b/noir/test_programs/acir_artifacts/to_be_bytes/target/witness.gz deleted file mode 100644 index b2ac9601bae..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_be_bytes/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_bytes_consistent/target/acir.gz b/noir/test_programs/acir_artifacts/to_bytes_consistent/target/acir.gz deleted file mode 100644 index 2371186e8fc..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_bytes_consistent/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_bytes_consistent/target/witness.gz b/noir/test_programs/acir_artifacts/to_bytes_consistent/target/witness.gz deleted file mode 100644 index 610802628c6..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_bytes_consistent/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_bytes_integration/target/acir.gz b/noir/test_programs/acir_artifacts/to_bytes_integration/target/acir.gz deleted file mode 100644 index 4deef489b9c..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_bytes_integration/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_bytes_integration/target/witness.gz b/noir/test_programs/acir_artifacts/to_bytes_integration/target/witness.gz deleted file mode 100644 index 71d29209eba..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_bytes_integration/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_le_bytes/target/acir.gz b/noir/test_programs/acir_artifacts/to_le_bytes/target/acir.gz deleted file mode 100644 index 02d2bd105f1..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_le_bytes/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/to_le_bytes/target/witness.gz b/noir/test_programs/acir_artifacts/to_le_bytes/target/witness.gz deleted file mode 100644 index 610802628c6..00000000000 Binary files a/noir/test_programs/acir_artifacts/to_le_bytes/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/trait_as_return_type/target/acir.gz b/noir/test_programs/acir_artifacts/trait_as_return_type/target/acir.gz deleted file mode 100644 index 1d34f5becaa..00000000000 Binary files a/noir/test_programs/acir_artifacts/trait_as_return_type/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/trait_as_return_type/target/witness.gz b/noir/test_programs/acir_artifacts/trait_as_return_type/target/witness.gz deleted file mode 100644 index c3b8e758662..00000000000 Binary files a/noir/test_programs/acir_artifacts/trait_as_return_type/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/trait_impl_base_type/target/acir.gz b/noir/test_programs/acir_artifacts/trait_impl_base_type/target/acir.gz deleted file mode 100644 index 531a1baf42e..00000000000 Binary files a/noir/test_programs/acir_artifacts/trait_impl_base_type/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/trait_impl_base_type/target/witness.gz b/noir/test_programs/acir_artifacts/trait_impl_base_type/target/witness.gz deleted file mode 100644 index c3b8e758662..00000000000 Binary files a/noir/test_programs/acir_artifacts/trait_impl_base_type/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/traits_in_crates_1/target/acir.gz b/noir/test_programs/acir_artifacts/traits_in_crates_1/target/acir.gz deleted file mode 100644 index 6eb630ce2ff..00000000000 Binary files a/noir/test_programs/acir_artifacts/traits_in_crates_1/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/traits_in_crates_1/target/witness.gz b/noir/test_programs/acir_artifacts/traits_in_crates_1/target/witness.gz deleted file mode 100644 index 60fc9526465..00000000000 Binary files a/noir/test_programs/acir_artifacts/traits_in_crates_1/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/traits_in_crates_2/target/acir.gz b/noir/test_programs/acir_artifacts/traits_in_crates_2/target/acir.gz deleted file mode 100644 index 6eb630ce2ff..00000000000 Binary files a/noir/test_programs/acir_artifacts/traits_in_crates_2/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/traits_in_crates_2/target/witness.gz b/noir/test_programs/acir_artifacts/traits_in_crates_2/target/witness.gz deleted file mode 100644 index 60fc9526465..00000000000 Binary files a/noir/test_programs/acir_artifacts/traits_in_crates_2/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/tuple_inputs/target/acir.gz b/noir/test_programs/acir_artifacts/tuple_inputs/target/acir.gz deleted file mode 100644 index 79ae7dccb3d..00000000000 Binary files a/noir/test_programs/acir_artifacts/tuple_inputs/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/tuple_inputs/target/witness.gz b/noir/test_programs/acir_artifacts/tuple_inputs/target/witness.gz deleted file mode 100644 index 0eb0d6f09f6..00000000000 Binary files a/noir/test_programs/acir_artifacts/tuple_inputs/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/tuples/target/acir.gz b/noir/test_programs/acir_artifacts/tuples/target/acir.gz deleted file mode 100644 index a053f565e5b..00000000000 Binary files a/noir/test_programs/acir_artifacts/tuples/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/tuples/target/witness.gz b/noir/test_programs/acir_artifacts/tuples/target/witness.gz deleted file mode 100644 index 10cffba7141..00000000000 Binary files a/noir/test_programs/acir_artifacts/tuples/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/type_aliases/target/acir.gz b/noir/test_programs/acir_artifacts/type_aliases/target/acir.gz deleted file mode 100644 index 7855747826f..00000000000 Binary files a/noir/test_programs/acir_artifacts/type_aliases/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/type_aliases/target/witness.gz b/noir/test_programs/acir_artifacts/type_aliases/target/witness.gz deleted file mode 100644 index 8137a9d31c5..00000000000 Binary files a/noir/test_programs/acir_artifacts/type_aliases/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/xor/target/acir.gz b/noir/test_programs/acir_artifacts/xor/target/acir.gz deleted file mode 100644 index eda28c748c5..00000000000 Binary files a/noir/test_programs/acir_artifacts/xor/target/acir.gz and /dev/null differ diff --git a/noir/test_programs/acir_artifacts/xor/target/witness.gz b/noir/test_programs/acir_artifacts/xor/target/witness.gz deleted file mode 100644 index 444c8e01cd1..00000000000 Binary files a/noir/test_programs/acir_artifacts/xor/target/witness.gz and /dev/null differ diff --git a/noir/test_programs/compile_failure/negate_unsigned/Nargo.toml b/noir/test_programs/compile_failure/negate_unsigned/Nargo.toml new file mode 100644 index 00000000000..0b5486024c2 --- /dev/null +++ b/noir/test_programs/compile_failure/negate_unsigned/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "negate_unsigned" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_failure/negate_unsigned/Prover.toml b/noir/test_programs/compile_failure/negate_unsigned/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/test_programs/compile_failure/negate_unsigned/src/main.nr b/noir/test_programs/compile_failure/negate_unsigned/src/main.nr new file mode 100644 index 00000000000..db5f9b0820f --- /dev/null +++ b/noir/test_programs/compile_failure/negate_unsigned/src/main.nr @@ -0,0 +1,6 @@ +use dep::std; + +fn main() { + let var = -1 as u8; + std::println(var); +} diff --git a/noir/test_programs/compile_failure/no_nested_impl/src/main.nr b/noir/test_programs/compile_failure/no_nested_impl/src/main.nr index 916567a7c04..1f1056fb6d9 100644 --- a/noir/test_programs/compile_failure/no_nested_impl/src/main.nr +++ b/noir/test_programs/compile_failure/no_nested_impl/src/main.nr @@ -1,21 +1,21 @@ fn main() { let a: [[[[Field; 2]; 2]; 2]; 2] = [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]], [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]]; - assert(a.eq(a)); + assert(a.my_eq(a)); } -trait Eq { - fn eq(self, other: Self) -> bool; +trait MyEq { + fn my_eq(self, other: Self) -> bool; } -impl Eq for [T; 2] where T: Eq { - fn eq(self, other: Self) -> bool { - self[0].eq(other[0]) - & self[0].eq(other[0]) +impl MyEq for [T; 2] where T: MyEq { + fn my_eq(self, other: Self) -> bool { + self[0].my_eq(other[0]) + & self[0].my_eq(other[0]) } } // Impl for u32 but not Field -impl Eq for u32 { - fn eq(self, other: Self) -> bool { +impl MyEq for u32 { + fn my_eq(self, other: Self) -> bool { self == other } } diff --git a/noir/tooling/nargo_cli/tests/compile_failure/raw_string_huge/Nargo.toml b/noir/test_programs/compile_failure/raw_string_huge/Nargo.toml similarity index 100% rename from noir/tooling/nargo_cli/tests/compile_failure/raw_string_huge/Nargo.toml rename to noir/test_programs/compile_failure/raw_string_huge/Nargo.toml diff --git a/noir/tooling/nargo_cli/tests/compile_failure/raw_string_huge/src/main.nr b/noir/test_programs/compile_failure/raw_string_huge/src/main.nr similarity index 100% rename from noir/tooling/nargo_cli/tests/compile_failure/raw_string_huge/src/main.nr rename to noir/test_programs/compile_failure/raw_string_huge/src/main.nr diff --git a/noir/test_programs/compile_success_contract/simple_contract/src/main.nr b/noir/test_programs/compile_success_contract/simple_contract/src/main.nr index 88edd4ac2c3..fea0ae08c22 100644 --- a/noir/test_programs/compile_success_contract/simple_contract/src/main.nr +++ b/noir/test_programs/compile_success_contract/simple_contract/src/main.nr @@ -11,4 +11,9 @@ contract Foo { open internal fn skibbidy(x: Field) -> pub Field { x * 5 } + // Regression for issue #3344 + #[contract_library_method] + fn foo(x : u8) -> u8 { + x + } } diff --git a/noir/test_programs/compile_success_empty/brillig_set_slice_of_slice/Nargo.toml b/noir/test_programs/compile_success_empty/brillig_set_slice_of_slice/Nargo.toml new file mode 100644 index 00000000000..071254266f4 --- /dev/null +++ b/noir/test_programs/compile_success_empty/brillig_set_slice_of_slice/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "brillig_set_slice_of_slice" +type = "bin" +authors = [""] +compiler_version = ">=0.19.4" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_success_empty/brillig_set_slice_of_slice/src/main.nr b/noir/test_programs/compile_success_empty/brillig_set_slice_of_slice/src/main.nr new file mode 100644 index 00000000000..c0e9c7d172f --- /dev/null +++ b/noir/test_programs/compile_success_empty/brillig_set_slice_of_slice/src/main.nr @@ -0,0 +1,51 @@ +struct Property +{ + key : [u8], + value : [u8], +} + +struct JSON +{ + doc : [Property] +} + +unconstrained fn slice_eq(self: [u8], other: [u8]) -> bool { + let mut equal = true; + for i in 0..self.len() { + if self[i] != other[i] { + equal = false; + } + } + equal +} + +// This test acts a regression for issue #3476 +unconstrained fn main() { + let mut json = JSON { doc: [] }; + let mut prop = Property { key: [], value:[] }; + + let other_prop = Property { key: [0, 1, 2], value:[10] }; + json.doc = json.doc.push_back(other_prop); + + for i in 0..3 { + prop.key = prop.key.push_back(i as u8); + } + prop.value = prop.value.push_back(5); + + // add property to json or replace existing + let len : Field = json.doc.len(); + let mut found = false; + for i in 0..len + { + if (!found) + { + if (slice_eq(prop.key, json.doc[i].key)) + { + json.doc[i].value = prop.value; + found = true; + } + } + } + assert(found == true); + assert(json.doc[0].value[0] == 5); +} \ No newline at end of file diff --git a/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml b/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml new file mode 100644 index 00000000000..92c9b942008 --- /dev/null +++ b/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "short" +type = "bin" +authors = [""] +compiler_version = ">=0.19.4" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/compile_success_empty/method_call_regression/src/main.nr b/noir/test_programs/compile_success_empty/method_call_regression/src/main.nr new file mode 100644 index 00000000000..8bb7ebcac45 --- /dev/null +++ b/noir/test_programs/compile_success_empty/method_call_regression/src/main.nr @@ -0,0 +1,25 @@ +use dep::std; + +fn main() { + // s: Struct + let s = Struct { b: () }; + // Regression for #3089 + s.foo(); +} + +struct Struct { b: B } + +// Before the fix, this candidate is searched first, binding ? to `u8` permanently. +impl Struct { + fn foo(self) {} +} + +// Then this candidate would be searched next but would not be a valid +// candidate since `Struct` != `Struct`. +// +// With the fix, the type of `s` correctly no longer changes until a +// method is actually selected. So this candidate is now valid since +// `Struct` unifies with `Struct` with `? = u32`. +impl Struct { + fn foo(self) {} +} diff --git a/noir/tooling/nargo_cli/tests/compile_success_empty/raw_string/Nargo.toml b/noir/test_programs/compile_success_empty/raw_string/Nargo.toml similarity index 100% rename from noir/tooling/nargo_cli/tests/compile_success_empty/raw_string/Nargo.toml rename to noir/test_programs/compile_success_empty/raw_string/Nargo.toml diff --git a/noir/tooling/nargo_cli/tests/compile_success_empty/raw_string/src/main.nr b/noir/test_programs/compile_success_empty/raw_string/src/main.nr similarity index 100% rename from noir/tooling/nargo_cli/tests/compile_success_empty/raw_string/src/main.nr rename to noir/test_programs/compile_success_empty/raw_string/src/main.nr diff --git a/noir/test_programs/compile_success_empty/regression_3635/Nargo.toml b/noir/test_programs/compile_success_empty/regression_3635/Nargo.toml new file mode 100644 index 00000000000..4f34121439e --- /dev/null +++ b/noir/test_programs/compile_success_empty/regression_3635/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_3635" +version = "0.1.0" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/compile_success_empty/regression_3635/src/main.nr b/noir/test_programs/compile_success_empty/regression_3635/src/main.nr new file mode 100644 index 00000000000..97a04f9d93f --- /dev/null +++ b/noir/test_programs/compile_success_empty/regression_3635/src/main.nr @@ -0,0 +1,8 @@ +use dep::std; + +fn main() { + let x: u8 = 0x61; + let y: u8 = "a".as_bytes()[0]; + assert_eq(x, y); + assert_eq(x >> 1, y >> 1); +} diff --git a/noir/test_programs/compile_success_empty/trait_static_methods/src/main.nr b/noir/test_programs/compile_success_empty/trait_static_methods/src/main.nr index 0150da68315..838e47ee82e 100644 --- a/noir/test_programs/compile_success_empty/trait_static_methods/src/main.nr +++ b/noir/test_programs/compile_success_empty/trait_static_methods/src/main.nr @@ -38,4 +38,27 @@ impl ATrait for Bar { fn main() { assert(Foo::static_method() == 100); assert(Bar::static_method() == 200); + + // Regression for #3773 + let zero: Field = MyDefault::my_default(); + assert(zero == 0); +} + +trait MyDefault { + fn my_default() -> Self; +} + +// This impl is first, so if the type directed search picks the first impl +// instead of the correct Field impl below, we'll get a panic in SSA from +// a type mismatch. +impl MyDefault for (Field, Field) { + fn my_default() -> (Field, Field) { + (0, 0) + } +} + +impl MyDefault for Field { + fn my_default() -> Field { + 0 + } } diff --git a/noir/tooling/nargo_cli/tests/execution_success/brillig_cow/Nargo.toml b/noir/test_programs/execution_success/brillig_cow/Nargo.toml similarity index 100% rename from noir/tooling/nargo_cli/tests/execution_success/brillig_cow/Nargo.toml rename to noir/test_programs/execution_success/brillig_cow/Nargo.toml diff --git a/noir/tooling/nargo_cli/tests/execution_success/brillig_cow/Prover.toml b/noir/test_programs/execution_success/brillig_cow/Prover.toml similarity index 100% rename from noir/tooling/nargo_cli/tests/execution_success/brillig_cow/Prover.toml rename to noir/test_programs/execution_success/brillig_cow/Prover.toml diff --git a/noir/tooling/nargo_cli/tests/execution_success/brillig_cow/src/main.nr b/noir/test_programs/execution_success/brillig_cow/src/main.nr similarity index 100% rename from noir/tooling/nargo_cli/tests/execution_success/brillig_cow/src/main.nr rename to noir/test_programs/execution_success/brillig_cow/src/main.nr diff --git a/noir/test_programs/execution_success/databus/Nargo.toml b/noir/test_programs/execution_success/databus/Nargo.toml new file mode 100644 index 00000000000..72360f7aefe --- /dev/null +++ b/noir/test_programs/execution_success/databus/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "databus" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/databus/Prover.toml b/noir/test_programs/execution_success/databus/Prover.toml new file mode 100644 index 00000000000..2d034508dd8 --- /dev/null +++ b/noir/test_programs/execution_success/databus/Prover.toml @@ -0,0 +1,3 @@ +x = "3" +y = "4" +z = [1,2,3,4] diff --git a/noir/test_programs/execution_success/databus/src/main.nr b/noir/test_programs/execution_success/databus/src/main.nr new file mode 100644 index 00000000000..631331ef2d7 --- /dev/null +++ b/noir/test_programs/execution_success/databus/src/main.nr @@ -0,0 +1,10 @@ +// Test unsafe integer multiplication with overflow: 12^8 = 429 981 696 +// The circuit should handle properly the growth of the bit size +use dep::std; + +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + +let a = z[x]; + a+y + +} diff --git a/noir/test_programs/execution_success/regression_2660/Nargo.toml b/noir/test_programs/execution_success/regression_2660/Nargo.toml new file mode 100644 index 00000000000..1ea0058684b --- /dev/null +++ b/noir/test_programs/execution_success/regression_2660/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_2660" +version = "0.1.0" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/execution_success/regression_2660/Prover.toml b/noir/test_programs/execution_success/regression_2660/Prover.toml new file mode 100644 index 00000000000..4dd6b405159 --- /dev/null +++ b/noir/test_programs/execution_success/regression_2660/Prover.toml @@ -0,0 +1 @@ +x = "1" diff --git a/noir/test_programs/execution_success/regression_2660/src/main.nr b/noir/test_programs/execution_success/regression_2660/src/main.nr new file mode 100644 index 00000000000..f32bc924e3a --- /dev/null +++ b/noir/test_programs/execution_success/regression_2660/src/main.nr @@ -0,0 +1,6 @@ +global foo = -1; + +fn main(x: i32) { + let y = x + foo; + assert(y == 0); +} diff --git a/noir/test_programs/execution_success/regression_3394/Nargo.toml b/noir/test_programs/execution_success/regression_3394/Nargo.toml new file mode 100644 index 00000000000..4949962b16a --- /dev/null +++ b/noir/test_programs/execution_success/regression_3394/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "regression_3394" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/regression_3394/Prover.toml b/noir/test_programs/execution_success/regression_3394/Prover.toml new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/noir/test_programs/execution_success/regression_3394/Prover.toml @@ -0,0 +1 @@ + diff --git a/noir/test_programs/execution_success/regression_3394/src/main.nr b/noir/test_programs/execution_success/regression_3394/src/main.nr new file mode 100644 index 00000000000..cc45487b98b --- /dev/null +++ b/noir/test_programs/execution_success/regression_3394/src/main.nr @@ -0,0 +1,6 @@ +use dep::std; + +fn main() { + let x : i8 = -128; + std::println(x); +} \ No newline at end of file diff --git a/noir/test_programs/execution_success/regression_3607/Nargo.toml b/noir/test_programs/execution_success/regression_3607/Nargo.toml new file mode 100644 index 00000000000..8757f88b90e --- /dev/null +++ b/noir/test_programs/execution_success/regression_3607/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "regression_3607" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/regression_3607/Prover.toml b/noir/test_programs/execution_success/regression_3607/Prover.toml new file mode 100644 index 00000000000..4dd6b405159 --- /dev/null +++ b/noir/test_programs/execution_success/regression_3607/Prover.toml @@ -0,0 +1 @@ +x = "1" diff --git a/noir/test_programs/execution_success/regression_3607/src/main.nr b/noir/test_programs/execution_success/regression_3607/src/main.nr new file mode 100644 index 00000000000..c09211c2810 --- /dev/null +++ b/noir/test_programs/execution_success/regression_3607/src/main.nr @@ -0,0 +1,8 @@ +fn main(mut x: u32) { + if x == 0 { + x = (x+1) / x; + } else { + x = (x+1) / x; + } + assert(x != 0); +} \ No newline at end of file diff --git a/noir/test_programs/execution_success/side_effects_constrain_array/Nargo.toml b/noir/test_programs/execution_success/side_effects_constrain_array/Nargo.toml new file mode 100644 index 00000000000..fc817f0921f --- /dev/null +++ b/noir/test_programs/execution_success/side_effects_constrain_array/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "side_effects_constrain_array" +type = "bin" +authors = [""] +compiler_version = ">=0.20.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/execution_success/side_effects_constrain_array/Prover.toml b/noir/test_programs/execution_success/side_effects_constrain_array/Prover.toml new file mode 100644 index 00000000000..7127baac5bf --- /dev/null +++ b/noir/test_programs/execution_success/side_effects_constrain_array/Prover.toml @@ -0,0 +1 @@ +y = "3" diff --git a/noir/test_programs/execution_success/side_effects_constrain_array/src/main.nr b/noir/test_programs/execution_success/side_effects_constrain_array/src/main.nr new file mode 100644 index 00000000000..fb3c346a460 --- /dev/null +++ b/noir/test_programs/execution_success/side_effects_constrain_array/src/main.nr @@ -0,0 +1,17 @@ +struct Bar { + inner: [Field; 3], +} + +fn main(y: pub u32) { + let bar = Bar { inner: [100, 101, 102] }; + + // The assert inside the if should be hit + if y < 10 { + assert(bar.inner == [100, 101, 102]); + } + + // The assert inside the if should not be hit + if y > 10 { + assert(bar.inner == [0, 1, 2]); + } +} \ No newline at end of file diff --git a/noir/test_programs/execution_success/slice_dynamic_index/src/main.nr b/noir/test_programs/execution_success/slice_dynamic_index/src/main.nr index 2e5c0122dfb..374d2ba4c26 100644 --- a/noir/test_programs/execution_success/slice_dynamic_index/src/main.nr +++ b/noir/test_programs/execution_success/slice_dynamic_index/src/main.nr @@ -123,13 +123,13 @@ fn dynamic_slice_merge_if(mut slice: [Field], x: Field) { let (first_elem, rest_of_slice) = popped_slice.pop_front(); assert(first_elem == 12); assert(rest_of_slice.len() == 6); - // TODO(#2462): SliceInsert and SliceRemove with a dynamic index are not yet implemented in ACIR gen - slice = rest_of_slice.insert(2, 20); + + slice = rest_of_slice.insert(x - 2, 20); assert(slice[2] == 20); assert(slice[6] == 30); assert(slice.len() == 7); - // TODO(#2462): SliceInsert and SliceRemove with a dynamic index are not yet implemented in ACIR gen - let (removed_slice, removed_elem) = slice.remove(3); + + let (removed_slice, removed_elem) = slice.remove(x - 1); // The deconstructed tuple assigns to the slice but is not seen outside of the if statement // without a direct assignment slice = removed_slice; diff --git a/noir/test_programs/execution_success/slice_struct_field/src/main.nr b/noir/test_programs/execution_success/slice_struct_field/src/main.nr index c00fdf85180..a5b971ada4b 100644 --- a/noir/test_programs/execution_success/slice_struct_field/src/main.nr +++ b/noir/test_programs/execution_success/slice_struct_field/src/main.nr @@ -23,12 +23,12 @@ fn main(y: pub Field) { let foo_two = Foo { a: 4, b: b_two, bar: Bar { inner: [103, 104, 105] } }; let foo_three = Foo { a: 7, b: [8, 9, 22], bar: Bar { inner: [106, 107, 108] } }; - let foo_four = Foo { a: 10, b: [11, 12, 23], bar: Bar { inner: [109, 110, 111] } }; + let mut foo_four = Foo { a: 10, b: [11, 12, 23], bar: Bar { inner: [109, 110, 111] } }; let mut x = [foo_one, foo_two]; x = x.push_back(foo_three); x = x.push_back(foo_four); - + assert(x[y - 3].a == 1); let struct_slice = x[y - 3].b; for i in 0..4 { @@ -60,6 +60,14 @@ fn main(y: pub Field) { assert(x[y].bar.inner == [109, 110, 111]); // Check that switching the lhs and rhs is still valid assert([109, 110, 111] == x[y].bar.inner); + + assert(x[y - 3].bar.inner == [100, 101, 102]); + assert(x[y - 2].bar.inner == [103, 104, 105]); + assert(x[y - 1].bar.inner == [106, 107, 108]); + assert(x[y].bar.inner == [109, 110, 111]); + // Check that switching the lhs and rhs is still valid + assert([109, 110, 111] == x[y].bar.inner); + // TODO: Enable merging nested slices // if y != 2 { // x[y].a = 50; @@ -75,12 +83,13 @@ fn main(y: pub Field) { // assert(x[2].b[0] == 100); // assert(x[2].b[1] == 101); // assert(x[2].b[2] == 102); + let q = x.push_back(foo_four); let foo_parent_one = FooParent { parent_arr: [0, 1, 2], foos: x }; let foo_parent_two = FooParent { parent_arr: [3, 4, 5], foos: q }; let mut foo_parents = [foo_parent_one]; foo_parents = foo_parents.push_back(foo_parent_two); - // TODO: make a separate test for compile time + // TODO: make a separate test for entirely compile time // foo_parents[1].foos.push_back(foo_four); // TODO: Merging nested slices is broken // if y == 3 { @@ -88,6 +97,7 @@ fn main(y: pub Field) { // } else { // foo_parents[y - 2].foos[y - 1].b[y - 1] = 1000; // } + assert(foo_parents[y - 2].foos[y - 2].b[y - 1] == 21); foo_parents[y - 2].foos[y - 2].b[y - 1] = 5000; assert(foo_parents[y - 2].foos[y - 2].b[y - 1] == 5000); @@ -108,11 +118,15 @@ fn main(y: pub Field) { assert(foo_parents[y - 2].foos[y - 1].a == 7); foo_parents[y - 2].foos[y - 1].a = 50; + assert(foo_parents[y - 2].foos[y - 1].a == 50); let b_array = foo_parents[y - 2].foos[y - 1].b; + assert(b_array[0] == 8); + assert(b_array[1] == 9); assert(b_array[2] == 22); assert(b_array.len() == 3); - // Test setting a nested array with non-dynamic + + // // Test setting a nested array with non-dynamic let x = [5, 6, 5000, 21, 100, 101].as_slice(); foo_parents[y - 2].foos[y - 1].b = x; @@ -120,16 +134,52 @@ fn main(y: pub Field) { assert(foo_parents[y - 2].foos[y - 1].b[4] == 100); assert(foo_parents[y - 2].foos[y - 1].b[5] == 101); + // Need to account for that foo_parents is not modified outside of this function test_basic_intrinsics_nested_slices(foo_parents, y); - // TODO(#3364): still have to enable slice intrinsics on dynamic nested slices - // assert(foo_parents[y - 2].foos.len() == 5); - // foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo_four); - // assert(foo_parents[y - 2].foos.len() == 6); + test_complex_intrinsic_nested_slices(foo_parents, y); + + foo_parents[y - 2].foos[y - 1].b = foo_parents[y - 2].foos[y - 1].b.push_back(500); + assert(foo_parents[y - 2].foos[y - 1].b.len() == 7); + assert(foo_parents[y - 2].foos[y - 1].b[6] == 500); + + let (popped_slice, last_elem) = foo_parents[y - 2].foos[y - 1].b.pop_back(); + foo_parents[y - 2].foos[y - 1].b = popped_slice; + assert(foo_parents[y - 2].foos[y - 1].b.len() == 6); + assert(last_elem == 500); + + foo_parents[y - 2].foos[y - 1].b = foo_parents[y - 2].foos[y - 1].b.push_front(11); + assert(foo_parents[y - 2].foos[y - 1].b.len() == 7); + assert(foo_parents[y - 2].foos[y - 1].b[0] == 11); + + assert(foo_parents[y - 2].foos.len() == 5); + foo_four.a = 40; + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo_four); + assert(foo_parents[y - 2].foos.len() == 6); + assert(foo_parents[y - 2].foos[y + 2].bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo_four); + assert(foo_parents[y - 2].foos.len() == 7); + assert(foo_parents[y - 2].foos[6].a == 40); + assert(foo_parents[y - 2].foos[5].bar.inner == [109, 110, 111]); + assert(foo_parents[y - 2].foos[6].bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo_four); + assert(foo_parents[y - 2].foos.len() == 8); + assert(foo_parents[y - 2].foos[6].a == 40); + assert(foo_parents[y - 2].foos[5].bar.inner == [109, 110, 111]); + assert(foo_parents[y - 2].foos[6].bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo_four); + assert(foo_parents[y - 2].foos.len() == 9); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo_four); + assert(foo_parents[y - 2].foos.len() == 10); + let b_array = foo_parents[y - 2].foos[y - 1].b; - assert(b_array[0] == 5); - assert(b_array[1] == 6); - assert(b_array[2] == 5000); - assert(b_array[3] == 21); + assert(b_array[0] == 11); + assert(b_array[1] == 5); + assert(b_array[2] == 6); + assert(b_array[3] == 5000); let b_array = foo_parents[y - 2].foos[y].b; assert(foo_parents[y - 2].foos[y].a == 10); @@ -175,3 +225,248 @@ fn test_basic_intrinsics_nested_slices(mut foo_parents: [FooParent], y: Field) { assert(foo_parents[y - 2].foos[y - 1].b[2] == 20); assert(foo_parents[y - 2].foos[y - 1].b[3] == 21); } + +// This method test intrinsics on nested slices with complex inputs such as +// pushing a `Foo` struct onto a slice in `FooParents`. +fn test_complex_intrinsic_nested_slices(mut foo_parents: [FooParent], y: Field) { + let mut foo = Foo { a: 13, b: [14, 15, 16], bar: Bar { inner: [109, 110, 111] } }; + assert(foo_parents[y - 2].foos.len() == 5); + foo.a = 40; + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_back(foo); + assert(foo_parents[1].foos.len() == 6); + assert(foo_parents[1].foos[5].a == 40); + assert(foo_parents[1].foos[5].b[0] == 14); + assert(foo_parents[1].foos[5].b[2] == 16); + assert(foo_parents[1].foos[5].b.len() == 3); + assert(foo_parents[1].foos[5].bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos[y - 1].b = foo_parents[y - 2].foos[y - 1].b.push_back(500); + assert(foo_parents[1].foos[2].b.len() == 7); + assert(foo_parents[1].foos[2].b[6] == 500); + assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]); + assert(foo_parents[1].foos[5].a == 40); + assert(foo_parents[1].foos[5].b[0] == 14); + assert(foo_parents[1].foos[5].b[2] == 16); + assert(foo_parents[1].foos[5].b.len() == 3); + assert(foo_parents[1].foos[5].bar.inner == [109, 110, 111]); + + let (popped_slice, last_foo) = foo_parents[y - 2].foos.pop_back(); + foo_parents[y - 2].foos = popped_slice; + assert(foo_parents[y - 2].foos.len() == 5); + assert(last_foo.a == 40); + assert(last_foo.b[0] == 14); + assert(last_foo.b[1] == 15); + assert(last_foo.b[2] == 16); + assert(last_foo.bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.push_front(foo); + assert(foo_parents[1].foos.len() == 6); + assert(foo_parents[1].foos[0].a == 40); + assert(foo_parents[1].foos[0].b[0] == 14); + assert(foo_parents[1].foos[0].b[1] == 15); + assert(foo_parents[1].foos[0].b[2] == 16); + assert(foo_parents[1].foos[5].a == 10); + assert(foo_parents[1].foos[5].b.len() == 3); + assert(foo_parents[1].foos[5].b[0] == 11); + assert(foo_parents[1].foos[5].b[2] == 23); + assert(foo_parents[1].foos[5].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[1].a == 1); + assert(foo_parents[1].foos[1].bar.inner == [100, 101, 102]); + + let (first_foo, rest_of_slice) = foo_parents[y - 2].foos.pop_front(); + + foo_parents[y - 2].foos = rest_of_slice; + assert(first_foo.a == 40); + assert(first_foo.b[0] == 14); + assert(first_foo.b[1] == 15); + assert(first_foo.b[2] == 16); + assert(first_foo.bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[0].a == 1); + assert(foo_parents[1].foos[0].b[0] == 2); + assert(foo_parents[1].foos[0].b[1] == 3); + assert(foo_parents[1].foos[0].b[2] == 20); + assert(foo_parents[1].foos[0].b[3] == 20); + assert(foo_parents[1].foos[0].bar.inner == [100, 101, 102]); + + test_insert_remove_const_index(foo_parents, y, foo); + + // Check values before insertion + assert(foo_parents[1].foos[1].a == 4); + assert(foo_parents[1].foos[1].b[0] == 5); + assert(foo_parents[1].foos[1].b[1] == 6); + assert(foo_parents[1].foos[1].b[2] == 5000); + assert(foo_parents[1].foos[1].b[3] == 21); + assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]); + + assert(foo_parents[1].foos.len() == 5); + assert(foo_parents[1].foos[2].a == 50); + assert(foo_parents[1].foos[2].b[0] == 5); + assert(foo_parents[1].foos[2].b[2] == 5000); + assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]); + + assert(foo_parents[1].foos[3].a == 10); + assert(foo_parents[1].foos[3].b[0] == 11); + assert(foo_parents[1].foos[3].b[2] == 23); + assert(foo_parents[1].foos[3].bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.insert(y - 1, foo); + assert(foo_parents[1].foos.len() == 6); + + // Check values correctly moved after insertion + assert(foo_parents[1].foos[0].a == 1); + assert(foo_parents[1].foos[0].b[0] == 2); + assert(foo_parents[1].foos[0].b[1] == 3); + assert(foo_parents[1].foos[0].b[2] == 20); + assert(foo_parents[1].foos[0].b[3] == 20); + assert(foo_parents[1].foos[0].bar.inner == [100, 101, 102]); + + assert(foo_parents[1].foos[1].a == 4); + assert(foo_parents[1].foos[1].b[0] == 5); + assert(foo_parents[1].foos[1].b[1] == 6); + assert(foo_parents[1].foos[1].b[2] == 5000); + assert(foo_parents[1].foos[1].b[3] == 21); + assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]); + + assert(foo_parents[1].foos[2].a == 40); + assert(foo_parents[1].foos[2].b[0] == 14); + assert(foo_parents[1].foos[2].b[2] == 16); + assert(foo_parents[1].foos[2].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[3].a == 50); + assert(foo_parents[1].foos[3].b[0] == 5); + assert(foo_parents[1].foos[3].b[2] == 5000); + assert(foo_parents[1].foos[3].bar.inner == [106, 107, 108]); + + assert(foo_parents[1].foos[4].a == 10); + assert(foo_parents[1].foos[4].b[0] == 11); + assert(foo_parents[1].foos[4].b[2] == 23); + assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[5].a == 10); + assert(foo_parents[1].foos[5].b[0] == 11); + assert(foo_parents[1].foos[5].b[2] == 23); + assert(foo_parents[1].foos[5].bar.inner == [109, 110, 111]); + + let (rest_of_slice, removed_elem) = foo_parents[y - 2].foos.remove(y - 1); + foo_parents[1].foos = rest_of_slice; + + // Check that the accurate element was removed + assert(removed_elem.a == 40); + assert(removed_elem.b[0] == 14); + assert(removed_elem.b[2] == 16); + assert(removed_elem.bar.inner == [109, 110, 111]); + + // Check that we have altered our slice accurately following a removal + assert(foo_parents[1].foos[1].a == 4); + assert(foo_parents[1].foos[1].b[0] == 5); + assert(foo_parents[1].foos[1].b[1] == 6); + assert(foo_parents[1].foos[1].b[2] == 5000); + assert(foo_parents[1].foos[1].b[3] == 21); + assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]); + + assert(foo_parents[1].foos[2].a == 50); + assert(foo_parents[1].foos[2].b[0] == 5); + assert(foo_parents[1].foos[2].b[2] == 5000); + assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]); + + assert(foo_parents[1].foos[3].a == 10); + assert(foo_parents[1].foos[3].b[0] == 11); + assert(foo_parents[1].foos[3].b[2] == 23); + assert(foo_parents[1].foos[3].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[4].b[0] == 11); + assert(foo_parents[1].foos[4].b[2] == 23); + assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]); +} + +fn test_insert_remove_const_index(mut foo_parents: [FooParent], y: Field, foo: Foo) { + // Check values before insertion + assert(foo_parents[1].foos[1].a == 4); + assert(foo_parents[1].foos[1].b[0] == 5); + assert(foo_parents[1].foos[1].b[1] == 6); + assert(foo_parents[1].foos[1].b[2] == 5000); + assert(foo_parents[1].foos[1].b[3] == 21); + assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]); + + assert(foo_parents[1].foos.len() == 5); + assert(foo_parents[1].foos[2].a == 50); + assert(foo_parents[1].foos[2].b[0] == 5); + assert(foo_parents[1].foos[2].b[2] == 5000); + assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]); + + assert(foo_parents[1].foos[3].a == 10); + assert(foo_parents[1].foos[3].b[0] == 11); + assert(foo_parents[1].foos[3].b[2] == 23); + assert(foo_parents[1].foos[3].bar.inner == [109, 110, 111]); + + foo_parents[y - 2].foos = foo_parents[y - 2].foos.insert(2, foo); + assert(foo_parents[1].foos.len() == 6); + + // Check values correctly moved after insertion + assert(foo_parents[1].foos[0].a == 1); + assert(foo_parents[1].foos[0].b[0] == 2); + assert(foo_parents[1].foos[0].b[1] == 3); + assert(foo_parents[1].foos[0].b[2] == 20); + assert(foo_parents[1].foos[0].b[3] == 20); + assert(foo_parents[1].foos[0].bar.inner == [100, 101, 102]); + + assert(foo_parents[1].foos[1].a == 4); + assert(foo_parents[1].foos[1].b[0] == 5); + assert(foo_parents[1].foos[1].b[1] == 6); + assert(foo_parents[1].foos[1].b[2] == 5000); + assert(foo_parents[1].foos[1].b[3] == 21); + assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]); + + assert(foo_parents[1].foos[2].a == 40); + assert(foo_parents[1].foos[2].b[0] == 14); + assert(foo_parents[1].foos[2].b[2] == 16); + assert(foo_parents[1].foos[2].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[3].a == 50); + assert(foo_parents[1].foos[3].b[0] == 5); + assert(foo_parents[1].foos[3].b[2] == 5000); + assert(foo_parents[1].foos[3].bar.inner == [106, 107, 108]); + + assert(foo_parents[1].foos[4].a == 10); + assert(foo_parents[1].foos[4].b[0] == 11); + assert(foo_parents[1].foos[4].b[2] == 23); + assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[5].a == 10); + assert(foo_parents[1].foos[5].b[0] == 11); + assert(foo_parents[1].foos[5].b[2] == 23); + assert(foo_parents[1].foos[5].bar.inner == [109, 110, 111]); + + let (rest_of_slice, removed_elem) = foo_parents[y - 2].foos.remove(2); + foo_parents[1].foos = rest_of_slice; + + // Check that the accurate element was removed + assert(removed_elem.a == 40); + assert(removed_elem.b[0] == 14); + assert(removed_elem.b[2] == 16); + assert(removed_elem.bar.inner == [109, 110, 111]); + + // Check that we have altered our slice accurately following a removal + assert(foo_parents[1].foos[1].a == 4); + assert(foo_parents[1].foos[1].b[0] == 5); + assert(foo_parents[1].foos[1].b[1] == 6); + assert(foo_parents[1].foos[1].b[2] == 5000); + assert(foo_parents[1].foos[1].b[3] == 21); + assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]); + + assert(foo_parents[1].foos[2].a == 50); + assert(foo_parents[1].foos[2].b[0] == 5); + assert(foo_parents[1].foos[2].b[2] == 5000); + assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]); + + assert(foo_parents[1].foos[3].a == 10); + assert(foo_parents[1].foos[3].b[0] == 11); + assert(foo_parents[1].foos[3].b[2] == 23); + assert(foo_parents[1].foos[3].bar.inner == [109, 110, 111]); + + assert(foo_parents[1].foos[4].b[0] == 11); + assert(foo_parents[1].foos[4].b[2] == 23); + assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]); +} diff --git a/noir/test_programs/execution_success/strings/src/main.nr b/noir/test_programs/execution_success/strings/src/main.nr index cb2218837f3..cff229d368a 100644 --- a/noir/test_programs/execution_success/strings/src/main.nr +++ b/noir/test_programs/execution_success/strings/src/main.nr @@ -10,24 +10,34 @@ fn main(message: pub str<11>, y: Field, hex_as_string: str<4>, hex_as_field: Fie let x = 10; let z = x * 5; std::println(10); + std::print(10); std::println(z); // x * 5 in println not yet supported + std::print(z); std::println(x); + std::print(x); let array = [1, 2, 3, 5, 8]; assert(y == 5); // Change to y != 5 to see how the later print statements are not called std::println(array); + std::print(array); bad_message = "hell\0\"world"; std::println(bad_message); + std::print(bad_message); assert(message != bad_message); let hash = std::hash::pedersen_commitment([x]); std::println(hash); + std::print(hash); assert(hex_as_string == "0x41"); // assert(hex_as_string != 0x41); This will fail with a type mismatch between str[4] and Field assert(hex_as_field == 0x41); + + // Single digit & odd length hex literals are valid + assert(hex_as_field == 0x041); + assert(hex_as_field != 0x1); } #[test] @@ -36,6 +46,10 @@ fn test_prints_strings() { std::println(message); std::println("goodbye world"); + + std::print(message); + std::print("\n"); + std::print("goodbye world\n"); } #[test] @@ -52,8 +66,6 @@ fn test_prints_array() { } fn failed_constraint(hex_as_field: Field) { - // TODO(#2116): Note that `println` will not work if a failed constraint can be - // evaluated at compile time. // When this method is called from a test method or with constant values // a `Failed constraint` compile error will be caught before this `println` // is executed as the input will be a constant. diff --git a/noir/test_programs/rebuild.sh b/noir/test_programs/rebuild.sh index fd3e4478d62..a3137920fd5 100755 --- a/noir/test_programs/rebuild.sh +++ b/noir/test_programs/rebuild.sh @@ -14,17 +14,7 @@ process_dir() { if [ -d ./target/ ]; then rm -r ./target/ fi - nargo compile && nargo execute witness - - if [ -f ./target/witness.tr ]; then - mv ./target/witness.tr ./target/witness.gz - fi - - if [ -f ./target/${dir_name}.json ]; then - jq -r '.bytecode' ./target/${dir_name}.json | base64 -d > ./target/acir.gz - fi - - rm ./target/${dir_name}.json + nargo compile --only-acir && nargo execute witness if [ -d "$current_dir/acir_artifacts/$dir_name/target" ]; then rm -r "$current_dir/acir_artifacts/$dir_name/target" diff --git a/noir/tooling/backend_interface/Cargo.toml b/noir/tooling/backend_interface/Cargo.toml index 14b1609dd4a..32c5d28e3b0 100644 --- a/noir/tooling/backend_interface/Cargo.toml +++ b/noir/tooling/backend_interface/Cargo.toml @@ -16,8 +16,9 @@ thiserror.workspace = true serde.workspace = true serde_json.workspace = true bb_abstraction_leaks.workspace = true +log.workspace = true -tempfile = "3.6.0" +tempfile.workspace = true ## bb binary downloading tar = "~0.4.15" diff --git a/noir/tooling/backend_interface/src/cli/info.rs b/noir/tooling/backend_interface/src/cli/info.rs index d3fd89bd2bc..81b811f0e32 100644 --- a/noir/tooling/backend_interface/src/cli/info.rs +++ b/noir/tooling/backend_interface/src/cli/info.rs @@ -1,9 +1,8 @@ -use acvm::Language; +use acvm::ExpressionWidth; use serde::Deserialize; -use std::collections::HashSet; use std::path::{Path, PathBuf}; -use crate::{BackendError, BackendOpcodeSupport}; +use crate::BackendError; use super::string_from_stderr; @@ -14,7 +13,11 @@ pub(crate) struct InfoCommand { #[derive(Deserialize)] struct InfoResponse { language: LanguageResponse, + #[allow(dead_code)] + #[deprecated(note = "This field is deprecated and will be removed in the future")] opcodes_supported: Vec, + #[allow(dead_code)] + #[deprecated(note = "This field is deprecated and will be removed in the future")] black_box_functions_supported: Vec, } @@ -24,20 +27,8 @@ struct LanguageResponse { width: Option, } -impl BackendOpcodeSupport { - fn new(info: InfoResponse) -> Self { - let opcodes: HashSet = info.opcodes_supported.into_iter().collect(); - let black_box_functions: HashSet = - info.black_box_functions_supported.into_iter().collect(); - Self { opcodes, black_box_functions } - } -} - impl InfoCommand { - pub(crate) fn run( - self, - binary_path: &Path, - ) -> Result<(Language, BackendOpcodeSupport), BackendError> { + pub(crate) fn run(self, binary_path: &Path) -> Result { let mut command = std::process::Command::new(binary_path); command.arg("info").arg("-c").arg(self.crs_path).arg("-o").arg("-"); @@ -50,32 +41,27 @@ impl InfoCommand { let backend_info: InfoResponse = serde_json::from_slice(&output.stdout).expect("Backend should return valid json"); - let language: Language = match backend_info.language.name.as_str() { + let expression_width: ExpressionWidth = match backend_info.language.name.as_str() { "PLONK-CSAT" => { let width = backend_info.language.width.unwrap(); - Language::PLONKCSat { width } + ExpressionWidth::Bounded { width } } - "R1CS" => Language::R1CS, - _ => panic!("Unknown langauge"), + "R1CS" => ExpressionWidth::Unbounded, + _ => panic!("Unknown Expression width configuration"), }; - Ok((language, BackendOpcodeSupport::new(backend_info))) + Ok(expression_width) } } #[test] fn info_command() -> Result<(), BackendError> { - use acvm::acir::circuit::opcodes::Opcode; - - use acvm::acir::native_types::Expression; - let backend = crate::get_mock_backend()?; let crs_path = backend.backend_directory(); - let (language, opcode_support) = InfoCommand { crs_path }.run(backend.binary_path())?; + let expression_width = InfoCommand { crs_path }.run(backend.binary_path())?; - assert!(matches!(language, Language::PLONKCSat { width: 3 })); - assert!(opcode_support.is_opcode_supported(&Opcode::Arithmetic(Expression::default()))); + assert!(matches!(expression_width, ExpressionWidth::Bounded { width: 3 })); Ok(()) } diff --git a/noir/tooling/backend_interface/src/lib.rs b/noir/tooling/backend_interface/src/lib.rs index 36ebe5ebb91..8ed164fc217 100644 --- a/noir/tooling/backend_interface/src/lib.rs +++ b/noir/tooling/backend_interface/src/lib.rs @@ -1,15 +1,14 @@ #![warn(unused_crate_dependencies, unused_extern_crates)] #![warn(unreachable_pub)] -use std::{collections::HashSet, path::PathBuf}; +use std::path::PathBuf; mod cli; mod download; mod proof_system; mod smart_contract; -use acvm::acir::circuit::Opcode; -use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; +pub use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; use bb_abstraction_leaks::BB_VERSION; use cli::VersionCommand; pub use download::download_backend; @@ -116,7 +115,7 @@ impl Backend { // If version doesn't match then download the correct version. Ok(version_string) => { - println!("`{ACVM_BACKEND_BARRETENBERG}` version `{version_string}` is different from expected `{BB_VERSION}`. Downloading expected version..."); + log::warn!("`{ACVM_BACKEND_BARRETENBERG}` version `{version_string}` is different from expected `{BB_VERSION}`. Downloading expected version..."); let bb_url = std::env::var("BB_BINARY_URL") .unwrap_or_else(|_| bb_abstraction_leaks::BB_DOWNLOAD_URL.to_owned()); download_backend(&bb_url, binary_path)?; @@ -124,7 +123,7 @@ impl Backend { // If `bb` fails to report its version, then attempt to fix it by re-downloading the binary. Err(_) => { - println!("Could not determine version of `{ACVM_BACKEND_BARRETENBERG}`. Downloading expected version..."); + log::warn!("Could not determine version of `{ACVM_BACKEND_BARRETENBERG}`. Downloading expected version..."); let bb_url = std::env::var("BB_BINARY_URL") .unwrap_or_else(|_| bb_abstraction_leaks::BB_DOWNLOAD_URL.to_owned()); download_backend(&bb_url, binary_path)?; @@ -135,54 +134,6 @@ impl Backend { } } -pub struct BackendOpcodeSupport { - opcodes: HashSet, - black_box_functions: HashSet, -} - -impl BackendOpcodeSupport { - pub fn is_opcode_supported(&self, opcode: &Opcode) -> bool { - match opcode { - Opcode::Arithmetic(_) => self.opcodes.contains("arithmetic"), - Opcode::Directive(_) => self.opcodes.contains("directive"), - Opcode::Brillig(_) => self.opcodes.contains("brillig"), - Opcode::MemoryInit { .. } => self.opcodes.contains("memory_init"), - Opcode::MemoryOp { .. } => self.opcodes.contains("memory_op"), - Opcode::BlackBoxFuncCall(func) => { - self.black_box_functions.contains(func.get_black_box_func().name()) - } - } - } - - pub fn all() -> BackendOpcodeSupport { - BackendOpcodeSupport { - opcodes: HashSet::from([ - "arithmetic".to_string(), - "directive".to_string(), - "brillig".to_string(), - "memory_init".to_string(), - "memory_op".to_string(), - ]), - black_box_functions: HashSet::from([ - "sha256".to_string(), - "schnorr_verify".to_string(), - "blake2s".to_string(), - "pedersen".to_string(), - "pedersen_hash".to_string(), - "hash_to_field_128_security".to_string(), - "ecdsa_secp256k1".to_string(), - "fixed_base_scalar_mul".to_string(), - "and".to_string(), - "xor".to_string(), - "range".to_string(), - "keccak256".to_string(), - "recursive_aggregation".to_string(), - "ecdsa_secp256r1".to_string(), - ]), - } - } -} - #[cfg(test)] mod backend { use crate::{Backend, BackendError}; diff --git a/noir/tooling/backend_interface/src/proof_system.rs b/noir/tooling/backend_interface/src/proof_system.rs index dcf1dad56b0..01842a81da9 100644 --- a/noir/tooling/backend_interface/src/proof_system.rs +++ b/noir/tooling/backend_interface/src/proof_system.rs @@ -3,15 +3,15 @@ use std::io::Write; use std::path::Path; use acvm::acir::{circuit::Circuit, native_types::WitnessMap}; +use acvm::ExpressionWidth; use acvm::FieldElement; -use acvm::Language; use tempfile::tempdir; use crate::cli::{ GatesCommand, InfoCommand, ProofAsFieldsCommand, ProveCommand, VerifyCommand, VkAsFieldsCommand, WriteVkCommand, }; -use crate::{Backend, BackendError, BackendOpcodeSupport}; +use crate::{Backend, BackendError}; impl Backend { pub fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { @@ -30,21 +30,22 @@ impl Backend { .run(binary_path) } - pub fn get_backend_info(&self) -> Result<(Language, BackendOpcodeSupport), BackendError> { + pub fn get_backend_info(&self) -> Result { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; InfoCommand { crs_path: self.crs_directory() }.run(binary_path) } - /// If we cannot get a valid backend, returns the default backend which supports all the opcodes - /// and uses Plonk with width 3 + /// If we cannot get a valid backend, returns `ExpressionWidth::Bound { width: 3 }`` /// The function also prints a message saying we could not find a backend - pub fn get_backend_info_or_default(&self) -> (Language, BackendOpcodeSupport) { - if let Ok(backend_info) = self.get_backend_info() { - (backend_info.0, backend_info.1) + pub fn get_backend_info_or_default(&self) -> ExpressionWidth { + if let Ok(expression_width) = self.get_backend_info() { + expression_width } else { - println!("No valid backend found, defaulting to Plonk with width 3 and all opcodes supported"); - (Language::PLONKCSat { width: 3 }, BackendOpcodeSupport::all()) + log::warn!( + "No valid backend found, ExpressionWidth defaulting to Bounded with a width of 3" + ); + ExpressionWidth::Bounded { width: 3 } } } diff --git a/noir/tooling/debugger/README.md b/noir/tooling/debugger/README.md new file mode 100644 index 00000000000..964784cb730 --- /dev/null +++ b/noir/tooling/debugger/README.md @@ -0,0 +1,348 @@ +# Noir Debugger + +There are currently two ways of debugging Noir programs, both in active development and in experimental phase: + +1. The REPL debugger, which currently ships with Nargo behind a feature flag. +2. The VS Code extension, which hasn't still reached minimum viability, and so must be manually set up. + +This README explains how to use each of them as well as specifying which features are currently mature and which ones are unstable. + +## Supported project types + +At the time of writing, the debugger supports debugging binary projects, but not contracts. At the end of this README, we'll elaborate on what the current state of Noir contract debugging is, and the pre-requisites to fulfil. + + +## REPL debugger + +In order to use the REPL debugger, you will need to install a new enough version of Nargo. At the time of writing, the nightly version is 0.20.0, so we'll base this guide on it. + +Let's debug a simple circuit: + +``` +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` + +To start the REPL debugger, using a terminal, go to a Noir circuit's home directory. Then: + +`$ nargo debug` + +You should be seeing this in your terminal: + +``` +[main] Starting debugger +At opcode 0: EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] +At ~/noir-examples/recursion/circuits/main/src/main.nr:2:12 + 1 fn main(x : Field, y : pub Field) { + 2 -> assert(x != y); + 3 } +> +``` + +The debugger displays the current opcode, and the corresponding Noir code location associated to it, and it is now waiting for us to drive it. + +Let's first take a look at the available commands. For that we'll use the `help` command. + +``` +At ~/noir-examples/recursion/circuits/main/src/main.nr:2:12 + 1 fn main(x : Field, y : pub Field) { + 2 -> assert(x != y); + 3 } +> help +Available commands: + + break LOCATION:OpcodeLocation add a breakpoint at an opcode location + memory show Brillig memory (valid when executing a + Brillig block) + into step into to the next opcode + next step until a new source location is reached + delete LOCATION:OpcodeLocation delete breakpoint at an opcode location + step step to the next ACIR opcode + registers show Brillig registers (valid when executing + a Brillig block) + regset index:usize value:String update a Brillig register with the given + value + restart restart the debugging session + witness show witness map + witness index:u32 display a single witness from the witness map + witness index:u32 value:String update a witness with the given value + continue continue execution until the end of the + program + opcodes display ACIR opcodes + memset index:usize value:String update a Brillig memory cell with the given + value + +Other commands: + + help Show this help message + quit Quit repl +``` + +The command menu is pretty self-explanatory. Some commands operate only at Brillig level, such as `memory`, `memset`, `registers`, `regset`. If you try to use them while execution is paused at an ACIR opcode, the debugger will simply inform you that you are not executing Brillig code: + +``` +> registers +Not executing a Brillig block +> +``` + +Before continuing, we can take a look at the initial witness map: + +``` +> witness +_1 = 1 +_2 = 2 +> +``` + +Cool, since `x==1`, `y==2`, and we want to check that `x != y`, our circuit should succeed. At this point we could intervene and use the witness setter command to change one of the witnesses. Let's set `y=3`, then back to 2: + +``` +> witness +_1 = 1 +_2 = 2 +> witness 2 3 +_2 = 3 +> witness +_1 = 1 +_2 = 3 +> witness 2 2 +_2 = 2 +> witness +_1 = 1 +_2 = 2 +> +``` + +Let's take a look at this circuit's ACIR, using the `opcodes` command: + +``` +> opcodes + 0 -> EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] + 1 BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] + | outputs=[Simple(Witness(4))] + 1.0 | JumpIfNot { condition: RegisterIndex(0), location: 3 } + 1.1 | Const { destination: RegisterIndex(1), value: Value { inner: 1 } } + 1.2 | BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } + 1.3 | Stop + 2 EXPR [ (1, _3, _4) (1, _5) -1 ] + 3 EXPR [ (1, _3, _5) 0 ] + 4 EXPR [ (-1, _5) 0 ] +> +``` + +Note: in future versions of the debugger, we could explore prettier or more compact formats to print opcodes. + +So the next opcode will take us to Brillig execution. Let's step into opcode 1 so we can explore Brillig debugger commands. + +``` +> into +At opcode 1: BRILLIG: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] +outputs: [Simple(Witness(4))] +[JumpIfNot { condition: RegisterIndex(0), location: 3 }, Const { destination: RegisterIndex(1), value: Value { inner: 1 } }, BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) }, Stop] + +At /~/noir-examples/recursion/circuits/main/src/main.nr:2:12 + 1 fn main(x : Field, y : pub Field) { + 2 -> assert(x != y); + 3 } +``` + +In disassembly view: + +``` +> op + 0 EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] + 1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] + | outputs=[Simple(Witness(4))] + 1.0 |-> JumpIfNot { condition: RegisterIndex(0), location: 3 } + 1.1 | Const { destination: RegisterIndex(1), value: Value { inner: 1 } } + 1.2 | BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } + 1.3 | Stop + 2 EXPR [ (1, _3, _4) (1, _5) -1 ] + 3 EXPR [ (1, _3, _5) 0 ] + 4 EXPR [ (-1, _5) 0 ] +> witness +_1 = 1 +_2 = 2 +_3 = 1 +> +``` + +We can see two arrow `->` cursors: one indicates where we are from the perspective of ACIR (opcode 1), and the other one shows us where we are in the context of the current Brillig block (opcode 1.0). + +Note: REPL commands are autocompleted when not ambiguous, so `opcodes` can be run just with `op`, `into` with `i`, etc. + +The next opcode to execute is a `JumpIfNot`, which reads from register 0. Let's inspect Brillig register state: + +``` +> op + 0 EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] + 1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] + | outputs=[Simple(Witness(4))] + 1.0 |-> JumpIfNot { condition: RegisterIndex(0), location: 3 } + 1.1 | Const { destination: RegisterIndex(1), value: Value { inner: 1 } } + 1.2 | BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } + 1.3 | Stop + 2 EXPR [ (1, _3, _4) (1, _5) -1 ] + 3 EXPR [ (1, _3, _5) 0 ] + 4 EXPR [ (-1, _5) 0 ] +> registers +Brillig VM registers not available +``` + +Oops. This is unexpected, even though we were already in a Brillig block, we couldn't access the Brillig registers. This is a known issue: when just entering the Brillig block, the ACVM has not yet initialized the Brillig VM, so we can't introspect it. + +Note: In order to solve this, we would have to change the way the ACVM works, or add special handling for this case (after all, the debugger does know we're at the first opcode of a Brillig block and could keep track of how registers will be initialized). At the time of writing, we haven't yet solved this case. + +For now, let's just step once more: + +``` +> i +At opcode 1.1: Const { destination: RegisterIndex(1), value: Value { inner: 1 } } +> registers +0 = 1 +> +``` + +Now we can see that register 0 was initialized with a value of 1, so the `JumpIfNot` didn't activate. After executing opcode 1, we should see register 1 gets a value of 1: + +``` +> i +At opcode 1.2: BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } +> regist +0 = 1 +1 = 1 +> +``` + +The last operation will compute `Reg0 <- Reg1 / Reg0`: + +``` +> i +At opcode 1.3: Stop +> registers +0 = 1 +1 = 1 +> +``` + +Once we step again, we'll be out of Brillig and back on ACVM territory. With a new witness `_4` corresponding to the result of the Brillig block execution: + +``` +> op + 0 EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] + 1 BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] + | outputs=[Simple(Witness(4))] + 1.0 | JumpIfNot { condition: RegisterIndex(0), location: 3 } + 1.1 | Const { destination: RegisterIndex(1), value: Value { inner: 1 } } + 1.2 | BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } + 1.3 | Stop + 2 -> EXPR [ (1, _3, _4) (1, _5) -1 ] + 3 EXPR [ (1, _3, _5) 0 ] + 4 EXPR [ (-1, _5) 0 ] +> wit +_1 = 1 +_2 = 2 +_3 = 1 +_4 = 1 +> +``` + +At any time, we might also decide to restart from the beginning: + +``` +> restart +Restarted debugging session. +At opcode 0: EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] +At ~/noir-examples/recursion/circuits/main/src/main.nr:2:12 + 1 fn main(x : Field, y : pub Field) { + 2 -> assert(x != y); + 3 } +> +``` + +Let's set a breakpoint. For that, we can use the opcode id's listed by the `opcodes` command: + +``` +> opcodes + 0 -> EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] + 1 BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] + | outputs=[Simple(Witness(4))] + 1.0 | JumpIfNot { condition: RegisterIndex(0), location: 3 } + 1.1 | Const { destination: RegisterIndex(1), value: Value { inner: 1 } } + 1.2 | BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } + 1.3 | Stop + 2 EXPR [ (1, _3, _4) (1, _5) -1 ] + 3 EXPR [ (1, _3, _5) 0 ] + 4 EXPR [ (-1, _5) 0 ] +> break 1.2 +Added breakpoint at opcode 1.2 +``` + +Now we can have the debugger continue all the way to opcode 1.2: + +``` +> break 1.2 +Added breakpoint at opcode 1.2 +> continue +(Continuing execution...) +Stopped at breakpoint in opcode 1.2 +At opcode 1.2: BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } +> opcodes + 0 EXPR [ (-1, _1) (1, _2) (-1, _3) 0 ] + 1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(3))], q_c: 0 })] + | outputs=[Simple(Witness(4))] + 1.0 | JumpIfNot { condition: RegisterIndex(0), location: 3 } + 1.1 | Const { destination: RegisterIndex(1), value: Value { inner: 1 } } + 1.2 |-> BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) } + 1.3 | Stop + 2 EXPR [ (1, _3, _4) (1, _5) -1 ] + 3 EXPR [ (1, _3, _5) 0 ] + 4 EXPR [ (-1, _5) 0 ] +> +``` + +Let's continue to the end: + +``` +> continue +(Continuing execution...) +Finished execution +> q +[main] Circuit witness successfully solved +``` + +Upon quitting the debugger after a solved circuit, the resulting circuit witness gets saved, equivalent to what would happen if we had run the same circuit with `nargo execute`. + +## VS Code extension + +We're working on extending Noir's official VS Code extension so it uses the editor's debugger facilities to debug Noir programs. + +This section will soon show how to load the extension from sources, in order to test the debugger. + + +## Variable value inspection (unstable) + +To enable the inspection of variable values at runtime from the debugger, we're in the process of instrumenting the compiler to track and collect the necessary mappings between source code level variable names and ACIR/Brillig state. + +At the time of writing, there are still some parts of the language that haven't been fully instrumented, which means certain programs will crash when compiled with this. + +It is however possible to try out this feature, both from the REPL and VS Code, by building Nargo from branch https://github.com/manastech/noir/tree/dap-with-vars. + +We'll soon expand this section with details on how to do so for the adventurous. + + +## Towards debugging contracts + +### Contracts Runtime + +The execution of Noir contracts depends on a foreign call execution runtime to resolve all the oracle calls that the contract functions depend on. + +This means for the debugger to be usable with contracts we need to be able to do at least one of the following: + +1. Let users mock out a foreign call executor, and run the debugger with it. +2. Instrument live environments, such as the Sandbox, so that calls and transactions can be driven by the debugger, which ultimately means the debugger would use the same foreign call executor a live Sandbox uses for normal execution of Noir circuits. + +Both of these scenarios imply making the debugger available to language runtimes external to Noir. The Sandbox/PXE runs on JS runtimes, and an hypothetical mockable foreign executor could be in principle written in any language. So it seems the most promising way forward is to make sure that the debugger itself is consumable in JS runtimes. + diff --git a/noir/tooling/debugger/src/context.rs b/noir/tooling/debugger/src/context.rs index 4c429ca2a67..1475827fbea 100644 --- a/noir/tooling/debugger/src/context.rs +++ b/noir/tooling/debugger/src/context.rs @@ -321,221 +321,218 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } #[cfg(test)] -struct StubbedSolver; - -#[cfg(test)] -impl BlackBoxFunctionSolver for StubbedSolver { - fn schnorr_verify( - &self, - _public_key_x: &FieldElement, - _public_key_y: &FieldElement, - _signature: &[u8], - _message: &[u8], - ) -> Result { - unimplemented!(); - } - - fn pedersen_commitment( - &self, - _inputs: &[FieldElement], - _domain_separator: u32, - ) -> Result<(FieldElement, FieldElement), acvm::BlackBoxResolutionError> { - unimplemented!(); - } - - fn pedersen_hash( - &self, - _inputs: &[FieldElement], - _domain_separator: u32, - ) -> Result { - unimplemented!(); - } - - fn fixed_base_scalar_mul( - &self, - _low: &FieldElement, - _high: &FieldElement, - ) -> Result<(FieldElement, FieldElement), acvm::BlackBoxResolutionError> { - unimplemented!(); - } -} - -#[cfg(test)] -#[test] -fn test_resolve_foreign_calls_stepping_into_brillig() { +mod tests { + use super::*; + use crate::context::{DebugCommandResult, DebugContext}; + + use acvm::{ + acir::{ + circuit::brillig::{Brillig, BrilligInputs, BrilligOutputs}, + native_types::Expression, + }, + brillig_vm::brillig::{ + BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, + }, + }; + use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor}; use std::collections::BTreeMap; - use acvm::acir::{ - brillig::{Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory}, - circuit::brillig::{Brillig, BrilligInputs}, - native_types::Expression, - }; + struct StubbedSolver; + + impl BlackBoxFunctionSolver for StubbedSolver { + fn schnorr_verify( + &self, + _public_key_x: &FieldElement, + _public_key_y: &FieldElement, + _signature: &[u8], + _message: &[u8], + ) -> Result { + unimplemented!(); + } - use nargo::ops::DefaultForeignCallExecutor; - - let fe_0 = FieldElement::zero(); - let fe_1 = FieldElement::one(); - let w_x = Witness(1); - - let blackbox_solver = &StubbedSolver; - - let brillig_opcodes = Brillig { - inputs: vec![BrilligInputs::Single(Expression { - linear_combinations: vec![(fe_1, w_x)], - ..Expression::default() - })], - outputs: vec![], - bytecode: vec![ - BrilligOpcode::Const { destination: RegisterIndex::from(1), value: Value::from(fe_0) }, - BrilligOpcode::ForeignCall { - function: "clear_mock".into(), - destinations: vec![], - inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], - }, - BrilligOpcode::Stop, - ], - predicate: None, - }; - let opcodes = vec![Opcode::Brillig(brillig_opcodes)]; - let current_witness_index = 2; - let circuit = &Circuit { current_witness_index, opcodes, ..Circuit::default() }; - - let debug_symbols = vec![]; - let file_map = BTreeMap::new(); - let warnings = vec![]; - let debug_artifact = &DebugArtifact { debug_symbols, file_map, warnings }; - - let initial_witness = BTreeMap::from([(Witness(1), fe_1)]).into(); - - let mut context = DebugContext::new( - blackbox_solver, - circuit, - debug_artifact, - initial_witness, - Box::new(DefaultForeignCallExecutor::new(true)), - ); - - assert_eq!(context.get_current_opcode_location(), Some(OpcodeLocation::Acir(0))); - - // execute the first Brillig opcode (const) - let result = context.step_into_opcode(); - assert!(matches!(result, DebugCommandResult::Ok)); - assert_eq!( - context.get_current_opcode_location(), - Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }) - ); - - // try to execute the second Brillig opcode (and resolve the foreign call) - let result = context.step_into_opcode(); - assert!(matches!(result, DebugCommandResult::Ok)); - assert_eq!( - context.get_current_opcode_location(), - Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }) - ); - - // retry the second Brillig opcode (foreign call should be finished) - let result = context.step_into_opcode(); - assert!(matches!(result, DebugCommandResult::Ok)); - assert_eq!( - context.get_current_opcode_location(), - Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 }) - ); - - // last Brillig opcode - let result = context.step_into_opcode(); - assert!(matches!(result, DebugCommandResult::Done)); - assert_eq!(context.get_current_opcode_location(), None); -} + fn pedersen_commitment( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result<(FieldElement, FieldElement), acvm::BlackBoxResolutionError> { + unimplemented!(); + } -#[cfg(test)] -#[test] -fn test_break_brillig_block_while_stepping_acir_opcodes() { - use std::collections::BTreeMap; + fn pedersen_hash( + &self, + _inputs: &[FieldElement], + _domain_separator: u32, + ) -> Result { + unimplemented!(); + } - use acvm::acir::{ - brillig::{Opcode as BrilligOpcode, RegisterIndex}, - circuit::brillig::{Brillig, BrilligInputs, BrilligOutputs}, - native_types::Expression, - }; - use acvm::brillig_vm::brillig::BinaryFieldOp; - use nargo::ops::DefaultForeignCallExecutor; + fn fixed_base_scalar_mul( + &self, + _low: &FieldElement, + _high: &FieldElement, + ) -> Result<(FieldElement, FieldElement), acvm::BlackBoxResolutionError> { + unimplemented!(); + } + } - let fe_0 = FieldElement::zero(); - let fe_1 = FieldElement::one(); - let w_x = Witness(1); - let w_y = Witness(2); - let w_z = Witness(3); + #[test] + fn test_resolve_foreign_calls_stepping_into_brillig() { + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let w_x = Witness(1); - let blackbox_solver = &StubbedSolver; + let blackbox_solver = &StubbedSolver; - // This Brillig block is equivalent to: z = x + y - let brillig_opcodes = Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { + let brillig_opcodes = Brillig { + inputs: vec![BrilligInputs::Single(Expression { linear_combinations: vec![(fe_1, w_x)], ..Expression::default() + })], + outputs: vec![], + bytecode: vec![ + BrilligOpcode::Const { + destination: RegisterIndex::from(1), + value: Value::from(fe_0), + }, + BrilligOpcode::ForeignCall { + function: "clear_mock".into(), + destinations: vec![], + inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + }, + BrilligOpcode::Stop, + ], + predicate: None, + }; + let opcodes = vec![Opcode::Brillig(brillig_opcodes)]; + let current_witness_index = 2; + let circuit = &Circuit { current_witness_index, opcodes, ..Circuit::default() }; + + let debug_symbols = vec![]; + let file_map = BTreeMap::new(); + let warnings = vec![]; + let debug_artifact = &DebugArtifact { debug_symbols, file_map, warnings }; + + let initial_witness = BTreeMap::from([(Witness(1), fe_1)]).into(); + + let mut context = DebugContext::new( + blackbox_solver, + circuit, + debug_artifact, + initial_witness, + Box::new(DefaultForeignCallExecutor::new(true)), + ); + + assert_eq!(context.get_current_opcode_location(), Some(OpcodeLocation::Acir(0))); + + // execute the first Brillig opcode (const) + let result = context.step_into_opcode(); + assert!(matches!(result, DebugCommandResult::Ok)); + assert_eq!( + context.get_current_opcode_location(), + Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }) + ); + + // try to execute the second Brillig opcode (and resolve the foreign call) + let result = context.step_into_opcode(); + assert!(matches!(result, DebugCommandResult::Ok)); + assert_eq!( + context.get_current_opcode_location(), + Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }) + ); + + // retry the second Brillig opcode (foreign call should be finished) + let result = context.step_into_opcode(); + assert!(matches!(result, DebugCommandResult::Ok)); + assert_eq!( + context.get_current_opcode_location(), + Some(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 }) + ); + + // last Brillig opcode + let result = context.step_into_opcode(); + assert!(matches!(result, DebugCommandResult::Done)); + assert_eq!(context.get_current_opcode_location(), None); + } + + #[test] + fn test_break_brillig_block_while_stepping_acir_opcodes() { + let fe_0 = FieldElement::zero(); + let fe_1 = FieldElement::one(); + let w_x = Witness(1); + let w_y = Witness(2); + let w_z = Witness(3); + + let blackbox_solver = &StubbedSolver; + + // This Brillig block is equivalent to: z = x + y + let brillig_opcodes = Brillig { + inputs: vec![ + BrilligInputs::Single(Expression { + linear_combinations: vec![(fe_1, w_x)], + ..Expression::default() + }), + BrilligInputs::Single(Expression { + linear_combinations: vec![(fe_1, w_y)], + ..Expression::default() + }), + ], + outputs: vec![BrilligOutputs::Simple(w_z)], + bytecode: vec![ + BrilligOpcode::BinaryFieldOp { + destination: RegisterIndex::from(0), + op: BinaryFieldOp::Add, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + }, + BrilligOpcode::Stop, + ], + predicate: None, + }; + let opcodes = vec![ + // z = x + y + Opcode::Brillig(brillig_opcodes), + // x + y - z = 0 + 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, }), - BrilligInputs::Single(Expression { - linear_combinations: vec![(fe_1, w_y)], - ..Expression::default() - }), - ], - outputs: vec![BrilligOutputs::Simple(w_z)], - bytecode: vec![ - BrilligOpcode::BinaryFieldOp { - destination: RegisterIndex::from(0), - op: BinaryFieldOp::Add, - lhs: RegisterIndex::from(0), - rhs: RegisterIndex::from(1), - }, - BrilligOpcode::Stop, - ], - predicate: None, - }; - let opcodes = vec![ - // z = x + y - Opcode::Brillig(brillig_opcodes), - // x + y - z = 0 - 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, - }), - ]; - let current_witness_index = 3; - let circuit = &Circuit { current_witness_index, opcodes, ..Circuit::default() }; - - let debug_symbols = vec![]; - let file_map = BTreeMap::new(); - let warnings = vec![]; - let debug_artifact = &DebugArtifact { debug_symbols, file_map, warnings }; - - let initial_witness = BTreeMap::from([(Witness(1), fe_1), (Witness(2), fe_1)]).into(); - - let mut context = DebugContext::new( - blackbox_solver, - circuit, - debug_artifact, - initial_witness, - Box::new(DefaultForeignCallExecutor::new(true)), - ); - - // set breakpoint - let breakpoint_location = OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }; - assert!(context.add_breakpoint(breakpoint_location)); - - // execute the first ACIR opcode (Brillig block) -> should reach the breakpoint instead - let result = context.step_acir_opcode(); - assert!(matches!(result, DebugCommandResult::BreakpointReached(_))); - assert_eq!(context.get_current_opcode_location(), Some(breakpoint_location)); - - // continue execution to the next ACIR opcode - let result = context.step_acir_opcode(); - assert!(matches!(result, DebugCommandResult::Ok)); - assert_eq!(context.get_current_opcode_location(), Some(OpcodeLocation::Acir(1))); - - // last ACIR opcode - let result = context.step_acir_opcode(); - assert!(matches!(result, DebugCommandResult::Done)); - assert_eq!(context.get_current_opcode_location(), None); + ]; + let current_witness_index = 3; + let circuit = &Circuit { current_witness_index, opcodes, ..Circuit::default() }; + + let debug_symbols = vec![]; + let file_map = BTreeMap::new(); + let warnings = vec![]; + let debug_artifact = &DebugArtifact { debug_symbols, file_map, warnings }; + + let initial_witness = BTreeMap::from([(Witness(1), fe_1), (Witness(2), fe_1)]).into(); + + let mut context = DebugContext::new( + blackbox_solver, + circuit, + debug_artifact, + initial_witness, + Box::new(DefaultForeignCallExecutor::new(true)), + ); + + // set breakpoint + let breakpoint_location = OpcodeLocation::Brillig { acir_index: 0, brillig_index: 1 }; + assert!(context.add_breakpoint(breakpoint_location)); + + // execute the first ACIR opcode (Brillig block) -> should reach the breakpoint instead + let result = context.step_acir_opcode(); + assert!(matches!(result, DebugCommandResult::BreakpointReached(_))); + assert_eq!(context.get_current_opcode_location(), Some(breakpoint_location)); + + // continue execution to the next ACIR opcode + let result = context.step_acir_opcode(); + assert!(matches!(result, DebugCommandResult::Ok)); + assert_eq!(context.get_current_opcode_location(), Some(OpcodeLocation::Acir(1))); + + // last ACIR opcode + let result = context.step_acir_opcode(); + assert!(matches!(result, DebugCommandResult::Done)); + assert_eq!(context.get_current_opcode_location(), None); + } } diff --git a/noir/tooling/lsp/Cargo.toml b/noir/tooling/lsp/Cargo.toml index 67778c744db..5f5e701da67 100644 --- a/noir/tooling/lsp/Cargo.toml +++ b/noir/tooling/lsp/Cargo.toml @@ -11,7 +11,6 @@ license.workspace = true [dependencies] acvm.workspace = true codespan-lsp.workspace = true -codespan-reporting.workspace = true lsp-types.workspace = true nargo.workspace = true nargo_fmt.workspace = true @@ -22,7 +21,6 @@ noirc_frontend.workspace = true serde.workspace = true serde_json.workspace = true tower.workspace = true -cfg-if.workspace = true async-lsp = { workspace = true, features = ["omni-trait"] } serde_with = "3.2.0" fm.workspace = true diff --git a/noir/tooling/lsp/src/lib.rs b/noir/tooling/lsp/src/lib.rs index d8a992155dd..2ad8096a13f 100644 --- a/noir/tooling/lsp/src/lib.rs +++ b/noir/tooling/lsp/src/lib.rs @@ -7,7 +7,7 @@ use std::{ collections::HashMap, future::Future, ops::{self, ControlFlow}, - path::{Path, PathBuf}, + path::PathBuf, pin::Pin, task::{self, Poll}, }; @@ -17,7 +17,7 @@ use async_lsp::{ router::Router, AnyEvent, AnyNotification, AnyRequest, ClientSocket, Error, LspService, ResponseError, }; -use codespan_reporting::files; +use fm::codespan_files as files; use noirc_frontend::{ graph::{CrateId, CrateName}, hir::{Context, FunctionNameMatch}, @@ -27,7 +27,7 @@ use notifications::{ on_did_open_text_document, on_did_save_text_document, on_exit, on_initialized, }; use requests::{ - on_code_lens_request, on_formatting, on_initialize, on_profile_run_request, on_shutdown, + on_formatting, on_goto_definition_request, on_initialize, on_profile_run_request, on_shutdown, on_test_run_request, on_tests_request, }; use serde_json::Value as JsonValue; @@ -72,10 +72,10 @@ impl NargoLspService { .request::(on_initialize) .request::(on_formatting) .request::(on_shutdown) - .request::(on_code_lens_request) .request::(on_tests_request) .request::(on_test_run_request) .request::(on_profile_run_request) + .request::(on_goto_definition_request) .notification::(on_initialized) .notification::(on_did_change_configuration) .notification::(on_did_open_text_document) @@ -175,29 +175,3 @@ fn byte_span_to_range<'a, F: files::Files<'a> + ?Sized>( None } } - -cfg_if::cfg_if! { - if #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] { - use wasm_bindgen::{prelude::*, JsValue}; - - #[wasm_bindgen(module = "@noir-lang/source-resolver")] - extern "C" { - - #[wasm_bindgen(catch)] - fn read_file(path: &str) -> Result; - - } - - fn get_non_stdlib_asset(path_to_file: &Path) -> std::io::Result { - let path_str = path_to_file.to_str().unwrap(); - match read_file(path_str) { - Ok(buffer) => Ok(buffer), - Err(_) => Err(Error::new(ErrorKind::Other, "could not read file using wasm")), - } - } - } else { - fn get_non_stdlib_asset(path_to_file: &Path) -> std::io::Result { - std::fs::read_to_string(path_to_file) - } - } -} diff --git a/noir/tooling/lsp/src/notifications/mod.rs b/noir/tooling/lsp/src/notifications/mod.rs index f6484f49d48..61f0d231738 100644 --- a/noir/tooling/lsp/src/notifications/mod.rs +++ b/noir/tooling/lsp/src/notifications/mod.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; use nargo::prepare_package; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; +use nargo_toml::{find_file_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{check_crate, NOIR_ARTIFACT_VERSION_STRING}; use noirc_errors::{DiagnosticKind, FileDiagnostic}; @@ -13,7 +13,7 @@ use crate::types::{ PublishDiagnosticsParams, }; -use crate::{byte_span_to_range, get_non_stdlib_asset, get_package_tests_in_crate, LspState}; +use crate::{byte_span_to_range, get_package_tests_in_crate, LspState}; pub(super) fn on_initialized( _state: &mut LspState, @@ -69,29 +69,21 @@ pub(super) fn on_did_save_text_document( } }; - let root_path = match &state.root_path { - Some(root) => root, - None => { - return ControlFlow::Break(Err(ResponseError::new( - ErrorCode::REQUEST_FAILED, - "Could not find project root", - ) - .into())); - } - }; + let package_root = find_file_manifest(file_path.as_path()); - let toml_path = match find_package_manifest(root_path, &file_path) { - Ok(toml_path) => toml_path, - Err(err) => { + let toml_path = match package_root { + Some(toml_path) => toml_path, + None => { // If we cannot find a manifest, we log a warning but return no diagnostics // We can reconsider this when we can build a file without the need for a Nargo.toml file to resolve deps let _ = state.client.log_message(LogMessageParams { typ: MessageType::WARNING, - message: format!("{err}"), + message: format!("Nargo.toml not found for file: {:}", file_path.display()), }); return ControlFlow::Continue(()); } }; + let workspace = match resolve_workspace_from_toml( &toml_path, PackageSelection::All, @@ -111,9 +103,9 @@ pub(super) fn on_did_save_text_document( let diagnostics: Vec<_> = workspace .into_iter() .flat_map(|package| -> Vec { - let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); + let (mut context, crate_id) = prepare_package(package); - let file_diagnostics = match check_crate(&mut context, crate_id, false) { + let file_diagnostics = match check_crate(&mut context, crate_id, false, false) { Ok(((), warnings)) => warnings, Err(errors_and_warnings) => errors_and_warnings, }; @@ -161,9 +153,6 @@ pub(super) fn on_did_save_text_document( }) .collect(); - // We need to refresh lenses when we compile since that's the only time they can be accurately reflected - std::mem::drop(state.client.code_lens_refresh(())); - let _ = state.client.publish_diagnostics(PublishDiagnosticsParams { uri: params.text_document.uri, version: None, diff --git a/noir/tooling/lsp/src/requests/code_lens_request.rs b/noir/tooling/lsp/src/requests/code_lens_request.rs deleted file mode 100644 index 602ed268981..00000000000 --- a/noir/tooling/lsp/src/requests/code_lens_request.rs +++ /dev/null @@ -1,235 +0,0 @@ -use std::future::{self, Future}; - -use async_lsp::{ErrorCode, LanguageClient, ResponseError}; - -use nargo::{package::Package, prepare_package, workspace::Workspace}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; -use noirc_driver::{check_crate, NOIR_ARTIFACT_VERSION_STRING}; -use noirc_frontend::hir::FunctionNameMatch; - -use crate::{ - byte_span_to_range, get_non_stdlib_asset, - types::{CodeLens, CodeLensParams, CodeLensResult, Command, LogMessageParams, MessageType}, - LspState, -}; - -const ARROW: &str = "▶\u{fe0e}"; -const TEST_COMMAND: &str = "nargo.test"; -const TEST_CODELENS_TITLE: &str = "Run Test"; -const COMPILE_COMMAND: &str = "nargo.compile"; -const COMPILE_CODELENS_TITLE: &str = "Compile"; -const INFO_COMMAND: &str = "nargo.info"; -const INFO_CODELENS_TITLE: &str = "Info"; -const EXECUTE_COMMAND: &str = "nargo.execute"; -const EXECUTE_CODELENS_TITLE: &str = "Execute"; - -const PROFILE_COMMAND: &str = "nargo.profile"; -const PROFILE_CODELENS_TITLE: &str = "Profile"; - -fn with_arrow(title: &str) -> String { - format!("{ARROW} {title}") -} - -fn package_selection_args(workspace: &Workspace, package: &Package) -> Vec { - vec![ - "--program-dir".into(), - workspace.root_dir.display().to_string().into(), - "--package".into(), - package.name.to_string().into(), - ] -} - -pub(crate) fn on_code_lens_request( - state: &mut LspState, - params: CodeLensParams, -) -> impl Future> { - future::ready(on_code_lens_request_inner(state, params)) -} - -fn on_code_lens_request_inner( - state: &mut LspState, - params: CodeLensParams, -) -> Result { - let file_path = params.text_document.uri.to_file_path().map_err(|_| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") - })?; - - let root_path = state.root_path.as_deref().ok_or_else(|| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "Could not find project root") - })?; - - let toml_path = match find_package_manifest(root_path, &file_path) { - Ok(toml_path) => toml_path, - Err(err) => { - // If we cannot find a manifest, we log a warning but return no code lenses - // We can reconsider this when we can build a file without the need for a Nargo.toml file to resolve deps - let _ = state.client.log_message(LogMessageParams { - typ: MessageType::WARNING, - message: err.to_string(), - }); - return Ok(None); - } - }; - let workspace = resolve_workspace_from_toml( - &toml_path, - PackageSelection::All, - Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), - ) - .map_err(|err| { - // If we found a manifest, but the workspace is invalid, we raise an error about it - ResponseError::new(ErrorCode::REQUEST_FAILED, err) - })?; - - let mut lenses: Vec = vec![]; - - for package in &workspace { - let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - // We ignore the warnings and errors produced by compilation for producing code lenses - // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false); - - let fm = &context.file_manager; - let files = fm.as_file_map(); - let tests = context - .get_all_test_functions_in_crate_matching(&crate_id, FunctionNameMatch::Anything); - - for (func_name, test_function) in tests { - let location = context.function_meta(&test_function.get_id()).name.location; - let file_id = location.file; - - // Ignore diagnostics for any file that wasn't the file we saved - // TODO: In the future, we could create "related" diagnostics for these files - if fm.path(file_id) != file_path { - continue; - } - - let range = - byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); - - let test_command = Command { - title: with_arrow(TEST_CODELENS_TITLE), - command: TEST_COMMAND.into(), - arguments: Some( - [ - package_selection_args(&workspace, package), - vec!["--exact".into(), func_name.into()], - ] - .concat(), - ), - }; - - let test_lens = CodeLens { range, command: Some(test_command), data: None }; - - lenses.push(test_lens); - } - - if package.is_binary() { - if let Some(main_func_id) = context.get_main_function(&crate_id) { - let location = context.function_meta(&main_func_id).name.location; - let file_id = location.file; - - // Ignore diagnostics for any file that wasn't the file we saved - // TODO: In the future, we could create "related" diagnostics for these files - if fm.path(file_id) != file_path { - continue; - } - - let range = - byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); - - let compile_command = Command { - title: with_arrow(COMPILE_CODELENS_TITLE), - command: COMPILE_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let compile_lens = CodeLens { range, command: Some(compile_command), data: None }; - - lenses.push(compile_lens); - - let info_command = Command { - title: INFO_CODELENS_TITLE.to_string(), - command: INFO_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let info_lens = CodeLens { range, command: Some(info_command), data: None }; - - lenses.push(info_lens); - - let execute_command = Command { - title: EXECUTE_CODELENS_TITLE.to_string(), - command: EXECUTE_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let execute_lens = CodeLens { range, command: Some(execute_command), data: None }; - - lenses.push(execute_lens); - - let profile_command = Command { - title: PROFILE_CODELENS_TITLE.to_string(), - command: PROFILE_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let profile_lens = CodeLens { range, command: Some(profile_command), data: None }; - - lenses.push(profile_lens); - } - } - - if package.is_contract() { - // Currently not looking to deduplicate this since we don't have a clear decision on if the Contract stuff is staying - for contract in context.get_all_contracts(&crate_id) { - let location = contract.location; - let file_id = location.file; - - // Ignore diagnostics for any file that wasn't the file we saved - // TODO: In the future, we could create "related" diagnostics for these files - if fm.path(file_id) != file_path { - continue; - } - - let range = - byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); - - let compile_command = Command { - title: with_arrow(COMPILE_CODELENS_TITLE), - command: COMPILE_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let compile_lens = CodeLens { range, command: Some(compile_command), data: None }; - - lenses.push(compile_lens); - - let info_command = Command { - title: INFO_CODELENS_TITLE.to_string(), - command: INFO_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let info_lens = CodeLens { range, command: Some(info_command), data: None }; - - lenses.push(info_lens); - - let profile_command = Command { - title: PROFILE_CODELENS_TITLE.to_string(), - command: PROFILE_COMMAND.into(), - arguments: Some(package_selection_args(&workspace, package)), - }; - - let profile_lens = CodeLens { range, command: Some(profile_command), data: None }; - - lenses.push(profile_lens); - } - } - } - - if lenses.is_empty() { - Ok(None) - } else { - Ok(Some(lenses)) - } -} diff --git a/noir/tooling/lsp/src/requests/goto_definition.rs b/noir/tooling/lsp/src/requests/goto_definition.rs new file mode 100644 index 00000000000..558851d4ecf --- /dev/null +++ b/noir/tooling/lsp/src/requests/goto_definition.rs @@ -0,0 +1,216 @@ +use std::future::{self, Future}; + +use crate::{types::GotoDefinitionResult, LspState}; +use async_lsp::{ErrorCode, LanguageClient, ResponseError}; +use fm::codespan_files::Error; +use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, Location}; +use lsp_types::{Position, Url}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; +use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; + +pub(crate) fn on_goto_definition_request( + state: &mut LspState, + params: GotoDefinitionParams, +) -> impl Future> { + let result = on_goto_definition_inner(state, params); + future::ready(result) +} + +fn on_goto_definition_inner( + state: &mut LspState, + params: GotoDefinitionParams, +) -> Result { + let root_path = state.root_path.as_deref().ok_or_else(|| { + ResponseError::new(ErrorCode::REQUEST_FAILED, "Could not find project root") + })?; + + let file_path = + params.text_document_position_params.text_document.uri.to_file_path().map_err(|_| { + ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") + })?; + + let toml_path = match find_package_manifest(root_path, &file_path) { + Ok(toml_path) => toml_path, + Err(err) => { + let _ = state.client.log_message(lsp_types::LogMessageParams { + typ: lsp_types::MessageType::WARNING, + message: err.to_string(), + }); + return Ok(None); + } + }; + let workspace = resolve_workspace_from_toml( + &toml_path, + PackageSelection::All, + Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), + ) + .map_err(|err| { + // If we found a manifest, but the workspace is invalid, we raise an error about it + ResponseError::new(ErrorCode::REQUEST_FAILED, err) + })?; + + let mut definition_position = None; + + for package in &workspace { + let (mut context, crate_id) = nargo::prepare_package(package); + + // We ignore the warnings and errors produced by compilation while resolving the definition + let _ = noirc_driver::check_crate(&mut context, crate_id, false, false); + + let files = context.file_manager.as_file_map(); + let file_id = context.file_manager.name_to_id(file_path.clone()); + + if let Some(file_id) = file_id { + let byte_index = position_to_byte_index( + files, + file_id, + ¶ms.text_document_position_params.position, + ); + + if let Ok(byte_index) = byte_index { + let search_for_location = noirc_errors::Location { + file: file_id, + span: noirc_errors::Span::single_char(byte_index as u32), + }; + let found_location = context.get_definition_location_from(search_for_location); + + if let Some(found_location) = found_location { + let file_id = found_location.file; + definition_position = to_lsp_location(files, file_id, found_location.span); + } + } + } + } + + if let Some(definition_position) = definition_position { + let response: GotoDefinitionResponse = + GotoDefinitionResponse::from(definition_position).to_owned(); + Ok(Some(response)) + } else { + Ok(None) + } +} + +fn to_lsp_location<'a, F>( + files: &'a F, + file_id: F::FileId, + definition_span: noirc_errors::Span, +) -> Option +where + F: fm::codespan_files::Files<'a> + ?Sized, +{ + let range = crate::byte_span_to_range(files, file_id, definition_span.into())?; + let file_name = files.name(file_id).ok()?; + + let path = file_name.to_string(); + let uri = Url::from_file_path(path).ok()?; + + Some(Location { uri, range }) +} + +pub(crate) fn position_to_byte_index<'a, F>( + files: &'a F, + file_id: F::FileId, + position: &Position, +) -> Result +where + F: fm::codespan_files::Files<'a> + ?Sized, +{ + let source = files.source(file_id)?; + let source = source.as_ref(); + + let line_span = files.line_range(file_id, position.line as usize)?; + + let line_str = source.get(line_span.clone()); + + if let Some(line_str) = line_str { + let byte_offset = character_to_line_offset(line_str, position.character)?; + Ok(line_span.start + byte_offset) + } else { + Err(Error::InvalidCharBoundary { given: position.line as usize }) + } +} + +fn character_to_line_offset(line: &str, character: u32) -> Result { + let line_len = line.len(); + let mut character_offset = 0; + + let mut chars = line.chars(); + while let Some(ch) = chars.next() { + if character_offset == character { + let chars_off = chars.as_str().len(); + let ch_off = ch.len_utf8(); + + return Ok(line_len - chars_off - ch_off); + } + + character_offset += ch.len_utf16() as u32; + } + + // Handle positions after the last character on the line + if character_offset == character { + Ok(line_len) + } else { + Err(Error::ColumnTooLarge { given: character_offset as usize, max: line.len() }) + } +} + +#[cfg(test)] +mod goto_definition_tests { + + use async_lsp::ClientSocket; + use tokio::test; + + use crate::solver::MockBackend; + + use super::*; + + #[test] + async fn test_on_goto_definition() { + let client = ClientSocket::new_closed(); + let solver = MockBackend; + let mut state = LspState::new(&client, solver); + + let root_path = std::env::current_dir() + .unwrap() + .join("../../test_programs/execution_success/7_function") + .canonicalize() + .expect("Could not resolve root path"); + let noir_text_document = Url::from_file_path(root_path.join("src/main.nr").as_path()) + .expect("Could not convert text document path to URI"); + let root_uri = Some( + Url::from_file_path(root_path.as_path()).expect("Could not convert root path to URI"), + ); + + #[allow(deprecated)] + let initialize_params = lsp_types::InitializeParams { + process_id: Default::default(), + root_path: None, + root_uri, + initialization_options: None, + capabilities: Default::default(), + trace: Some(lsp_types::TraceValue::Verbose), + workspace_folders: None, + client_info: None, + locale: None, + }; + let _initialize_response = crate::requests::on_initialize(&mut state, initialize_params) + .await + .expect("Could not initialize LSP server"); + + let params = GotoDefinitionParams { + text_document_position_params: lsp_types::TextDocumentPositionParams { + text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, + position: Position { line: 95, character: 5 }, + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }; + + let response = on_goto_definition_request(&mut state, params) + .await + .expect("Could execute on_goto_definition_request"); + + assert!(&response.is_some()); + } +} diff --git a/noir/tooling/lsp/src/requests/mod.rs b/noir/tooling/lsp/src/requests/mod.rs index a319f2593a4..e2fdcdf08da 100644 --- a/noir/tooling/lsp/src/requests/mod.rs +++ b/noir/tooling/lsp/src/requests/mod.rs @@ -1,6 +1,6 @@ use std::future::Future; -use crate::types::{CodeLensOptions, InitializeParams}; +use crate::types::InitializeParams; use async_lsp::ResponseError; use lsp_types::{Position, TextDocumentSyncCapability, TextDocumentSyncKind}; use nargo_fmt::Config; @@ -20,13 +20,13 @@ use crate::{ // They are not attached to the `NargoLspService` struct so they can be unit tested with only `LspState` // and params passed in. -mod code_lens_request; +mod goto_definition; mod profile_run; mod test_run; mod tests; pub(crate) use { - code_lens_request::on_code_lens_request, profile_run::on_profile_run_request, + goto_definition::on_goto_definition_request, profile_run::on_profile_run_request, test_run::on_test_run_request, tests::on_tests_request, }; @@ -39,8 +39,6 @@ pub(crate) fn on_initialize( async { let text_document_sync = TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL); - let code_lens = CodeLensOptions { resolve_provider: Some(false) }; - let nargo = NargoCapability { tests: Some(NargoTestsOptions { fetch: Some(true), @@ -52,9 +50,9 @@ pub(crate) fn on_initialize( Ok(InitializeResult { capabilities: ServerCapabilities { text_document_sync: Some(text_document_sync), - code_lens_provider: Some(code_lens), document_formatting_provider: true, nargo: Some(nargo), + definition_provider: Some(lsp_types::OneOf::Left(true)), }, server_info: None, }) @@ -107,9 +105,7 @@ pub(crate) fn on_shutdown( #[cfg(test)] mod initialization { use async_lsp::ClientSocket; - use lsp_types::{ - CodeLensOptions, InitializeParams, TextDocumentSyncCapability, TextDocumentSyncKind, - }; + use lsp_types::{InitializeParams, TextDocumentSyncCapability, TextDocumentSyncKind}; use tokio::test; use crate::{ @@ -129,7 +125,6 @@ mod initialization { text_document_sync: Some(TextDocumentSyncCapability::Kind( TextDocumentSyncKind::FULL )), - code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(false) }), document_formatting_provider: true, .. } diff --git a/noir/tooling/lsp/src/requests/profile_run.rs b/noir/tooling/lsp/src/requests/profile_run.rs index 84888d30ba5..4c4d7f11fde 100644 --- a/noir/tooling/lsp/src/requests/profile_run.rs +++ b/noir/tooling/lsp/src/requests/profile_run.rs @@ -3,7 +3,7 @@ use std::{ future::{self, Future}, }; -use acvm::{acir::circuit::Opcode, Language}; +use acvm::ExpressionWidth; use async_lsp::{ErrorCode, ResponseError}; use nargo::artifacts::debug::DebugArtifact; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -57,16 +57,13 @@ fn on_profile_run_request_inner( .cloned() .partition(|package| package.is_binary()); - // # TODO(#3504): Consider how to incorporate Backend relevant information in wider context. - let is_opcode_supported = |_opcode: &Opcode| true; - let np_language = Language::PLONKCSat { width: 3 }; + let expression_width = ExpressionWidth::Bounded { width: 3 }; let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( &workspace, &binary_packages, &contract_packages, - np_language, - is_opcode_supported, + expression_width, &CompileOptions::default(), ) .map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?; diff --git a/noir/tooling/lsp/src/requests/test_run.rs b/noir/tooling/lsp/src/requests/test_run.rs index 962fe99a49b..e5245de426f 100644 --- a/noir/tooling/lsp/src/requests/test_run.rs +++ b/noir/tooling/lsp/src/requests/test_run.rs @@ -10,7 +10,6 @@ use noirc_driver::{check_crate, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; use noirc_frontend::hir::FunctionNameMatch; use crate::{ - get_non_stdlib_asset, types::{NargoTestRunParams, NargoTestRunResult}, LspState, }; @@ -51,8 +50,8 @@ fn on_test_run_request_inner( // Since we filtered on crate name, this should be the only item in the iterator match workspace.into_iter().next() { Some(package) => { - let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); - if check_crate(&mut context, crate_id, false).is_err() { + let (mut context, crate_id) = prepare_package(package); + if check_crate(&mut context, crate_id, false, false).is_err() { let result = NargoTestRunResult { id: params.id.clone(), result: "error".to_string(), diff --git a/noir/tooling/lsp/src/requests/tests.rs b/noir/tooling/lsp/src/requests/tests.rs index 6b94b921a06..9a67eaae6db 100644 --- a/noir/tooling/lsp/src/requests/tests.rs +++ b/noir/tooling/lsp/src/requests/tests.rs @@ -7,7 +7,7 @@ use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSele use noirc_driver::{check_crate, NOIR_ARTIFACT_VERSION_STRING}; use crate::{ - get_non_stdlib_asset, get_package_tests_in_crate, + get_package_tests_in_crate, types::{NargoPackageTests, NargoTestsParams, NargoTestsResult}, LspState, }; @@ -53,10 +53,10 @@ fn on_tests_request_inner( let package_tests: Vec<_> = workspace .into_iter() .filter_map(|package| { - let (mut context, crate_id) = prepare_package(package, Box::new(get_non_stdlib_asset)); + let (mut context, crate_id) = prepare_package(package); // We ignore the warnings and errors produced by compilation for producing tests // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, false); + let _ = check_crate(&mut context, crate_id, false, false); // We don't add test headings for a package if it contains no `#[test]` functions get_package_tests_in_crate(&context, &crate_id, &package.name) diff --git a/noir/tooling/lsp/src/types.rs b/noir/tooling/lsp/src/types.rs index ba964cba0c1..48c412eb5ad 100644 --- a/noir/tooling/lsp/src/types.rs +++ b/noir/tooling/lsp/src/types.rs @@ -1,4 +1,5 @@ use fm::FileId; +use lsp_types::{DefinitionOptions, OneOf}; use noirc_driver::DebugFile; use noirc_errors::{debug_info::OpCodesCount, Location}; use noirc_frontend::graph::CrateName; @@ -8,11 +9,10 @@ use std::collections::{BTreeMap, HashMap}; // Re-providing lsp_types that we don't need to override pub(crate) use lsp_types::{ - CodeLens, CodeLensOptions, CodeLensParams, Command, Diagnostic, DiagnosticSeverity, - DidChangeConfigurationParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, - DidOpenTextDocumentParams, DidSaveTextDocumentParams, InitializeParams, InitializedParams, - LogMessageParams, MessageType, Position, PublishDiagnosticsParams, Range, ServerInfo, - TextDocumentSyncCapability, Url, + Diagnostic, DiagnosticSeverity, DidChangeConfigurationParams, DidChangeTextDocumentParams, + DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, + InitializeParams, InitializedParams, LogMessageParams, MessageType, Position, + PublishDiagnosticsParams, Range, ServerInfo, TextDocumentSyncCapability, Url, }; pub(crate) mod request { @@ -24,7 +24,7 @@ pub(crate) mod request { }; // Re-providing lsp_types that we don't need to override - pub(crate) use lsp_types::request::{CodeLensRequest as CodeLens, Formatting, Shutdown}; + pub(crate) use lsp_types::request::{Formatting, GotoDefinition, Shutdown}; #[derive(Debug)] pub(crate) struct Initialize; @@ -108,9 +108,9 @@ pub(crate) struct ServerCapabilities { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) text_document_sync: Option, - /// The server provides code lens. + /// The server provides goto definition support. #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) code_lens_provider: Option, + pub(crate) definition_provider: Option>, /// The server provides document formatting. pub(crate) document_formatting_provider: bool, @@ -214,4 +214,4 @@ pub(crate) struct NargoProfileRunResult { pub(crate) opcodes_counts: HashMap, } -pub(crate) type CodeLensResult = Option>; +pub(crate) type GotoDefinitionResult = Option; diff --git a/noir/tooling/nargo/Cargo.toml b/noir/tooling/nargo/Cargo.toml index f8269459968..f0733d7ad44 100644 --- a/noir/tooling/nargo/Cargo.toml +++ b/noir/tooling/nargo/Cargo.toml @@ -24,4 +24,10 @@ iter-extended.workspace = true serde.workspace = true thiserror.workspace = true codespan-reporting.workspace = true -rayon = "1.8.0" \ No newline at end of file +log.workspace = true +rayon = "1.8.0" + +[dev-dependencies] +# TODO: This dependency is used to generate unit tests for `get_all_paths_in_dir` +# TODO: once that method is moved to nargo_cli, we can move this dependency to nargo_cli +tempfile.workspace = true \ No newline at end of file diff --git a/noir/tooling/nargo/src/artifacts/contract.rs b/noir/tooling/nargo/src/artifacts/contract.rs index f9e8d45b02e..4ade4f5660e 100644 --- a/noir/tooling/nargo/src/artifacts/contract.rs +++ b/noir/tooling/nargo/src/artifacts/contract.rs @@ -14,8 +14,6 @@ pub struct PreprocessedContract { pub noir_version: String, /// The name of the contract. pub name: String, - /// The identifier of the proving backend which this contract has been compiled for. - pub backend: String, /// Each of the contract's functions are compiled into a separate program stored in this `Vec`. pub functions: Vec, /// All the events defined inside the contract scope. diff --git a/noir/tooling/nargo/src/artifacts/debug.rs b/noir/tooling/nargo/src/artifacts/debug.rs index 40acc7db8f8..324c476d13d 100644 --- a/noir/tooling/nargo/src/artifacts/debug.rs +++ b/noir/tooling/nargo/src/artifacts/debug.rs @@ -34,7 +34,7 @@ impl DebugArtifact { .collect(); for file_id in files_with_debug_symbols { - let file_source = file_manager.fetch_file(file_id).source(); + let file_source = file_manager.fetch_file(file_id); file_map.insert( file_id, diff --git a/noir/tooling/nargo/src/artifacts/program.rs b/noir/tooling/nargo/src/artifacts/program.rs index 890b6c55f7d..664db0adca4 100644 --- a/noir/tooling/nargo/src/artifacts/program.rs +++ b/noir/tooling/nargo/src/artifacts/program.rs @@ -17,7 +17,6 @@ pub struct PreprocessedProgram { /// Used to short-circuit compilation in the case of the source code not changing since the last compilation. pub hash: u64, - pub backend: String, pub abi: Abi, #[serde( diff --git a/noir/tooling/nargo/src/constants.rs b/noir/tooling/nargo/src/constants.rs index 5e448277694..ff8da403c69 100644 --- a/noir/tooling/nargo/src/constants.rs +++ b/noir/tooling/nargo/src/constants.rs @@ -20,4 +20,4 @@ pub const PKG_FILE: &str = "Nargo.toml"; /// The extension for files containing circuit proofs. pub const PROOF_EXT: &str = "proof"; /// The extension for files containing proof witnesses. -pub const WITNESS_EXT: &str = "tr"; +pub const WITNESS_EXT: &str = "gz"; diff --git a/noir/tooling/nargo/src/errors.rs b/noir/tooling/nargo/src/errors.rs index bca8ca24767..c743768bee2 100644 --- a/noir/tooling/nargo/src/errors.rs +++ b/noir/tooling/nargo/src/errors.rs @@ -47,12 +47,6 @@ pub enum NargoError { ForeignCallError(#[from] ForeignCallError), } -impl From for NargoError { - fn from(_: acvm::compiler::CompileError) -> Self { - NargoError::CompilationError - } -} - impl NargoError { /// Extracts the user defined failure message from the ExecutionError /// If one exists. @@ -69,7 +63,6 @@ impl NargoError { ExecutionError::AssertionFailed(message, _) => Some(message), ExecutionError::SolvingError(error) => match error { OpcodeResolutionError::IndexOutOfBounds { .. } - | OpcodeResolutionError::UnsupportedBlackBoxFunc(_) | OpcodeResolutionError::OpcodeNotSolvable(_) | OpcodeResolutionError::UnsatisfiedConstrain { .. } => None, OpcodeResolutionError::BrilligFunctionFailed { message, .. } => Some(message), diff --git a/noir/tooling/nargo/src/lib.rs b/noir/tooling/nargo/src/lib.rs index ef014fb436b..f0c7277060f 100644 --- a/noir/tooling/nargo/src/lib.rs +++ b/noir/tooling/nargo/src/lib.rs @@ -16,10 +16,10 @@ pub mod workspace; use std::collections::BTreeMap; -use fm::{FileManager, FileReader}; +use fm::FileManager; use noirc_driver::{add_dep, prepare_crate, prepare_dependency}; use noirc_frontend::{ - graph::{CrateGraph, CrateId, CrateName}, + graph::{CrateId, CrateName}, hir::Context, }; use package::{Dependency, Package}; @@ -42,11 +42,56 @@ pub fn prepare_dependencies( } } -pub fn prepare_package(package: &Package, file_reader: Box) -> (Context, CrateId) { - // TODO: FileManager continues to leak into various crates - let fm = FileManager::new(&package.root_dir, file_reader); - let graph = CrateGraph::default(); - let mut context = Context::new(fm, graph); +// We will pre-populate the file manager with all the files in the package +// This is so that we can avoid having to read from disk when we are compiling +// +// This does not require parsing because we are interested in the files under the src directory +// it may turn out that we do not need to include some Noir files that we add to the file +// manager +pub fn insert_all_files_for_package_into_file_manager( + package: &Package, + file_manager: &mut FileManager, +) { + // Start off at the entry path and read all files in the parent directory. + let entry_path_parent = package + .entry_path + .parent() + .unwrap_or_else(|| panic!("The entry path is expected to be a single file within a directory and so should have a parent {:?}", package.entry_path)) + .clone(); + + // Get all files in the package and add them to the file manager + let paths = + get_all_paths_in_dir(entry_path_parent).expect("could not get all paths in the package"); + for path in paths { + let source = std::fs::read_to_string(path.as_path()) + .unwrap_or_else(|_| panic!("could not read file {:?} into string", path)); + file_manager.add_file_with_source(path.as_path(), source); + } + + insert_all_files_for_packages_dependencies_into_file_manager(package, file_manager); +} + +// Inserts all files for the dependencies of the package into the file manager +// too +fn insert_all_files_for_packages_dependencies_into_file_manager( + package: &Package, + file_manager: &mut FileManager, +) { + for (_, dep) in package.dependencies.iter() { + match dep { + Dependency::Local { package } | Dependency::Remote { package } => { + insert_all_files_for_package_into_file_manager(package, file_manager); + insert_all_files_for_packages_dependencies_into_file_manager(package, file_manager); + } + } + } +} + +pub fn prepare_package(package: &Package) -> (Context, CrateId) { + let mut fm = FileManager::new(&package.root_dir); + insert_all_files_for_package_into_file_manager(package, &mut fm); + + let mut context = Context::new(fm); let crate_id = prepare_crate(&mut context, &package.entry_path); @@ -54,3 +99,72 @@ pub fn prepare_package(package: &Package, file_reader: Box) -> (Cont (context, crate_id) } + +// Get all paths in the directory and subdirectories. +// +// Panics: If the path is not a path to a directory. +// +// TODO: Along with prepare_package, this function is an abstraction leak +// TODO: given that this crate should not know about the file manager. +// TODO: We can clean this up in a future refactor +fn get_all_paths_in_dir(dir: &std::path::Path) -> std::io::Result> { + assert!(dir.is_dir(), "directory {dir:?} is not a path to a directory"); + + let mut paths = Vec::new(); + + if dir.is_dir() { + for entry in std::fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + let mut sub_paths = get_all_paths_in_dir(&path)?; + paths.append(&mut sub_paths); + } else { + paths.push(path); + } + } + } + + Ok(paths) +} + +#[cfg(test)] +mod tests { + use crate::get_all_paths_in_dir; + use std::{ + fs::{self, File}, + path::Path, + }; + use tempfile::tempdir; + + fn create_test_dir_structure(temp_dir: &Path) -> std::io::Result<()> { + fs::create_dir(temp_dir.join("subdir1"))?; + File::create(temp_dir.join("subdir1/file1.txt"))?; + fs::create_dir(temp_dir.join("subdir2"))?; + File::create(temp_dir.join("subdir2/file2.txt"))?; + File::create(temp_dir.join("file3.txt"))?; + Ok(()) + } + + #[test] + fn test_get_all_paths_in_dir() { + let temp_dir = tempdir().expect("could not create a temporary directory"); + create_test_dir_structure(temp_dir.path()) + .expect("could not create test directory structure"); + + let paths = get_all_paths_in_dir(temp_dir.path()) + .expect("could not get all paths in the test directory"); + + // This should be the paths to all of the files in the directory and the subdirectory + let expected_paths = vec![ + temp_dir.path().join("file3.txt"), + temp_dir.path().join("subdir1/file1.txt"), + temp_dir.path().join("subdir2/file2.txt"), + ]; + + assert_eq!(paths.len(), expected_paths.len()); + for path in expected_paths { + assert!(paths.contains(&path)); + } + } +} diff --git a/noir/tooling/nargo/src/ops/compile.rs b/noir/tooling/nargo/src/ops/compile.rs index d4164eaa865..1a9e0a6c115 100644 --- a/noir/tooling/nargo/src/ops/compile.rs +++ b/noir/tooling/nargo/src/ops/compile.rs @@ -1,4 +1,4 @@ -use acvm::{acir::circuit::Opcode, Language}; +use acvm::ExpressionWidth; use fm::FileManager; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; @@ -17,23 +17,18 @@ pub fn compile_workspace( workspace: &Workspace, binary_packages: &[Package], contract_packages: &[Package], - np_language: Language, - is_opcode_supported: impl Fn(&Opcode) -> bool + std::marker::Sync, + expression_width: ExpressionWidth, compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CompileError> { // Compile all of the packages in parallel. let program_results: Vec<(FileManager, CompilationResult)> = binary_packages .par_iter() - .map(|package| { - compile_program(workspace, package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_program(workspace, package, compile_options, expression_width)) .collect(); let contract_results: Vec<(FileManager, CompilationResult)> = contract_packages .par_iter() - .map(|package| { - compile_contract(package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_contract(package, compile_options, expression_width)) .collect(); // Report any warnings/errors which were encountered during compilation. @@ -67,11 +62,9 @@ pub fn compile_program( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, + expression_width: ExpressionWidth, ) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = - prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); + let (mut context, crate_id) = prepare_package(package); let program_artifact_path = workspace.package_build_path(package); let mut debug_artifact_path = program_artifact_path.clone(); @@ -85,22 +78,8 @@ pub fn compile_program( } }; - // TODO: we say that pedersen hashing is supported by all backends for now - let is_opcode_supported_pedersen_hash = |opcode: &Opcode| -> bool { - if let Opcode::BlackBoxFuncCall( - acvm::acir::circuit::opcodes::BlackBoxFuncCall::PedersenHash { .. }, - ) = opcode - { - true - } else { - is_opcode_supported(opcode) - } - }; - // Apply backend specific optimizations. - let optimized_program = - crate::ops::optimize_program(program, np_language, &is_opcode_supported_pedersen_hash) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_program = crate::ops::optimize_program(program, expression_width); (context.file_manager, Ok((optimized_program, warnings))) } @@ -108,11 +87,9 @@ pub fn compile_program( fn compile_contract( package: &Package, compile_options: &CompileOptions, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, + expression_width: ExpressionWidth, ) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = - prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); + let (mut context, crate_id) = prepare_package(package); let (contract, warnings) = match noirc_driver::compile_contract(&mut context, crate_id, compile_options) { Ok(contracts_and_warnings) => contracts_and_warnings, @@ -121,9 +98,7 @@ fn compile_contract( } }; - let optimized_contract = - crate::ops::optimize_contract(contract, np_language, &is_opcode_supported) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_contract = crate::ops::optimize_contract(contract, expression_width); (context.file_manager, Ok((optimized_contract, warnings))) } diff --git a/noir/tooling/nargo/src/ops/execute.rs b/noir/tooling/nargo/src/ops/execute.rs index d7cb44188c4..2ac85781410 100644 --- a/noir/tooling/nargo/src/ops/execute.rs +++ b/noir/tooling/nargo/src/ops/execute.rs @@ -13,6 +13,7 @@ pub fn execute_circuit( blackbox_solver: &B, foreign_call_executor: &mut F, ) -> Result { + log::trace!("Start circuit execution"); let mut acvm = ACVM::new(blackbox_solver, &circuit.opcodes, initial_witness); loop { @@ -55,5 +56,7 @@ pub fn execute_circuit( } let solved_witness = acvm.finalize(); + + log::trace!("Finish circuit execution"); Ok(solved_witness) } diff --git a/noir/tooling/nargo/src/ops/foreign_calls.rs b/noir/tooling/nargo/src/ops/foreign_calls.rs index 1ca270a5bf7..bc1e19cdcf4 100644 --- a/noir/tooling/nargo/src/ops/foreign_calls.rs +++ b/noir/tooling/nargo/src/ops/foreign_calls.rs @@ -14,7 +14,7 @@ pub trait ForeignCallExecutor { /// This enumeration represents the Brillig foreign calls that are natively supported by nargo. /// After resolution of a foreign call, nargo will restart execution of the ACVM pub(crate) enum ForeignCall { - Println, + Print, CreateMock, SetMockParams, SetMockReturns, @@ -31,7 +31,7 @@ impl std::fmt::Display for ForeignCall { impl ForeignCall { pub(crate) fn name(&self) -> &'static str { match self { - ForeignCall::Println => "println", + ForeignCall::Print => "print", ForeignCall::CreateMock => "create_mock", ForeignCall::SetMockParams => "set_mock_params", ForeignCall::SetMockReturns => "set_mock_returns", @@ -42,7 +42,7 @@ impl ForeignCall { pub(crate) fn lookup(op_name: &str) -> Option { match op_name { - "println" => Some(ForeignCall::Println), + "print" => Some(ForeignCall::Print), "create_mock" => Some(ForeignCall::CreateMock), "set_mock_params" => Some(ForeignCall::SetMockParams), "set_mock_returns" => Some(ForeignCall::SetMockReturns), @@ -92,7 +92,7 @@ pub struct DefaultForeignCallExecutor { last_mock_id: usize, /// The registered mocks mocked_responses: Vec, - /// Whether to print [`ForeignCall::Println`] output. + /// Whether to print [`ForeignCall::Print`] output. show_output: bool, } @@ -120,9 +120,14 @@ impl DefaultForeignCallExecutor { decode_string_value(&fields) } - fn execute_println(foreign_call_inputs: &[ForeignCallParam]) -> Result<(), ForeignCallError> { - let display_values: PrintableValueDisplay = foreign_call_inputs.try_into()?; - println!("{display_values}"); + fn execute_print(foreign_call_inputs: &[ForeignCallParam]) -> Result<(), ForeignCallError> { + let skip_newline = foreign_call_inputs[0].unwrap_value().is_zero(); + let display_values: PrintableValueDisplay = foreign_call_inputs + .split_first() + .ok_or(ForeignCallError::MissingForeignCallInputs)? + .1 + .try_into()?; + print!("{display_values}{}", if skip_newline { "" } else { "\n" }); Ok(()) } } @@ -134,9 +139,9 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { ) -> Result { let foreign_call_name = foreign_call.function.as_str(); match ForeignCall::lookup(foreign_call_name) { - Some(ForeignCall::Println) => { + Some(ForeignCall::Print) => { if self.show_output { - Self::execute_println(&foreign_call.inputs)?; + Self::execute_print(&foreign_call.inputs)?; } Ok(ForeignCallResult { values: vec![] }) } diff --git a/noir/tooling/nargo/src/ops/optimize.rs b/noir/tooling/nargo/src/ops/optimize.rs index 54e2432aa40..d3a36dd65ac 100644 --- a/noir/tooling/nargo/src/ops/optimize.rs +++ b/noir/tooling/nargo/src/ops/optimize.rs @@ -1,34 +1,30 @@ -use acvm::{acir::circuit::Opcode, Language}; -use iter_extended::try_vecmap; +use acvm::ExpressionWidth; +use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; -use crate::NargoError; - pub fn optimize_program( mut program: CompiledProgram, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, -) -> Result { + expression_width: ExpressionWidth, +) -> CompiledProgram { let (optimized_circuit, location_map) = - acvm::compiler::compile(program.circuit, np_language, is_opcode_supported)?; + acvm::compiler::compile(program.circuit, expression_width); program.circuit = optimized_circuit; program.debug.update_acir(location_map); - Ok(program) + program } pub fn optimize_contract( contract: CompiledContract, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, -) -> Result { - let functions = try_vecmap(contract.functions, |mut func| { + expression_width: ExpressionWidth, +) -> CompiledContract { + let functions = vecmap(contract.functions, |mut func| { let (optimized_bytecode, location_map) = - acvm::compiler::compile(func.bytecode, np_language, is_opcode_supported)?; + acvm::compiler::compile(func.bytecode, expression_width); func.bytecode = optimized_bytecode; func.debug.update_acir(location_map); - Ok::<_, NargoError>(func) - })?; + func + }); - Ok(CompiledContract { functions, ..contract }) + CompiledContract { functions, ..contract } } diff --git a/noir/tooling/nargo_cli/Cargo.toml b/noir/tooling/nargo_cli/Cargo.toml index 07298ae25d2..2f99fefb778 100644 --- a/noir/tooling/nargo_cli/Cargo.toml +++ b/noir/tooling/nargo_cli/Cargo.toml @@ -46,17 +46,23 @@ hex.workspace = true similar-asserts.workspace = true termcolor = "1.1.2" color-eyre = "0.6.2" +env_logger = "0.9.0" tokio = { version = "1.0", features = ["io-std"] } # Backends backend-interface = { path = "../backend_interface" } bb_abstraction_leaks.workspace = true +# Logs +tracing.workspace = true +tracing-subscriber = "0.3.18" +tracing-appender = "0.2.3" + [target.'cfg(not(unix))'.dependencies] tokio-util = { version = "0.7.8", features = ["compat"] } [dev-dependencies] -tempfile = "3.6.0" +tempfile.workspace = true dirs.workspace = true assert_cmd = "2.0.8" assert_fs = "1.0.10" diff --git a/noir/tooling/nargo_cli/build.rs b/noir/tooling/nargo_cli/build.rs index 27a9b83d836..6f6d65ee89c 100644 --- a/noir/tooling/nargo_cli/build.rs +++ b/noir/tooling/nargo_cli/build.rs @@ -201,7 +201,9 @@ fn compile_success_empty_{test_name}() {{ }} // `compile_success_empty` tests should be able to compile down to an empty circuit. - let json: serde_json::Value = serde_json::from_slice(&output.stdout).expect("JSON was not well-formatted"); + let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap_or_else(|_| {{ + panic!("JSON was not well-formatted {{:?}}",output.stdout) + }}); let num_opcodes = &json["programs"][0]["acir_opcodes"]; assert_eq!(num_opcodes.as_u64().unwrap(), 0); }} diff --git a/noir/tooling/nargo_cli/src/backends.rs b/noir/tooling/nargo_cli/src/backends.rs index 8b1da2cd118..2b3e9d8861f 100644 --- a/noir/tooling/nargo_cli/src/backends.rs +++ b/noir/tooling/nargo_cli/src/backends.rs @@ -7,7 +7,7 @@ fn active_backend_file_path() -> PathBuf { backends_directory().join(".selected_backend") } -pub(crate) const ACVM_BACKEND_BARRETENBERG: &str = "acvm-backend-barretenberg"; +pub(crate) use backend_interface::ACVM_BACKEND_BARRETENBERG; pub(crate) fn clear_active_backend() { let active_backend_file = active_backend_file_path(); diff --git a/noir/tooling/nargo_cli/src/cli/check_cmd.rs b/noir/tooling/nargo_cli/src/cli/check_cmd.rs index 57b36b8932b..0ea8186a237 100644 --- a/noir/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/check_cmd.rs @@ -55,12 +55,12 @@ pub(crate) fn run( } fn check_package(package: &Package, compile_options: &CompileOptions) -> Result<(), CompileError> { - let (mut context, crate_id) = - prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); + let (mut context, crate_id) = prepare_package(package); check_crate_and_report_errors( &mut context, crate_id, compile_options.deny_warnings, + compile_options.disable_macros, compile_options.silence_warnings, )?; @@ -182,9 +182,10 @@ pub(crate) fn check_crate_and_report_errors( context: &mut Context, crate_id: CrateId, deny_warnings: bool, + disable_macros: bool, silence_warnings: bool, ) -> Result<(), CompileError> { - let result = check_crate(context, crate_id, deny_warnings); + let result = check_crate(context, crate_id, deny_warnings, disable_macros); super::compile_cmd::report_errors( result, &context.file_manager, diff --git a/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index 02c83adb59a..b72ce01e1a9 100644 --- a/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -6,8 +6,7 @@ use super::{ use crate::backends::Backend; use crate::errors::CliError; -use acvm::Language; -use backend_interface::BackendOpcodeSupport; +use acvm::ExpressionWidth; use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; use clap::Args; use nargo::package::Package; @@ -46,15 +45,14 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; - let (np_language, opcode_support) = backend.get_backend_info()?; + let expression_width = backend.get_backend_info()?; for package in &workspace { let smart_contract_string = smart_contract_for_package( &workspace, backend, package, &args.compile_options, - np_language, - &opcode_support, + expression_width, )?; let contract_dir = workspace.contracts_directory_path(package); @@ -73,11 +71,9 @@ fn smart_contract_for_package( backend: &Backend, package: &Package, compile_options: &CompileOptions, - np_language: Language, - opcode_support: &BackendOpcodeSupport, + expression_width: ExpressionWidth, ) -> Result { - let program = - compile_bin_package(workspace, package, compile_options, np_language, opcode_support)?; + let program = compile_bin_package(workspace, package, compile_options, expression_width)?; let mut smart_contract_string = backend.eth_contract(&program.circuit)?; diff --git a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/tooling/nargo_cli/src/cli/compile_cmd.rs index 69533292bbd..5ee053c5088 100644 --- a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,9 +1,6 @@ use std::path::Path; -use acvm::acir::circuit::opcodes::BlackBoxFuncCall; -use acvm::acir::circuit::Opcode; -use acvm::Language; -use backend_interface::BackendOpcodeSupport; +use acvm::ExpressionWidth; use fm::FileManager; use iter_extended::vecmap; use nargo::artifacts::contract::PreprocessedContract; @@ -24,6 +21,7 @@ use clap::Args; use crate::backends::Backend; use crate::errors::CliError; +use super::fs::program::only_acir; use super::fs::program::{ read_debug_artifact_from_file, read_program_from_file, save_contract_to_file, save_debug_artifact_to_file, save_program_to_file, @@ -31,16 +29,9 @@ use super::fs::program::{ use super::NargoConfig; use rayon::prelude::*; -// TODO(#1388): pull this from backend. -const BACKEND_IDENTIFIER: &str = "acvm-backend-barretenberg"; - /// Compile the program and its secret execution trace into ACIR format #[derive(Debug, Clone, Args)] pub(crate) struct CompileCommand { - /// Include Proving and Verification keys in the build artifacts. - #[arg(long)] - include_keys: bool, - /// The name of the package to compile #[clap(long, conflicts_with = "workspace")] package: Option, @@ -76,13 +67,12 @@ pub(crate) fn run( .cloned() .partition(|package| package.is_binary()); - let (np_language, opcode_support) = backend.get_backend_info_or_default(); + let expression_width = backend.get_backend_info_or_default(); let (_, compiled_contracts) = compile_workspace( &workspace, &binary_packages, &contract_packages, - np_language, - &opcode_support, + expression_width, &args.compile_options, )?; @@ -98,25 +88,18 @@ pub(super) fn compile_workspace( workspace: &Workspace, binary_packages: &[Package], contract_packages: &[Package], - np_language: Language, - opcode_support: &BackendOpcodeSupport, + expression_width: ExpressionWidth, compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CliError> { // Compile all of the packages in parallel. let program_results: Vec<(FileManager, CompilationResult)> = binary_packages .par_iter() - .map(|package| { - let is_opcode_supported = |opcode: &_| opcode_support.is_opcode_supported(opcode); - compile_program(workspace, package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_program(workspace, package, compile_options, expression_width)) .collect(); let contract_results: Vec<(FileManager, CompilationResult)> = contract_packages .par_iter() - .map(|package| { - let is_opcode_supported = |opcode: &_| opcode_support.is_opcode_supported(opcode); - compile_contract(package, compile_options, np_language, &is_opcode_supported) - }) + .map(|package| compile_contract(package, compile_options, expression_width)) .collect(); // Report any warnings/errors which were encountered during compilation. @@ -150,17 +133,14 @@ pub(crate) fn compile_bin_package( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - np_language: Language, - opcode_support: &BackendOpcodeSupport, + expression_width: ExpressionWidth, ) -> Result { if package.is_library() { return Err(CompileError::LibraryCrate(package.name.clone()).into()); } let (file_manager, compilation_result) = - compile_program(workspace, package, compile_options, np_language, &|opcode| { - opcode_support.is_opcode_supported(opcode) - }); + compile_program(workspace, package, compile_options, expression_width); let program = report_errors( compilation_result, @@ -176,11 +156,9 @@ fn compile_program( workspace: &Workspace, package: &Package, compile_options: &CompileOptions, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, + expression_width: ExpressionWidth, ) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = - prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); + let (mut context, crate_id) = prepare_package(package); let program_artifact_path = workspace.package_build_path(package); let mut debug_artifact_path = program_artifact_path.clone(); @@ -217,21 +195,10 @@ fn compile_program( } }; - // TODO: we say that pedersen hashing is supported by all backends for now - let is_opcode_supported_pedersen_hash = |opcode: &Opcode| -> bool { - if let Opcode::BlackBoxFuncCall(BlackBoxFuncCall::PedersenHash { .. }) = opcode { - true - } else { - is_opcode_supported(opcode) - } - }; - // Apply backend specific optimizations. - let optimized_program = - nargo::ops::optimize_program(program, np_language, &is_opcode_supported_pedersen_hash) - .expect("Backend does not support an opcode that is in the IR"); - - save_program(optimized_program.clone(), package, &workspace.target_directory_path()); + let optimized_program = nargo::ops::optimize_program(program, expression_width); + let only_acir = compile_options.only_acir; + save_program(optimized_program.clone(), package, &workspace.target_directory_path(), only_acir); (context.file_manager, Ok((optimized_program, warnings))) } @@ -239,11 +206,9 @@ fn compile_program( fn compile_contract( package: &Package, compile_options: &CompileOptions, - np_language: Language, - is_opcode_supported: &impl Fn(&Opcode) -> bool, + expression_width: ExpressionWidth, ) -> (FileManager, CompilationResult) { - let (mut context, crate_id) = - prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); + let (mut context, crate_id) = prepare_package(package); let (contract, warnings) = match noirc_driver::compile_contract(&mut context, crate_id, compile_options) { Ok(contracts_and_warnings) => contracts_and_warnings, @@ -252,23 +217,28 @@ fn compile_contract( } }; - let optimized_contract = - nargo::ops::optimize_contract(contract, np_language, &is_opcode_supported) - .expect("Backend does not support an opcode that is in the IR"); + let optimized_contract = nargo::ops::optimize_contract(contract, expression_width); (context.file_manager, Ok((optimized_contract, warnings))) } -fn save_program(program: CompiledProgram, package: &Package, circuit_dir: &Path) { +fn save_program( + program: CompiledProgram, + package: &Package, + circuit_dir: &Path, + only_acir_opt: bool, +) { let preprocessed_program = PreprocessedProgram { hash: program.hash, - backend: String::from(BACKEND_IDENTIFIER), abi: program.abi, noir_version: program.noir_version, bytecode: program.circuit, }; - - save_program_to_file(&preprocessed_program, &package.name, circuit_dir); + if only_acir_opt { + only_acir(&preprocessed_program, circuit_dir); + } else { + save_program_to_file(&preprocessed_program, &package.name, circuit_dir); + } let debug_artifact = DebugArtifact { debug_symbols: vec![program.debug], @@ -301,7 +271,6 @@ fn save_contract(contract: CompiledContract, package: &Package, circuit_dir: &Pa let preprocessed_contract = PreprocessedContract { noir_version: contract.noir_version, name: contract.name, - backend: String::from(BACKEND_IDENTIFIER), functions: preprocessed_functions, events: contract.events, }; diff --git a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs b/noir/tooling/nargo_cli/src/cli/debug_cmd.rs index 5204e0f122c..6eab626a08d 100644 --- a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -49,7 +49,7 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; let target_dir = &workspace.target_directory_path(); - let (np_language, opcode_support) = backend.get_backend_info()?; + let expression_width = backend.get_backend_info()?; let Some(package) = workspace.into_iter().find(|p| p.is_binary()) else { println!( @@ -58,13 +58,8 @@ pub(crate) fn run( return Ok(()); }; - let compiled_program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let compiled_program = + compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; run_async(package, compiled_program, &args.prover_name, &args.witness_name, target_dir) } diff --git a/noir/tooling/nargo_cli/src/cli/execute_cmd.rs b/noir/tooling/nargo_cli/src/cli/execute_cmd.rs index 2f69b4c7df7..10760f43a45 100644 --- a/noir/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -56,15 +56,10 @@ pub(crate) fn run( )?; let target_dir = &workspace.target_directory_path(); - let (np_language, opcode_support) = backend.get_backend_info_or_default(); + let expression_width = backend.get_backend_info_or_default(); for package in &workspace { - let compiled_program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let compiled_program = + compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; let (return_value, solved_witness) = execute_program_and_decode(compiled_program, package, &args.prover_name)?; diff --git a/noir/tooling/nargo_cli/src/cli/fmt_cmd.rs b/noir/tooling/nargo_cli/src/cli/fmt_cmd.rs index ec3d373a483..e62fc560217 100644 --- a/noir/tooling/nargo_cli/src/cli/fmt_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/fmt_cmd.rs @@ -2,6 +2,7 @@ use std::{fs::DirEntry, path::Path}; use clap::Args; use fm::FileManager; +use nargo::insert_all_files_for_package_into_file_manager; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use noirc_errors::CustomDiagnostic; @@ -35,11 +36,11 @@ pub(crate) fn run(args: FormatCommand, config: NargoConfig) -> Result<(), CliErr let mut check_exit_code_one = false; for package in &workspace { - let mut file_manager = - FileManager::new(&package.root_dir, Box::new(|path| std::fs::read_to_string(path))); + let mut file_manager = FileManager::new(&package.root_dir); + insert_all_files_for_package_into_file_manager(package, &mut file_manager); visit_noir_files(&package.root_dir.join("src"), &mut |entry| { - let file_id = file_manager.add_file(&entry.path()).expect("file exists"); + let file_id = file_manager.name_to_id(entry.path().to_path_buf()).expect("The file should exist since we added all files in the package into the file manager"); let (parsed_module, errors) = parse_file(&file_manager, file_id); let is_all_warnings = errors.iter().all(ParserError::is_warning); @@ -61,7 +62,7 @@ pub(crate) fn run(args: FormatCommand, config: NargoConfig) -> Result<(), CliErr return Ok(()); } - let original = file_manager.fetch_file(file_id).source(); + let original = file_manager.fetch_file(file_id); let formatted = nargo_fmt::format(original, parsed_module, &config); if check_mode { diff --git a/noir/tooling/nargo_cli/src/cli/fs/inputs.rs b/noir/tooling/nargo_cli/src/cli/fs/inputs.rs index f3f0baf10f4..023195010ac 100644 --- a/noir/tooling/nargo_cli/src/cli/fs/inputs.rs +++ b/noir/tooling/nargo_cli/src/cli/fs/inputs.rs @@ -73,7 +73,7 @@ mod tests { use nargo::constants::VERIFIER_INPUT_FILE; use noirc_abi::{ input_parser::{Format, InputValue}, - Abi, AbiParameter, AbiType, AbiVisibility, + Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, }; use tempfile::TempDir; @@ -98,7 +98,10 @@ mod tests { visibility: AbiVisibility::Private, }, ], - return_type: Some(AbiType::Field), + return_type: Some(AbiReturnType { + abi_type: AbiType::Field, + visibility: AbiVisibility::Public, + }), // Input serialization is only dependent on types, not position in witness map. // Neither of these should be relevant so we leave them empty. diff --git a/noir/tooling/nargo_cli/src/cli/fs/program.rs b/noir/tooling/nargo_cli/src/cli/fs/program.rs index e82f2d55264..807df25ba48 100644 --- a/noir/tooling/nargo_cli/src/cli/fs/program.rs +++ b/noir/tooling/nargo_cli/src/cli/fs/program.rs @@ -1,5 +1,6 @@ use std::path::{Path, PathBuf}; +use acvm::acir::circuit::Circuit; use nargo::artifacts::{ contract::PreprocessedContract, debug::DebugArtifact, program::PreprocessedProgram, }; @@ -18,6 +19,19 @@ pub(crate) fn save_program_to_file>( save_build_artifact_to_file(compiled_program, &circuit_name, circuit_dir) } +/// Writes the bytecode as acir.gz +pub(crate) fn only_acir>( + compiled_program: &PreprocessedProgram, + circuit_dir: P, +) -> PathBuf { + create_named_dir(circuit_dir.as_ref(), "target"); + let circuit_path = circuit_dir.as_ref().join("acir").with_extension("gz"); + let bytes = Circuit::serialize_circuit(&compiled_program.bytecode); + write_to_file(&bytes, &circuit_path); + + circuit_path +} + pub(crate) fn save_contract_to_file>( compiled_contract: &PreprocessedContract, circuit_name: &str, diff --git a/noir/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/tooling/nargo_cli/src/cli/info_cmd.rs index b0f771bfc1c..e25051c1df7 100644 --- a/noir/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/info_cmd.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acvm::Language; +use acvm::ExpressionWidth; use backend_interface::BackendError; use clap::Args; use iter_extended::vecmap; @@ -67,13 +67,12 @@ pub(crate) fn run( .cloned() .partition(|package| package.is_binary()); - let (np_language, opcode_support) = backend.get_backend_info_or_default(); + let expression_width = backend.get_backend_info_or_default(); let (compiled_programs, compiled_contracts) = compile_workspace( &workspace, &binary_packages, &contract_packages, - np_language, - &opcode_support, + expression_width, &args.compile_options, )?; @@ -98,13 +97,13 @@ pub(crate) fn run( .into_par_iter() .zip(compiled_programs) .map(|(package, program)| { - count_opcodes_and_gates_in_program(backend, program, &package, np_language) + count_opcodes_and_gates_in_program(backend, program, &package, expression_width) }) .collect::>()?; let contract_info = compiled_contracts .into_par_iter() - .map(|contract| count_opcodes_and_gates_in_contract(backend, contract, np_language)) + .map(|contract| count_opcodes_and_gates_in_contract(backend, contract, expression_width)) .collect::>()?; let info_report = InfoReport { programs: program_info, contracts: contract_info }; @@ -115,7 +114,7 @@ pub(crate) fn run( } else { // Otherwise print human-readable table. if !info_report.programs.is_empty() { - let mut program_table = table!([Fm->"Package", Fm->"Language", Fm->"ACIR Opcodes", Fm->"Backend Circuit Size"]); + let mut program_table = table!([Fm->"Package", Fm->"Expression Width", Fm->"ACIR Opcodes", Fm->"Backend Circuit Size"]); for program in info_report.programs { program_table.add_row(program.into()); @@ -126,7 +125,7 @@ pub(crate) fn run( let mut contract_table = table!([ Fm->"Contract", Fm->"Function", - Fm->"Language", + Fm->"Expression Width", Fm->"ACIR Opcodes", Fm->"Backend Circuit Size" ]); @@ -203,7 +202,7 @@ struct InfoReport { struct ProgramInfo { name: String, #[serde(skip)] - language: Language, + expression_width: ExpressionWidth, acir_opcodes: usize, circuit_size: u32, } @@ -212,7 +211,7 @@ impl From for Row { fn from(program_info: ProgramInfo) -> Self { row![ Fm->format!("{}", program_info.name), - format!("{:?}", program_info.language), + format!("{:?}", program_info.expression_width), Fc->format!("{}", program_info.acir_opcodes), Fc->format!("{}", program_info.circuit_size), ] @@ -223,7 +222,7 @@ impl From for Row { struct ContractInfo { name: String, #[serde(skip)] - language: Language, + expression_width: ExpressionWidth, functions: Vec, } @@ -240,7 +239,7 @@ impl From for Vec { row![ Fm->format!("{}", contract_info.name), Fc->format!("{}", function.name), - format!("{:?}", contract_info.language), + format!("{:?}", contract_info.expression_width), Fc->format!("{}", function.acir_opcodes), Fc->format!("{}", function.circuit_size), ] @@ -252,11 +251,11 @@ fn count_opcodes_and_gates_in_program( backend: &Backend, compiled_program: CompiledProgram, package: &Package, - language: Language, + expression_width: ExpressionWidth, ) -> Result { Ok(ProgramInfo { name: package.name.to_string(), - language, + expression_width, acir_opcodes: compiled_program.circuit.opcodes.len(), circuit_size: backend.get_exact_circuit_size(&compiled_program.circuit)?, }) @@ -265,7 +264,7 @@ fn count_opcodes_and_gates_in_program( fn count_opcodes_and_gates_in_contract( backend: &Backend, contract: CompiledContract, - language: Language, + expression_width: ExpressionWidth, ) -> Result { let functions = contract .functions @@ -279,5 +278,5 @@ fn count_opcodes_and_gates_in_contract( }) .collect::>()?; - Ok(ContractInfo { name: contract.name, language, functions }) + Ok(ContractInfo { name: contract.name, expression_width, functions }) } diff --git a/noir/tooling/nargo_cli/src/cli/init_cmd.rs b/noir/tooling/nargo_cli/src/cli/init_cmd.rs index e53c2e4cdc9..dd3af97ecd6 100644 --- a/noir/tooling/nargo_cli/src/cli/init_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/init_cmd.rs @@ -1,4 +1,3 @@ -use crate::backends::Backend; use crate::errors::CliError; use super::fs::{create_named_dir, write_to_file}; @@ -34,12 +33,7 @@ const BIN_EXAMPLE: &str = include_str!("./noir_template_files/binary.nr"); const CONTRACT_EXAMPLE: &str = include_str!("./noir_template_files/contract.nr"); const LIB_EXAMPLE: &str = include_str!("./noir_template_files/library.nr"); -pub(crate) fn run( - // Backend is currently unused, but we might want to use it to inform the "new" template in the future - _backend: &Backend, - args: InitCommand, - config: NargoConfig, -) -> Result<(), CliError> { +pub(crate) fn run(args: InitCommand, config: NargoConfig) -> Result<(), CliError> { let package_name = match args.name { Some(name) => name, None => { diff --git a/noir/tooling/nargo_cli/src/cli/mod.rs b/noir/tooling/nargo_cli/src/cli/mod.rs index 88c6b57a98c..448e28fb6a7 100644 --- a/noir/tooling/nargo_cli/src/cli/mod.rs +++ b/noir/tooling/nargo_cli/src/cli/mod.rs @@ -100,7 +100,7 @@ pub(crate) fn start_cli() -> eyre::Result<()> { match command { NargoCommand::New(args) => new_cmd::run(&backend, args, config), - NargoCommand::Init(args) => init_cmd::run(&backend, args, config), + NargoCommand::Init(args) => init_cmd::run(args, config), NargoCommand::Check(args) => check_cmd::run(&backend, args, config), NargoCommand::Compile(args) => compile_cmd::run(&backend, args, config), NargoCommand::Debug(args) => debug_cmd::run(&backend, args, config), diff --git a/noir/tooling/nargo_cli/src/cli/prove_cmd.rs b/noir/tooling/nargo_cli/src/cli/prove_cmd.rs index 54b148ec3a2..cb1751e7cef 100644 --- a/noir/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -57,15 +57,10 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; - let (np_language, opcode_support) = backend.get_backend_info()?; + let expression_width = backend.get_backend_info()?; for package in &workspace { - let program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let program = + compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; prove_package( backend, diff --git a/noir/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/tooling/nargo_cli/src/cli/test_cmd.rs index e117d8555a5..fcad4d4ee9f 100644 --- a/noir/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/test_cmd.rs @@ -82,23 +82,43 @@ pub(crate) fn run( fn run_tests( blackbox_solver: &S, package: &Package, - test_name: FunctionNameMatch, + fn_name: FunctionNameMatch, show_output: bool, compile_options: &CompileOptions, ) -> Result<(), CliError> { - let (mut context, crate_id) = - prepare_package(package, Box::new(|path| std::fs::read_to_string(path))); + let (mut context, crate_id) = prepare_package(package); check_crate_and_report_errors( &mut context, crate_id, compile_options.deny_warnings, + compile_options.disable_macros, compile_options.silence_warnings, )?; - let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, test_name); + let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, fn_name); + let count_all = test_functions.len(); + if count_all == 0 { + match &fn_name { + FunctionNameMatch::Exact(pattern) => { + return Err(CliError::Generic(format!( + "[{}] Found 0 tests matching input '{pattern}'.", + package.name + ))) + } + FunctionNameMatch::Contains(pattern) => { + return Err(CliError::Generic(format!( + "[{}] Found 0 tests containing '{pattern}'.", + package.name + ))) + } + // If we are running all tests in a crate, having none is not an error + FunctionNameMatch::Anything => {} + }; + } - println!("[{}] Running {} test functions", package.name, test_functions.len()); - let mut failing = 0; + let plural = if count_all == 1 { "" } else { "s" }; + println!("[{}] Running {count_all} test function{plural}", package.name); + let mut count_failed = 0; let writer = StandardStream::stderr(ColorChoice::Always); let mut writer = writer.lock(); @@ -116,13 +136,10 @@ fn run_tests( writeln!(writer, "ok").expect("Failed to write to stdout"); } TestStatus::Fail { message, error_diagnostic } => { - let writer = StandardStream::stderr(ColorChoice::Always); - let mut writer = writer.lock(); writer .set_color(ColorSpec::new().set_fg(Some(Color::Red))) .expect("Failed to set color"); - writeln!(writer, "{message}").expect("Failed to write to stdout"); - writer.reset().expect("Failed to reset writer"); + writeln!(writer, "{message}\n").expect("Failed to write to stdout"); if let Some(diag) = error_diagnostic { noirc_errors::reporter::report_all( context.file_manager.as_file_map(), @@ -131,7 +148,7 @@ fn run_tests( compile_options.silence_warnings, ); } - failing += 1; + count_failed += 1; } TestStatus::CompileError(err) => { noirc_errors::reporter::report_all( @@ -140,21 +157,37 @@ fn run_tests( compile_options.deny_warnings, compile_options.silence_warnings, ); - failing += 1; + count_failed += 1; } } writer.reset().expect("Failed to reset writer"); } - if failing == 0 { - write!(writer, "[{}] ", package.name).expect("Failed to write to stdout"); + write!(writer, "[{}] ", package.name).expect("Failed to write to stdout"); + + if count_failed == 0 { writer.set_color(ColorSpec::new().set_fg(Some(Color::Green))).expect("Failed to set color"); - writeln!(writer, "All tests passed").expect("Failed to write to stdout"); + writeln!(writer, "{count_all} test{plural} passed").expect("Failed to write to stdout"); + writer.reset().expect("Failed to reset writer"); + + Ok(()) } else { - let plural = if failing == 1 { "" } else { "s" }; - return Err(CliError::Generic(format!("[{}] {failing} test{plural} failed", package.name))); - } + let count_passed = count_all - count_failed; + let plural_failed = if count_failed == 1 { "" } else { "s" }; + let plural_passed = if count_passed == 1 { "" } else { "s" }; + + if count_passed != 0 { + writer + .set_color(ColorSpec::new().set_fg(Some(Color::Green))) + .expect("Failed to set color"); + write!(writer, "{count_passed} test{plural_passed} passed, ",) + .expect("Failed to write to stdout"); + } + writer.set_color(ColorSpec::new().set_fg(Some(Color::Red))).expect("Failed to set color"); + writeln!(writer, "{count_failed} test{plural_failed} failed") + .expect("Failed to write to stdout"); + writer.reset().expect("Failed to reset writer"); - writer.reset().expect("Failed to reset writer"); - Ok(()) + Err(CliError::Generic(String::new())) + } } diff --git a/noir/tooling/nargo_cli/src/cli/verify_cmd.rs b/noir/tooling/nargo_cli/src/cli/verify_cmd.rs index 2f8a6efbba4..9659286b5ab 100644 --- a/noir/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -48,15 +48,10 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; - let (np_language, opcode_support) = backend.get_backend_info()?; + let expression_width = backend.get_backend_info()?; for package in &workspace { - let program = compile_bin_package( - &workspace, - package, - &args.compile_options, - np_language, - &opcode_support, - )?; + let program = + compile_bin_package(&workspace, package, &args.compile_options, expression_width)?; verify_package(backend, &workspace, package, program, &args.verifier_name)?; } diff --git a/noir/tooling/nargo_cli/src/main.rs b/noir/tooling/nargo_cli/src/main.rs index 92bd7b94988..7eeca2ab2b0 100644 --- a/noir/tooling/nargo_cli/src/main.rs +++ b/noir/tooling/nargo_cli/src/main.rs @@ -11,11 +11,28 @@ mod backends; mod cli; mod errors; +use std::env; + use color_eyre::config::HookBuilder; +use env_logger::{Builder, Env}; +use tracing_appender::rolling; const PANIC_MESSAGE: &str = "This is a bug. We may have already fixed this in newer versions of Nargo so try searching for similar issues at https://github.com/noir-lang/noir/issues/.\nIf there isn't an open issue for this bug, consider opening one at https://github.com/noir-lang/noir/issues/new?labels=bug&template=bug_report.yml"; fn main() { + let env = Env::default().filter_or("NOIR_LOG", "error"); // Default to 'error' if NOIR_LOG is not set + Builder::from_env(env).init(); + + // Setup tracing + if let Ok(log_dir) = env::var("NARGO_LOG_DIR") { + let debug_file = rolling::daily(log_dir, "nargo-log"); + tracing_subscriber::fmt() + .with_writer(debug_file) + .with_ansi(false) + .with_max_level(tracing::Level::TRACE) + .init(); + } + // Register a panic hook to display more readable panic messages to end-users let (panic_hook, _) = HookBuilder::default().display_env_section(false).panic_section(PANIC_MESSAGE).into_hooks(); diff --git a/noir/tooling/nargo_cli/tests/execution_success/prelude/Nargo.toml b/noir/tooling/nargo_cli/tests/execution_success/prelude/Nargo.toml new file mode 100644 index 00000000000..35f223bce02 --- /dev/null +++ b/noir/tooling/nargo_cli/tests/execution_success/prelude/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "prelude" +type = "bin" +authors = [""] +compiler_version = ">=0.20.0" + +[dependencies] \ No newline at end of file diff --git a/noir/tooling/nargo_cli/tests/execution_success/prelude/src/main.nr b/noir/tooling/nargo_cli/tests/execution_success/prelude/src/main.nr new file mode 100644 index 00000000000..9bf2ec18f3a --- /dev/null +++ b/noir/tooling/nargo_cli/tests/execution_success/prelude/src/main.nr @@ -0,0 +1,32 @@ +fn main(x: Field, y: pub Field) { + let xs = Vec::new(); + let option = Option::none(); + + print("42\n"); + println("42"); +} + +mod a { + // We don't want to give an error due to re-importing elements that are already in the prelude. + use dep::std::collections::vec::Vec; + use dep::std::option::Option; + use dep::{print, println}; + + fn main() { + let xs = Vec::new(); + let option = Option::none(); + + print("42\n"); + println("42"); + } +} + +mod b { + fn main() { + let xs = Vec::new(); + let option = Option::none(); + + print("42\n"); + println("42"); + } +} diff --git a/noir/tooling/nargo_fmt/build.rs b/noir/tooling/nargo_fmt/build.rs index cd93866ece9..c356b403ae5 100644 --- a/noir/tooling/nargo_fmt/build.rs +++ b/noir/tooling/nargo_fmt/build.rs @@ -46,8 +46,8 @@ fn generate_formatter_tests(test_file: &mut File, test_data_dir: &Path) { .collect::>() .join("\n"); - let output_source_path = outputs_dir.join(file_name); - let output_source = std::fs::read_to_string(output_source_path).unwrap(); + let output_source_path = outputs_dir.join(file_name).display().to_string(); + let output_source = std::fs::read_to_string(output_source_path.clone()).unwrap(); write!( test_file, @@ -58,11 +58,14 @@ fn format_{test_name}() {{ let expected_output = r#"{output_source}"#; - let (parsed_module, errors) = noirc_frontend::parse_program(&input); + let (parsed_module, _errors) = noirc_frontend::parse_program(&input); let config = nargo_fmt::Config::of("{config}").unwrap(); let fmt_text = nargo_fmt::format(&input, parsed_module, &config); + if std::env::var("UPDATE_EXPECT").is_ok() {{ + std::fs::write("{output_source_path}", fmt_text.clone()).unwrap(); + }} similar_asserts::assert_eq!(fmt_text, expected_output); }} diff --git a/noir/tooling/nargo_fmt/src/rewrite.rs b/noir/tooling/nargo_fmt/src/rewrite.rs index 5a9baf0aa05..6a95eba8759 100644 --- a/noir/tooling/nargo_fmt/src/rewrite.rs +++ b/noir/tooling/nargo_fmt/src/rewrite.rs @@ -2,8 +2,10 @@ mod array; mod expr; mod infix; mod parenthesized; +mod typ; pub(crate) use array::rewrite as array; pub(crate) use expr::{rewrite as expr, rewrite_sub_expr as sub_expr}; pub(crate) use infix::rewrite as infix; pub(crate) use parenthesized::rewrite as parenthesized; +pub(crate) use typ::rewrite as typ; diff --git a/noir/tooling/nargo_fmt/src/rewrite/expr.rs b/noir/tooling/nargo_fmt/src/rewrite/expr.rs index 3c46319c1aa..32d104f559b 100644 --- a/noir/tooling/nargo_fmt/src/rewrite/expr.rs +++ b/noir/tooling/nargo_fmt/src/rewrite/expr.rs @@ -110,7 +110,7 @@ pub(crate) fn rewrite( NewlineMode::Normal, ), ExpressionKind::Literal(literal) => match literal { - Literal::Integer(_) + Literal::Integer(_, _) | Literal::Bool(_) | Literal::Str(_) | Literal::RawStr(..) diff --git a/noir/tooling/nargo_fmt/src/rewrite/typ.rs b/noir/tooling/nargo_fmt/src/rewrite/typ.rs new file mode 100644 index 00000000000..4c6411e92b8 --- /dev/null +++ b/noir/tooling/nargo_fmt/src/rewrite/typ.rs @@ -0,0 +1,70 @@ +use noirc_frontend::{UnresolvedType, UnresolvedTypeData}; + +use crate::{ + utils::span_is_empty, + visitor::{FmtVisitor, Shape}, +}; + +pub(crate) fn rewrite(visitor: &FmtVisitor, _shape: Shape, typ: UnresolvedType) -> String { + match typ.typ { + UnresolvedTypeData::Array(length, element) => { + let typ = rewrite(visitor, _shape, *element); + if let Some(length) = length { + let length = visitor.slice(length.span()); + format!("[{typ}; {length}]") + } else { + format!("[{typ}]") + } + } + UnresolvedTypeData::Parenthesized(typ) => { + let typ = rewrite(visitor, _shape, *typ); + format!("({typ})") + } + UnresolvedTypeData::MutableReference(typ) => { + let typ = rewrite(visitor, _shape, *typ); + format!("&mut {typ}") + } + UnresolvedTypeData::Tuple(mut types) => { + if types.len() == 1 { + let typ = types.pop().unwrap(); + let typ = rewrite(visitor, _shape, typ); + + format!("({typ},)") + } else { + let types: Vec<_> = + types.into_iter().map(|typ| rewrite(visitor, _shape, typ)).collect(); + let types = types.join(", "); + format!("({types})") + } + } + UnresolvedTypeData::Function(args, return_type, env) => { + let env = if span_is_empty(env.span.unwrap()) { + "".into() + } else { + let ty = rewrite(visitor, _shape, *env); + format!("[{ty}]") + }; + + let args = args + .into_iter() + .map(|arg| rewrite(visitor, _shape, arg)) + .collect::>() + .join(", "); + + let return_type = rewrite(visitor, _shape, *return_type); + + format!("fn{env}({args}) -> {return_type}") + } + UnresolvedTypeData::Unspecified => todo!(), + UnresolvedTypeData::FieldElement + | UnresolvedTypeData::Integer(_, _) + | UnresolvedTypeData::Bool + | UnresolvedTypeData::Named(_, _) + | UnresolvedTypeData::Unit + | UnresolvedTypeData::Expression(_) + | UnresolvedTypeData::String(_) + | UnresolvedTypeData::FormatString(_, _) + | UnresolvedTypeData::TraitAsType(_, _) => visitor.slice(typ.span.unwrap()).into(), + UnresolvedTypeData::Error => unreachable!(), + } +} diff --git a/noir/tooling/nargo_fmt/src/utils.rs b/noir/tooling/nargo_fmt/src/utils.rs index 0d422e57de1..1160f01972f 100644 --- a/noir/tooling/nargo_fmt/src/utils.rs +++ b/noir/tooling/nargo_fmt/src/utils.rs @@ -250,13 +250,14 @@ impl Item for Param { self.span } - fn format(self, visitor: &FmtVisitor, _shape: Shape) -> String { + fn format(self, visitor: &FmtVisitor, shape: Shape) -> String { let visibility = match self.visibility { Visibility::Public => "pub ", Visibility::Private => "", + Visibility::DataBus => "call_data", }; let pattern = visitor.slice(self.pattern.span()); - let ty = visitor.slice(self.typ.span.unwrap()); + let ty = rewrite::typ(visitor, shape, self.typ); format!("{pattern}: {visibility}{ty}") } @@ -295,3 +296,7 @@ pub(crate) fn last_line_used_width(s: &str, offset: usize) -> usize { offset + s.chars().count() } } + +pub(crate) fn span_is_empty(span: Span) -> bool { + span.start() == span.end() +} diff --git a/noir/tooling/nargo_fmt/src/visitor/item.rs b/noir/tooling/nargo_fmt/src/visitor/item.rs index c0a255b7ef6..eb2086168ba 100644 --- a/noir/tooling/nargo_fmt/src/visitor/item.rs +++ b/noir/tooling/nargo_fmt/src/visitor/item.rs @@ -6,6 +6,7 @@ use noirc_frontend::{ }; use crate::{ + rewrite, utils::{last_line_contains_single_line_comment, last_line_used_width, FindToken}, visitor::expr::{format_seq, NewlineMode}, }; @@ -122,7 +123,8 @@ impl super::FmtVisitor<'_> { result.push_str("pub "); } - result.push_str(self.slice(span)); + let typ = rewrite::typ(self, self.shape(), func.return_type()); + result.push_str(&typ); let slice = self.slice(span.end()..func_span.start()); if !slice.trim().is_empty() { diff --git a/noir/tooling/nargo_fmt/tests/expected/fn.nr b/noir/tooling/nargo_fmt/tests/expected/fn.nr index 7fd45648c67..0088dba6a8f 100644 --- a/noir/tooling/nargo_fmt/tests/expected/fn.nr +++ b/noir/tooling/nargo_fmt/tests/expected/fn.nr @@ -36,7 +36,21 @@ fn apply_binary_field_op( registers: &mut Registers ) -> bool {} -fn main() -> distinct pub [Field;2] {} +fn main() -> distinct pub [Field; 2] {} + +fn ret_normal_lambda1() -> ((fn() -> Field)) {} + +fn ret_normal_lambda1() -> fn() -> Field {} + +fn ret_closure1() -> fn[(Field,)]() -> Field {} + +fn ret_closure2() -> fn[(Field, Field)]() -> Field {} + +fn ret_closure3() -> fn[(u32, u64)]() -> u64 {} + +fn make_counter() -> fn[(&mut Field,)]() -> Field {} + +fn get_some(generator: fn[Env]() -> Field) -> [Field; 5] {} fn main( message: [u8; 10], @@ -45,3 +59,5 @@ fn main( pub_key_y: Field, signature: [u8; 64] ) {} + +pub fn from_baz(x: [Field; crate::foo::MAGIC_NUMBER]) {} diff --git a/noir/tooling/nargo_fmt/tests/expected/print.nr b/noir/tooling/nargo_fmt/tests/expected/print.nr index e169f565455..3bce0941da2 100644 --- a/noir/tooling/nargo_fmt/tests/expected/print.nr +++ b/noir/tooling/nargo_fmt/tests/expected/print.nr @@ -1,5 +1,6 @@ use dep::std; fn main() { + std::print("Hello world"); std::println("Hello world"); } diff --git a/noir/tooling/nargo_fmt/tests/expected/print2.nr b/noir/tooling/nargo_fmt/tests/expected/print2.nr index 80284444af8..3bce0941da2 100644 --- a/noir/tooling/nargo_fmt/tests/expected/print2.nr +++ b/noir/tooling/nargo_fmt/tests/expected/print2.nr @@ -1,5 +1,6 @@ use dep::std; -fn main( ) { +fn main() { + std::print("Hello world"); std::println("Hello world"); } diff --git a/noir/tooling/nargo_fmt/tests/input/fn.nr b/noir/tooling/nargo_fmt/tests/input/fn.nr index 45dc3370f14..26ff5933802 100644 --- a/noir/tooling/nargo_fmt/tests/input/fn.nr +++ b/noir/tooling/nargo_fmt/tests/input/fn.nr @@ -25,6 +25,22 @@ fn apply_binary_field_op(lhs: RegisterIndex, rhs: RegisterIndex, result: Regi fn main() -> distinct pub [Field;2] {} +fn ret_normal_lambda1() -> ((fn() -> Field)) {} + +fn ret_normal_lambda1() -> fn() -> Field {} + +fn ret_closure1() -> fn[(Field,)]() -> Field {} + +fn ret_closure2() -> fn[(Field,Field)]() -> Field {} + +fn ret_closure3() -> fn[(u32,u64)]() -> u64 {} + +fn make_counter() -> fn[(&mut Field,)]() -> Field {} + +fn get_some(generator: fn[Env]() -> Field) -> [Field;5] {} + fn main( message: [u8; 10], message_field: Field, pub_key_x: Field, pub_key_y: Field, signature: [u8; 64] ) {} + +pub fn from_baz(x: [Field; crate::foo::MAGIC_NUMBER]) {} diff --git a/noir/tooling/nargo_fmt/tests/input/print.nr b/noir/tooling/nargo_fmt/tests/input/print.nr index 8afa562dada..3bce0941da2 100644 --- a/noir/tooling/nargo_fmt/tests/input/print.nr +++ b/noir/tooling/nargo_fmt/tests/input/print.nr @@ -1,3 +1,6 @@ use dep::std; -fn main() { std::println("Hello world"); } +fn main() { + std::print("Hello world"); + std::println("Hello world"); +} diff --git a/noir/tooling/nargo_fmt/tests/input/print2.nr b/noir/tooling/nargo_fmt/tests/input/print2.nr index 07ef9dd0386..3bce0941da2 100644 --- a/noir/tooling/nargo_fmt/tests/input/print2.nr +++ b/noir/tooling/nargo_fmt/tests/input/print2.nr @@ -1,5 +1,6 @@ use dep::std; -fn main( ) { -std::println("Hello world"); +fn main() { + std::print("Hello world"); + std::println("Hello world"); } diff --git a/noir/tooling/nargo_toml/src/lib.rs b/noir/tooling/nargo_toml/src/lib.rs index 141cb3411b3..6c77fe85f2b 100644 --- a/noir/tooling/nargo_toml/src/lib.rs +++ b/noir/tooling/nargo_toml/src/lib.rs @@ -24,6 +24,27 @@ mod semver; pub use errors::ManifestError; use git::clone_git_repo; +/// Searches for a `Nargo.toml` file in the current directory and all parent directories. +/// For example, if the current directory is `/workspace/package/src`, then this function +/// will search for a `Nargo.toml` file in +/// * `/workspace/package/src`, +/// * `/workspace/package`, +/// * `/workspace`. +/// +/// Returns the [PathBuf] of the `Nargo.toml` file if found, otherwise returns None. +/// +/// It will return innermost `Nargo.toml` file, which is the one closest to the current directory. +/// For example, if the current directory is `/workspace/package/src`, then this function +/// will return the `Nargo.toml` file in `/workspace/package/Nargo.toml` +pub fn find_file_manifest(current_path: &Path) -> Option { + for path in current_path.ancestors() { + if let Ok(toml_path) = get_package_manifest(path) { + return Some(toml_path); + } + } + None +} + /// Returns the [PathBuf] of the directory containing the `Nargo.toml` by searching from `current_path` to the root of its [Path]. /// /// Returns a [ManifestError] if no parent directories of `current_path` contain a manifest file. @@ -249,7 +270,6 @@ struct PackageMetadata { // We also state that ACIR and the compiler will upgrade in lockstep. // so you will not need to supply an ACIR and compiler version compiler_version: Option, - backend: Option, license: Option, } @@ -411,7 +431,7 @@ pub fn resolve_workspace_from_toml( let nargo_toml = read_toml(toml_path)?; let workspace = toml_to_workspace(nargo_toml, package_selection)?; if let Some(current_compiler_version) = current_compiler_version { - semver::semver_check_workspace(workspace.clone(), current_compiler_version)?; + semver::semver_check_workspace(&workspace, current_compiler_version)?; } Ok(workspace) } diff --git a/noir/tooling/nargo_toml/src/semver.rs b/noir/tooling/nargo_toml/src/semver.rs index 6acc68afa47..7c6e2a18b31 100644 --- a/noir/tooling/nargo_toml/src/semver.rs +++ b/noir/tooling/nargo_toml/src/semver.rs @@ -12,7 +12,7 @@ pub(crate) fn parse_semver_compatible_version(version: &str) -> Result Result<(), ManifestError> { let version = parse_semver_compatible_version(¤t_compiler_version) diff --git a/noir/tooling/noir_codegen/package.json b/noir/tooling/noir_codegen/package.json index 9879991f6e7..3ae31d9834f 100644 --- a/noir/tooling/noir_codegen/package.json +++ b/noir/tooling/noir_codegen/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.19.4", + "version": "0.22.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", @@ -27,7 +27,7 @@ "dev": "tsc-multi --watch", "build": "tsc", "test": "yarn test:codegen && yarn test:node && yarn test:clean", - "test:codegen": "ts-node --esm src/main.ts ./test/assert_lt/target/** --out-dir ./test/codegen", + "test:codegen": "tsx src/main.ts ./test/assert_lt/target/** --out-dir ./test/codegen", "test:node": "mocha --timeout 25000 --exit --config ./.mocharc.json", "test:clean": "rm -rf ./test/codegen", "prettier": "prettier 'src/**/*.ts'", @@ -50,6 +50,7 @@ "mocha": "^10.2.0", "prettier": "3.0.3", "ts-node": "^10.9.1", + "tsx": "^4.6.2", "typescript": "^5.2.2" } } diff --git a/noir/tooling/noir_codegen/src/noir_types.ts b/noir/tooling/noir_codegen/src/noir_types.ts index d1a22a3e2da..ba4f8650b3b 100644 --- a/noir/tooling/noir_codegen/src/noir_types.ts +++ b/noir/tooling/noir_codegen/src/noir_types.ts @@ -170,7 +170,7 @@ export function generateTsInterface( // Generating Return type, if it exists if (abiObj.return_type != null) { - result += generateStructInterfaces(abiObj.return_type, outputStructs, primitiveTypeMap); + result += generateStructInterfaces(abiObj.return_type.abi_type, outputStructs, primitiveTypeMap); } return [result, getTsFunctionSignature(abiObj, primitiveTypeMap)]; @@ -184,6 +184,6 @@ function getTsFunctionSignature( param.name, abiTypeToTs(param.type, primitiveTypeMap), ]); - const returnValue = abi.return_type ? abiTypeToTs(abi.return_type, primitiveTypeMap) : null; + const returnValue = abi.return_type ? abiTypeToTs(abi.return_type.abi_type, primitiveTypeMap) : null; return { inputs, returnValue }; } diff --git a/noir/tooling/noir_codegen/test/assert_lt/target/assert_lt.json b/noir/tooling/noir_codegen/test/assert_lt/target/assert_lt.json index 6d928a26d43..a1ab87a99fe 100644 --- a/noir/tooling/noir_codegen/test/assert_lt/target/assert_lt.json +++ b/noir/tooling/noir_codegen/test/assert_lt/target/assert_lt.json @@ -1 +1 @@ -{"noir_version":"0.19.3+e9322d14070fa444d77ee5c43c905dd86a67c6e3","hash":9449934793688855780,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},{"name":"array","type":{"kind":"array","length":5,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"my_struct","type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]},"visibility":"private"},{"name":"string","type":{"kind":"string","length":5},"visibility":"private"}],"param_witnesses":{"array":[{"start":3,"end":8}],"my_struct":[{"start":8,"end":24}],"string":[{"start":24,"end":29}],"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"kind":"tuple","fields":[{"kind":"integer","sign":"unsigned","width":64},{"kind":"integer","sign":"unsigned","width":64},{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}]},"return_witnesses":[31,32,33,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"bytecode":"H4sIAAAAAAAA/81XbU/CMBDu5hv4gopvvGw49JOJH1q2wfaN+E+AddFEgzGL/H250Go5dInumnhJ0z2jXJ9er7s+t4yxe7YyZ9lc1Y8N7CK8tWw1A28jvIPwLsJ7Cus5mfIPxquZqBlzmX5DPowiORpIEYoJH6TTJOZRPB0mIhFxEmeDJAxlEiWjdJqOeCqiUIo8TsNcOa7RceQ6DnUUl32EDxA+RPgI4QbCxwifIHyKcBPhM4TPEb5A+BLhK4RbCLcR7iDcRdhjX3mjzUb+jIlyxibPFgFPmYNlVnm2yXjOcps8O3Q8pU2eXTqemU2eHh3PGdQbl22aS8zZYXRn3/07L4FffLN0Mt9mXH3V99iqhuu80GOgzj+wzZxxjGdXjXFLxjg/+Kkb7/T/G8bvVRe/EQxzciqfvgok9QXEp+P4eQHpGT61bRHHw9ahqurrhjCeZfH7JU+OeAqfcM09wn2tEL/SD9x/Pjdl+8yr2do54dVMUJ6Ta0b/3TF92tr3gI53aJNnn3DfuwZHyE8o2FDIQYBr0Q1FFoQmiEsQlCAiociCWASBCKIQhCCIPxB8IPJA2IGYA9EBF3q4LMNcHlsv/E31XGUOyI1g2fpsvfDfqd5T/aQo5MtrERTzYJJlweKpeAzm7/Itf54vPgBYg2KL1RAAAA=="} \ No newline at end of file +{"noir_version":"0.19.4+55670ff82c270534a4bdb999ab0de5cea7017093","hash":11505576107297330043,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},{"name":"array","type":{"kind":"array","length":5,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"my_struct","type":{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]},"visibility":"private"},{"name":"string","type":{"kind":"string","length":5},"visibility":"private"}],"param_witnesses":{"array":[{"start":3,"end":8}],"my_struct":[{"start":8,"end":24}],"string":[{"start":24,"end":29}],"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"tuple","fields":[{"kind":"integer","sign":"unsigned","width":64},{"kind":"integer","sign":"unsigned","width":64},{"kind":"struct","path":"MyStruct","fields":[{"name":"foo","type":{"kind":"boolean"}},{"name":"bar","type":{"kind":"array","length":3,"type":{"kind":"string","length":5}}}]}]},"visibility":"public"},"return_witnesses":[31,32,33,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"bytecode":"H4sIAAAAAAAA/81XbU/CMBDu5hv4gopvvGw49JOJH1q2wfaN+E+AddFEgzGL/H250Go5dInumnhJ0z2jXJ9er7s+t4yxe7YyZ9lc1Y8N7CK8tWw1A28jvIPwLsJ7Cus5mfIPxquZqBlzmX5DPowiORpIEYoJH6TTJOZRPB0mIhFxEmeDJAxlEiWjdJqOeCqiUIo8TsNcOa7RceQ6DnUUl32EDxA+RPgI4QbCxwifIHyKcBPhM4TPEb5A+BLhK4RbCLcR7iDcRdhjX3mjzUb+jIlyxibPFgFPmYNlVnm2yXjOcps8O3Q8pU2eXTqemU2eHh3PGdQbl22aS8zZYXRn3/07L4FffLN0Mt9mXH3V99iqhuu80GOgzj+wzZxxjGdXjXFLxjg/+Kkb7/T/G8bvVRe/EQxzciqfvgok9QXEp+P4eQHpGT61bRHHw9ahqurrhjCeZfH7JU+OeAqfcM09wn2tEL/SD9x/Pjdl+8yr2do54dVMUJ6Ta0b/3TF92tr3gI53aJNnn3DfuwZHyE8o2FDIQYBr0Q1FFoQmiEsQlCAiociCWASBCKIQhCCIPxB8IPJA2IGYA9EBF3q4LMNcHlsv/E31XGUOyI1g2fpsvfDfqd5T/aQo5MtrERTzYJJlweKpeAzm7/Itf54vPgBYg2KL1RAAAA=="} \ No newline at end of file diff --git a/noir/tooling/noir_js/.mocharc.json b/noir/tooling/noir_js/.mocharc.json index c2e70b73d0f..be7e952e7ca 100644 --- a/noir/tooling/noir_js/.mocharc.json +++ b/noir/tooling/noir_js/.mocharc.json @@ -1,6 +1,5 @@ { - "require": "ts-node/register", - "loader": "ts-node/esm", + "require": "tsx", "extensions": ["ts", "cjs"], "spec": [ "test/node/**/*.test.ts*" diff --git a/noir/tooling/noir_js/package.json b/noir/tooling/noir_js/package.json index 7818e689181..d5ea4b4ad5d 100644 --- a/noir/tooling/noir_js/package.json +++ b/noir/tooling/noir_js/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.19.4", + "version": "0.22.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", @@ -50,6 +50,7 @@ "prettier": "3.0.3", "ts-node": "^10.9.1", "tsc-multi": "^1.1.0", + "tsx": "^4.6.2", "typescript": "^5.2.2" } } diff --git a/noir/tooling/noir_js/src/program.ts b/noir/tooling/noir_js/src/program.ts index 711413bbc84..809943727eb 100644 --- a/noir/tooling/noir_js/src/program.ts +++ b/noir/tooling/noir_js/src/program.ts @@ -67,12 +67,12 @@ export class Noir { * * @example * ```typescript - * async generateFinalproof(input) + * async generateFinalProof(input) * ``` * */ - async generateFinalProof(inputs: InputMap): Promise { - const { witness } = await this.execute(inputs); + async generateFinalProof(inputs: InputMap, foreignCallHandler?: ForeignCallHandler): Promise { + const { witness } = await this.execute(inputs, foreignCallHandler); return this.getBackend().generateFinalProof(witness); } diff --git a/noir/tooling/noir_js/src/witness_generation.ts b/noir/tooling/noir_js/src/witness_generation.ts index e3ddb1a2a21..a329c79c919 100644 --- a/noir/tooling/noir_js/src/witness_generation.ts +++ b/noir/tooling/noir_js/src/witness_generation.ts @@ -3,7 +3,14 @@ import { base64Decode } from './base64_decode.js'; import { executeCircuit, WitnessMap, ForeignCallHandler, ForeignCallInput } from '@noir-lang/acvm_js'; import { CompiledCircuit } from '@noir-lang/types'; -const defaultForeignCallHandler: ForeignCallHandler = (name: string, args: ForeignCallInput[]) => { +const defaultForeignCallHandler: ForeignCallHandler = async (name: string, args: ForeignCallInput[]) => { + if (name == 'print') { + // By default we do not print anything for `print` foreign calls due to a need for formatting, + // however we provide an empty response in order to not halt execution. + // + // If a user needs to print values then they should provide a custom foreign call handler. + return []; + } throw Error(`Unexpected oracle during execution: ${name}(${args.join(', ')})`); }; diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr index 0698cbce4a8..693e7285736 100644 --- a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr +++ b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr @@ -1,4 +1,9 @@ +use dep::std; + fn main(x: u64, y: pub u64) -> pub u64 { + // We include a println statement to show that noirJS will ignore this and continue execution + std::println("foo"); + assert(x < y); x + y } diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json index c01b2c5d3f5..5b511cdc140 100644 --- a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json +++ b/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/assert_lt.json @@ -1 +1 @@ -{"hash":13834844072603749544,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"}],"param_witnesses":{"x":[{ "start": 1, "end": 2 }],"y":[{ "start": 2, "end": 3 }]},"return_type":{"kind":"integer","sign":"unsigned","width":64},"return_witnesses":[12]},"bytecode":"H4sIAAAAAAAA/+1WUW6DMAx1QksZoGr72jUcAiX8VbvJ0Oj9j7ChJpKbtXw0NpvUWkImUXixn53w3gDgHc6mfh7t/ZGMtR9TU96HeYuHtp36ZjLWfGIzjK7DthsPzjjTue6rcdZOrnX9MA49Dqa1kzl1gz3h2bL7sTDCMhmJbylmTDOT8WEhjXfjH/DcB8u8zwVygWifmL/9lTnWzSWKsxHA3QJf00vlveWvERJIUU4x0eb86aEJppljVox9oO+Py8QTV1Jnw6a85t7vSL8pwvN89j7gd88o8q79Gr2wRt3AeSFz4XvRSyokl5MAtSfgGO2ZCewdsDibLRVrDzIXTMxfqiLIGXPeMdY1gb/Fg8+tznJY50eSGmfB2DNrqciCD+tCRc4X5FNFJmIWnkhu3BL+t4qc8y75aySqIkvGOP9CRWKaGQ0ydUrsgUUVWXlfw4OpyAouVWQN66pITDPDqSJfQaZxuVVkxZhzzVgLTv5uHbDwXhN+vwGywklHPBQAAA=="} \ No newline at end of file +{"noir_version":"0.20.0+010fdb69616f47fc0a9f252a65a903316d3cbe80","hash":17538653710107541030,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"x","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"private"},{"name":"y","type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"}],"param_witnesses":{"x":[{"start":1,"end":2}],"y":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"integer","sign":"unsigned","width":64},"visibility":"public"},"return_witnesses":[5]},"bytecode":"H4sIAAAAAAAA/9Wa627aMBiGHcKhBBLOR+0Hl+Ak5PQP9U6gBK3SNqoqWm9kFzzMYu2DujhbPjvFEkrsJu/7vJ+TFDAtQkiH/GnG6VXLtxvQr+V9Mx/jx5pE3Db5lpZqYahI96Ba91e+bee1g60J6objS90mehbqN8nfuUbSpLAeNVAjXg++bZxeD/m+k9esjlyz6+t3A/p1MFfYvkyzharpPrXzmsFmXPU3YL8F8jUV5HvA1aRMs42qGe2YhgVqwuvH2Tvg721QLwu5Xgbw5Lq8bynz9Tye8Vb+joCjozF/R5lveJ7/riR/V8DR1Zi/q8w3TJiGLclvCzhsjfltZb5hyjQcSX5HwOFozO8o8w3XTKMnyd8TcPQ05od8RVmtilnxff0t0+hL8vcFHH2N+SFfUVarYlZ838hnGgNJ/oGAY6Ax/0CZb3R+rgwl+YcCjqHG/ENlvtH5fdVIkn8k4BhpzA/5irJ274jVrpgV3zeMmMZYkn8s4BhrzA/5irJaFbPi+3pPTGMiyT8RcEw05od8RVmtilnxfcPzXE0l+acCjqnG/FNlvmHANGaS/DMBx0xjfshXlNW+I9bRHbEOKmbF9w1jpjGX5J8LOOYa80O+oqzWHbH2KmbF9/XPnwUXkvwLAcdCY/6FMt9ozzSWkvxLAcdSY/4l8MVet3gAmV9en39kHKAOYPg+X2xlzQRjXOALOIeDtsj7hR60qpnk/eolAWNYPgbQ8k/fTK7TyEtd391SL9nFAV0HuzB2YzeIg70X+34ar+Mo2SURTdy1n7qHIPEPuVjt/7nc6wFBdDRtWFe46tgAE18D44/geLgCb4A5eQTniI4xPtBpgzF+vkMUXljQHEvTJJc/T+C6ZS8oE4+R8kmtk8vlWELwfxKg6qYqq9VErOet+v0jJ73idE3EzHXEeS1Rv5sPuM9839yaZ1quXdwntFxzMe+TBsF/7nDNj/6B8P0GuXz4848R/B3INsvS7y/ZKjuutvv96u05+7o6/kxfD9+Ob78Bhjydn08mAAA="} \ No newline at end of file diff --git a/noir/tooling/noir_js_backend_barretenberg/package.json b/noir/tooling/noir_js_backend_barretenberg/package.json index baf8c0f58fd..c34b8dfc825 100644 --- a/noir/tooling/noir_js_backend_barretenberg/package.json +++ b/noir/tooling/noir_js_backend_barretenberg/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.19.4", + "version": "0.22.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/noir/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts b/noir/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts index 98189eaed5f..dab1c56436a 100644 --- a/noir/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts +++ b/noir/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts @@ -38,18 +38,21 @@ const abi: Abi = { ], }, return_type: { - kind: 'tuple', - fields: [ - { - kind: 'field', - }, - { - kind: 'field', - }, - { - kind: 'field', - }, - ], + abi_type: { + kind: 'tuple', + fields: [ + { + kind: 'field', + }, + { + kind: 'field', + }, + { + kind: 'field', + }, + ], + }, + visibility: 'public', }, return_witnesses: [2, 13, 13], }; diff --git a/noir/tooling/noir_js_types/package.json b/noir/tooling/noir_js_types/package.json index 991052f1ad9..51856cfe465 100644 --- a/noir/tooling/noir_js_types/package.json +++ b/noir/tooling/noir_js_types/package.json @@ -4,7 +4,7 @@ "The Noir Team " ], "packageManager": "yarn@3.5.1", - "version": "0.19.4", + "version": "0.22.0", "license": "(MIT OR Apache-2.0)", "files": [ "lib", diff --git a/noir/tooling/noirc_abi/src/input_parser/json.rs b/noir/tooling/noirc_abi/src/input_parser/json.rs index e2b1a83ee6b..7618cd6c15a 100644 --- a/noir/tooling/noirc_abi/src/input_parser/json.rs +++ b/noir/tooling/noirc_abi/src/input_parser/json.rs @@ -28,8 +28,11 @@ pub(crate) fn parse_json( if let (Some(return_type), Some(json_return_value)) = (&abi.return_type, data.get(MAIN_RETURN_NAME)) { - let return_value = - InputValue::try_from_json(json_return_value.clone(), return_type, MAIN_RETURN_NAME)?; + let return_value = InputValue::try_from_json( + json_return_value.clone(), + &return_type.abi_type, + MAIN_RETURN_NAME, + )?; parsed_inputs.insert(MAIN_RETURN_NAME.to_owned(), return_value); } @@ -48,7 +51,7 @@ pub(crate) fn serialize_to_json( if let (Some(return_type), Some(return_value)) = (&abi.return_type, input_map.get(MAIN_RETURN_NAME)) { - let return_value = JsonTypes::try_from_input_value(return_value, return_type)?; + let return_value = JsonTypes::try_from_input_value(return_value, &return_type.abi_type)?; json_map.insert(MAIN_RETURN_NAME.to_owned(), return_value); } diff --git a/noir/tooling/noirc_abi/src/input_parser/mod.rs b/noir/tooling/noirc_abi/src/input_parser/mod.rs index 7bbcb42296c..26c5a89c83a 100644 --- a/noir/tooling/noirc_abi/src/input_parser/mod.rs +++ b/noir/tooling/noirc_abi/src/input_parser/mod.rs @@ -130,7 +130,8 @@ mod serialization_tests { use strum::IntoEnumIterator; use crate::{ - input_parser::InputValue, Abi, AbiParameter, AbiType, AbiVisibility, Sign, MAIN_RETURN_NAME, + input_parser::InputValue, Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, Sign, + MAIN_RETURN_NAME, }; use super::Format; @@ -159,7 +160,10 @@ mod serialization_tests { visibility: AbiVisibility::Private, }, ], - return_type: Some(AbiType::String { length: 5 }), + return_type: Some(AbiReturnType { + abi_type: AbiType::String { length: 5 }, + visibility: AbiVisibility::Public, + }), // These two fields are unused when serializing/deserializing to file. param_witnesses: BTreeMap::new(), return_witnesses: Vec::new(), @@ -293,7 +297,6 @@ mod test { #[test] fn rejects_noncanonical_fields() { let noncanonical_field = FieldElement::modulus().to_string(); - let parsed_field = parse_str_to_field(&noncanonical_field); - println!("{parsed_field:?}"); + assert!(parse_str_to_field(&noncanonical_field).is_err()); } } diff --git a/noir/tooling/noirc_abi/src/input_parser/toml.rs b/noir/tooling/noirc_abi/src/input_parser/toml.rs index 645b59b00cd..b216fe58794 100644 --- a/noir/tooling/noirc_abi/src/input_parser/toml.rs +++ b/noir/tooling/noirc_abi/src/input_parser/toml.rs @@ -28,8 +28,11 @@ pub(crate) fn parse_toml( if let (Some(return_type), Some(toml_return_value)) = (&abi.return_type, data.get(MAIN_RETURN_NAME)) { - let return_value = - InputValue::try_from_toml(toml_return_value.clone(), return_type, MAIN_RETURN_NAME)?; + let return_value = InputValue::try_from_toml( + toml_return_value.clone(), + &return_type.abi_type, + MAIN_RETURN_NAME, + )?; parsed_inputs.insert(MAIN_RETURN_NAME.to_owned(), return_value); } @@ -48,7 +51,7 @@ pub(crate) fn serialize_to_toml( if let (Some(return_type), Some(return_value)) = (&abi.return_type, input_map.get(MAIN_RETURN_NAME)) { - let return_value = TomlTypes::try_from_input_value(return_value, return_type)?; + let return_value = TomlTypes::try_from_input_value(return_value, &return_type.abi_type)?; toml_map.insert(MAIN_RETURN_NAME.to_owned(), return_value); } diff --git a/noir/tooling/noirc_abi/src/lib.rs b/noir/tooling/noirc_abi/src/lib.rs index 7092f05c26e..884c49c0106 100644 --- a/noir/tooling/noirc_abi/src/lib.rs +++ b/noir/tooling/noirc_abi/src/lib.rs @@ -78,6 +78,7 @@ pub enum AbiVisibility { // Constants are not allowed in the ABI for main at the moment. // Constant, Private, + DataBus, } impl From for AbiVisibility { @@ -85,6 +86,7 @@ impl From for AbiVisibility { match value { Visibility::Public => AbiVisibility::Public, Visibility::Private => AbiVisibility::Private, + Visibility::DataBus => AbiVisibility::DataBus, } } } @@ -94,6 +96,7 @@ impl From<&Visibility> for AbiVisibility { match value { Visibility::Public => AbiVisibility::Public, Visibility::Private => AbiVisibility::Private, + Visibility::DataBus => AbiVisibility::DataBus, } } } @@ -158,7 +161,7 @@ impl AbiType { Type::Error => unreachable!(), Type::Unit => unreachable!(), Type::Constant(_) => unreachable!(), - Type::TraitAsType(_) => unreachable!(), + Type::TraitAsType(..) => unreachable!(), Type::Struct(def, ref args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); @@ -212,6 +215,11 @@ impl AbiParameter { } } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AbiReturnType { + pub abi_type: AbiType, + pub visibility: AbiVisibility, +} #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Abi { /// An ordered list of the arguments to the program's `main` function, specifying their types and visibility. @@ -219,7 +227,7 @@ pub struct Abi { /// A map from the ABI's parameters to the indices they are written to in the [`WitnessMap`]. /// This defines how to convert between the [`InputMap`] and [`WitnessMap`]. pub param_witnesses: BTreeMap>>, - pub return_type: Option, + pub return_type: Option, pub return_witnesses: Vec, } @@ -327,7 +335,7 @@ impl Abi { // When encoding public inputs to be passed to the verifier, the user can must provide a return value // to be inserted into the witness map. This is not needed when generating a witness when proving the circuit. match (&self.return_type, return_value) { - (Some(return_type), Some(return_value)) => { + (Some(AbiReturnType { abi_type: return_type, .. }), Some(return_value)) => { if !return_value.matches_abi(return_type) { return Err(AbiError::ReturnTypeMismatch { return_type: return_type.clone(), @@ -426,7 +434,7 @@ impl Abi { .copied() }) { - Some(decode_value(&mut return_witness_values.into_iter(), return_type)?) + Some(decode_value(&mut return_witness_values.into_iter(), &return_type.abi_type)?) } else { // Unlike for the circuit inputs, we tolerate not being able to find the witness values for the return value. // This is because the user may be decoding a partial witness map for which is hasn't been calculated yet. @@ -546,7 +554,10 @@ mod test { use acvm::{acir::native_types::Witness, FieldElement}; - use crate::{input_parser::InputValue, Abi, AbiParameter, AbiType, AbiVisibility, InputMap}; + use crate::{ + input_parser::InputValue, Abi, AbiParameter, AbiReturnType, AbiType, AbiVisibility, + InputMap, + }; #[test] fn witness_encoding_roundtrip() { @@ -568,7 +579,10 @@ mod test { ("thing1".to_string(), vec![(Witness(1)..Witness(3))]), ("thing2".to_string(), vec![(Witness(3)..Witness(4))]), ]), - return_type: Some(AbiType::Field), + return_type: Some(AbiReturnType { + abi_type: AbiType::Field, + visibility: AbiVisibility::Public, + }), return_witnesses: vec![Witness(3)], }; diff --git a/noir/tooling/noirc_abi_wasm/package.json b/noir/tooling/noirc_abi_wasm/package.json index f1c68df8804..5b2cd344eab 100644 --- a/noir/tooling/noirc_abi_wasm/package.json +++ b/noir/tooling/noirc_abi_wasm/package.json @@ -3,7 +3,7 @@ "collaborators": [ "The Noir Team " ], - "version": "0.19.4", + "version": "0.22.0", "license": "(MIT OR Apache-2.0)", "files": [ "nodejs", diff --git a/noir/tooling/noirc_abi_wasm/src/lib.rs b/noir/tooling/noirc_abi_wasm/src/lib.rs index a3d829dd40f..fb4c295b8c8 100644 --- a/noir/tooling/noirc_abi_wasm/src/lib.rs +++ b/noir/tooling/noirc_abi_wasm/src/lib.rs @@ -47,7 +47,7 @@ extern "C" { #[wasm_bindgen(typescript_custom_section)] const ABI: &'static str = r#" -export type Visibility = "public" | "private"; +export type Visibility = "public" | "private" | "databus"; export type Sign = "unsigned" | "signed"; export type AbiType = { kind: "field" } | @@ -67,7 +67,7 @@ export type AbiParameter = { export type Abi = { parameters: AbiParameter[], param_witnesses: Record, - return_type: AbiType | null, + return_type: {abi_type: AbiType, visibility: Visibility} | null, return_witnesses: number[], } "#; @@ -96,7 +96,7 @@ pub fn abi_encode( .expect("could not decode return value"); InputValue::try_from_json( toml_return_value, - abi.return_type.as_ref().unwrap(), + &abi.return_type.as_ref().unwrap().abi_type, MAIN_RETURN_NAME, ) }) @@ -134,7 +134,7 @@ pub fn abi_decode(abi: JsAbi, witness_map: JsWitnessMap) -> Result=16" + react: ">=16" + checksum: a780cff9d7f7639d6fc21c9d4e0a6ac1370c3209ea0db176923df7f9145785309591cf871f227f5135d1fe2accce0d5df9a22fc0530e5dda0c7b4b105705f20d languageName: node linkType: hard @@ -3225,10 +3698,36 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.1.2": - version: 1.1.2 - resolution: "@noble/hashes@npm:1.1.2" - checksum: 3c2a8cb7c2e053811032f242155d870c5eb98844d924d69702244d48804cb03b42d4a666c49c2b71164420d8229cb9a6f242b972d50d5bb2f1d673b98b041de2 +"@monaco-editor/loader@npm:^1.4.0": + version: 1.4.0 + resolution: "@monaco-editor/loader@npm:1.4.0" + dependencies: + state-local: ^1.0.6 + peerDependencies: + monaco-editor: ">= 0.21.0 < 1" + checksum: 374ec0ea872ee15b33310e105a43217148161480d3955c5cece87d0f801754cd2c45a3f6c539a75da18a066c1615756fb87eaf1003f1df6a64a0cbce5d2c3749 + languageName: node + linkType: hard + +"@monaco-editor/react@npm:4.6.0": + version: 4.6.0 + resolution: "@monaco-editor/react@npm:4.6.0" + dependencies: + "@monaco-editor/loader": ^1.4.0 + peerDependencies: + monaco-editor: ">= 0.25.0 < 1" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 9d44e76c5baad6db5f84c90a5540fbd3c9af691b97d76cf2a99b3c8273004d0efe44c2572d80e9d975c9af10022c21e4a66923924950a5201e82017c8b20428c + languageName: node + linkType: hard + +"@noble/curves@npm:1.2.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": 1.3.2 + checksum: bb798d7a66d8e43789e93bc3c2ddff91a1e19fdb79a99b86cd98f1e5eff0ee2024a2672902c2576ef3577b6f282f3b5c778bebd55761ddbb30e36bf275e83dd0 languageName: node linkType: hard @@ -3239,6 +3738,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.3.2": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474 + languageName: node + linkType: hard + "@noble/secp256k1@npm:1.7.1, @noble/secp256k1@npm:~1.7.0": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" @@ -3412,6 +3918,13 @@ __metadata: languageName: node linkType: hard +"@noir-lang/acvm_js@npm:0.35.0": + version: 0.35.0 + resolution: "@noir-lang/acvm_js@npm:0.35.0" + checksum: 0a2209f60242d9dbef31e72b738d70ff802da71f12d4b4f278144d373941f30844c8d041518970e71ba82eb9337cf4cc3a40fbd4b2c50acff45d84d2ee7dd435 + languageName: node + linkType: hard + "@noir-lang/acvm_js@workspace:*, @noir-lang/acvm_js@workspace:acvm-repo/acvm_js": version: 0.0.0-use.local resolution: "@noir-lang/acvm_js@workspace:acvm-repo/acvm_js" @@ -3430,6 +3943,17 @@ __metadata: languageName: unknown linkType: soft +"@noir-lang/backend_barretenberg@npm:^0.19.2": + version: 0.19.4 + resolution: "@noir-lang/backend_barretenberg@npm:0.19.4" + dependencies: + "@aztec/bb.js": 0.16.0 + "@noir-lang/types": 0.19.4 + fflate: ^0.8.0 + checksum: b84382e71f29f0e10415f8c3a68eb7bb0653f56df1b3e8afd66c22df7adc950fb9016124f32253abad3d05583bccf26b1d0c0cabc601218083fd27d0601a3c02 + languageName: node + linkType: hard + "@noir-lang/backend_barretenberg@workspace:*, @noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg": version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" @@ -3469,12 +3993,24 @@ __metadata: prettier: 3.0.3 ts-command-line-args: ^2.5.1 ts-node: ^10.9.1 + tsx: ^4.6.2 typescript: ^5.2.2 bin: noir-codegen: lib/main.js languageName: unknown linkType: soft +"@noir-lang/noir_js@npm:^0.19.2": + version: 0.19.4 + resolution: "@noir-lang/noir_js@npm:0.19.4" + dependencies: + "@noir-lang/acvm_js": 0.35.0 + "@noir-lang/noirc_abi": 0.19.4 + "@noir-lang/types": 0.19.4 + checksum: 1ee6140019861cee3a27d511951e6b3ed629925a83328b0fbe18791a534c36d26d33ae3ca3aa25252fac8932dfeefedc0d5f07169d5d08f1485d6290965d2491 + languageName: node + linkType: hard + "@noir-lang/noir_js@workspace:*, @noir-lang/noir_js@workspace:tooling/noir_js": version: 0.0.0-use.local resolution: "@noir-lang/noir_js@workspace:tooling/noir_js" @@ -3493,10 +4029,20 @@ __metadata: prettier: 3.0.3 ts-node: ^10.9.1 tsc-multi: ^1.1.0 + tsx: ^4.6.2 typescript: ^5.2.2 languageName: unknown linkType: soft +"@noir-lang/noir_wasm@npm:^0.19.2": + version: 0.19.4 + resolution: "@noir-lang/noir_wasm@npm:0.19.4" + peerDependencies: + "@noir-lang/source-resolver": 0.19.4 + checksum: b69748240e27851f19b20b4ce1d0c57da7e9055b9d0e0c16f699338394912c00277e5586afcff77d3f6f08e17bbf1bc6253ff1ad156b8f4985c4435adad0ba49 + languageName: node + linkType: hard + "@noir-lang/noir_wasm@workspace:*, @noir-lang/noir_wasm@workspace:compiler/wasm": version: 0.0.0-use.local resolution: "@noir-lang/noir_wasm@workspace:compiler/wasm" @@ -3506,11 +4052,16 @@ __metadata: "@web/test-runner": ^0.15.3 "@web/test-runner-playwright": ^0.10.0 mocha: ^10.2.0 - peerDependencies: - "@noir-lang/source-resolver": "workspace:*" languageName: unknown linkType: soft +"@noir-lang/noirc_abi@npm:0.19.4": + version: 0.19.4 + resolution: "@noir-lang/noirc_abi@npm:0.19.4" + checksum: 7446127935c954ae1b2bfdfa6cf111a9c14a2024f13a2d7e7e0a612319b0b4cc199acdbceaa94168e3bd5d82760b9d2fd2c9eec6677d57ed76e7b666e2b28c7d + languageName: node + linkType: hard + "@noir-lang/noirc_abi@workspace:*, @noir-lang/noirc_abi@workspace:tooling/noirc_abi_wasm": version: 0.0.0-use.local resolution: "@noir-lang/noirc_abi@workspace:tooling/noirc_abi_wasm" @@ -3540,15 +4091,21 @@ __metadata: languageName: unknown linkType: soft -"@noir-lang/source-resolver@workspace:*, @noir-lang/source-resolver@workspace:compiler/source-resolver": - version: 0.0.0-use.local - resolution: "@noir-lang/source-resolver@workspace:compiler/source-resolver" +"@noir-lang/source-resolver@npm:^0.19.2": + version: 0.19.4 + resolution: "@noir-lang/source-resolver@npm:0.19.4" + checksum: f0e51bb54daa1197894a17e5d0d125481aa0872c49c0d955feec2629b8ff51b9b48144778def6539a87b723a9b4c5eacc79d6eb935f0da6a1893d8d403689683 + languageName: node + linkType: hard + +"@noir-lang/types@npm:0.19.4, @noir-lang/types@npm:^0.19.2": + version: 0.19.4 + resolution: "@noir-lang/types@npm:0.19.4" dependencies: - "@types/node": ^20.5.7 - ava: ^5.2.0 - typescript: 4.9.4 - languageName: unknown - linkType: soft + "@noir-lang/noirc_abi": 0.19.4 + checksum: 1d0ce99895c0bc98e9daf67028132f71e30f60b2dc0799ee99f311d917e84459a0d2a37c318f5ab14e594e7dd26f5e612e5fd9a7e0a20a692a7017d7c883bb4d + languageName: node + linkType: hard "@noir-lang/types@workspace:*, @noir-lang/types@workspace:tooling/noir_js_types": version: 0.0.0-use.local @@ -3739,15 +4296,15 @@ __metadata: linkType: hard "@nomicfoundation/hardhat-ethers@npm:^3.0.0": - version: 3.0.4 - resolution: "@nomicfoundation/hardhat-ethers@npm:3.0.4" + version: 3.0.5 + resolution: "@nomicfoundation/hardhat-ethers@npm:3.0.5" dependencies: debug: ^4.1.1 lodash.isequal: ^4.5.0 peerDependencies: ethers: ^6.1.0 hardhat: ^2.0.0 - checksum: 57cbb13682cf0e14cf5bb17b47a2004f69765358fffba7d660ab277a6aff38583216637aa3c5c68410a649a9cd41f774a8df2cb89098f6f616f6108c0f6e5d7a + checksum: 34b092dfec68f8d8673c96af717660327edc814bc5c9cdb5bc1f82d5bde2b18bc9b9d3499a632784a3d4f2505ac174217e55d31b546b7eaa77a5bb30b3c80bb4 languageName: node linkType: hard @@ -3860,6 +4417,19 @@ __metadata: languageName: node linkType: hard +"@npmcli/agent@npm:^2.0.0": + version: 2.2.0 + resolution: "@npmcli/agent@npm:2.2.0" + dependencies: + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.1 + checksum: 3b25312edbdfaa4089af28e2d423b6f19838b945e47765b0c8174c1395c79d43c3ad6d23cb364b43f59fd3acb02c93e3b493f72ddbe3dfea04c86843a7311fc4 + languageName: node + linkType: hard + "@npmcli/fs@npm:^3.1.0": version: 3.1.0 resolution: "@npmcli/fs@npm:3.1.0" @@ -3876,7 +4446,7 @@ __metadata: languageName: node linkType: hard -"@pkgr/utils@npm:^2.3.1": +"@pkgr/utils@npm:^2.4.2": version: 2.4.2 resolution: "@pkgr/utils@npm:2.4.2" dependencies: @@ -3890,10 +4460,37 @@ __metadata: languageName: node linkType: hard +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: a3d2b57e35eec9543d9eb085854f6e33e8102dac99fdef2fad2eebdbbfc345e93299f0c20e8eb61c1b4c7aa123bfd47c175678626f161cda65dd147c2b6e1fa0 + languageName: node + linkType: hard + +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" + dependencies: + graceful-fs: 4.2.10 + checksum: d8d0884646500576bd5390464d13db1bb9a62e32a1069293e5bddb2ad8354b354b7e2d2a35e12850025651e795e6a80ce9e601c66312504667b7e3ee7b52becc + languageName: node + linkType: hard + +"@pnpm/npm-conf@npm:^2.1.0": + version: 2.2.2 + resolution: "@pnpm/npm-conf@npm:2.2.2" + dependencies: + "@pnpm/config.env-replace": ^1.1.0 + "@pnpm/network.ca-file": ^1.0.1 + config-chain: ^1.1.11 + checksum: d64aa4464be584caa855eafa8f109509390489997e36d602d6215784e2973b896bef3968426bb00896cf4ae7d440fed2cee7bb4e0dbc90362f024ea3f9e27ab1 + languageName: node + linkType: hard + "@polka/url@npm:^1.0.0-next.20": - version: 1.0.0-next.23 - resolution: "@polka/url@npm:1.0.0-next.23" - checksum: 4b0330de1ceecd1002c7e7449094d0c41f2ed0e21765f4835ccc7b003f2f024ac557d503b9ffdf0918cf50b80d5b8c99dfc5a91927e7b3c468b09c6bb42a3c41 + version: 1.0.0-next.24 + resolution: "@polka/url@npm:1.0.0-next.24" + checksum: 00baec4458ac86ca27edf7ce807ccfad97cd1d4b67bdedaf3401a9e755757588f3331e891290d1deea52d88df2bf2387caf8d94a6835b614d5b37b638a688273 languageName: node linkType: hard @@ -4082,6 +4679,27 @@ __metadata: languageName: node linkType: hard +"@signorecello/noir_playground@npm:^0.6.0": + version: 0.6.0 + resolution: "@signorecello/noir_playground@npm:0.6.0" + dependencies: + "@monaco-editor/react": 4.6.0 + "@noir-lang/backend_barretenberg": ^0.19.2 + "@noir-lang/noir_js": ^0.19.2 + "@noir-lang/noir_wasm": ^0.19.2 + "@noir-lang/source-resolver": ^0.19.2 + "@noir-lang/types": ^0.19.2 + fflate: ^0.8.1 + js-base64: ^3.7.5 + monaco-editor: ^0.44.0 + monaco-editor-textmate: ^4.0.0 + monaco-textmate: ^3.0.1 + onigasm: ^2.2.5 + react-toastify: ^9.1.3 + checksum: a1fa6f5b6aded80ad8ecdf8841dbbcd70e2a3faa479bc39f8077d3e96d65ceab53488f278db1a991a6cc8c6ce63206cc1627fe87e683187941359251e67c48ed + languageName: node + linkType: hard + "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -4096,6 +4714,31 @@ __metadata: languageName: node linkType: hard +"@sindresorhus/is@npm:^4.6.0": + version: 4.6.0 + resolution: "@sindresorhus/is@npm:4.6.0" + checksum: 83839f13da2c29d55c97abc3bc2c55b250d33a0447554997a85c539e058e57b8da092da396e252b11ec24a0279a0bed1f537fa26302209327060643e327f81d2 + languageName: node + linkType: hard + +"@sindresorhus/is@npm:^5.2.0": + version: 5.6.0 + resolution: "@sindresorhus/is@npm:5.6.0" + checksum: 2e6e0c3acf188dcd9aea0f324ac1b6ad04c9fc672392a7b5a1218512fcde066965797eba8b9fe2108657a504388bd4a6664e6e6602555168e828a6df08b9f10e + languageName: node + linkType: hard + +"@slorber/remark-comment@npm:^1.0.0": + version: 1.0.0 + resolution: "@slorber/remark-comment@npm:1.0.0" + dependencies: + micromark-factory-space: ^1.0.0 + micromark-util-character: ^1.1.0 + micromark-util-symbol: ^1.0.1 + checksum: c96f1533d09913c57381859966f10a706afd8eb680923924af1c451f3b72f22c31e394028d7535131c10f8682d3c60206da95c50fb4f016fbbd04218c853cc88 + languageName: node + linkType: hard + "@slorber/static-site-generator-webpack-plugin@npm:^4.0.7": version: 4.0.7 resolution: "@slorber/static-site-generator-webpack-plugin@npm:4.0.7" @@ -4247,7 +4890,7 @@ __metadata: languageName: node linkType: hard -"@svgr/webpack@npm:^6.2.1": +"@svgr/webpack@npm:^6.2.1, @svgr/webpack@npm:^6.5.1": version: 6.5.1 resolution: "@svgr/webpack@npm:6.5.1" dependencies: @@ -4272,10 +4915,12 @@ __metadata: languageName: node linkType: hard -"@tootallnate/once@npm:2": - version: 2.0.0 - resolution: "@tootallnate/once@npm:2.0.0" - checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 +"@szmarczak/http-timer@npm:^5.0.1": + version: 5.0.1 + resolution: "@szmarczak/http-timer@npm:5.0.1" + dependencies: + defer-to-connect: ^2.0.1 + checksum: fc9cb993e808806692e4a3337c90ece0ec00c89f4b67e3652a356b89730da98bc824273a6d67ca84d5f33cd85f317dcd5ce39d8cc0a2f060145a608a7cb8ce92 languageName: node linkType: hard @@ -4315,18 +4960,27 @@ __metadata: linkType: hard "@types/accepts@npm:*": - version: 1.3.5 - resolution: "@types/accepts@npm:1.3.5" + version: 1.3.7 + resolution: "@types/accepts@npm:1.3.7" dependencies: "@types/node": "*" - checksum: 590b7580570534a640510c071e09074cf63b5958b237a728f94322567350aea4d239f8a9d897a12b15c856b992ee4d7907e9812bb079886af2c00714e7fb3f60 + checksum: 7678cf74976e16093aff6e6f9755826faf069ac1e30179276158ce46ea246348ff22ca6bdd46cef08428881337d9ceefbf00bab08a7731646eb9fc9449d6a1e7 + languageName: node + linkType: hard + +"@types/acorn@npm:^4.0.0": + version: 4.0.6 + resolution: "@types/acorn@npm:4.0.6" + dependencies: + "@types/estree": "*" + checksum: 60e1fd28af18d6cb54a93a7231c7c18774a9a8739c9b179e9e8750dca631e10cbef2d82b02830ea3f557b1d121e6406441e9e1250bd492dc81d4b3456e76e4d4 languageName: node linkType: hard "@types/babel__code-frame@npm:^7.0.2": - version: 7.0.4 - resolution: "@types/babel__code-frame@npm:7.0.4" - checksum: eb4adb0a79c5cbf2d88ad087b2694a1e38749dc0056693e6125c17a3967fc8d4cc1eb33eab26d3dcaaa8995236cba4a088965cc3a115967545f2a01ee430c87f + version: 7.0.6 + resolution: "@types/babel__code-frame@npm:7.0.6" + checksum: 5325ab85d95e58fe84279757788ddb0de68bfd6814bc636e868f9ff7b5229915873f28847c4baf48fd3a4a460a73b4ea87bc9e1d78a3a5a60cfc7ca627a722c5 languageName: node linkType: hard @@ -4340,142 +4994,160 @@ __metadata: linkType: hard "@types/bn.js@npm:^5.1.0": - version: 5.1.2 - resolution: "@types/bn.js@npm:5.1.2" + version: 5.1.5 + resolution: "@types/bn.js@npm:5.1.5" dependencies: "@types/node": "*" - checksum: 8d9fdb43836646c2ecd445041de03e057f9b459885be57faee64104160487a63730b9f371e8ad7d33f360b3cc6dc0e323543962fc5fa296b92b322b946732be0 + checksum: c87b28c4af74545624f8a3dae5294b16aa190c222626e8d4b2e327b33b1a3f1eeb43e7a24d914a9774bca43d8cd6e1cb0325c1f4b3a244af6693a024e1d918e6 languageName: node linkType: hard "@types/body-parser@npm:*": - version: 1.19.3 - resolution: "@types/body-parser@npm:1.19.3" + version: 1.19.5 + resolution: "@types/body-parser@npm:1.19.5" dependencies: "@types/connect": "*" "@types/node": "*" - checksum: 932fa71437c275023799123680ef26ffd90efd37f51a1abe405e6ae6e5b4ad9511b7a3a8f5a12877ed1444a02b6286c0a137a98e914b3c61932390c83643cc2c + checksum: 1e251118c4b2f61029cc43b0dc028495f2d1957fe8ee49a707fb940f86a9bd2f9754230805598278fe99958b49e9b7e66eec8ef6a50ab5c1f6b93e1ba2aaba82 languageName: node linkType: hard "@types/bonjour@npm:^3.5.9": - version: 3.5.11 - resolution: "@types/bonjour@npm:3.5.11" + version: 3.5.13 + resolution: "@types/bonjour@npm:3.5.13" dependencies: "@types/node": "*" - checksum: 12fb86a1bb4a610f16ef6d7d68f85e7c31070029f02b6622073794a271e75abcf58230ed205a2ae23c53be2c08b9e507d3b91fa0dc9dfe76c4b1f5e19e9370cb + checksum: e827570e097bd7d625a673c9c208af2d1a22fa3885c0a1646533cf24394c839c3e5f60ac1bc60c0ddcc69c0615078c9fb2c01b42596c7c582d895d974f2409ee languageName: node linkType: hard "@types/chai-as-promised@npm:^7.1.3": - version: 7.1.6 - resolution: "@types/chai-as-promised@npm:7.1.6" + version: 7.1.8 + resolution: "@types/chai-as-promised@npm:7.1.8" dependencies: "@types/chai": "*" - checksum: f765dd249ae9384540f8e6402bd3a9f5e87b97f9078ef58f4b5ec15f7c3673e1f10f0089f819eceb20e00b3df40b7aae1bd44d2b8f4edbbedfcb33ce296f6791 + checksum: f0e5eab451b91bc1e289ed89519faf6591932e8a28d2ec9bbe95826eb73d28fe43713633e0c18706f3baa560a7d97e7c7c20dc53ce639e5d75bac46b2a50bf21 languageName: node linkType: hard "@types/chai@npm:*, @types/chai@npm:^4, @types/chai@npm:^4.2.12": - version: 4.3.6 - resolution: "@types/chai@npm:4.3.6" - checksum: 32a6c18bf53fb3dbd89d1bfcadb1c6fd45cc0007c34e436393cc37a0a5a556f9e6a21d1e8dd71674c40cc36589d2f30bf4d9369d7787021e54d6e997b0d7300a + version: 4.3.11 + resolution: "@types/chai@npm:4.3.11" + checksum: d0c05fe5d02b2e6bbca2bd4866a2ab20a59cf729bc04af0060e7a3277eaf2fb65651b90d4c74b0ebf1d152b4b1d49fa8e44143acef276a2bbaa7785fbe5642d3 languageName: node linkType: hard "@types/co-body@npm:^6.1.0": - version: 6.1.1 - resolution: "@types/co-body@npm:6.1.1" + version: 6.1.3 + resolution: "@types/co-body@npm:6.1.3" dependencies: "@types/node": "*" "@types/qs": "*" - checksum: 38a5198c712bfb40f36c7c5fd85964cabfdac0d0aa4d703993c205ccafa113995b67846e59d5d05415dcba230e21126060e04c1287d8073fc2dc71257cb2ea0c + checksum: e93fdc177f69ee0535cf401783258e4255f5eb8235c58b5a2a5a8958cf341fadf3d0bf2c75907ed6b7d188ce2c2f2cf9593a71d4eef12900beba54ebbbdd5cc1 languageName: node linkType: hard "@types/command-line-args@npm:^5.0.0": - version: 5.2.1 - resolution: "@types/command-line-args@npm:5.2.1" - checksum: a5df8562a7a0eb7c4da218661360ff8369a63c0fd783310d1940f0ece55826d5173eeb3732bab48dbfb60b1614d61989a9d87c6cdbee04353c4df6f45387d417 + version: 5.2.3 + resolution: "@types/command-line-args@npm:5.2.3" + checksum: 3d90db5b4bbaabd049654a0d12fa378989ab0d76a0f98d4c606761b5a08ce76458df0f9bb175219e187b4cd57e285e6f836d23e86b2c3d997820854cc3ed9121 languageName: node linkType: hard "@types/connect-history-api-fallback@npm:^1.3.5": - version: 1.5.1 - resolution: "@types/connect-history-api-fallback@npm:1.5.1" + version: 1.5.4 + resolution: "@types/connect-history-api-fallback@npm:1.5.4" dependencies: "@types/express-serve-static-core": "*" "@types/node": "*" - checksum: bc5e46663300eba56eaf8ef242156256e2bdadc52bb7d6543f4b37f2945b6a810901c245711f8321fce7d94c7b588b308a86519f3e1f87a80eb87841d808dbdc + checksum: e1dee43b8570ffac02d2d47a2b4ba80d3ca0dd1840632dafb221da199e59dbe3778d3d7303c9e23c6b401f37c076935a5bc2aeae1c4e5feaefe1c371fe2073fd languageName: node linkType: hard "@types/connect@npm:*": - version: 3.4.36 - resolution: "@types/connect@npm:3.4.36" + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" dependencies: "@types/node": "*" - checksum: 4dee3d966fb527b98f0cbbdcf6977c9193fc3204ed539b7522fe5e64dfa45f9017bdda4ffb1f760062262fce7701a0ee1c2f6ce2e50af36c74d4e37052303172 + checksum: 7eb1bc5342a9604facd57598a6c62621e244822442976c443efb84ff745246b10d06e8b309b6e80130026a396f19bf6793b7cecd7380169f369dac3bfc46fb99 languageName: node linkType: hard "@types/content-disposition@npm:*": - version: 0.5.6 - resolution: "@types/content-disposition@npm:0.5.6" - checksum: da07798d52cc8fc46a8843d768b48d54c70f1a44c861dc2c73c4c25a1e08af859709629ab0e4d23d5198107b8926bb48c593df436ba68123d87191f5e25fe4bc + version: 0.5.8 + resolution: "@types/content-disposition@npm:0.5.8" + checksum: eeea868fb510ae7a32aa2d7de680fba79d59001f3e758a334621e10bc0a6496d3a42bb79243a5e53b9c63cb524522853ccc144fe1ab160c4247d37cdb81146c4 languageName: node linkType: hard "@types/convert-source-map@npm:^2.0.0": - version: 2.0.1 - resolution: "@types/convert-source-map@npm:2.0.1" - checksum: 200b2792b37748e89e4363ef07686b074f64e21a26f27381d51bc336222a85503cfa1266e29d3b9c9121c8156e0a3973f3adbe2f4be59516fa255c080b4ca976 + version: 2.0.3 + resolution: "@types/convert-source-map@npm:2.0.3" + checksum: 411cf9a02cf5dbe204e325dd5ebf50de00b58b38d1d2a3064c6ea28417c23bae956206eaa9ed3a75a994909b4ab3f9c6389073d0636a62500fa6d6333c64d45a languageName: node linkType: hard "@types/cookies@npm:*": - version: 0.7.8 - resolution: "@types/cookies@npm:0.7.8" + version: 0.7.10 + resolution: "@types/cookies@npm:0.7.10" dependencies: "@types/connect": "*" "@types/express": "*" "@types/keygrip": "*" "@types/node": "*" - checksum: 7945b0cfe370bf1f05a1f328c9eba55333dac1bb9d7efa3148b107c260ab924263546351f9fd168daa72948d195464d395319a24477995f9f887a3a99fbcb5b5 + checksum: 99cd44a193398932ff7926cfaac1eb4441d3dc47c3f64fdfb28861acbeb290b6db6a20376f993defc9d302db92bb1d36189b89ba447a633f960535f3f0d34e2d languageName: node linkType: hard "@types/debounce@npm:^1.2.0": - version: 1.2.1 - resolution: "@types/debounce@npm:1.2.1" - checksum: bea6d414acefbee50adfe87cee10f8a855d033e4778567ab03bdc3cb2648b6bf9237ca53f4ee76fe4be75f77f86d4688411499626fe409bc870f53631d24231f + version: 1.2.4 + resolution: "@types/debounce@npm:1.2.4" + checksum: decef3eee65d681556d50f7fac346f1b33134f6b21f806d41326f9dfb362fa66b0282ff0640ae6791b690694c9dc3dad4e146e909e707e6f96650f3aa325b9da + languageName: node + linkType: hard + +"@types/debug@npm:^4.0.0": + version: 4.1.12 + resolution: "@types/debug@npm:4.1.12" + dependencies: + "@types/ms": "*" + checksum: 47876a852de8240bfdaf7481357af2b88cb660d30c72e73789abf00c499d6bc7cd5e52f41c915d1b9cd8ec9fef5b05688d7b7aef17f7f272c2d04679508d1053 languageName: node linkType: hard "@types/eslint-scope@npm:^3.7.3": - version: 3.7.5 - resolution: "@types/eslint-scope@npm:3.7.5" + version: 3.7.7 + resolution: "@types/eslint-scope@npm:3.7.7" dependencies: "@types/eslint": "*" "@types/estree": "*" - checksum: e91ce335c3791c2cf6084caa0073f90d5b7ae3fcf27785ade8422b7d896159fa14a5a3f1efd31ef03e9ebc1ff04983288280dfe8c9a5579a958539f59df8cc9f + checksum: e2889a124aaab0b89af1bab5959847c5bec09809209255de0e63b9f54c629a94781daa04adb66bffcdd742f5e25a17614fb933965093c0eea64aacda4309380e languageName: node linkType: hard "@types/eslint@npm:*": - version: 8.44.4 - resolution: "@types/eslint@npm:8.44.4" + version: 8.44.8 + resolution: "@types/eslint@npm:8.44.8" dependencies: "@types/estree": "*" "@types/json-schema": "*" - checksum: 15bafdaba800e2995f38d3a2a929d8e9303035315e8d3535523a21cd719b6769a45884afa955f0b845ffa545a4150429b0178e2c44feeedf59ebb285eeae9825 + checksum: c3bc70166075e6e9f7fb43978882b9ac0b22596b519900b08dc8a1d761bbbddec4c48a60cc4eb674601266223c6f11db30f3fb6ceaae96c23c54b35ad88022bc + languageName: node + linkType: hard + +"@types/estree-jsx@npm:^1.0.0": + version: 1.0.3 + resolution: "@types/estree-jsx@npm:1.0.3" + dependencies: + "@types/estree": "*" + checksum: 6887a134308b6db4a33a147b56c9d0a47c17ea7e810bdd7c498c306a0fd00bcf2619cb0f57f74009d03dda974b3cd7e414767f85332b1d1b2be30a3ef9e1cca9 languageName: node linkType: hard "@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.2 - resolution: "@types/estree@npm:1.0.2" - checksum: aeedb1b2fe20cbe06f44b99b562bf9703e360bfcdf5bb3d61d248182ee1dd63500f2474e12f098ffe1f5ac3202b43b3e18ec99902d9328d5374f5512fa077e45 + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a languageName: node linkType: hard @@ -4486,51 +5158,27 @@ __metadata: languageName: node linkType: hard -"@types/express-serve-static-core@npm:*": - version: 4.17.37 - resolution: "@types/express-serve-static-core@npm:4.17.37" - dependencies: - "@types/node": "*" - "@types/qs": "*" - "@types/range-parser": "*" - "@types/send": "*" - checksum: 2dab1380e45eb44e56ecc1be1c42c4b897364d2f2a08e03ca28fbcb1e6866e390217385435813711c046f9acd684424d088855dc32825d5cbecf72c60ecd037f - languageName: node - linkType: hard - -"@types/express-serve-static-core@npm:^4.17.33": - version: 4.17.36 - resolution: "@types/express-serve-static-core@npm:4.17.36" +"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33": + version: 4.17.41 + resolution: "@types/express-serve-static-core@npm:4.17.41" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: 410b13cbd663f18c0f8729e7f2ff54d960d96de76ebbae7cadb612972f85cc66c54051e00d32f11aa230c0a683d81a6d6fc7f7e4e383a95c0801494c517f36e1 - languageName: node - linkType: hard - -"@types/express@npm:*": - version: 4.17.17 - resolution: "@types/express@npm:4.17.17" - dependencies: - "@types/body-parser": "*" - "@types/express-serve-static-core": ^4.17.33 - "@types/qs": "*" - "@types/serve-static": "*" - checksum: 0196dacc275ac3ce89d7364885cb08e7fb61f53ca101f65886dbf1daf9b7eb05c0943e2e4bbd01b0cc5e50f37e0eea7e4cbe97d0304094411ac73e1b7998f4da + checksum: 12750f6511dd870bbaccfb8208ad1e79361cf197b147f62a3bedc19ec642f3a0f9926ace96705f4bc88ec2ae56f61f7ca8c2438e6b22f5540842b5569c28a121 languageName: node linkType: hard -"@types/express@npm:^4.17.13": - version: 4.17.19 - resolution: "@types/express@npm:4.17.19" +"@types/express@npm:*, @types/express@npm:^4.17.13": + version: 4.17.21 + resolution: "@types/express@npm:4.17.21" dependencies: "@types/body-parser": "*" "@types/express-serve-static-core": ^4.17.33 "@types/qs": "*" "@types/serve-static": "*" - checksum: 3d39d0655eb0825d96fec100985a38737767ddd6da2dbda1e330a3adf36c98a9b7cd8d9539db32876d1fbb47a09343cad7b38c30c8dd7c291271fcb9b85cb21b + checksum: fb238298630370a7392c7abdc80f495ae6c716723e114705d7e3fb67e3850b3859bbfd29391463a3fb8c0b32051847935933d99e719c0478710f8098ee7091c5 languageName: node linkType: hard @@ -4543,12 +5191,28 @@ __metadata: languageName: node linkType: hard +"@types/gtag.js@npm:^0.0.12": + version: 0.0.12 + resolution: "@types/gtag.js@npm:0.0.12" + checksum: 34efc27fbfd0013255b8bfd4af38ded9d5a6ba761130c76f17fd3a9585d83acc88d8005aab667cfec4bdec0e7c7217f689739799a8f61aed0edb929be58b162e + languageName: node + linkType: hard + "@types/hast@npm:^2.0.0": - version: 2.3.6 - resolution: "@types/hast@npm:2.3.6" + version: 2.3.8 + resolution: "@types/hast@npm:2.3.8" dependencies: "@types/unist": ^2 - checksum: c004372f6ab919ec92a2de43e4380707e27b76fe371c7d06ab26547c1e851dfba2a7c740c544218df8c7e0a94443458793c43730ad563a39e3fdc1a48904d7f5 + checksum: 4c3b3efb7067d32a568a9bf5d2a7599f99ec08c2eaade3aaeb579b7a31bcdf8f6475f56c1ac5bc3f4e4e07b84a93a9b1cf1ef9a8b52b39e3deabea7989e5dd4b + languageName: node + linkType: hard + +"@types/hast@npm:^3.0.0": + version: 3.0.3 + resolution: "@types/hast@npm:3.0.3" + dependencies: + "@types/unist": "*" + checksum: ca204207550fd6848ee20b5ba2018fd54f515d59a8b80375cdbe392ba2b4b130dac25fdfbaf9f2a70d2aec9d074a34dc14d4d59d31fa3ede80ef9850afad5d3c languageName: node linkType: hard @@ -4567,71 +5231,78 @@ __metadata: linkType: hard "@types/http-assert@npm:*": - version: 1.5.3 - resolution: "@types/http-assert@npm:1.5.3" - checksum: 9553e5a0b8bcfdac4b51d3fa3b89a91b5450171861a667a5b4c47204e0f4a1ca865d97396e6ceaf220e87b64d06b7a8bad7bfba15ef97acb41a87507c9940dbc + version: 1.5.5 + resolution: "@types/http-assert@npm:1.5.5" + checksum: cd6bb7fd42cc6e2a702cb55370b8b25231954ad74c04bcd185b943a74ded3d4c28099c30f77b26951df2426441baff41718816c60b5af80efe2b8888d900bf93 + languageName: node + linkType: hard + +"@types/http-cache-semantics@npm:^4.0.2": + version: 4.0.4 + resolution: "@types/http-cache-semantics@npm:4.0.4" + checksum: 7f4dd832e618bc1e271be49717d7b4066d77c2d4eed5b81198eb987e532bb3e1c7e02f45d77918185bad936f884b700c10cebe06305f50400f382ab75055f9e8 languageName: node linkType: hard "@types/http-errors@npm:*": - version: 2.0.2 - resolution: "@types/http-errors@npm:2.0.2" - checksum: d7f14045240ac4b563725130942b8e5c8080bfabc724c8ff3f166ea928ff7ae02c5194763bc8f6aaf21897e8a44049b0492493b9de3e058247e58fdfe0f86692 + version: 2.0.4 + resolution: "@types/http-errors@npm:2.0.4" + checksum: 1f3d7c3b32c7524811a45690881736b3ef741bf9849ae03d32ad1ab7062608454b150a4e7f1351f83d26a418b2d65af9bdc06198f1c079d75578282884c4e8e3 languageName: node linkType: hard "@types/http-proxy@npm:^1.17.8": - version: 1.17.12 - resolution: "@types/http-proxy@npm:1.17.12" + version: 1.17.14 + resolution: "@types/http-proxy@npm:1.17.14" dependencies: "@types/node": "*" - checksum: 89700c8e3c8f2c59c87c8db8e7a070c97a3b30a4a38223aca6b8b817e6f2ca931f5a500e16ecadc1ebcfed2676cc60e073d8f887e621d84420298728ec6fd000 + checksum: 491320bce3565bbb6c7d39d25b54bce626237cfb6b09e60ee7f77b56ae7c6cbad76f08d47fe01eaa706781124ee3dfad9bb737049254491efd98ed1f014c4e83 languageName: node linkType: hard "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1, @types/istanbul-lib-coverage@npm:^2.0.3": - version: 2.0.4 - resolution: "@types/istanbul-lib-coverage@npm:2.0.4" - checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 + version: 2.0.6 + resolution: "@types/istanbul-lib-coverage@npm:2.0.6" + checksum: 3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 languageName: node linkType: hard "@types/istanbul-lib-report@npm:*": - version: 3.0.0 - resolution: "@types/istanbul-lib-report@npm:3.0.0" + version: 3.0.3 + resolution: "@types/istanbul-lib-report@npm:3.0.3" dependencies: "@types/istanbul-lib-coverage": "*" - checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36 + checksum: b91e9b60f865ff08cb35667a427b70f6c2c63e88105eadd29a112582942af47ed99c60610180aa8dcc22382fa405033f141c119c69b95db78c4c709fbadfeeb4 languageName: node linkType: hard "@types/istanbul-reports@npm:^3.0.0": - version: 3.0.1 - resolution: "@types/istanbul-reports@npm:3.0.1" + version: 3.0.4 + resolution: "@types/istanbul-reports@npm:3.0.4" dependencies: "@types/istanbul-lib-report": "*" - checksum: f1ad54bc68f37f60b30c7915886b92f86b847033e597f9b34f2415acdbe5ed742fa559a0a40050d74cdba3b6a63c342cac1f3a64dba5b68b66a6941f4abd7903 + checksum: 93eb18835770b3431f68ae9ac1ca91741ab85f7606f310a34b3586b5a34450ec038c3eed7ab19266635499594de52ff73723a54a72a75b9f7d6a956f01edee95 languageName: node linkType: hard "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.13 - resolution: "@types/json-schema@npm:7.0.13" - checksum: 345df21a678fa72fb389f35f33de77833d09d4a142bb2bcb27c18690efa4cf70fc2876e43843cefb3fbdb9fcb12cd3e970a90936df30f53bbee899865ff605ab + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 languageName: node linkType: hard -"@types/katex@npm:^0.11.0": - version: 0.11.1 - resolution: "@types/katex@npm:0.11.1" - checksum: 1e51988b4b386a1b6fa8e22826ab4705bf3e6c9fb03461f2c91d28cb31095232bdeff491069ac9bc74bc4c26110be6a11a41e12ca77a2e4169f3afd8cd349355 +"@types/katex@npm:^0.16.0": + version: 0.16.7 + resolution: "@types/katex@npm:0.16.7" + checksum: 4fd15d93553be97c02c064e16be18d7ccbabf66ec72a9dc7fd5bfa47f0c7581da2f942f693c7cb59499de4c843c2189796e49c9647d336cbd52b777b6722a95a languageName: node linkType: hard "@types/keygrip@npm:*": - version: 1.0.3 - resolution: "@types/keygrip@npm:1.0.3" - checksum: adee9a3efda3db9c64466af1c7c91a6d049420ee50589500cfd36e3e38d6abefdd858da88e6da63ed186e588127af3e862c1dc64fb0ad45c91870e6c35fe3be0 + version: 1.0.6 + resolution: "@types/keygrip@npm:1.0.6" + checksum: d157f60bf920492347791d2b26d530d5069ce05796549fbacd4c24d66ffbebbcb0ab67b21e7a1b80a593b9fd4b67dc4843dec04c12bbc2e0fddfb8577a826c41 languageName: node linkType: hard @@ -4645,17 +5316,17 @@ __metadata: linkType: hard "@types/koa-compose@npm:*": - version: 3.2.6 - resolution: "@types/koa-compose@npm:3.2.6" + version: 3.2.8 + resolution: "@types/koa-compose@npm:3.2.8" dependencies: "@types/koa": "*" - checksum: 1204c5bfa4c69448b692aba29c566ef6bedbdbe5842fa180450267a23d3606faa13ef209876fd0c989edb5bc381812a66610fcfeac196ce4e76364354756ba1f + checksum: 95c32bdee738ac7c10439bbf6342ca3b9f0aafd7e8118739eac7fb0fa703a23cfe4c88f63e13a69a16fbde702e0bcdc62b272aa734325fc8efa7e5625479752e languageName: node linkType: hard "@types/koa@npm:*, @types/koa@npm:^2.11.6": - version: 2.13.9 - resolution: "@types/koa@npm:2.13.9" + version: 2.13.12 + resolution: "@types/koa@npm:2.13.12" dependencies: "@types/accepts": "*" "@types/content-disposition": "*" @@ -4665,14 +5336,14 @@ __metadata: "@types/keygrip": "*" "@types/koa-compose": "*" "@types/node": "*" - checksum: af9cd599c8e17e2ae0f4168a61d964e343f713d002b65fd995658d7addc6551ccadecfd32b3405cf44e4d360178ee4f972d6881533548261ae1f636a655d24b1 + checksum: 4a2e7e19bf91779d0a3c46b8838d6faba5ee0e9a888e5ef8683722c21aa8efcf35f86d1a661adb56ca9f239f7724e306055e33bfa1b2dc008b9c0fa9fcc12bee languageName: node linkType: hard "@types/lodash@npm:^4": - version: 4.14.200 - resolution: "@types/lodash@npm:4.14.200" - checksum: 6471f8bb5da692a6ecf03a8da4935bfbc341e67ee9bcb4f5730bfacff0c367232548f0a01e8ac5ea18c6fe78fb085d502494e33ccb47a7ee87cbdee03b47d00d + version: 4.14.202 + resolution: "@types/lodash@npm:4.14.202" + checksum: a91acf3564a568c6f199912f3eb2c76c99c5a0d7e219394294213b3f2d54f672619f0fde4da22b29dc5d4c31457cd799acc2e5cb6bd90f9af04a1578483b6ff7 languageName: node linkType: hard @@ -4684,39 +5355,55 @@ __metadata: linkType: hard "@types/mdast@npm:^3.0.0": - version: 3.0.13 - resolution: "@types/mdast@npm:3.0.13" + version: 3.0.15 + resolution: "@types/mdast@npm:3.0.15" dependencies: "@types/unist": ^2 - checksum: f13fa17a2931ed1492a2f0012a3abd6de3a2d1128145981321909e03fedba80162668f284a4af92aca3732b27e933c5f4772336d96b9ae660bfde696d07abbe6 + checksum: af85042a4e3af3f879bde4059fa9e76c71cb552dffc896cdcc6cf9dc1fd38e37035c2dbd6245cfa6535b433f1f0478f5549696234ccace47a64055a10c656530 + languageName: node + linkType: hard + +"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.2": + version: 4.0.3 + resolution: "@types/mdast@npm:4.0.3" + dependencies: + "@types/unist": "*" + checksum: 345c5a22fccf05f35239ea6313ee4aaf6ebed5927c03ac79744abccb69b9ba5e692f9b771e36a012b79e17429082cada30f579e9c43b8a54e0ffb365431498b6 + languageName: node + linkType: hard + +"@types/mdx@npm:^2.0.0": + version: 2.0.10 + resolution: "@types/mdx@npm:2.0.10" + checksum: 3e2fb24b7bfae739a59573344171292b6c31256ad9afddc00232e9de4fbc97b270e1a11d13cb935cba0d9bbb9bc7348793eda82ee752233c5d2289f4b897f719 languageName: node linkType: hard "@types/mime@npm:*": - version: 3.0.1 - resolution: "@types/mime@npm:3.0.1" - checksum: 4040fac73fd0cea2460e29b348c1a6173da747f3a87da0dbce80dd7a9355a3d0e51d6d9a401654f3e5550620e3718b5a899b2ec1debf18424e298a2c605346e7 + version: 3.0.4 + resolution: "@types/mime@npm:3.0.4" + checksum: a6139c8e1f705ef2b064d072f6edc01f3c099023ad7c4fce2afc6c2bf0231888202adadbdb48643e8e20da0ce409481a49922e737eca52871b3dc08017455843 languageName: node linkType: hard "@types/mime@npm:^1": - version: 1.3.2 - resolution: "@types/mime@npm:1.3.2" - checksum: 0493368244cced1a69cb791b485a260a422e6fcc857782e1178d1e6f219f1b161793e9f87f5fae1b219af0f50bee24fcbe733a18b4be8fdd07a38a8fb91146fd + version: 1.3.5 + resolution: "@types/mime@npm:1.3.5" + checksum: e29a5f9c4776f5229d84e525b7cd7dd960b51c30a0fb9a028c0821790b82fca9f672dab56561e2acd9e8eed51d431bde52eafdfef30f643586c4162f1aecfc78 languageName: node linkType: hard "@types/minimist@npm:^1.2.2": - version: 1.2.2 - resolution: "@types/minimist@npm:1.2.2" - checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + version: 1.2.5 + resolution: "@types/minimist@npm:1.2.5" + checksum: 477047b606005058ab0263c4f58097136268007f320003c348794f74adedc3166ffc47c80ec3e94687787f2ab7f4e72c468223946e79892cf0fd9e25e9970a90 languageName: node linkType: hard "@types/mocha@npm:^10.0.1": - version: 10.0.1 - resolution: "@types/mocha@npm:10.0.1" - checksum: 224ea9fce7b1734ccdb9aa99a622d902a538ce1847bca7fd22c5fb38adcf3ed536f50f48f587085db988a4bb3c2eb68f4b98e1cd6a38bc5547bd3bbbedc54495 + version: 10.0.6 + resolution: "@types/mocha@npm:10.0.6" + checksum: f7c836cf6cf27dc0f5970d262591b56f2a3caeaec8cfdc612c12e1cfbb207f601f710ece207e935164d4e3343b93be5054d0db5544f31f453b3923775d82099f languageName: node linkType: hard @@ -4727,10 +5414,28 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^20.5.7, @types/node@npm:^20.6.2": - version: 20.6.3 - resolution: "@types/node@npm:20.6.3" - checksum: 444a6f1f41cfa8d3e20ce0108e6e43960fb2ae0e481f233bb1c14d6252aa63a92e021de561cd317d9fdb411688f871065f40175a1f18763282dee2613a08f8a3 +"@types/ms@npm:*": + version: 0.7.34 + resolution: "@types/ms@npm:0.7.34" + checksum: f38d36e7b6edecd9badc9cf50474159e9da5fa6965a75186cceaf883278611b9df6669dc3a3cc122b7938d317b68a9e3d573d316fcb35d1be47ec9e468c6bd8a + languageName: node + linkType: hard + +"@types/node-forge@npm:^1.3.0": + version: 1.3.10 + resolution: "@types/node-forge@npm:1.3.10" + dependencies: + "@types/node": "*" + checksum: 363af42c83956c7e2483a71e398a02101ef6a55b4d86386c276315ca98bad02d6050b99fdbe13debcd1bcda250086b4a5b5c15a6fb2953d32420d269865ca7f8 + languageName: node + linkType: hard + +"@types/node@npm:*, @types/node@npm:^20.6.2": + version: 20.10.4 + resolution: "@types/node@npm:20.10.4" + dependencies: + undici-types: ~5.26.4 + checksum: 054b296417e771ab524bea63cf3289559c6bdf290d45428f7cc68e9b00030ff7a0ece47b8c99a26b4f47a443919813bcf42beadff2f0bea7d8125fa541d92eb0 languageName: node linkType: hard @@ -4749,16 +5454,18 @@ __metadata: linkType: hard "@types/node@npm:^18.7.20": - version: 18.17.18 - resolution: "@types/node@npm:18.17.18" - checksum: 59cbd906363d37017fe9ba0c08c1446e440d4d977459609c5f90b8fb7eb41f273ce8af30c5a5b5d599d7de934c1b3702bc9fc27caf8d2270e5cdb659c5232991 + version: 18.19.3 + resolution: "@types/node@npm:18.19.3" + dependencies: + undici-types: ~5.26.4 + checksum: 58c4fa45a78fcec75c78182a4b266395905957633654eb0311c5f9c30ac15c179ea2287ab1af034e46c2db7bb0589ef0000ee64c1de8f568a0aad29eaadb100c languageName: node linkType: hard "@types/parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/parse-json@npm:4.0.0" - checksum: fd6bce2b674b6efc3db4c7c3d336bd70c90838e8439de639b909ce22f3720d21344f52427f1d9e57b265fcb7f6c018699b99e5e0c208a1a4823014269a6bf35b + version: 4.0.2 + resolution: "@types/parse-json@npm:4.0.2" + checksum: 5bf62eec37c332ad10059252fc0dab7e7da730764869c980b0714777ad3d065e490627be9f40fc52f238ffa3ac4199b19de4127196910576c2fe34dd47c7a470 languageName: node linkType: hard @@ -4777,11 +5484,11 @@ __metadata: linkType: hard "@types/pbkdf2@npm:^3.0.0": - version: 3.1.0 - resolution: "@types/pbkdf2@npm:3.1.0" + version: 3.1.2 + resolution: "@types/pbkdf2@npm:3.1.2" dependencies: "@types/node": "*" - checksum: d15024b1957c21cf3b8887329d9bd8dfde754cf13a09d76ae25f1391cfc62bb8b8d7b760773c5dbaa748172fba8b3e0c3dbe962af6ccbd69b76df12a48dfba40 + checksum: bebe1e596cbbe5f7d2726a58859e61986c5a42459048e29cb7f2d4d764be6bbb0844572fd5d70ca8955a8a17e8b4ed80984fc4903e165d9efb8807a3fbb051aa languageName: node linkType: hard @@ -4794,42 +5501,49 @@ __metadata: languageName: node linkType: hard +"@types/prismjs@npm:^1.26.0": + version: 1.26.3 + resolution: "@types/prismjs@npm:1.26.3" + checksum: c627fa9d9f4277ce413bb8347944152cddfc892702e34ff4b099dc1cf3f00c09514d36349c23529b903b0e57f3b2e0dc91ee66e98af07fbbe1e3fe8346b23370 + languageName: node + linkType: hard + "@types/prop-types@npm:*": - version: 15.7.8 - resolution: "@types/prop-types@npm:15.7.8" - checksum: 61dfad79da8b1081c450bab83b77935df487ae1cdd4660ec7df6be8e74725c15fa45cf486ce057addc956ca4ae78300b97091e2a25061133d1b9a1440bc896ae + version: 15.7.11 + resolution: "@types/prop-types@npm:15.7.11" + checksum: 7519ff11d06fbf6b275029fe03fff9ec377b4cb6e864cac34d87d7146c7f5a7560fd164bdc1d2dbe00b60c43713631251af1fd3d34d46c69cd354602bc0c7c54 languageName: node linkType: hard "@types/ps-tree@npm:^1.1.2": - version: 1.1.2 - resolution: "@types/ps-tree@npm:1.1.2" - checksum: 575c3b2b83ea8935ab296ac9e17f6a2c1a5bb155f9e30663bb7a7c741a8ca4641f0df9748866230f1d6c3f87ed4ffa3fa91f1df444ef9979a3df31114534bf25 + version: 1.1.6 + resolution: "@types/ps-tree@npm:1.1.6" + checksum: bf5b7bb9bd11b8762a8302b93c335728ecb19c85a74c640a3888d476368a03733f11612b9a87b1ad9ea56f95720db23a824c78113b16024dc59264b7f9008df5 languageName: node linkType: hard "@types/qs@npm:*": - version: 6.9.8 - resolution: "@types/qs@npm:6.9.8" - checksum: c28e07d00d07970e5134c6eed184a0189b8a4649e28fdf36d9117fe671c067a44820890de6bdecef18217647a95e9c6aebdaaae69f5fe4b0bec9345db885f77e + version: 6.9.10 + resolution: "@types/qs@npm:6.9.10" + checksum: 3e479ee056bd2b60894baa119d12ecd33f20a25231b836af04654e784c886f28a356477630430152a86fba253da65d7ecd18acffbc2a8877a336e75aa0272c67 languageName: node linkType: hard "@types/range-parser@npm:*": - version: 1.2.4 - resolution: "@types/range-parser@npm:1.2.4" - checksum: b7c0dfd5080a989d6c8bb0b6750fc0933d9acabeb476da6fe71d8bdf1ab65e37c136169d84148034802f48378ab94e3c37bb4ef7656b2bec2cb9c0f8d4146a95 + version: 1.2.7 + resolution: "@types/range-parser@npm:1.2.7" + checksum: 95640233b689dfbd85b8c6ee268812a732cf36d5affead89e806fe30da9a430767af8ef2cd661024fd97e19d61f3dec75af2df5e80ec3bea000019ab7028629a languageName: node linkType: hard -"@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.6": - version: 5.0.8 - resolution: "@types/react-router-config@npm:5.0.8" +"@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.6, @types/react-router-config@npm:^5.0.7": + version: 5.0.11 + resolution: "@types/react-router-config@npm:5.0.11" dependencies: "@types/history": ^4.7.11 "@types/react": "*" "@types/react-router": ^5.1.0 - checksum: afbd96e526fcdd19a3c8604912496a5a7ecfdcd848632a003ef8af69701ca74f14451e4fac93d265b678ca07c82ec4a103126f64c040a4aefa1a8172619be2bd + checksum: 4b72d9b71e0576e193c11e5085bbdac43f31debfa3b6ebc24666f3d646ef25c1f57f16c29b1ddd3051c881e85f8e0d4ab5a7bbd5fc215b9377f57675b210be7c languageName: node linkType: hard @@ -4855,13 +5569,13 @@ __metadata: linkType: hard "@types/react@npm:*": - version: 18.2.28 - resolution: "@types/react@npm:18.2.28" + version: 18.2.43 + resolution: "@types/react@npm:18.2.43" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 81381bedeba83278f4c9febb0b83e0bd3f42a25897a50b9cb36ef53651d34b3d50f87ebf11211ea57ea575131f85d31e93e496ce46478a00b0f9bf7b26b5917a + checksum: e7e4da18c7b14e4b8b1ea630d1d8224835698f2bb2485766455bfb9dea93b8ee6cc549a9fe1cb10c984e62685db44fcfb61e8fac913b008cd30a92087f25b9df languageName: node linkType: hard @@ -4885,11 +5599,11 @@ __metadata: linkType: hard "@types/responselike@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/responselike@npm:1.0.1" + version: 1.0.3 + resolution: "@types/responselike@npm:1.0.3" dependencies: "@types/node": "*" - checksum: ae8c36c9354aaedfa462dab655aa17613529d545a418acc54ba0214145fc1d0454be2ae107031a1b2c24768f19f2af7e4096a85d1e604010becd0bec2355cb0e + checksum: 6ac4b35723429b11b117e813c7acc42c3af8b5554caaf1fc750404c1ae59f9b7376bc69b9e9e194a5a97357a597c2228b7173d317320f0360d617b6425212f58 languageName: node linkType: hard @@ -4901,91 +5615,87 @@ __metadata: linkType: hard "@types/sax@npm:^1.2.1": - version: 1.2.5 - resolution: "@types/sax@npm:1.2.5" + version: 1.2.7 + resolution: "@types/sax@npm:1.2.7" dependencies: "@types/node": "*" - checksum: a4bf27d7eb1b99030e75dea01fab2fa3959554f5c463b4f577dbbc9d8ed88a5b26b83ac84d045ae5a53e350057f120574db6e1c4e8507c011299dd023e4fa4f2 + checksum: 7ece5fbb5d9c8fc76ab0de2f99d705edf92f18e701d4f9d9b0647275e32eb65e656c1badf9dfaa12f4e1ff3e250561c8c9cfe79e8b5f33dd1417ac0f1804f6cc languageName: node linkType: hard "@types/scheduler@npm:*": - version: 0.16.4 - resolution: "@types/scheduler@npm:0.16.4" - checksum: a57b0f10da1b021e6bd5eeef8a1917dd3b08a8715bd8029e2ded2096d8f091bb1bb1fef2d66e139588a983c4bfbad29b59e48011141725fa83c76e986e1257d7 + version: 0.16.8 + resolution: "@types/scheduler@npm:0.16.8" + checksum: 6c091b096daa490093bf30dd7947cd28e5b2cd612ec93448432b33f724b162587fed9309a0acc104d97b69b1d49a0f3fc755a62282054d62975d53d7fd13472d languageName: node linkType: hard "@types/secp256k1@npm:^4.0.1": - version: 4.0.4 - resolution: "@types/secp256k1@npm:4.0.4" + version: 4.0.6 + resolution: "@types/secp256k1@npm:4.0.6" dependencies: "@types/node": "*" - checksum: 6f521a08486a98e71c8529f5c3119f99e610196a47243cc6052c6160b216dff2c85dc50a8f3208ed47028dbb470bbb6fdee47a3fdc064687e46021d5a712767c + checksum: 984494caf49a4ce99fda2b9ea1840eb47af946b8c2737314108949bcc0c06b4880e871296bd49ed6ea4c8423e3a302ad79fec43abfc987330e7eb98f0c4e8ba4 languageName: node linkType: hard "@types/semver@npm:^7.5.0": - version: 7.5.3 - resolution: "@types/semver@npm:7.5.3" - checksum: 349fdd1ab6c213bac5c991bac766bd07b8b12e63762462bb058740dcd2eb09c8193d068bb226f134661275f2022976214c0e727a4e5eb83ec1b131127c980d3e + version: 7.5.6 + resolution: "@types/semver@npm:7.5.6" + checksum: 563a0120ec0efcc326567db2ed920d5d98346f3638b6324ea6b50222b96f02a8add3c51a916b6897b51523aad8ac227d21d3dcf8913559f1bfc6c15b14d23037 languageName: node linkType: hard "@types/send@npm:*": - version: 0.17.1 - resolution: "@types/send@npm:0.17.1" + version: 0.17.4 + resolution: "@types/send@npm:0.17.4" dependencies: "@types/mime": ^1 "@types/node": "*" - checksum: 10b620a5960058ef009afbc17686f680d6486277c62f640845381ec4baa0ea683fdd77c3afea4803daf5fcddd3fb2972c8aa32e078939f1d4e96f83195c89793 + checksum: cf4db48251bbb03cd6452b4de6e8e09e2d75390a92fd798eca4a803df06444adc94ed050246c94c7ed46fb97be1f63607f0e1f13c3ce83d71788b3e08640e5e0 languageName: node linkType: hard "@types/serve-index@npm:^1.9.1": - version: 1.9.2 - resolution: "@types/serve-index@npm:1.9.2" + version: 1.9.4 + resolution: "@types/serve-index@npm:1.9.4" dependencies: "@types/express": "*" - checksum: 4fd0a8fcdd6e2b2d7704a539b7c1e0d143e9e00be4c3992394fe2ef7e9b67283d74b43db3f92b0e0717d779aa51184168bbae617d30456357cb95ec58aa59ea8 + checksum: 72727c88d54da5b13275ebfb75dcdc4aa12417bbe9da1939e017c4c5f0c906fae843aa4e0fbfe360e7ee9df2f3d388c21abfc488f77ce58693fb57809f8ded92 languageName: node linkType: hard -"@types/serve-static@npm:*": - version: 1.15.2 - resolution: "@types/serve-static@npm:1.15.2" +"@types/serve-static@npm:*, @types/serve-static@npm:^1.13.10": + version: 1.15.5 + resolution: "@types/serve-static@npm:1.15.5" dependencies: "@types/http-errors": "*" "@types/mime": "*" "@types/node": "*" - checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e + checksum: 0ff4b3703cf20ba89c9f9e345bc38417860a88e85863c8d6fe274a543220ab7f5f647d307c60a71bb57dc9559f0890a661e8dc771a6ec5ef195d91c8afc4a893 languageName: node linkType: hard -"@types/serve-static@npm:^1.13.10": - version: 1.15.3 - resolution: "@types/serve-static@npm:1.15.3" +"@types/sockjs@npm:^0.3.33": + version: 0.3.36 + resolution: "@types/sockjs@npm:0.3.36" dependencies: - "@types/http-errors": "*" - "@types/mime": "*" "@types/node": "*" - checksum: afa52252f0ba94cdb5391e80f23e17fd629bdf2a31be8876e2c4490312ed6b0570822dd7de7cea04c9002049e207709563568b7f4ee10bb9f456321db1e83e40 + checksum: b4b5381122465d80ea8b158537c00bc82317222d3fb31fd7229ff25b31fa89134abfbab969118da55622236bf3d8fee75759f3959908b5688991f492008f29bc languageName: node linkType: hard -"@types/sockjs@npm:^0.3.33": - version: 0.3.34 - resolution: "@types/sockjs@npm:0.3.34" - dependencies: - "@types/node": "*" - checksum: 1d38b1976a97f5895a6be00cead1b2a59d842f023b6e35450b7eec8a3131c860c447aba3f7ea3c880c066d8277b0c76fae9d080be1aad475811b568ed6079d49 +"@types/unist@npm:*, @types/unist@npm:^3.0.0": + version: 3.0.2 + resolution: "@types/unist@npm:3.0.2" + checksum: 3d04d0be69316e5f14599a0d993a208606c12818cf631fd399243d1dc7a9bd8a3917d6066baa6abc290814afbd744621484756803c80cba892c39cd4b4a85616 languageName: node linkType: hard "@types/unist@npm:^2, @types/unist@npm:^2.0.0, @types/unist@npm:^2.0.2, @types/unist@npm:^2.0.3": - version: 2.0.8 - resolution: "@types/unist@npm:2.0.8" - checksum: f4852d10a6752dc70df363917ef74453e5d2fd42824c0f6d09d19d530618e1402193977b1207366af4415aaec81d4e262c64d00345402020c4ca179216e553c7 + version: 2.0.10 + resolution: "@types/unist@npm:2.0.10" + checksum: e2924e18dedf45f68a5c6ccd6015cd62f1643b1b43baac1854efa21ae9e70505db94290434a23da1137d9e31eb58e54ca175982005698ac37300a1c889f6c4aa languageName: node linkType: hard @@ -5006,48 +5716,48 @@ __metadata: linkType: hard "@types/ws@npm:^8.5.5": - version: 8.5.7 - resolution: "@types/ws@npm:8.5.7" + version: 8.5.10 + resolution: "@types/ws@npm:8.5.10" dependencies: "@types/node": "*" - checksum: 4502085c0f7ae6b36d5419c0fc6ce4b9002ee5e997a8708d6ed10b393e97091e1b986e8038ec604945c194f14aac150e74d6596629a2775628d122f552009c35 + checksum: 3ec416ea2be24042ebd677932a462cf16d2080393d8d7d0b1b3f5d6eaa4a7387aaf0eefb99193c0bfd29444857cf2e0c3ac89899e130550dc6c14ada8a46d25e languageName: node linkType: hard "@types/yargs-parser@npm:*": - version: 21.0.1 - resolution: "@types/yargs-parser@npm:21.0.1" - checksum: 64e6316c2045e2d460c4fb79572f872f9d2f98fddc6d9d3949c71f0b6ad0ef8a2706cf49db26dfb02a9cb81433abb8f340f015e1d20a9692279abe9477b72c8e + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: ef236c27f9432983e91432d974243e6c4cdae227cb673740320eff32d04d853eed59c92ca6f1142a335cfdc0e17cccafa62e95886a8154ca8891cc2dec4ee6fc languageName: node linkType: hard "@types/yargs@npm:^17.0.8": - version: 17.0.28 - resolution: "@types/yargs@npm:17.0.28" + version: 17.0.32 + resolution: "@types/yargs@npm:17.0.32" dependencies: "@types/yargs-parser": "*" - checksum: f78c5e5c29903933c0557b4ffcd1d0b8564d66859c8ca4aa51da3714e49109ed7c2644334a1918d033df19028f4cecc91fd2e502651bb8e8451f246c371da847 + checksum: 4505bdebe8716ff383640c6e928f855b5d337cb3c68c81f7249fc6b983d0aa48de3eee26062b84f37e0d75a5797bc745e0c6e76f42f81771252a758c638f36ba languageName: node linkType: hard "@types/yauzl@npm:^2.9.1": - version: 2.10.0 - resolution: "@types/yauzl@npm:2.10.0" + version: 2.10.3 + resolution: "@types/yauzl@npm:2.10.3" dependencies: "@types/node": "*" - checksum: 55d27ae5d346ea260e40121675c24e112ef0247649073848e5d4e03182713ae4ec8142b98f61a1c6cbe7d3b72fa99bbadb65d8b01873e5e605cdc30f1ff70ef2 + checksum: 5ee966ea7bd6b2802f31ad4281c92c4c0b6dfa593c378a2582c58541fa113bec3d70eb0696b34ad95e8e6861a884cba6c3e351285816693ed176222f840a8c08 languageName: node linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/eslint-plugin@npm:6.7.3" + version: 6.13.2 + resolution: "@typescript-eslint/eslint-plugin@npm:6.13.2" dependencies: "@eslint-community/regexpp": ^4.5.1 - "@typescript-eslint/scope-manager": 6.7.3 - "@typescript-eslint/type-utils": 6.7.3 - "@typescript-eslint/utils": 6.7.3 - "@typescript-eslint/visitor-keys": 6.7.3 + "@typescript-eslint/scope-manager": 6.13.2 + "@typescript-eslint/type-utils": 6.13.2 + "@typescript-eslint/utils": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 debug: ^4.3.4 graphemer: ^1.4.0 ignore: ^5.2.4 @@ -5060,44 +5770,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ac2790882199047abc59c0407a862f3339645623d03ea0aae5a73fd4bac6abfb753afcf9f23fd51cd1d5aa73f132ef94e2850774c4b2a3d99ebb83030b09429c + checksum: e50cbbe7104eecef59faf3355ab981d9f353b19327f0b4607dfd829b4726f9e694b536fe43ab55f50bb00fbfdd2e4268a7e2a568b28d5fcd0d2a32a8d2466218 languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/parser@npm:6.7.3" + version: 6.13.2 + resolution: "@typescript-eslint/parser@npm:6.13.2" dependencies: - "@typescript-eslint/scope-manager": 6.7.3 - "@typescript-eslint/types": 6.7.3 - "@typescript-eslint/typescript-estree": 6.7.3 - "@typescript-eslint/visitor-keys": 6.7.3 + "@typescript-eslint/scope-manager": 6.13.2 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/typescript-estree": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 debug: ^4.3.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 658f3294b281db06ebb46884b92172d45eb402ec25c7d4a09cc2461eee359266029af7a49eb9006ee7c3e0003ba53a06f4bee84aa2e99d2d9a3507b9c84ff775 + checksum: aeafc414d295d7855384f10d57abb4f5f2ff35b57991b5c8854f43268761b3cc995e62af585dea1dc48295d762f466b565b5ae5699bfe642585d3f83ba8e1515 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/scope-manager@npm:6.7.3" +"@typescript-eslint/scope-manager@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/scope-manager@npm:6.13.2" dependencies: - "@typescript-eslint/types": 6.7.3 - "@typescript-eslint/visitor-keys": 6.7.3 - checksum: 08215444b7c70af5c45e185ba3c31c550a0a671ab464a67058cbee680c94aa9d1a062958976d8b09f7bcabf2f63114cdc7be2e4e32e2dfdcb2d7cc79961b7b32 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 + checksum: ff8fd64ddf324e296e2e0e34a8f73149c9a5f14d1761ea8e8665fc5998faa2b0bbbd1a5d416aa10d725f13c804032d532f68e39a0ca6cc36d1c9b9c0aea94311 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/type-utils@npm:6.7.3" +"@typescript-eslint/type-utils@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/type-utils@npm:6.13.2" dependencies: - "@typescript-eslint/typescript-estree": 6.7.3 - "@typescript-eslint/utils": 6.7.3 + "@typescript-eslint/typescript-estree": 6.13.2 + "@typescript-eslint/utils": 6.13.2 debug: ^4.3.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -5105,23 +5815,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: f30a5ab4f88f76457810d72e3ada79fefd94dbbb456069ac004bd7601c9b7f15689b906b66cd849c230f30ae65f6f7039fb169609177ab545b34bacab64f015e + checksum: ba54e5746139f778c35e4058e523ec8c20b68cf6472b3a7784170328e48c228f0761d2fc7e43dab053ca7d85ac4378b6965567774e6afedf551e600638404215 languageName: node linkType: hard -"@typescript-eslint/types@npm:6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/types@npm:6.7.3" - checksum: 4adb6177ec710e7438610fee553839a7abecc498dbb36d0170786bab66c5e5415cd720ac06419fd905458ad88c39b661603af5f013adc299137ccb4c51c4c879 +"@typescript-eslint/types@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/types@npm:6.13.2" + checksum: 4493ff06fa07c68c5adbcbd842f6dd6f5c88f14d160b53c3379b6b703e6f62808fab7fdebcc06ff06a56f20ab432b6ceeb0afb8931dc97d4061cb417e787f2c1 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/typescript-estree@npm:6.7.3" +"@typescript-eslint/typescript-estree@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/typescript-estree@npm:6.13.2" dependencies: - "@typescript-eslint/types": 6.7.3 - "@typescript-eslint/visitor-keys": 6.7.3 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/visitor-keys": 6.13.2 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -5130,34 +5840,41 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: eaba1feb0e6882b0bad292172c118aac43ba683d1f04b940b542a20035468d030b062b036ea49eca36aa21782e9b1019e87717003b3c3db7d12dc707466b7eb7 + checksum: 0c18ee5ef594a2411a788fe9d7bc6d51a03bce38d9d764bcb24ab557e5bc1942c2ddf9bd6fb4877eb102b0ae488974fb7b7fe72daa70a2054bf04d3cc6803546 languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/utils@npm:6.7.3" +"@typescript-eslint/utils@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/utils@npm:6.13.2" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/scope-manager": 6.7.3 - "@typescript-eslint/types": 6.7.3 - "@typescript-eslint/typescript-estree": 6.7.3 + "@typescript-eslint/scope-manager": 6.13.2 + "@typescript-eslint/types": 6.13.2 + "@typescript-eslint/typescript-estree": 6.13.2 semver: ^7.5.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 685b7c9fa95ad085f30e26431dc41b3059a42a16925defe2a94b32fb46974bfc168000de7d4d9ad4a1d0568a983f9d3c01ea6bc6cfa9a798e482719af9e9165b + checksum: b66bcf2a945e9c55f3dccb48af49565863d974837ee23b2f01ce7f3fb2462eb8a5871784d4a2fcc80dac7d5cd4ed90c8d01431cd177c0249de89a448f6663fc8 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.7.3": - version: 6.7.3 - resolution: "@typescript-eslint/visitor-keys@npm:6.7.3" +"@typescript-eslint/visitor-keys@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/visitor-keys@npm:6.13.2" dependencies: - "@typescript-eslint/types": 6.7.3 + "@typescript-eslint/types": 6.13.2 eslint-visitor-keys: ^3.4.1 - checksum: cef64173a919107f420703e204d97d0afef0d9bd7a67570df5bdb39ac9464211c5a7b3af735d8f41e8004b443ab83e88b1d6fb951886aed4d3fe9d4778667199 + checksum: 4b4def7acd7451e6a18dab3ee13f06504b3d23e51f195fced7c544f2203ee8a83426c82fa57ab6b58725c70fdedaf7a3eccb69793180be35756eed0f2c69fe04 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.0.0, @ungap/structured-clone@npm:^1.2.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 4f656b7b4672f2ce6e272f2427d8b0824ed11546a601d8d5412b9d7704e83db38a8d9f402ecdf2b9063fc164af842ad0ec4a55819f621ed7e7ea4d1efcc74524 languageName: node linkType: hard @@ -5170,12 +5887,12 @@ __metadata: languageName: node linkType: hard -"@web/browser-logs@npm:^0.3.2": - version: 0.3.3 - resolution: "@web/browser-logs@npm:0.3.3" +"@web/browser-logs@npm:^0.3.4": + version: 0.3.4 + resolution: "@web/browser-logs@npm:0.3.4" dependencies: errorstacks: ^2.2.0 - checksum: 08db1332f7151e8e0fb1ed61e6e10f736e44f5c9675423f3af0c24f3a764560ea115e956cf3a4d9cd7a0826c0126accf966ebdb0bfa25a72c7e79da47b2cee3b + checksum: fe212c91c26deada3458b6562a8d7d2ae98b7b51c7099e1cdb972e9f799c63f6cd170776b2eadbe43c47531cb6d9b06f48282113a5944f4394270a0076f8565e languageName: node linkType: hard @@ -5214,13 +5931,13 @@ __metadata: languageName: node linkType: hard -"@web/dev-server-core@npm:^0.5.1": - version: 0.5.2 - resolution: "@web/dev-server-core@npm:0.5.2" +"@web/dev-server-core@npm:^0.6.2": + version: 0.6.3 + resolution: "@web/dev-server-core@npm:0.6.3" dependencies: "@types/koa": ^2.11.6 "@types/ws": ^7.4.0 - "@web/parse5-utils": ^2.0.0 + "@web/parse5-utils": ^2.0.2 chokidar: ^3.4.3 clone: ^2.1.2 es-module-lexer: ^1.0.0 @@ -5236,7 +5953,7 @@ __metadata: parse5: ^6.0.1 picomatch: ^2.2.2 ws: ^7.4.2 - checksum: 1a42f71a3d7eafd41bdb33a8cf9d37bb7e205704f3bcde9e32bd0aa639759d7a6e4448efe448be127042c46816931dd7585575e0f30a15c1b22576d578ccaacc + checksum: 98ba42df5eb865828c223bd1de098d013efd8e89983efff28e26ecd9d08c8b35fd29b4c1256ed08b05ecb365abe1aa80d2854e1953bdebbbe230a7e2a597dd8f languageName: node linkType: hard @@ -5302,13 +6019,13 @@ __metadata: languageName: node linkType: hard -"@web/parse5-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "@web/parse5-utils@npm:2.0.1" +"@web/parse5-utils@npm:^2.0.2": + version: 2.1.0 + resolution: "@web/parse5-utils@npm:2.1.0" dependencies: "@types/parse5": ^6.0.1 parse5: ^6.0.1 - checksum: d3993b0dee350e040bf5b13749283df88c97a48b063f8938fb21623422cd5f03b641393ca03bc724936e9f17d8bfd7939f501de6eb1c33ad82f6ac5112bf6cff + checksum: 0faa93c51d61934e0006bebc2e257036f8cedeb455c7bf22b8fdbc17919929518c2cc99ced3769f8eb3b1d6694dd4a7186d66ad2b3c4330140fd2ce03dc6c4d2 languageName: node linkType: hard @@ -5368,9 +6085,9 @@ __metadata: languageName: node linkType: hard -"@web/test-runner-core@npm:^0.11.0": - version: 0.11.4 - resolution: "@web/test-runner-core@npm:0.11.4" +"@web/test-runner-core@npm:^0.12.0": + version: 0.12.0 + resolution: "@web/test-runner-core@npm:0.12.0" dependencies: "@babel/code-frame": ^7.12.11 "@types/babel__code-frame": ^7.0.2 @@ -5379,8 +6096,8 @@ __metadata: "@types/debounce": ^1.2.0 "@types/istanbul-lib-coverage": ^2.0.3 "@types/istanbul-reports": ^3.0.0 - "@web/browser-logs": ^0.3.2 - "@web/dev-server-core": ^0.5.1 + "@web/browser-logs": ^0.3.4 + "@web/dev-server-core": ^0.6.2 chokidar: ^3.4.3 cli-cursor: ^3.1.0 co-body: ^6.1.0 @@ -5398,7 +6115,7 @@ __metadata: open: ^8.0.2 picomatch: ^2.2.2 source-map: ^0.7.3 - checksum: 45aea23ae1b0d112e2d331c15e1e581b5d208c278e6ecab746cffba81d0d11a8fd7b3fb0da488dd3c3c01e49debf7f3e8261031c2b86a7c8716fb3cc3e1a172c + checksum: e71afa227f9dc2ea4ec67838b1bc4c8af2c61d3e6002b78e37724e3dc09be466e7f7aa5e6795d5431dca1a0b13b94765a880103f98c5497c97943c2f708327eb languageName: node linkType: hard @@ -5414,16 +6131,16 @@ __metadata: languageName: node linkType: hard -"@web/test-runner-coverage-v8@npm:^0.7.0": - version: 0.7.1 - resolution: "@web/test-runner-coverage-v8@npm:0.7.1" +"@web/test-runner-coverage-v8@npm:^0.7.3": + version: 0.7.3 + resolution: "@web/test-runner-coverage-v8@npm:0.7.3" dependencies: - "@web/test-runner-core": ^0.11.0 + "@web/test-runner-core": ^0.12.0 istanbul-lib-coverage: ^3.0.0 lru-cache: ^8.0.4 picomatch: ^2.2.2 v8-to-istanbul: ^9.0.1 - checksum: 317b11502b1378097598458a54054353fdb94d3bf9e0954daa9a3b1dcc1f0664032cd18f48292e763b890a132a980f5a5ead6555c33e9fb064d0ca960a884292 + checksum: 05d7a9a4df8ca30991307a8d69ac9388a6572a9c6585887a925e7bdb158a0430f213c81cb356b8dcb7bf9cd3423d0071030b481c29358562bd344da8ea814daa languageName: node linkType: hard @@ -5438,13 +6155,13 @@ __metadata: linkType: hard "@web/test-runner-playwright@npm:^0.10.0": - version: 0.10.1 - resolution: "@web/test-runner-playwright@npm:0.10.1" + version: 0.10.3 + resolution: "@web/test-runner-playwright@npm:0.10.3" dependencies: - "@web/test-runner-core": ^0.11.0 - "@web/test-runner-coverage-v8": ^0.7.0 + "@web/test-runner-core": ^0.12.0 + "@web/test-runner-coverage-v8": ^0.7.3 playwright: ^1.22.2 - checksum: d2aebc54c0444fb434671dc0d3a3912f76570eae4a909b7912cf46b9535232c7f7829729554e8629f546abce48433f9f5b21d583011582753fbb40e288c28e80 + checksum: 7c765d34482f2e299742c3ffe80790229d0825569016ccfccbb1a0c915f89551a3cc14a1454ed7c6895aaa03605ea444f7c1846eeab82bf02702e87a60628b3c languageName: node linkType: hard @@ -5640,10 +6357,17 @@ __metadata: languageName: node linkType: hard -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 +"@zeit/schemas@npm:2.29.0": + version: 2.29.0 + resolution: "@zeit/schemas@npm:2.29.0" + checksum: 3cea06bb67d790336aca0cc17580fd492ff3fc66ef4d180dce7053ff7ff54ab81b56bf718ba6f537148c581161d06306a481ec218d540bff922e0e009844ffd1 + languageName: node + linkType: hard + +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 0e994ad2aa6575f94670d8a2149afe94465de9cedaaaac364e7fb43a40c3691c980ff74899f682f4ca58fa96b4cbd7421a015d3a6defe43a442117d7821a2f36 languageName: node linkType: hard @@ -5681,7 +6405,7 @@ __metadata: languageName: node linkType: hard -"acorn-jsx@npm:^5.3.2": +"acorn-jsx@npm:^5.0.0, acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" peerDependencies: @@ -5690,19 +6414,19 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.2.0": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 +"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.1.1": + version: 8.3.1 + resolution: "acorn-walk@npm:8.3.1" + checksum: 5c8926ddb5400bc825b6baca782931f9df4ace603ba1a517f5243290fd9cdb089d52877840687b5d5c939591ebc314e2e63721514feaa37c6829c828f2b940ce languageName: node linkType: hard -"acorn@npm:^8.0.4, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" +"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": + version: 8.11.2 + resolution: "acorn@npm:8.11.2" bin: acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + checksum: 818450408684da89423e3daae24e4dc9b68692db8ab49ea4569c7c5abb7a3f23669438bf129cc81dfdada95e1c9b944ee1bfca2c57a05a4dc73834a612fbf6a7 languageName: node linkType: hard @@ -5734,7 +6458,7 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:6, agent-base@npm:^6.0.2": +"agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" dependencies: @@ -5743,12 +6467,12 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.2.1": - version: 4.5.0 - resolution: "agentkeepalive@npm:4.5.0" +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0": + version: 7.1.0 + resolution: "agent-base@npm:7.1.0" dependencies: - humanize-ms: ^1.2.1 - checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 + debug: ^4.3.4 + checksum: f7828f991470a0cc22cb579c86a18cbae83d8a3cbed39992ab34fc7217c4d126017f1c74d0ab66be87f71455318a8ea3e757d6a37881b8d0f2a2c6aa55e5418f languageName: node linkType: hard @@ -5762,16 +6486,6 @@ __metadata: languageName: node linkType: hard -"aggregate-error@npm:^4.0.0": - version: 4.0.1 - resolution: "aggregate-error@npm:4.0.1" - dependencies: - clean-stack: ^4.0.0 - indent-string: ^5.0.0 - checksum: bb3ffdfd13447800fff237c2cba752c59868ee669104bb995dfbbe0b8320e967d679e683dabb640feb32e4882d60258165cde0baafc4cd467cc7d275a13ad6b5 - languageName: node - linkType: hard - "ajv-formats@npm:^2.1.1": version: 2.1.1 resolution: "ajv-formats@npm:2.1.1" @@ -5806,6 +6520,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:8.11.0": + version: 8.11.0 + resolution: "ajv@npm:8.11.0" + dependencies: + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 5e0ff226806763be73e93dd7805b634f6f5921e3e90ca04acdf8db81eed9d8d3f0d4c5f1213047f45ebbf8047ffe0c840fa1ef2ec42c3a644899f69aa72b5bef + languageName: node + linkType: hard + "ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -5830,18 +6556,18 @@ __metadata: languageName: node linkType: hard -"algoliasearch-helper@npm:^3.10.0": - version: 3.14.2 - resolution: "algoliasearch-helper@npm:3.14.2" +"algoliasearch-helper@npm:^3.13.3": + version: 3.16.0 + resolution: "algoliasearch-helper@npm:3.16.0" dependencies: "@algolia/events": ^4.0.1 peerDependencies: algoliasearch: ">= 3.1 < 6" - checksum: d66444b25fe8ee64675bb660ff1980870751818cb4a29c57bda6ca410372f2bfa031a455dcd5981941736db89d8294187c5b3bc1ce2a2567c6e43657ccd208b8 + checksum: e024ad33c65d1eb7a31290bcf0bec37f2485154364e90ada45e07242ac35155313fe913fabd08cdb4d69e2794cc7d09dda03878566cea286cfac8fd4cc61f33f languageName: node linkType: hard -"algoliasearch@npm:^4.13.1, algoliasearch@npm:^4.19.1": +"algoliasearch@npm:^4.18.0, algoliasearch@npm:^4.19.1": version: 4.20.0 resolution: "algoliasearch@npm:4.20.0" dependencies: @@ -5943,7 +6669,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": +"ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 @@ -5960,20 +6686,17 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 +"arch@npm:^2.2.0": + version: 2.2.0 + resolution: "arch@npm:2.2.0" + checksum: e21b7635029fe8e9cdd5a026f9a6c659103e63fff423834323cdf836a1bb240a72d0c39ca8c470f84643385cf581bd8eda2cad8bf493e27e54bd9783abe9101f languageName: node linkType: hard -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 +"arg@npm:5.0.2, arg@npm:^5.0.0": + version: 5.0.2 + resolution: "arg@npm:5.0.2" + checksum: 6c69ada1a9943d332d9e5382393e897c500908d91d5cb735a01120d5f71daf1b339b7b8980cbeaba8fd1afc68e658a739746179e4315a26e8a28951ff9930078 languageName: node linkType: hard @@ -5984,13 +6707,6 @@ __metadata: languageName: node linkType: hard -"arg@npm:^5.0.0": - version: 5.0.2 - resolution: "arg@npm:5.0.2" - checksum: 6c69ada1a9943d332d9e5382393e897c500908d91d5cb735a01120d5f71daf1b339b7b8980cbeaba8fd1afc68e658a739746179e4315a26e8a28951ff9930078 - languageName: node - linkType: hard - "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -6028,13 +6744,6 @@ __metadata: languageName: node linkType: hard -"array-find-index@npm:^1.0.1": - version: 1.0.2 - resolution: "array-find-index@npm:1.0.2" - checksum: aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081 - languageName: node - linkType: hard - "array-flatten@npm:1.1.1": version: 1.1.1 resolution: "array-flatten@npm:1.1.1" @@ -6056,27 +6765,6 @@ __metadata: languageName: node linkType: hard -"arrgv@npm:^1.0.2": - version: 1.0.2 - resolution: "arrgv@npm:1.0.2" - checksum: 470bbb406ea3b34810dd8b03c0b33282617a42d9fce0ab45d58596efefd042fc548eda49161fa8e3f607cbe9df90e7a67003a09043ab9081eff70f97c63dd0e2 - languageName: node - linkType: hard - -"arrify@npm:^3.0.0": - version: 3.0.0 - resolution: "arrify@npm:3.0.0" - checksum: d6c6f3dad9571234f320e130d57fddb2cc283c87f2ac7df6c7005dffc5161b7bb9376f4be655ed257050330336e84afc4f3020d77696ad231ff580a94ae5aba6 - languageName: node - linkType: hard - -"asap@npm:~2.0.3": - version: 2.0.6 - resolution: "asap@npm:2.0.6" - checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d - languageName: node - linkType: hard - "assertion-error@npm:^1.1.0": version: 1.1.0 resolution: "assertion-error@npm:1.1.0" @@ -6091,6 +6779,15 @@ __metadata: languageName: node linkType: hard +"astring@npm:^1.8.0": + version: 1.8.6 + resolution: "astring@npm:1.8.6" + bin: + astring: bin/astring + checksum: 6f034d2acef1dac8bb231e7cc26c573d3c14e1975ea6e04f20312b43d4f462f963209bc64187d25d477a182dc3c33277959a0156ab7a3617aa79b1eac4d88e1f + languageName: node + linkType: hard + "async@npm:^2.6.4": version: 2.6.4 resolution: "async@npm:2.6.4" @@ -6114,7 +6811,7 @@ __metadata: languageName: node linkType: hard -"autoprefixer@npm:^10.4.12, autoprefixer@npm:^10.4.7": +"autoprefixer@npm:^10.4.12, autoprefixer@npm:^10.4.14, autoprefixer@npm:^10.4.7": version: 10.4.16 resolution: "autoprefixer@npm:10.4.16" dependencies: @@ -6132,67 +6829,9 @@ __metadata: languageName: node linkType: hard -"ava@npm:^5.2.0": - version: 5.3.1 - resolution: "ava@npm:5.3.1" - dependencies: - acorn: ^8.8.2 - acorn-walk: ^8.2.0 - ansi-styles: ^6.2.1 - arrgv: ^1.0.2 - arrify: ^3.0.0 - callsites: ^4.0.0 - cbor: ^8.1.0 - chalk: ^5.2.0 - chokidar: ^3.5.3 - chunkd: ^2.0.1 - ci-info: ^3.8.0 - ci-parallel-vars: ^1.0.1 - clean-yaml-object: ^0.1.0 - cli-truncate: ^3.1.0 - code-excerpt: ^4.0.0 - common-path-prefix: ^3.0.0 - concordance: ^5.0.4 - currently-unhandled: ^0.4.1 - debug: ^4.3.4 - emittery: ^1.0.1 - figures: ^5.0.0 - globby: ^13.1.4 - ignore-by-default: ^2.1.0 - indent-string: ^5.0.0 - is-error: ^2.2.2 - is-plain-object: ^5.0.0 - is-promise: ^4.0.0 - matcher: ^5.0.0 - mem: ^9.0.2 - ms: ^2.1.3 - p-event: ^5.0.1 - p-map: ^5.5.0 - picomatch: ^2.3.1 - pkg-conf: ^4.0.0 - plur: ^5.1.0 - pretty-ms: ^8.0.0 - resolve-cwd: ^3.0.0 - stack-utils: ^2.0.6 - strip-ansi: ^7.0.1 - supertap: ^3.0.1 - temp-dir: ^3.0.0 - write-file-atomic: ^5.0.1 - yargs: ^17.7.2 - peerDependencies: - "@ava/typescript": "*" - peerDependenciesMeta: - "@ava/typescript": - optional: true - bin: - ava: entrypoints/cli.mjs - checksum: 126a5932baef74eccd8bec992bd522e25c05b6ee4985dde87c20cece76c2377f0bf9448f242f3f9cd2abbf7a5ac932fe4e4abde2a23792d6271a6088e5a1984e - languageName: node - linkType: hard - -"axios@npm:^0.25.0": - version: 0.25.0 - resolution: "axios@npm:0.25.0" +"axios@npm:^0.25.0": + version: 0.25.0 + resolution: "axios@npm:0.25.0" dependencies: follow-redirects: ^1.14.7 checksum: 2a8a3787c05f2a0c9c3878f49782357e2a9f38945b93018fb0c4fd788171c43dceefbb577988628e09fea53952744d1ecebde234b561f1e703aa43e0a598a3ad @@ -6200,13 +6839,13 @@ __metadata: linkType: hard "axios@npm:^1.4.0": - version: 1.5.1 - resolution: "axios@npm:1.5.1" + version: 1.6.2 + resolution: "axios@npm:1.6.2" dependencies: follow-redirects: ^1.15.0 form-data: ^4.0.0 proxy-from-env: ^1.1.0 - checksum: 4444f06601f4ede154183767863d2b8e472b4a6bfc5253597ed6d21899887e1fd0ee2b3de792ac4f8459fe2e359d2aa07c216e45fd8b9e4e0688a6ebf48a5a8d + checksum: 4a7429e2b784be0f2902ca2680964391eae7236faa3967715f30ea45464b98ae3f1c6f631303b13dfe721b17126b01f486c7644b9ef276bfc63112db9fd379f8 languageName: node linkType: hard @@ -6225,6 +6864,19 @@ __metadata: languageName: node linkType: hard +"babel-loader@npm:^9.1.3": + version: 9.1.3 + resolution: "babel-loader@npm:9.1.3" + dependencies: + find-cache-dir: ^4.0.0 + schema-utils: ^4.0.0 + peerDependencies: + "@babel/core": ^7.12.0 + webpack: ">=5" + checksum: b168dde5b8cf11206513371a79f86bb3faa7c714e6ec9fffd420876b61f3d7f5f4b976431095ef6a14bc4d324505126deb91045fd41e312ba49f4deaa166fe28 + languageName: node + linkType: hard + "babel-plugin-apply-mdx-type-prop@npm:1.6.22": version: 1.6.22 resolution: "babel-plugin-apply-mdx-type-prop@npm:1.6.22" @@ -6269,14 +6921,14 @@ __metadata: linkType: hard "babel-plugin-polyfill-corejs3@npm:^0.8.5": - version: 0.8.5 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.5" + version: 0.8.6 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.6" dependencies: "@babel/helper-define-polyfill-provider": ^0.4.3 - core-js-compat: ^3.32.2 + core-js-compat: ^3.33.1 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 54ff3956c4f88e483d38b27ceec6199b9e73fceac10ebf969469d215e6a62929384e4433f85335c9a6ba809329636e27f9bdae2f54075f833e7a745341c07d84 + checksum: 36951c2edac42ac0f05b200502e90d77bf66ccee5b52e2937d23496c6ef2372cce31b8c64144da374b77bd3eb65e2721703a52eac56cad16a152326c092cbf77 languageName: node linkType: hard @@ -6298,6 +6950,13 @@ __metadata: languageName: node linkType: hard +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: aab4e8ccdc8d762bf3fdfce8e706601695620c0c2eda256dd85088dc0be3cfd7ff126f6e99c2bee1f24f5d418414aacf09d7f9702f16d6963df2fa488cda8824 + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -6314,13 +6973,6 @@ __metadata: languageName: node linkType: hard -"base16@npm:^1.0.0": - version: 1.0.0 - resolution: "base16@npm:1.0.0" - checksum: 0cd449a2db0f0f957e4b6b57e33bc43c9e20d4f1dd744065db94b5da35e8e71fa4dc4bc7a901e59a84d5f8b6936e3c520e2471787f667fc155fb0f50d8540f5d - languageName: node - linkType: hard - "base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -6343,9 +6995,9 @@ __metadata: linkType: hard "big-integer@npm:^1.6.44": - version: 1.6.51 - resolution: "big-integer@npm:1.6.51" - checksum: 3d444173d1b2e20747e2c175568bedeebd8315b0637ea95d75fd27830d3b8e8ba36c6af40374f36bdaea7b5de376dcada1b07587cb2a79a928fccdb6e6e3c518 + version: 1.6.52 + resolution: "big-integer@npm:1.6.52" + checksum: 6e86885787a20fed96521958ae9086960e4e4b5e74d04f3ef7513d4d0ad631a9f3bde2730fc8aaa4b00419fc865f6ec573e5320234531ef37505da7da192c40b languageName: node linkType: hard @@ -6388,13 +7040,6 @@ __metadata: languageName: node linkType: hard -"blueimp-md5@npm:^2.10.0": - version: 2.19.0 - resolution: "blueimp-md5@npm:2.19.0" - checksum: 28095dcbd2c67152a2938006e8d7c74c3406ba6556071298f872505432feb2c13241b0476644160ee0a5220383ba94cb8ccdac0053b51f68d168728f9c382530 - languageName: node - linkType: hard - "bn.js@npm:^4.11.0, bn.js@npm:^4.11.8, bn.js@npm:^4.11.9": version: 4.12.0 resolution: "bn.js@npm:4.12.0" @@ -6448,6 +7093,22 @@ __metadata: languageName: node linkType: hard +"boxen@npm:7.0.0": + version: 7.0.0 + resolution: "boxen@npm:7.0.0" + dependencies: + ansi-align: ^3.0.1 + camelcase: ^7.0.0 + chalk: ^5.0.1 + cli-boxes: ^3.0.0 + string-width: ^5.1.2 + type-fest: ^2.13.0 + widest-line: ^4.0.1 + wrap-ansi: ^8.0.1 + checksum: b917cf7a168ef3149635a8c02d5c9717d66182348bd27038d85328ad12655151e3324db0f2815253846c33e5f0ddf28b6cd52d56a12b9f88617b7f8f722b946a + languageName: node + linkType: hard + "boxen@npm:^5.0.0": version: 5.1.2 resolution: "boxen@npm:5.1.2" @@ -6480,6 +7141,22 @@ __metadata: languageName: node linkType: hard +"boxen@npm:^7.0.0": + version: 7.1.1 + resolution: "boxen@npm:7.1.1" + dependencies: + ansi-align: ^3.0.1 + camelcase: ^7.0.1 + chalk: ^5.2.0 + cli-boxes: ^3.0.0 + string-width: ^5.1.2 + type-fest: ^2.13.0 + widest-line: ^4.0.1 + wrap-ansi: ^8.1.0 + checksum: ad8833d5f2845b0a728fdf8a0bc1505dff0c518edcb0fd56979a08774b1f26cf48b71e66532179ccdfb9ed95b64aa008689cca26f7776f93f002b8000a683d76 + languageName: node + linkType: hard + "bplist-parser@npm:^0.2.0": version: 0.2.0 resolution: "bplist-parser@npm:0.2.0" @@ -6557,17 +7234,17 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9, browserslist@npm:^4.22.1": - version: 4.22.1 - resolution: "browserslist@npm:4.22.1" +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9, browserslist@npm:^4.22.2": + version: 4.22.2 + resolution: "browserslist@npm:4.22.2" dependencies: - caniuse-lite: ^1.0.30001541 - electron-to-chromium: ^1.4.535 - node-releases: ^2.0.13 + caniuse-lite: ^1.0.30001565 + electron-to-chromium: ^1.4.601 + node-releases: ^2.0.14 update-browserslist-db: ^1.0.13 bin: browserslist: cli.js - checksum: 7e6b10c53f7dd5d83fd2b95b00518889096382539fed6403829d447e05df4744088de46a571071afb447046abc3c66ad06fbc790e70234ec2517452e32ffd862 + checksum: 33ddfcd9145220099a7a1ac533cecfe5b7548ffeb29b313e1b57be6459000a1f8fa67e781cf4abee97268ac594d44134fcc4a6b2b4750ceddc9796e3a22076d9 languageName: node linkType: hard @@ -6662,23 +7339,23 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^17.0.0": - version: 17.1.4 - resolution: "cacache@npm:17.1.4" +"cacache@npm:^18.0.0": + version: 18.0.1 + resolution: "cacache@npm:18.0.1" dependencies: "@npmcli/fs": ^3.1.0 fs-minipass: ^3.0.0 glob: ^10.2.2 - lru-cache: ^7.7.1 + lru-cache: ^10.0.1 minipass: ^7.0.3 - minipass-collect: ^1.0.2 + minipass-collect: ^2.0.1 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 p-map: ^4.0.0 ssri: ^10.0.0 tar: ^6.1.11 unique-filename: ^3.0.0 - checksum: b7751df756656954a51201335addced8f63fc53266fa56392c9f5ae83c8d27debffb4458ac2d168a744a4517ec3f2163af05c20097f93d17bdc2dc8a385e14a6 + checksum: 5a0b3b2ea451a0379814dc1d3c81af48c7c6db15cd8f7d72e028501ae0036a599a99bbac9687bfec307afb2760808d1c7708e9477c8c70d2b166e7d80b162a23 languageName: node linkType: hard @@ -6692,6 +7369,28 @@ __metadata: languageName: node linkType: hard +"cacheable-lookup@npm:^7.0.0": + version: 7.0.0 + resolution: "cacheable-lookup@npm:7.0.0" + checksum: 9e2856763fc0a7347ab34d704c010440b819d4bb5e3593b664381b7433e942dd22e67ee5581f12256f908e79b82d30b86ebbacf40a081bfe10ee93fbfbc2d6a9 + languageName: node + linkType: hard + +"cacheable-request@npm:^10.2.8": + version: 10.2.14 + resolution: "cacheable-request@npm:10.2.14" + dependencies: + "@types/http-cache-semantics": ^4.0.2 + get-stream: ^6.0.1 + http-cache-semantics: ^4.1.1 + keyv: ^4.5.3 + mimic-response: ^4.0.0 + normalize-url: ^8.0.0 + responselike: ^3.0.0 + checksum: 56f2b8e1c497c91f8391f0b099d19907a7dde25e71087e622b23e45fc8061736c2a6964ef121b16f377c3c61079cf8dc17320ab54004209d1343e4d26aba7015 + languageName: node + linkType: hard + "cacheable-request@npm:^6.0.0": version: 6.1.0 resolution: "cacheable-request@npm:6.1.0" @@ -6707,13 +7406,14 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.5": + version: 1.0.5 + resolution: "call-bind@npm:1.0.5" dependencies: - function-bind: ^1.1.1 - get-intrinsic: ^1.0.2 - checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 + function-bind: ^1.1.2 + get-intrinsic: ^1.2.1 + set-function-length: ^1.1.1 + checksum: 449e83ecbd4ba48e7eaac5af26fea3b50f8f6072202c2dd7c5a6e7a6308f2421abe5e13a3bbd55221087f76320c5e09f25a8fdad1bab2b77c68ae74d92234ea5 languageName: node linkType: hard @@ -6724,13 +7424,6 @@ __metadata: languageName: node linkType: hard -"callsites@npm:^4.0.0": - version: 4.1.0 - resolution: "callsites@npm:4.1.0" - checksum: 4ad31de7b7615fa25bdab9c2373865209d2d5190f895cdf2e2f518bd1dafa7ebcda2e6e9cc9640f2dfde6b3893d82fa4359a78ffc27baad2503227553c6882fa - languageName: node - linkType: hard - "camel-case@npm:^4.1.2": version: 4.1.2 resolution: "camel-case@npm:4.1.2" @@ -6755,6 +7448,13 @@ __metadata: languageName: node linkType: hard +"camelcase@npm:^7.0.0, camelcase@npm:^7.0.1": + version: 7.0.1 + resolution: "camelcase@npm:7.0.1" + checksum: 86ab8f3ebf08bcdbe605a211a242f00ed30d8bfb77dab4ebb744dd36efbc84432d1c4adb28975ba87a1b8be40a80fbd1e60e2f06565315918fa7350011a26d3d + languageName: node + linkType: hard + "caniuse-api@npm:^3.0.0": version: 3.0.0 resolution: "caniuse-api@npm:3.0.0" @@ -6767,10 +7467,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001541": - version: 1.0.30001549 - resolution: "caniuse-lite@npm:1.0.30001549" - checksum: 7f2abeedc8cf8b92cc0613855d71b995ce436068c0bcdd798c5af7d297ccf9f52496b00181beda42d82d25079dd4b6e389c67486156d40d8854e5707a25cb054 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": + version: 1.0.30001568 + resolution: "caniuse-lite@npm:1.0.30001568" + checksum: 7092aaa246dc8531fbca5b47be91e92065db7e5c04cc9e3d864e848f8f1be769ac6754429e843a5e939f7331a771e8b0a1bc3b13495c66b748c65e2f5bdb1220 languageName: node linkType: hard @@ -6788,15 +7488,6 @@ __metadata: languageName: node linkType: hard -"cbor@npm:^8.1.0": - version: 8.1.0 - resolution: "cbor@npm:8.1.0" - dependencies: - nofilter: ^3.1.0 - checksum: a90338435dc7b45cc01461af979e3bb6ddd4f2a08584c437586039cd5f2235014c06e49d664295debbfb3514d87b2f06728092ab6aa6175e2e85e9cd7dc0c1fd - languageName: node - linkType: hard - "ccount@npm:^1.0.0": version: 1.1.0 resolution: "ccount@npm:1.1.0" @@ -6804,6 +7495,13 @@ __metadata: languageName: node linkType: hard +"ccount@npm:^2.0.0": + version: 2.0.1 + resolution: "ccount@npm:2.0.1" + checksum: 48193dada54c9e260e0acf57fc16171a225305548f9ad20d5471e0f7a8c026aedd8747091dccb0d900cde7df4e4ddbd235df0d8de4a64c71b12f0d3303eeafd4 + languageName: node + linkType: hard + "chai-as-promised@npm:^7.1.1": version: 7.1.1 resolution: "chai-as-promised@npm:7.1.1" @@ -6816,21 +7514,21 @@ __metadata: linkType: hard "chai@npm:^4.3.7, chai@npm:^4.3.8": - version: 4.3.8 - resolution: "chai@npm:4.3.8" + version: 4.3.10 + resolution: "chai@npm:4.3.10" dependencies: assertion-error: ^1.1.0 - check-error: ^1.0.2 - deep-eql: ^4.1.2 - get-func-name: ^2.0.0 - loupe: ^2.3.1 + check-error: ^1.0.3 + deep-eql: ^4.1.3 + get-func-name: ^2.0.2 + loupe: ^2.3.6 pathval: ^1.1.1 - type-detect: ^4.0.5 - checksum: 29e0984ed13308319cadc35437c8ef0a3e271544d226c991bf7e3b6d771bf89707321669e11d05e362bc0ad0bd26585079b989d1032f3c106e3bb95d7f079cce + type-detect: ^4.0.8 + checksum: 536668c60a0d985a0fbd94418028e388d243a925d7c5e858c7443e334753511614a3b6a124bac9ca077dfc4c37acc367d62f8c294960f440749536dc181dfc6d languageName: node linkType: hard -"chalk-template@npm:^0.4.0": +"chalk-template@npm:0.4.0, chalk-template@npm:^0.4.0": version: 0.4.0 resolution: "chalk-template@npm:0.4.0" dependencies: @@ -6839,6 +7537,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:5.0.1": + version: 5.0.1 + resolution: "chalk@npm:5.0.1" + checksum: 7b45300372b908f0471fbf7389ce2f5de8d85bb949026fd51a1b95b10d0ed32c7ed5aab36dd5e9d2bf3191867909b4404cef75c5f4d2d1daeeacd301dd280b76 + languageName: node + linkType: hard + "chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -6867,6 +7572,20 @@ __metadata: languageName: node linkType: hard +"char-regex@npm:^1.0.2": + version: 1.0.2 + resolution: "char-regex@npm:1.0.2" + checksum: b563e4b6039b15213114626621e7a3d12f31008bdce20f9c741d69987f62aeaace7ec30f6018890ad77b2e9b4d95324c9f5acfca58a9441e3b1dcdd1e2525d17 + languageName: node + linkType: hard + +"character-entities-html4@npm:^2.0.0": + version: 2.1.0 + resolution: "character-entities-html4@npm:2.1.0" + checksum: 7034aa7c7fa90309667f6dd50499c8a760c3d3a6fb159adb4e0bada0107d194551cdbad0714302f62d06ce4ed68565c8c2e15fdef2e8f8764eb63fa92b34b11d + languageName: node + linkType: hard + "character-entities-legacy@npm:^1.0.0": version: 1.1.4 resolution: "character-entities-legacy@npm:1.1.4" @@ -6874,6 +7593,13 @@ __metadata: languageName: node linkType: hard +"character-entities-legacy@npm:^3.0.0": + version: 3.0.0 + resolution: "character-entities-legacy@npm:3.0.0" + checksum: 7582af055cb488b626d364b7d7a4e46b06abd526fb63c0e4eb35bcb9c9799cc4f76b39f34fdccef2d1174ac95e53e9ab355aae83227c1a2505877893fce77731 + languageName: node + linkType: hard + "character-entities@npm:^1.0.0": version: 1.2.4 resolution: "character-entities@npm:1.2.4" @@ -6881,6 +7607,13 @@ __metadata: languageName: node linkType: hard +"character-entities@npm:^2.0.0": + version: 2.0.2 + resolution: "character-entities@npm:2.0.2" + checksum: cf1643814023697f725e47328fcec17923b8f1799102a8a79c1514e894815651794a2bffd84bb1b3a4b124b050154e4529ed6e81f7c8068a734aecf07a6d3def + languageName: node + linkType: hard + "character-reference-invalid@npm:^1.0.0": version: 1.1.4 resolution: "character-reference-invalid@npm:1.1.4" @@ -6888,10 +7621,19 @@ __metadata: languageName: node linkType: hard -"check-error@npm:^1.0.2": - version: 1.0.2 - resolution: "check-error@npm:1.0.2" - checksum: d9d106504404b8addd1ee3f63f8c0eaa7cd962a1a28eb9c519b1c4a1dc7098be38007fc0060f045ee00f075fbb7a2a4f42abcf61d68323677e11ab98dc16042e +"character-reference-invalid@npm:^2.0.0": + version: 2.0.1 + resolution: "character-reference-invalid@npm:2.0.1" + checksum: 98d3b1a52ae510b7329e6ee7f6210df14f1e318c5415975d4c9e7ee0ef4c07875d47c6e74230c64551f12f556b4a8ccc24d9f3691a2aa197019e72a95e9297ee + languageName: node + linkType: hard + +"check-error@npm:^1.0.2, check-error@npm:^1.0.3": + version: 1.0.3 + resolution: "check-error@npm:1.0.3" + dependencies: + get-func-name: ^2.0.2 + checksum: e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399 languageName: node linkType: hard @@ -6989,13 +7731,6 @@ __metadata: languageName: node linkType: hard -"chunkd@npm:^2.0.1": - version: 2.0.1 - resolution: "chunkd@npm:2.0.1" - checksum: bab8cc08c752a3648984385dc6f61d751e89dbeef648d22a3b661e1d470eaa0f5182f0b4303710f13ae83d2f85144f8eb2dde7a975861d9021b5c56b881f457b - languageName: node - linkType: hard - "ci-info@npm:^2.0.0": version: 2.0.0 resolution: "ci-info@npm:2.0.0" @@ -7010,20 +7745,6 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.8.0": - version: 3.8.0 - resolution: "ci-info@npm:3.8.0" - checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 - languageName: node - linkType: hard - -"ci-parallel-vars@npm:^1.0.1": - version: 1.0.1 - resolution: "ci-parallel-vars@npm:1.0.1" - checksum: ae859831f7e8e3585db731b8306c336616e37bd709dad1d7775ea4c0731aefd94741dabb48201edc6827d000008fd7fb72cb977967614ee2d99d6b499f0c35fe - languageName: node - linkType: hard - "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": version: 1.0.4 resolution: "cipher-base@npm:1.0.4" @@ -7048,12 +7769,12 @@ __metadata: languageName: node linkType: hard -"clean-css@npm:^5.2.2, clean-css@npm:^5.3.0": - version: 5.3.2 - resolution: "clean-css@npm:5.3.2" +"clean-css@npm:^5.2.2, clean-css@npm:^5.3.0, clean-css@npm:^5.3.2, clean-css@npm:~5.3.2": + version: 5.3.3 + resolution: "clean-css@npm:5.3.3" dependencies: source-map: ~0.6.0 - checksum: 8787b281acc9878f309b5f835d410085deedfd4e126472666773040a6a8a72f472a1d24185947d23b87b1c419bf2c5ed429395d5c5ff8279c98b05d8011e9758 + checksum: 941987c14860dd7d346d5cf121a82fd2caf8344160b1565c5387f7ccca4bbcaf885bace961be37c4f4713ce2d8c488dd89483c1add47bb779790edbfdcc79cbc languageName: node linkType: hard @@ -7064,22 +7785,6 @@ __metadata: languageName: node linkType: hard -"clean-stack@npm:^4.0.0": - version: 4.2.0 - resolution: "clean-stack@npm:4.2.0" - dependencies: - escape-string-regexp: 5.0.0 - checksum: 373f656a31face5c615c0839213b9b542a0a48057abfb1df66900eab4dc2a5c6097628e4a0b5aa559cdfc4e66f8a14ea47be9681773165a44470ef5fb8ccc172 - languageName: node - linkType: hard - -"clean-yaml-object@npm:^0.1.0": - version: 0.1.0 - resolution: "clean-yaml-object@npm:0.1.0" - checksum: 0374ad2f1fbd4984ecf56ebc62200092f6372b9ccf1b7971bb979c328fb12fe76e759fb1e8adc491c80b7b1861f9f00c7f19813dd2a0f49c88231422c70451f4 - languageName: node - linkType: hard - "cli-boxes@npm:^2.2.1": version: 2.2.1 resolution: "cli-boxes@npm:2.2.1" @@ -7103,7 +7808,7 @@ __metadata: languageName: node linkType: hard -"cli-table3@npm:^0.6.2": +"cli-table3@npm:^0.6.2, cli-table3@npm:^0.6.3": version: 0.6.3 resolution: "cli-table3@npm:0.6.3" dependencies: @@ -7116,13 +7821,14 @@ __metadata: languageName: node linkType: hard -"cli-truncate@npm:^3.1.0": - version: 3.1.0 - resolution: "cli-truncate@npm:3.1.0" +"clipboardy@npm:3.0.0": + version: 3.0.0 + resolution: "clipboardy@npm:3.0.0" dependencies: - slice-ansi: ^5.0.0 - string-width: ^5.0.0 - checksum: c3243e41974445691c63f8b405df1d5a24049dc33d324fe448dc572e561a7b772ae982692900b1a5960901cc4fc7def25a629b9c69a4208ee89d12ab3332617a + arch: ^2.2.0 + execa: ^5.1.1 + is-wsl: ^2.2.0 + checksum: 2c292acb59705494cbe07d7df7c8becff4f01651514d32ebd80f4aec2d20946d8f3824aac67ecdf2d09ef21fdf0eb24b6a7f033c137ccdceedc4661c54455c94 languageName: node linkType: hard @@ -7182,6 +7888,13 @@ __metadata: languageName: node linkType: hard +"clsx@npm:^2.0.0": + version: 2.0.0 + resolution: "clsx@npm:2.0.0" + checksum: a2cfb2351b254611acf92faa0daf15220f4cd648bdf96ce369d729813b85336993871a4bf6978ddea2b81b5a130478339c20d9d0b5c6fc287e5147f0c059276e + languageName: node + linkType: hard + "co-body@npm:^6.1.0": version: 6.1.0 resolution: "co-body@npm:6.1.0" @@ -7201,15 +7914,6 @@ __metadata: languageName: node linkType: hard -"code-excerpt@npm:^4.0.0": - version: 4.0.0 - resolution: "code-excerpt@npm:4.0.0" - dependencies: - convert-to-spaces: ^2.0.1 - checksum: d57137d8f4825879283a828cc02a1115b56858dc54ed06c625c8f67d6685d1becd2fbaa7f0ab19ecca1f5cca03f8c97bbc1f013cab40261e4d3275032e65efe9 - languageName: node - linkType: hard - "collapse-white-space@npm:^1.0.2": version: 1.0.6 resolution: "collapse-white-space@npm:1.0.6" @@ -7217,6 +7921,13 @@ __metadata: languageName: node linkType: hard +"collapse-white-space@npm:^2.0.0": + version: 2.1.0 + resolution: "collapse-white-space@npm:2.1.0" + checksum: c8978b1f4e7d68bf846cfdba6c6689ce8910511df7d331eb6e6757e51ceffb52768d59a28db26186c91dcf9594955b59be9f8ccd473c485790f5d8b90dc6726f + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -7249,15 +7960,6 @@ __metadata: languageName: node linkType: hard -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b - languageName: node - linkType: hard - "colord@npm:^2.9.1": version: 2.9.3 resolution: "colord@npm:2.9.3" @@ -7302,6 +8004,13 @@ __metadata: languageName: node linkType: hard +"comma-separated-tokens@npm:^2.0.0": + version: 2.0.3 + resolution: "comma-separated-tokens@npm:2.0.3" + checksum: e3bf9e0332a5c45f49b90e79bcdb4a7a85f28d6a6f0876a94f1bb9b2bfbdbbb9292aac50e1e742d8c0db1e62a0229a106f57917e2d067fca951d81737651700d + languageName: node + linkType: hard + "command-exists@npm:^1.2.8": version: 1.2.9 resolution: "command-exists@npm:1.2.9" @@ -7352,7 +8061,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^10.0.1": +"commander@npm:^10.0.0, commander@npm:^10.0.1": version: 10.0.1 resolution: "commander@npm:10.0.1" checksum: 436901d64a818295803c1996cd856621a74f30b9f9e28a588e726b2b1670665bccd7c1a77007ebf328729f0139838a88a19265858a0fa7a8728c4656796db948 @@ -7380,7 +8089,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^8.0.0, commander@npm:^8.3.0": +"commander@npm:^8.3.0": version: 8.3.0 resolution: "commander@npm:8.3.0" checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0 @@ -7410,7 +8119,7 @@ __metadata: languageName: node linkType: hard -"compression@npm:^1.7.4": +"compression@npm:1.7.4, compression@npm:^1.7.4": version: 1.7.4 resolution: "compression@npm:1.7.4" dependencies: @@ -7432,19 +8141,13 @@ __metadata: languageName: node linkType: hard -"concordance@npm:^5.0.4": - version: 5.0.4 - resolution: "concordance@npm:5.0.4" +"config-chain@npm:^1.1.11": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" dependencies: - date-time: ^3.1.0 - esutils: ^2.0.3 - fast-diff: ^1.2.0 - js-string-escape: ^1.0.1 - lodash: ^4.17.15 - md5-hex: ^3.0.1 - semver: ^7.3.2 - well-known-symbols: ^2.0.0 - checksum: 749153ba711492feb7c3d2f5bb04c107157440b3e39509bd5dd19ee7b3ac751d1e4cd75796d9f702e0a713312dbc661421c68aa4a2c34d5f6d91f47e3a1c64a6 + ini: ^1.3.4 + proto-list: ~1.2.1 + checksum: 828137a28e7c2fc4b7fb229bd0cd6c1397bcf83434de54347e608154008f411749041ee392cbe42fab6307e02de4c12480260bf769b7d44b778fdea3839eafab languageName: node linkType: hard @@ -7462,6 +8165,19 @@ __metadata: languageName: node linkType: hard +"configstore@npm:^6.0.0": + version: 6.0.0 + resolution: "configstore@npm:6.0.0" + dependencies: + dot-prop: ^6.0.1 + graceful-fs: ^4.2.6 + unique-string: ^3.0.0 + write-file-atomic: ^3.0.3 + xdg-basedir: ^5.0.1 + checksum: 81995351c10bc04c58507f17748477aeac6f47465109d20e3534cebc881d22e927cfd29e73dd852c46c55f62c2b7be4cd1fe6eb3a93ba51f7f9813c218f9bae0 + languageName: node + linkType: hard + "connect-history-api-fallback@npm:^2.0.0": version: 2.0.0 resolution: "connect-history-api-fallback@npm:2.0.0" @@ -7476,13 +8192,6 @@ __metadata: languageName: node linkType: hard -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed - languageName: node - linkType: hard - "content-disposition@npm:0.5.2": version: 0.5.2 resolution: "content-disposition@npm:0.5.2" @@ -7506,7 +8215,7 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": +"convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 @@ -7520,13 +8229,6 @@ __metadata: languageName: node linkType: hard -"convert-to-spaces@npm:^2.0.1": - version: 2.0.1 - resolution: "convert-to-spaces@npm:2.0.1" - checksum: bbb324e5916fe9866f65c0ff5f9c1ea933764d0bdb09fccaf59542e40545ed483db6b2339c6d9eb56a11965a58f1a6038f3174f0e2fb7601343c7107ca5e2751 - languageName: node - linkType: hard - "cookie-signature@npm:1.0.6": version: 1.0.6 resolution: "cookie-signature@npm:1.0.6" @@ -7558,7 +8260,7 @@ __metadata: languageName: node linkType: hard -"copy-text-to-clipboard@npm:^3.0.1": +"copy-text-to-clipboard@npm:^3.2.0": version: 3.2.0 resolution: "copy-text-to-clipboard@npm:3.2.0" checksum: df7115c197a166d51f59e4e20ab2a68a855ae8746d25ff149b5465c694d9a405c7e6684b73a9f87ba8d653070164e229c15dfdb9fd77c30be1ff0da569661060 @@ -7581,26 +8283,26 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.32.2": - version: 3.33.0 - resolution: "core-js-compat@npm:3.33.0" +"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.33.1": + version: 3.34.0 + resolution: "core-js-compat@npm:3.34.0" dependencies: - browserslist: ^4.22.1 - checksum: 83ae54008c09b8e0ae3c59457039866c342c7e28b0d30eebb638a5b51c01432e63fe97695c90645cbc6a8b073a4f9a8b0e75f0818bbf8b4b054e01f4c17d3181 + browserslist: ^4.22.2 + checksum: 6281f7f57a72f254c06611ec088445e11cf84e0b4edfb5f43dece1a1ff8b0ed0e81ed0bc291024761cd90c39d0f007d8bc46548265139808081d311c7cbc9c81 languageName: node linkType: hard "core-js-pure@npm:^3.30.2": - version: 3.33.0 - resolution: "core-js-pure@npm:3.33.0" - checksum: d47084a4de9a0cef9779eccd3ac9f435cf9fd7aa71794150cd4c6b305036bcc392d94766d4a7b6456bdd08faba7752d55c2ec40185bda161c3563081c9fa1e17 + version: 3.34.0 + resolution: "core-js-pure@npm:3.34.0" + checksum: 4c44ac4beff42e07f41eef3c9ecefc8ee3f9e91e1b9f278bf8520cc1fb37afb663cff77c182541dc42d58737f93ab0f30a33a5fe661fb161fdd8aa7fe78a5edf languageName: node linkType: hard -"core-js@npm:^3.23.3": - version: 3.33.0 - resolution: "core-js@npm:3.33.0" - checksum: dd62217935ac281faf6f833bb306fb891162919fcf9c1f0c975b1b91e82ac09a940f5deb5950bbb582739ceef716e8bd7e4f9eab8328932fb029d3bc2ecb2881 +"core-js@npm:^3.23.3, core-js@npm:^3.31.1": + version: 3.34.0 + resolution: "core-js@npm:3.34.0" + checksum: 26b0d103716b33fc660ee8737da7bc9475fbc655f93bbf1360ab692966449d18f2fc393805095937283db9f919ca2aa5c88d86d16f2846217983ad7da707e31e languageName: node linkType: hard @@ -7706,15 +8408,6 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:^3.1.5": - version: 3.1.8 - resolution: "cross-fetch@npm:3.1.8" - dependencies: - node-fetch: ^2.6.12 - checksum: 78f993fa099eaaa041122ab037fe9503ecbbcb9daef234d1d2e0b9230a983f64d645d088c464e21a247b825a08dc444a6e7064adfa93536d3a9454b4745b3632 - languageName: node - linkType: hard - "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -7733,6 +8426,15 @@ __metadata: languageName: node linkType: hard +"crypto-random-string@npm:^4.0.0": + version: 4.0.0 + resolution: "crypto-random-string@npm:4.0.0" + dependencies: + type-fest: ^1.0.1 + checksum: 91f148f27bcc8582798f0fb3e75a09d9174557f39c3c40a89dd1bd70fb5a14a02548245aa26fa7d663c426ac5026f4729841231c84f9e30e8c8ece5e38656741 + languageName: node + linkType: hard + "css-declaration-sorter@npm:^6.3.1": version: 6.4.1 resolution: "css-declaration-sorter@npm:6.4.1" @@ -7742,7 +8444,7 @@ __metadata: languageName: node linkType: hard -"css-loader@npm:^6.7.1": +"css-loader@npm:^6.7.1, css-loader@npm:^6.8.1": version: 6.8.1 resolution: "css-loader@npm:6.8.1" dependencies: @@ -7760,7 +8462,7 @@ __metadata: languageName: node linkType: hard -"css-minimizer-webpack-plugin@npm:^4.0.0": +"css-minimizer-webpack-plugin@npm:^4.0.0, css-minimizer-webpack-plugin@npm:^4.2.2": version: 4.2.2 resolution: "css-minimizer-webpack-plugin@npm:4.2.2" dependencies: @@ -7841,7 +8543,7 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-advanced@npm:^5.3.8": +"cssnano-preset-advanced@npm:^5.3.10, cssnano-preset-advanced@npm:^5.3.8": version: 5.3.10 resolution: "cssnano-preset-advanced@npm:5.3.10" dependencies: @@ -7905,7 +8607,7 @@ __metadata: languageName: node linkType: hard -"cssnano@npm:^5.1.12, cssnano@npm:^5.1.8": +"cssnano@npm:^5.1.12, cssnano@npm:^5.1.15, cssnano@npm:^5.1.8": version: 5.1.15 resolution: "cssnano@npm:5.1.15" dependencies: @@ -7928,18 +8630,9 @@ __metadata: linkType: hard "csstype@npm:^3.0.2": - version: 3.1.2 - resolution: "csstype@npm:3.1.2" - checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5 - languageName: node - linkType: hard - -"currently-unhandled@npm:^0.4.1": - version: 0.4.1 - resolution: "currently-unhandled@npm:0.4.1" - dependencies: - array-find-index: ^1.0.1 - checksum: 1f59fe10b5339b54b1a1eee110022f663f3495cf7cf2f480686e89edc7fa8bfe42dbab4b54f85034bc8b092a76cc7becbc2dad4f9adad332ab5831bec39ad540 + version: 3.1.3 + resolution: "csstype@npm:3.1.3" + checksum: 8db785cc92d259102725b3c694ec0c823f5619a84741b5c7991b8ad135dfaa66093038a1cc63e03361a6cd28d122be48f2106ae72334e067dd619a51f49eddf7 languageName: node linkType: hard @@ -7950,16 +8643,7 @@ __metadata: languageName: node linkType: hard -"date-time@npm:^3.1.0": - version: 3.1.0 - resolution: "date-time@npm:3.1.0" - dependencies: - time-zone: ^1.0.0 - checksum: f9cfcd1b15dfeabab15c0b9d18eb9e4e2d9d4371713564178d46a8f91ad577a290b5178b80050718d02d9c0cf646f8a875011e12d1ed05871e9f72c72c8a8fe6 - languageName: node - linkType: hard - -"debounce@npm:^1.2.0": +"debounce@npm:^1.2.0, debounce@npm:^1.2.1": version: 1.2.1 resolution: "debounce@npm:1.2.1" checksum: 682a89506d9e54fb109526f4da255c5546102fbb8e3ae75eef3b04effaf5d4853756aee97475cd4650641869794e44f410eeb20ace2b18ea592287ab2038519e @@ -7975,7 +8659,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.2.0, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.2.0, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -8003,6 +8687,15 @@ __metadata: languageName: node linkType: hard +"decode-named-character-reference@npm:^1.0.0": + version: 1.0.2 + resolution: "decode-named-character-reference@npm:1.0.2" + dependencies: + character-entities: ^2.0.0 + checksum: f4c71d3b93105f20076052f9cb1523a22a9c796b8296cd35eef1ca54239c78d182c136a848b83ff8da2071e3ae2b1d300bf29d00650a6d6e675438cc31b11d78 + languageName: node + linkType: hard + "decompress-response@npm:^3.3.0": version: 3.3.0 resolution: "decompress-response@npm:3.3.0" @@ -8012,7 +8705,16 @@ __metadata: languageName: node linkType: hard -"deep-eql@npm:^4.0.1, deep-eql@npm:^4.1.2": +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: ^3.1.0 + checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 + languageName: node + linkType: hard + +"deep-eql@npm:^4.0.1, deep-eql@npm:^4.1.3": version: 4.1.3 resolution: "deep-eql@npm:4.1.3" dependencies: @@ -8087,7 +8789,14 @@ __metadata: languageName: node linkType: hard -"define-data-property@npm:^1.0.1": +"defer-to-connect@npm:^2.0.1": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b + languageName: node + linkType: hard + +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.1": version: 1.1.1 resolution: "define-data-property@npm:1.1.1" dependencies: @@ -8112,7 +8821,7 @@ __metadata: languageName: node linkType: hard -"define-properties@npm:^1.1.4": +"define-properties@npm:^1.2.1": version: 1.2.1 resolution: "define-properties@npm:1.2.1" dependencies: @@ -8217,7 +8926,7 @@ __metadata: languageName: node linkType: hard -"detect-port@npm:^1.3.0": +"detect-port@npm:^1.3.0, detect-port@npm:^1.5.1": version: 1.5.1 resolution: "detect-port@npm:1.5.1" dependencies: @@ -8230,6 +8939,15 @@ __metadata: languageName: node linkType: hard +"devlop@npm:^1.0.0, devlop@npm:^1.1.0": + version: 1.1.0 + resolution: "devlop@npm:1.1.0" + dependencies: + dequal: ^2.0.0 + checksum: d2ff650bac0bb6ef08c48f3ba98640bb5fec5cce81e9957eb620408d1bab1204d382a45b785c6b3314dc867bb0684936b84c6867820da6db97cbb5d3c15dd185 + languageName: node + linkType: hard + "devtools-protocol@npm:0.0.1107588": version: 0.0.1107588 resolution: "devtools-protocol@npm:0.0.1107588" @@ -8287,27 +9005,37 @@ __metadata: version: 0.0.0-use.local resolution: "docs@workspace:docs" dependencies: - "@docusaurus/core": ^2.4.0 - "@docusaurus/module-type-aliases": ^2.4.0 - "@docusaurus/plugin-google-gtag": ^2.4.0 - "@docusaurus/preset-classic": ^2.4.0 + "@docusaurus/core": ^3.0.1 + "@docusaurus/module-type-aliases": ^3.0.1 + "@docusaurus/preset-classic": ^3.0.1 + "@docusaurus/tsconfig": ^3.0.1 + "@docusaurus/types": ^3.0.1 "@easyops-cn/docusaurus-search-local": ^0.35.0 - "@mdx-js/react": ^1.6.22 + "@mdx-js/react": ^3.0.0 "@noir-lang/noir_js": "workspace:*" + "@noir-lang/noirc_abi": "workspace:*" + "@noir-lang/types": "workspace:*" + "@signorecello/noir_playground": ^0.6.0 + "@types/prettier": ^3 axios: ^1.4.0 clsx: ^1.2.1 docusaurus-plugin-typedoc: 1.0.0-next.18 + eslint-plugin-prettier: ^5.0.0 hast-util-is-element: ^1.1.0 - prism-react-renderer: ^1.3.5 - react: ^17.0.2 - react-dom: ^17.0.2 - rehype-katex: ^5.0.0 - remark-math: ^3.0.1 + prettier: 3.0.3 + prism-react-renderer: ^2.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + react-spinners: ^0.13.8 + rehype-katex: ^7.0.0 + remark-math: ^6.0.0 + serve: ^14.2.1 + ts-node: ^10.9.1 typedoc: ^0.25.0 typedoc-plugin-frontmatter: ^0.0.2 typedoc-plugin-markdown: 4.0.0-next.25 typedoc-plugin-merge-modules: ^5.1.0 - typescript: ^5.2.2 + typescript: ~5.2.2 languageName: unknown linkType: soft @@ -8428,6 +9156,15 @@ __metadata: languageName: node linkType: hard +"dot-prop@npm:^6.0.1": + version: 6.0.1 + resolution: "dot-prop@npm:6.0.1" + dependencies: + is-obj: ^2.0.0 + checksum: 0f47600a4b93e1dc37261da4e6909652c008832a5d3684b5bf9a9a0d3f4c67ea949a86dceed9b72f5733ed8e8e6383cc5958df3bbd0799ee317fd181f2ece700 + languageName: node + linkType: hard + "duplexer3@npm:^0.1.4": version: 0.1.5 resolution: "duplexer3@npm:0.1.5" @@ -8456,10 +9193,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.535": - version: 1.4.554 - resolution: "electron-to-chromium@npm:1.4.554" - checksum: cbac43c50b43777327f4a7bf149ee3088c1da8b91bbcd80f78d2cc77bc52763f6d0941574499239d9caefd3430d3093f865e5f1093371418f7d6b70301eeae9b +"electron-to-chromium@npm:^1.4.601": + version: 1.4.609 + resolution: "electron-to-chromium@npm:1.4.609" + checksum: 4ef3c32b11adc01ed8227d7bdbe0978b436b817e6b3bd09f19b42afbf9affdb6ddf99f4d20a3b28a494772a2985df12ec95abca849a38cccb217c4ee338561bb languageName: node linkType: hard @@ -8478,13 +9215,6 @@ __metadata: languageName: node linkType: hard -"emittery@npm:^1.0.1": - version: 1.0.1 - resolution: "emittery@npm:1.0.1" - checksum: d95faee6ffb2e023cadaa6804265fea5298c53d079f170112af8dfae3e141761363ea4510966128259346418e3ec7639310fd75059ecce2423bf8afd07004226 - languageName: node - linkType: hard - "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -8499,6 +9229,13 @@ __metadata: languageName: node linkType: hard +"emojilib@npm:^2.4.0": + version: 2.4.0 + resolution: "emojilib@npm:2.4.0" + checksum: ea241c342abda5a86ffd3a15d8f4871a616d485f700e03daea38c6ce38205847cea9f6ff8d5e962c00516b004949cc96c6e37b05559ea71a0a496faba53b56da + languageName: node + linkType: hard + "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" @@ -8513,6 +9250,13 @@ __metadata: languageName: node linkType: hard +"emoticon@npm:^4.0.1": + version: 4.0.1 + resolution: "emoticon@npm:4.0.1" + checksum: 991ab6421927601af4eb44036b60e3125759a4d81f32d2ad96b66e3491e2fdb6a026eeb6bffbfa66724592dca95235570785963607d16961ea73a62ecce715e2 + languageName: node + linkType: hard + "encodeurl@npm:^1.0.2, encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" @@ -8596,16 +9340,16 @@ __metadata: linkType: hard "errorstacks@npm:^2.2.0": - version: 2.4.0 - resolution: "errorstacks@npm:2.4.0" - checksum: 59186ccd26d8b782682a17aa8c96a71c5b977e7e073ec1648a5b59d11acb02348000921751c28a1a8a5bea37481369b2dab27e6330c5b8ddf3ae9b610dfc02bf + version: 2.4.1 + resolution: "errorstacks@npm:2.4.1" + checksum: 1b46bdd3c40d3e30dbb6945c0529ffbef6ccdf2260eeecff6cc1ee95b708ec732094597d6adaa53ffe18d045150b366e3f7472d8594946f430941bfa4ad54479 languageName: node linkType: hard "es-module-lexer@npm:^1.0.0, es-module-lexer@npm:^1.2.1": - version: 1.3.1 - resolution: "es-module-lexer@npm:1.3.1" - checksum: 3beafa7e171eb1e8cc45695edf8d51638488dddf65294d7911f8d6a96249da6a9838c87529262cc6ea53988d8272cec0f4bff93f476ed031a54ba3afb51a0ed3 + version: 1.4.1 + resolution: "es-module-lexer@npm:1.4.1" + checksum: a11b5a256d4e8e9c7d94c2fd87415ccd1591617b6edd847e064503f8eaece2d25e2e9078a02c5ce3ed5e83bb748f5b4820efbe78072c8beb07ac619c2edec35d languageName: node linkType: hard @@ -8686,20 +9430,104 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 - languageName: node - linkType: hard - -"escape-goat@npm:^2.0.0": - version: 2.1.1 +"esbuild@npm:~0.18.20": + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" + dependencies: + "@esbuild/android-arm": 0.18.20 + "@esbuild/android-arm64": 0.18.20 + "@esbuild/android-x64": 0.18.20 + "@esbuild/darwin-arm64": 0.18.20 + "@esbuild/darwin-x64": 0.18.20 + "@esbuild/freebsd-arm64": 0.18.20 + "@esbuild/freebsd-x64": 0.18.20 + "@esbuild/linux-arm": 0.18.20 + "@esbuild/linux-arm64": 0.18.20 + "@esbuild/linux-ia32": 0.18.20 + "@esbuild/linux-loong64": 0.18.20 + "@esbuild/linux-mips64el": 0.18.20 + "@esbuild/linux-ppc64": 0.18.20 + "@esbuild/linux-riscv64": 0.18.20 + "@esbuild/linux-s390x": 0.18.20 + "@esbuild/linux-x64": 0.18.20 + "@esbuild/netbsd-x64": 0.18.20 + "@esbuild/openbsd-x64": 0.18.20 + "@esbuild/sunos-x64": 0.18.20 + "@esbuild/win32-arm64": 0.18.20 + "@esbuild/win32-ia32": 0.18.20 + "@esbuild/win32-x64": 0.18.20 + dependenciesMeta: + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b + languageName: node + linkType: hard + +"escalade@npm:^3.1.1": + version: 3.1.1 + resolution: "escalade@npm:3.1.1" + checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 + languageName: node + linkType: hard + +"escape-goat@npm:^2.0.0": + version: 2.1.1 resolution: "escape-goat@npm:2.1.1" checksum: ce05c70c20dd7007b60d2d644b625da5412325fdb57acf671ba06cb2ab3cd6789e2087026921a05b665b0a03fadee2955e7fc0b9a67da15a6551a980b260eba7 languageName: node linkType: hard +"escape-goat@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-goat@npm:4.0.0" + checksum: 7034e0025eec7b751074b837f10312c5b768493265bdad046347c0aadbc1e652776f7e5df94766473fecb5d3681169cc188fe9ccc1e22be53318c18be1671cc0 + languageName: node + linkType: hard + "escape-html@npm:^1.0.3, escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" @@ -8714,13 +9542,6 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:5.0.0, escape-string-regexp@npm:^5.0.0": - version: 5.0.0 - resolution: "escape-string-regexp@npm:5.0.0" - checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e - languageName: node - linkType: hard - "escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" @@ -8728,16 +9549,16 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^2.0.0": - version: 2.0.0 - resolution: "escape-string-regexp@npm:2.0.0" - checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e languageName: node linkType: hard "eslint-plugin-prettier@npm:^5.0.0": - version: 5.0.0 - resolution: "eslint-plugin-prettier@npm:5.0.0" + version: 5.0.1 + resolution: "eslint-plugin-prettier@npm:5.0.1" dependencies: prettier-linter-helpers: ^1.0.0 synckit: ^0.8.5 @@ -8750,7 +9571,7 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 84e88744b9050f2d5ef31b94e85294dda16f3a53c2449f9d33eac8ae6264889b459bf35a68e438fb6b329c2a1d6491aac4bfa00d86317e7009de3dad0311bec6 + checksum: c2261033b97bafe99ccb7cc47c2fac6fa85b8bbc8b128042e52631f906b69e12afed2cdd9d7e3021cc892ee8dd4204a3574e1f32a0b718b4bb3b440944b6983b languageName: node linkType: hard @@ -8782,16 +9603,17 @@ __metadata: linkType: hard "eslint@npm:^8.50.0": - version: 8.50.0 - resolution: "eslint@npm:8.50.0" + version: 8.55.0 + resolution: "eslint@npm:8.55.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.6.1 - "@eslint/eslintrc": ^2.1.2 - "@eslint/js": 8.50.0 - "@humanwhocodes/config-array": ^0.11.11 + "@eslint/eslintrc": ^2.1.4 + "@eslint/js": 8.55.0 + "@humanwhocodes/config-array": ^0.11.13 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 + "@ungap/structured-clone": ^1.2.0 ajv: ^6.12.4 chalk: ^4.0.0 cross-spawn: ^7.0.2 @@ -8824,7 +9646,7 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 9ebfe5615dc84700000d218e32ddfdcfc227ca600f65f18e5541ec34f8902a00356a9a8804d9468fd6c8637a5ef6a3897291dad91ba6579d5b32ffeae5e31768 + checksum: 83f82a604559dc1faae79d28fdf3dfc9e592ca221052e2ea516e1b379b37e77e4597705a16880e2f5ece4f79087c1dd13fd7f6e9746f794a401175519db18b41 languageName: node linkType: hard @@ -8881,6 +9703,65 @@ __metadata: languageName: node linkType: hard +"estree-util-attach-comments@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-attach-comments@npm:3.0.0" + dependencies: + "@types/estree": ^1.0.0 + checksum: 56254eaef39659e6351919ebc2ae53a37a09290a14571c19e373e9d5fad343a3403d9ad0c23ae465d6e7d08c3e572fd56fb8c793efe6434a261bf1489932dbd5 + languageName: node + linkType: hard + +"estree-util-build-jsx@npm:^3.0.0": + version: 3.0.1 + resolution: "estree-util-build-jsx@npm:3.0.1" + dependencies: + "@types/estree-jsx": ^1.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + estree-walker: ^3.0.0 + checksum: 185eff060eda2ba32cecd15904db4f5ba0681159fbdf54f0f6586cd9411e77e733861a833d0aee3415e1d1fd4b17edf08bc9e9872cee98e6ec7b0800e1a85064 + languageName: node + linkType: hard + +"estree-util-is-identifier-name@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-is-identifier-name@npm:3.0.0" + checksum: ea3909f0188ea164af0aadeca87c087e3e5da78d76da5ae9c7954ff1340ea3e4679c4653bbf4299ffb70caa9b322218cc1128db2541f3d2976eb9704f9857787 + languageName: node + linkType: hard + +"estree-util-to-js@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-to-js@npm:2.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + astring: ^1.8.0 + source-map: ^0.7.0 + checksum: 833edc94ab9978e0918f90261e0a3361bf4564fec4901f326d2237a9235d3f5fc6482da3be5acc545e702c8c7cb8bc5de5c7c71ba3b080eb1975bcfdf3923d79 + languageName: node + linkType: hard + +"estree-util-value-to-estree@npm:^3.0.1": + version: 3.0.1 + resolution: "estree-util-value-to-estree@npm:3.0.1" + dependencies: + "@types/estree": ^1.0.0 + is-plain-obj: ^4.0.0 + checksum: 7ab89084aa2c5677aeb0d7350ff21e71c9bbc424dc872a55bb4f25f63a7fd99fc7861626dd89b5544db3d3696212154bcf2b12b63ecd5a59dbfd07915c88aee4 + languageName: node + linkType: hard + +"estree-util-visit@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-visit@npm:2.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + "@types/unist": ^3.0.0 + checksum: 6444b38f224322945a6d19ea81a8828a0eec64aefb2bf1ea791fe20df496f7b7c543408d637df899e6a8e318b638f66226f16378a33c4c2b192ba5c3f891121f + languageName: node + linkType: hard + "estree-walker@npm:^1.0.1": version: 1.0.1 resolution: "estree-walker@npm:1.0.1" @@ -8888,14 +9769,23 @@ __metadata: languageName: node linkType: hard -"esutils@npm:^2.0.2, esutils@npm:^2.0.3": +"estree-walker@npm:^3.0.0": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": ^1.0.0 + checksum: a65728d5727b71de172c5df323385755a16c0fdab8234dc756c3854cfee343261ddfbb72a809a5660fac8c75d960bb3e21aa898c2d7e9b19bb298482ca58a3af + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 languageName: node linkType: hard -"eta@npm:^2.0.0": +"eta@npm:^2.0.0, eta@npm:^2.2.0": version: 2.2.0 resolution: "eta@npm:2.2.0" checksum: 6a09631481d4f26a9662a1eb736a65cc1cbc48e24935e6ff5d83a83b0cb509ea56d588d66d7c087d590601dc59bdabdac2356936b1b789d020eb0cf2d8304d54 @@ -9008,17 +9898,17 @@ __metadata: linkType: hard "ethers@npm:^6.7.1": - version: 6.7.1 - resolution: "ethers@npm:6.7.1" + version: 6.9.0 + resolution: "ethers@npm:6.9.0" dependencies: - "@adraffy/ens-normalize": 1.9.2 - "@noble/hashes": 1.1.2 - "@noble/secp256k1": 1.7.1 + "@adraffy/ens-normalize": 1.10.0 + "@noble/curves": 1.2.0 + "@noble/hashes": 1.3.2 "@types/node": 18.15.13 aes-js: 4.0.0-beta.5 tslib: 2.4.0 ws: 8.5.0 - checksum: 07833692e3f53b18e28c4cba9f53f3d5ebff8360de02ad57b2584c00c52b88f5b790373f9b9f6b4f6b52ffa2074530a6101192b30c3260f7cdeff929d34bb88b + checksum: e7b3b912b92b818fe65a192b32f4dd87ce0b71f4ffc194b4b3764b4b17d3b6ed953b667293e4c9276f785fa8c8659934c513843350317c61178af8e6165afbdd languageName: node linkType: hard @@ -9082,7 +9972,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": +"execa@npm:^5.0.0, execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -9202,7 +10092,7 @@ __metadata: languageName: node linkType: hard -"fast-diff@npm:^1.1.2, fast-diff@npm:^1.2.0": +"fast-diff@npm:^1.1.2": version: 1.3.0 resolution: "fast-diff@npm:1.3.0" checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3 @@ -9210,15 +10100,15 @@ __metadata: linkType: hard "fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": - version: 3.3.1 - resolution: "fast-glob@npm:3.3.1" + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" dependencies: "@nodelib/fs.stat": ^2.0.2 "@nodelib/fs.walk": ^1.2.3 glob-parent: ^5.1.2 merge2: ^1.3.0 micromatch: ^4.0.4 - checksum: b6f3add6403e02cf3a798bfbb1183d0f6da2afd368f27456010c0bc1f9640aea308243d4cb2c0ab142f618276e65ecb8be1661d7c62a7b4e5ba774b9ce5432e5 + checksum: 900e4979f4dbc3313840078419245621259f349950411ca2fa445a2f9a1a6d98c3b5e7e0660c5ccd563aa61abe133a21765c6c0dec8e57da1ba71d8000b05ec1 languageName: node linkType: hard @@ -9236,6 +10126,13 @@ __metadata: languageName: node linkType: hard +"fast-plist@npm:^0.1.2": + version: 0.1.3 + resolution: "fast-plist@npm:0.1.3" + checksum: e879f548db3a1fc89c654c476e9c9846f4335fdcd2283ec99e5f234c897f5616cee2a0a4201bf4b64ab6269e75c09daafc3933bd4a038c85af943fac0f113caa + languageName: node + linkType: hard + "fast-url-parser@npm:1.1.3": version: 1.1.3 resolution: "fast-url-parser@npm:1.1.3" @@ -9254,6 +10151,15 @@ __metadata: languageName: node linkType: hard +"fault@npm:^2.0.0": + version: 2.0.1 + resolution: "fault@npm:2.0.1" + dependencies: + format: ^0.2.0 + checksum: c9b30f47d95769177130a9409976a899ed31eb598450fbad5b0d39f2f5f56d5f4a9ff9257e0bee8407cb0fc3ce37165657888c6aa6d78472e403893104329b72 + languageName: node + linkType: hard + "faye-websocket@npm:^0.11.3": version: 0.11.4 resolution: "faye-websocket@npm:0.11.4" @@ -9263,37 +10169,6 @@ __metadata: languageName: node linkType: hard -"fbemitter@npm:^3.0.0": - version: 3.0.0 - resolution: "fbemitter@npm:3.0.0" - dependencies: - fbjs: ^3.0.0 - checksum: 069690b8cdff3521ade3c9beb92ba0a38d818a86ef36dff8690e66749aef58809db4ac0d6938eb1cacea2dbef5f2a508952d455669590264cdc146bbe839f605 - languageName: node - linkType: hard - -"fbjs-css-vars@npm:^1.0.0": - version: 1.0.2 - resolution: "fbjs-css-vars@npm:1.0.2" - checksum: 72baf6d22c45b75109118b4daecb6c8016d4c83c8c0f23f683f22e9d7c21f32fff6201d288df46eb561e3c7d4bb4489b8ad140b7f56444c453ba407e8bd28511 - languageName: node - linkType: hard - -"fbjs@npm:^3.0.0, fbjs@npm:^3.0.1": - version: 3.0.5 - resolution: "fbjs@npm:3.0.5" - dependencies: - cross-fetch: ^3.1.5 - fbjs-css-vars: ^1.0.0 - loose-envify: ^1.0.0 - object-assign: ^4.1.0 - promise: ^7.1.1 - setimmediate: ^1.0.5 - ua-parser-js: ^1.0.35 - checksum: e609b5b64686bc96495a5c67728ed9b2710b9b3d695c5759c5f5e47c9483d1c323543ac777a86459e3694efc5712c6ce7212e944feb19752867d699568bb0e54 - languageName: node - linkType: hard - "fd-slicer@npm:~1.1.0": version: 1.1.0 resolution: "fd-slicer@npm:1.1.0" @@ -9322,23 +10197,13 @@ __metadata: languageName: node linkType: hard -"fflate@npm:^0.8.0": +"fflate@npm:^0.8.0, fflate@npm:^0.8.1": version: 0.8.1 resolution: "fflate@npm:0.8.1" checksum: 7207e2d333243724485d2488095256b776184bd4545aa9967b655feaee5dc18e9525ed9b6d75f94cfd71d98fb285336f4902641683472f1d0c19a99137084cec languageName: node linkType: hard -"figures@npm:^5.0.0": - version: 5.0.0 - resolution: "figures@npm:5.0.0" - dependencies: - escape-string-regexp: ^5.0.0 - is-unicode-supported: ^1.2.0 - checksum: e6e8b6d1df2f554d4effae4a5ceff5d796f9449f6d4e912d74dab7d5f25916ecda6c305b9084833157d56485a0c78b37164430ddc5675bcee1330e346710669e - languageName: node - linkType: hard - "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -9402,6 +10267,16 @@ __metadata: languageName: node linkType: hard +"find-cache-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "find-cache-dir@npm:4.0.0" + dependencies: + common-path-prefix: ^3.0.0 + pkg-dir: ^7.0.0 + checksum: 52a456a80deeb27daa3af6e06059b63bdb9cc4af4d845fc6d6229887e505ba913cd56000349caa60bc3aa59dacdb5b4c37903d4ba34c75102d83cab330b70d2f + languageName: node + linkType: hard + "find-replace@npm:^3.0.0": version: 3.0.0 resolution: "find-replace@npm:3.0.0" @@ -9449,7 +10324,7 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^6.0.0": +"find-up@npm:^6.3.0": version: 6.3.0 resolution: "find-up@npm:6.3.0" dependencies: @@ -9460,13 +10335,13 @@ __metadata: linkType: hard "flat-cache@npm:^3.0.4": - version: 3.1.0 - resolution: "flat-cache@npm:3.1.0" + version: 3.2.0 + resolution: "flat-cache@npm:3.2.0" dependencies: - flatted: ^3.2.7 + flatted: ^3.2.9 keyv: ^4.5.3 rimraf: ^3.0.2 - checksum: 99312601d5b90f44aef403f17f056dc09be7e437703740b166cdc9386d99e681f74e6b6e8bd7d010bda66904ea643c9527276b1b80308a2119741d94108a4d8f + checksum: e7e0f59801e288b54bee5cb9681e9ee21ee28ef309f886b312c9d08415b79fc0f24ac842f84356ce80f47d6a53de62197ce0e6e148dc42d5db005992e2a756ec languageName: node linkType: hard @@ -9479,25 +10354,13 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.2.7": +"flatted@npm:^3.2.9": version: 3.2.9 resolution: "flatted@npm:3.2.9" checksum: f14167fbe26a9d20f6fca8d998e8f1f41df72c8e81f9f2c9d61ed2bea058248f5e1cbd05e7f88c0e5087a6a0b822a1e5e2b446e879f3cfbe0b07ba2d7f80b026 languageName: node linkType: hard -"flux@npm:^4.0.1": - version: 4.0.4 - resolution: "flux@npm:4.0.4" - dependencies: - fbemitter: ^3.0.0 - fbjs: ^3.0.1 - peerDependencies: - react: ^15.0.2 || ^16.0.0 || ^17.0.0 - checksum: 8fa5c2f9322258de3e331f67c6f1078a7f91c4dec9dbe8a54c4b8a80eed19a4f91889028b768668af4a796e8f2ee75e461e1571b8615432a3920ae95cc4ff794 - languageName: node - linkType: hard - "follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.7, follow-redirects@npm:^1.15.0": version: 1.15.3 resolution: "follow-redirects@npm:1.15.3" @@ -9549,6 +10412,13 @@ __metadata: languageName: node linkType: hard +"form-data-encoder@npm:^2.1.2": + version: 2.1.4 + resolution: "form-data-encoder@npm:2.1.4" + checksum: e0b3e5950fb69b3f32c273944620f9861f1933df9d3e42066e038e26dfb343d0f4465de9f27e0ead1a09d9df20bc2eed06a63c2ca2f8f00949e7202bae9e29dd + languageName: node + linkType: hard + "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -9560,6 +10430,13 @@ __metadata: languageName: node linkType: hard +"format@npm:^0.2.0": + version: 0.2.2 + resolution: "format@npm:0.2.2" + checksum: 646a60e1336250d802509cf24fb801e43bd4a70a07510c816fa133aa42cdbc9c21e66e9cc0801bb183c5b031c9d68be62e7fbb6877756e52357850f92aa28799 + languageName: node + linkType: hard + "formdata-polyfill@npm:^4.0.10": version: 4.0.10 resolution: "formdata-polyfill@npm:4.0.10" @@ -9642,6 +10519,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.1.1": + version: 11.2.0 + resolution: "fs-extra@npm:11.2.0" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: b12e42fa40ba47104202f57b8480dd098aa931c2724565e5e70779ab87605665594e76ee5fb00545f772ab9ace167fe06d2ab009c416dc8c842c5ae6df7aa7e8 + languageName: node + linkType: hard + "fs-extra@npm:^7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" @@ -9707,7 +10595,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:~2.3.2": +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -9726,7 +10614,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@~2.3.2#~builtin": +"fsevents@patch:fsevents@~2.3.2#~builtin, fsevents@patch:fsevents@~2.3.3#~builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -9735,10 +10623,10 @@ __metadata: languageName: node linkType: hard -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 2b0ff4ce708d99715ad14a6d1f894e2a83242e4a52ccfcefaee5e40050562e5f6dafc1adbb4ce2d4ab47279a45dc736ab91ea5042d843c3c092820dfe032efb1 languageName: node linkType: hard @@ -9749,22 +10637,6 @@ __metadata: languageName: node linkType: hard -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.1, gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -9779,22 +10651,22 @@ __metadata: languageName: node linkType: hard -"get-func-name@npm:^2.0.0": - version: 2.0.0 - resolution: "get-func-name@npm:2.0.0" - checksum: 8d82e69f3e7fab9e27c547945dfe5cc0c57fc0adf08ce135dddb01081d75684a03e7a0487466f478872b341d52ac763ae49e660d01ab83741f74932085f693c3 +"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2": + version: 2.0.2 + resolution: "get-func-name@npm:2.0.2" + checksum: 3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1": - version: 1.2.1 - resolution: "get-intrinsic@npm:1.2.1" +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2": + version: 1.2.2 + resolution: "get-intrinsic@npm:1.2.2" dependencies: - function-bind: ^1.1.1 - has: ^1.0.3 + function-bind: ^1.1.2 has-proto: ^1.0.1 has-symbols: ^1.0.3 - checksum: 5b61d88552c24b0cf6fa2d1b3bc5459d7306f699de060d76442cce49a4721f52b8c560a33ab392cf5575b7810277d54ded9d4d39a1ea61855619ebc005aa7e5f + hasown: ^2.0.0 + checksum: 447ff0724df26829908dc033b62732359596fcf66027bc131ab37984afb33842d9cd458fd6cecadfe7eac22fd8a54b349799ed334cf2726025c921c7250e7417 languageName: node linkType: hard @@ -9837,7 +10709,16 @@ __metadata: languageName: node linkType: hard -"github-slugger@npm:^1.4.0": +"get-tsconfig@npm:^4.7.2": + version: 4.7.2 + resolution: "get-tsconfig@npm:4.7.2" + dependencies: + resolve-pkg-maps: ^1.0.0 + checksum: 172358903250eff0103943f816e8a4e51d29b8e5449058bdf7266714a908a48239f6884308bd3a6ff28b09f692b9533dbebfd183ab63e4e14f073cda91f1bca9 + languageName: node + linkType: hard + +"github-slugger@npm:^1.4.0, github-slugger@npm:^1.5.0": version: 1.5.0 resolution: "github-slugger@npm:1.5.0" checksum: c70988224578b3bdaa25df65973ffc8c24594a77a28550c3636e495e49d17aef5cdb04c04fa3f1744babef98c61eecc6a43299a13ea7f3cc33d680bf9053ffbe @@ -9883,22 +10764,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2": - version: 10.3.5 - resolution: "glob@npm:10.3.5" - dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.0.3 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 - bin: - glob: dist/cjs/src/bin.js - checksum: 564f4799cae48c0bcc841c88a20b539b5701c27ed5596f8623f588b3c523262d3fc20eb1ea89cab9c75b0912faf40ca5501fc835f982225d0d0599282b09e97a - languageName: node - linkType: hard - -"glob@npm:^10.3.10": +"glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.3.10 resolution: "glob@npm:10.3.10" dependencies: @@ -9913,7 +10779,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -9964,11 +10830,11 @@ __metadata: linkType: hard "globals@npm:^13.19.0": - version: 13.22.0 - resolution: "globals@npm:13.22.0" + version: 13.24.0 + resolution: "globals@npm:13.24.0" dependencies: type-fest: ^0.20.2 - checksum: 64af5a09565341432770444085f7aa98b54331c3b69732e0de411003921fa2dd060222ae7b50bec0b98f29c4d00b4f49bf434049ba9f7c36ca4ee1773f60458c + checksum: 56066ef058f6867c04ff203b8a44c15b038346a62efbc3060052a1016be9f56f4cf0b2cd45b74b22b81e521a889fc7786c73691b0549c2f3a6e825b3d394f43c languageName: node linkType: hard @@ -9986,7 +10852,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^13.1.1, globby@npm:^13.1.2, globby@npm:^13.1.4": +"globby@npm:^13.1.1, globby@npm:^13.1.2": version: 13.2.2 resolution: "globby@npm:13.2.2" dependencies: @@ -10008,6 +10874,25 @@ __metadata: languageName: node linkType: hard +"got@npm:^12.1.0": + version: 12.6.1 + resolution: "got@npm:12.6.1" + dependencies: + "@sindresorhus/is": ^5.2.0 + "@szmarczak/http-timer": ^5.0.1 + cacheable-lookup: ^7.0.0 + cacheable-request: ^10.2.8 + decompress-response: ^6.0.0 + form-data-encoder: ^2.1.2 + get-stream: ^6.0.1 + http2-wrapper: ^2.1.10 + lowercase-keys: ^3.0.0 + p-cancelable: ^3.0.0 + responselike: ^3.0.0 + checksum: 3c37f5d858aca2859f9932e7609d35881d07e7f2d44c039d189396f0656896af6c77c22f2c51c563f8918be483f60ff41e219de742ab4642d4b106711baccbd5 + languageName: node + linkType: hard + "got@npm:^9.6.0": version: 9.6.0 resolution: "got@npm:9.6.0" @@ -10027,6 +10912,13 @@ __metadata: languageName: node linkType: hard +"graceful-fs@npm:4.2.10": + version: 4.2.10 + resolution: "graceful-fs@npm:4.2.10" + checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -10070,8 +10962,8 @@ __metadata: linkType: hard "hardhat@npm:^2.17.4": - version: 2.17.4 - resolution: "hardhat@npm:2.17.4" + version: 2.19.2 + resolution: "hardhat@npm:2.19.2" dependencies: "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 @@ -10131,7 +11023,7 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: da8762f29ac08b6178edaedf1bf4641e8bcf44759c944906af644519fa9d0d3fb6c30e87add3904d8899f9cebfbde47a8422e219ad0bb24226c6636f2d3ef7c2 + checksum: 0b5499890e46750ca8c51bbe1205599b1424a2e5293b40c9f7cb56320d56b9935fbd4e276de370e07664ae81fa57dc7ab227bf2b2363f5732ef9f06df1a9a6d9 languageName: node linkType: hard @@ -10150,11 +11042,11 @@ __metadata: linkType: hard "has-property-descriptors@npm:^1.0.0": - version: 1.0.0 - resolution: "has-property-descriptors@npm:1.0.0" + version: 1.0.1 + resolution: "has-property-descriptors@npm:1.0.1" dependencies: - get-intrinsic: ^1.1.1 - checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb + get-intrinsic: ^1.2.2 + checksum: 2bcc6bf6ec6af375add4e4b4ef586e43674850a91ad4d46666d0b28ba8e1fd69e424c7677d24d60f69470ad0afaa2f3197f508b20b0bb7dd99a8ab77ffc4b7c4 languageName: node linkType: hard @@ -10181,13 +11073,6 @@ __metadata: languageName: node linkType: hard -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 - languageName: node - linkType: hard - "has-yarn@npm:^2.1.0": version: 2.1.0 resolution: "has-yarn@npm:2.1.0" @@ -10195,12 +11080,10 @@ __metadata: languageName: node linkType: hard -"has@npm:^1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" - dependencies: - function-bind: ^1.1.1 - checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 +"has-yarn@npm:^3.0.0": + version: 3.0.0 + resolution: "has-yarn@npm:3.0.0" + checksum: b9e14e78e0a37bc070550c862b201534287bc10e62a86ec9c1f455ffb082db42817ce9aed914bd73f1d589bbf268520e194629ff2f62ff6b98a482c4bd2dcbfb languageName: node linkType: hard @@ -10225,6 +11108,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.0": + version: 2.0.0 + resolution: "hasown@npm:2.0.0" + dependencies: + function-bind: ^1.1.2 + checksum: 6151c75ca12554565098641c98a40f4cc86b85b0fd5b6fe92360967e4605a4f9610f7757260b4e8098dd1c2ce7f4b095f2006fe72a570e3b6d2d28de0298c176 + languageName: node + linkType: hard + "hast-to-hyperscript@npm:^9.0.0": version: 9.0.1 resolution: "hast-to-hyperscript@npm:9.0.1" @@ -10240,6 +11132,43 @@ __metadata: languageName: node linkType: hard +"hast-util-from-dom@npm:^5.0.0": + version: 5.0.0 + resolution: "hast-util-from-dom@npm:5.0.0" + dependencies: + "@types/hast": ^3.0.0 + hastscript: ^8.0.0 + web-namespaces: ^2.0.0 + checksum: bf8f96c480a598b42156227be2210bbb7a08da519ae4d57814385c8560b01e2b6b5fbde2afce808ce7ba7c5cd172822d4285b8f5edde2d13089bc9c3177c0d09 + languageName: node + linkType: hard + +"hast-util-from-html-isomorphic@npm:^2.0.0": + version: 2.0.0 + resolution: "hast-util-from-html-isomorphic@npm:2.0.0" + dependencies: + "@types/hast": ^3.0.0 + hast-util-from-dom: ^5.0.0 + hast-util-from-html: ^2.0.0 + unist-util-remove-position: ^5.0.0 + checksum: a98d02890bd1b5a804a1b2aaacd0332a6563f2a8df620450e38ab8962728cda0485cd29435824840621d1e653943776864e912d78d24cce6a7f484011ee7cef0 + languageName: node + linkType: hard + +"hast-util-from-html@npm:^2.0.0": + version: 2.0.1 + resolution: "hast-util-from-html@npm:2.0.1" + dependencies: + "@types/hast": ^3.0.0 + devlop: ^1.1.0 + hast-util-from-parse5: ^8.0.0 + parse5: ^7.0.0 + vfile: ^6.0.0 + vfile-message: ^4.0.0 + checksum: 8decdec1f2750d3d8d4933a4d06d78846a9fb3c97cded07395d160adae22bacfc69eaf113fd95a6ad696d1e5877580f2ac83a4161fa9f3becb0fafe2cec8b0ea + languageName: node + linkType: hard + "hast-util-from-parse5@npm:^6.0.0": version: 6.0.1 resolution: "hast-util-from-parse5@npm:6.0.1" @@ -10254,13 +11183,38 @@ __metadata: languageName: node linkType: hard -"hast-util-is-element@npm:^1.0.0, hast-util-is-element@npm:^1.1.0": +"hast-util-from-parse5@npm:^8.0.0": + version: 8.0.1 + resolution: "hast-util-from-parse5@npm:8.0.1" + dependencies: + "@types/hast": ^3.0.0 + "@types/unist": ^3.0.0 + devlop: ^1.0.0 + hastscript: ^8.0.0 + property-information: ^6.0.0 + vfile: ^6.0.0 + vfile-location: ^5.0.0 + web-namespaces: ^2.0.0 + checksum: fdd1ab8b03af13778ecb94ef9a58b1e3528410cdfceb3d6bb7600508967d0d836b451bc7bc3baf66efb7c730d3d395eea4bb1b30352b0162823d9f0de976774b + languageName: node + linkType: hard + +"hast-util-is-element@npm:^1.1.0": version: 1.1.0 resolution: "hast-util-is-element@npm:1.1.0" checksum: 30fad3f65e7ab2f0efd5db9e7344d0820b70971988dfe79f62d8447598b2a1ce8a59cd4bfc05ae0d9a1c451b9b53cbe1023743d7eac764d64720b6b73475f62f languageName: node linkType: hard +"hast-util-is-element@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-is-element@npm:3.0.0" + dependencies: + "@types/hast": ^3.0.0 + checksum: 82569a420eda5877c52fdbbdbe26675f012c02d70813dfd19acffdee328e42e4bd0b7ae34454cfcbcb932b2bedbd7ddc119f943a0cfb234120f9456d6c0c4331 + languageName: node + linkType: hard + "hast-util-parse-selector@npm:^2.0.0": version: 2.2.5 resolution: "hast-util-parse-selector@npm:2.2.5" @@ -10268,6 +11222,15 @@ __metadata: languageName: node linkType: hard +"hast-util-parse-selector@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-parse-selector@npm:4.0.0" + dependencies: + "@types/hast": ^3.0.0 + checksum: 76087670d3b0b50b23a6cb70bca53a6176d6608307ccdbb3ed18b650b82e7c3513bfc40348f1389dc0c5ae872b9a768851f4335f44654abd7deafd6974c52402 + languageName: node + linkType: hard + "hast-util-raw@npm:6.0.1": version: 6.0.1 resolution: "hast-util-raw@npm:6.0.1" @@ -10286,9 +11249,77 @@ __metadata: languageName: node linkType: hard -"hast-util-to-parse5@npm:^6.0.0": - version: 6.0.0 - resolution: "hast-util-to-parse5@npm:6.0.0" +"hast-util-raw@npm:^9.0.0": + version: 9.0.1 + resolution: "hast-util-raw@npm:9.0.1" + dependencies: + "@types/hast": ^3.0.0 + "@types/unist": ^3.0.0 + "@ungap/structured-clone": ^1.0.0 + hast-util-from-parse5: ^8.0.0 + hast-util-to-parse5: ^8.0.0 + html-void-elements: ^3.0.0 + mdast-util-to-hast: ^13.0.0 + parse5: ^7.0.0 + unist-util-position: ^5.0.0 + unist-util-visit: ^5.0.0 + vfile: ^6.0.0 + web-namespaces: ^2.0.0 + zwitch: ^2.0.0 + checksum: 4b486eb4782eafb471ae639d45c14ac8797676518cf5da16adc973f52d7b8e1075a1451558c023b390820bd9fd213213e6248a2dae71b68ac5040b277509b8d9 + languageName: node + linkType: hard + +"hast-util-to-estree@npm:^3.0.0": + version: 3.1.0 + resolution: "hast-util-to-estree@npm:3.1.0" + dependencies: + "@types/estree": ^1.0.0 + "@types/estree-jsx": ^1.0.0 + "@types/hast": ^3.0.0 + comma-separated-tokens: ^2.0.0 + devlop: ^1.0.0 + estree-util-attach-comments: ^3.0.0 + estree-util-is-identifier-name: ^3.0.0 + hast-util-whitespace: ^3.0.0 + mdast-util-mdx-expression: ^2.0.0 + mdast-util-mdx-jsx: ^3.0.0 + mdast-util-mdxjs-esm: ^2.0.0 + property-information: ^6.0.0 + space-separated-tokens: ^2.0.0 + style-to-object: ^0.4.0 + unist-util-position: ^5.0.0 + zwitch: ^2.0.0 + checksum: 61272f7c18c9d2a5e34df7cfd2c97cbf12f6e9d05114d60e4dedd64e5576565eb1e35c78b9213c909bb8f984f0f8e9c49b568f04bdb444b83d0bca9159e14f3c + languageName: node + linkType: hard + +"hast-util-to-jsx-runtime@npm:^2.0.0": + version: 2.3.0 + resolution: "hast-util-to-jsx-runtime@npm:2.3.0" + dependencies: + "@types/estree": ^1.0.0 + "@types/hast": ^3.0.0 + "@types/unist": ^3.0.0 + comma-separated-tokens: ^2.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + hast-util-whitespace: ^3.0.0 + mdast-util-mdx-expression: ^2.0.0 + mdast-util-mdx-jsx: ^3.0.0 + mdast-util-mdxjs-esm: ^2.0.0 + property-information: ^6.0.0 + space-separated-tokens: ^2.0.0 + style-to-object: ^1.0.0 + unist-util-position: ^5.0.0 + vfile-message: ^4.0.0 + checksum: 599a97c6ec61c1430776813d7fb42e6f96032bf4a04dfcbb8eceef3bc8d1845ecf242387a4426b9d3f52320dbbfa26450643b81124b3d6a0b9bbb0fff4d0ba83 + languageName: node + linkType: hard + +"hast-util-to-parse5@npm:^6.0.0": + version: 6.0.0 + resolution: "hast-util-to-parse5@npm:6.0.0" dependencies: hast-to-hyperscript: ^9.0.0 property-information: ^5.0.0 @@ -10299,14 +11330,39 @@ __metadata: languageName: node linkType: hard -"hast-util-to-text@npm:^2.0.0": - version: 2.0.1 - resolution: "hast-util-to-text@npm:2.0.1" +"hast-util-to-parse5@npm:^8.0.0": + version: 8.0.0 + resolution: "hast-util-to-parse5@npm:8.0.0" + dependencies: + "@types/hast": ^3.0.0 + comma-separated-tokens: ^2.0.0 + devlop: ^1.0.0 + property-information: ^6.0.0 + space-separated-tokens: ^2.0.0 + web-namespaces: ^2.0.0 + zwitch: ^2.0.0 + checksum: 137469209cb2b32b57387928878dc85310fbd5afa4807a8da69529199bb1d19044bfc95b50c3dc68d4fb2b6cb8bf99b899285597ab6ab318f50422eefd5599dd + languageName: node + linkType: hard + +"hast-util-to-text@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-to-text@npm:4.0.0" dependencies: - hast-util-is-element: ^1.0.0 - repeat-string: ^1.0.0 - unist-util-find-after: ^3.0.0 - checksum: 4e7960b414b7a6b2f0180e4af416cd8ae3c7ba1531d7eaec7e6dc9509daf88308784bbf5b94885384dccc42abcb74cc6cc26755c76914d646f32aa6bc32ea34b + "@types/hast": ^3.0.0 + "@types/unist": ^3.0.0 + hast-util-is-element: ^3.0.0 + unist-util-find-after: ^5.0.0 + checksum: 3beedbdf20e2ecc9352cdd0963848b741294c1f3872d43400125bc0ca2d7938d5358081b0f9c252ec15c22368f30a4e7e6ca0ce5a57d4d2bcdd02adbf884e2af + languageName: node + linkType: hard + +"hast-util-whitespace@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-whitespace@npm:3.0.0" + dependencies: + "@types/hast": ^3.0.0 + checksum: 41d93ccce218ba935dc3c12acdf586193c35069489c8c8f50c2aa824c00dec94a3c78b03d1db40fa75381942a189161922e4b7bca700b3a2cc779634c351a1e4 languageName: node linkType: hard @@ -10323,6 +11379,19 @@ __metadata: languageName: node linkType: hard +"hastscript@npm:^8.0.0": + version: 8.0.0 + resolution: "hastscript@npm:8.0.0" + dependencies: + "@types/hast": ^3.0.0 + comma-separated-tokens: ^2.0.0 + hast-util-parse-selector: ^4.0.0 + property-information: ^6.0.0 + space-separated-tokens: ^2.0.0 + checksum: ae3c20223e7b847320c0f98b6fb3c763ebe1bf3913c5805fbc176cf84553a9db1117ca34cf842a5235890b4b9ae0e94501bfdc9a9b870a5dbf5fc52426db1097 + languageName: node + linkType: hard + "he@npm:1.2.0, he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" @@ -10385,7 +11454,7 @@ __metadata: languageName: node linkType: hard -"html-escaper@npm:^2.0.0": +"html-escaper@npm:^2.0.0, html-escaper@npm:^2.0.2": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 @@ -10409,7 +11478,24 @@ __metadata: languageName: node linkType: hard -"html-tags@npm:^3.2.0": +"html-minifier-terser@npm:^7.2.0": + version: 7.2.0 + resolution: "html-minifier-terser@npm:7.2.0" + dependencies: + camel-case: ^4.1.2 + clean-css: ~5.3.2 + commander: ^10.0.0 + entities: ^4.4.0 + param-case: ^3.0.4 + relateurl: ^0.2.7 + terser: ^5.15.1 + bin: + html-minifier-terser: cli.js + checksum: 39feed354b5a8aafc8e910977d68cfd961d6db330a8e1a5b16a528c86b8ee7745d8945134822cf00acf7bf0d0135bf1abad650bf308bee4ea73adb003f5b8656 + languageName: node + linkType: hard + +"html-tags@npm:^3.2.0, html-tags@npm:^3.3.1": version: 3.3.1 resolution: "html-tags@npm:3.3.1" checksum: b4ef1d5a76b678e43cce46e3783d563607b1d550cab30b4f511211564574770aa8c658a400b100e588bc60b8234e59b35ff72c7851cc28f3b5403b13a2c6cbce @@ -10423,9 +11509,16 @@ __metadata: languageName: node linkType: hard -"html-webpack-plugin@npm:^5.5.0": - version: 5.5.3 - resolution: "html-webpack-plugin@npm:5.5.3" +"html-void-elements@npm:^3.0.0": + version: 3.0.0 + resolution: "html-void-elements@npm:3.0.0" + checksum: 59be397525465a7489028afa064c55763d9cccd1d7d9f630cca47137317f0e897a9ca26cef7e745e7cff1abc44260cfa407742b243a54261dfacd42230e94fce + languageName: node + linkType: hard + +"html-webpack-plugin@npm:^5.5.0, html-webpack-plugin@npm:^5.5.3": + version: 5.5.4 + resolution: "html-webpack-plugin@npm:5.5.4" dependencies: "@types/html-minifier-terser": ^6.0.0 html-minifier-terser: ^6.0.2 @@ -10434,7 +11527,7 @@ __metadata: tapable: ^2.0.0 peerDependencies: webpack: ^5.20.0 - checksum: ccf685195739c372ad641bbd0c9100a847904f34eedc7aff3ece7856cd6c78fd3746d2d615af1bb71e5727993fe711b89e9b744f033ed3fde646540bf5d5e954 + checksum: b49befb73d67a3716fd0e6f7776b108d2b0b7050fb8221f05cd114cbae13c03150a13b7cdf5e76170be040ce7936a1cf76f7a4bfd9ebe1552b72d7889a74c374 languageName: node linkType: hard @@ -10531,14 +11624,13 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "http-proxy-agent@npm:5.0.0" +"http-proxy-agent@npm:^7.0.0": + version: 7.0.0 + resolution: "http-proxy-agent@npm:7.0.0" dependencies: - "@tootallnate/once": 2 - agent-base: 6 - debug: 4 - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 + agent-base: ^7.1.0 + debug: ^4.3.4 + checksum: 48d4fac997917e15f45094852b63b62a46d0c8a4f0b9c6c23ca26d27b8df8d178bed88389e604745e748bd9a01f5023e25093722777f0593c3f052009ff438b6 languageName: node linkType: hard @@ -10571,6 +11663,16 @@ __metadata: languageName: node linkType: hard +"http2-wrapper@npm:^2.1.10": + version: 2.2.1 + resolution: "http2-wrapper@npm:2.2.1" + dependencies: + quick-lru: ^5.1.1 + resolve-alpn: ^1.2.0 + checksum: e95e55e22c6fd61182ce81fecb9b7da3af680d479febe8ad870d05f7ebbc9f076e455193766f4e7934e50913bf1d8da3ba121fb5cd2928892390b58cf9d5c509 + languageName: node + linkType: hard + "https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -10581,6 +11683,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.1": + version: 7.0.2 + resolution: "https-proxy-agent@npm:7.0.2" + dependencies: + agent-base: ^7.0.2 + debug: 4 + checksum: 088969a0dd476ea7a0ed0a2cf1283013682b08f874c3bc6696c83fa061d2c157d29ef0ad3eb70a2046010bb7665573b2388d10fdcb3e410a66995e5248444292 + languageName: node + linkType: hard + "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" @@ -10595,15 +11707,6 @@ __metadata: languageName: node linkType: hard -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: ^2.0.0 - checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - "iconv-lite@npm:0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -10638,21 +11741,14 @@ __metadata: languageName: node linkType: hard -"ignore-by-default@npm:^2.1.0": - version: 2.1.0 - resolution: "ignore-by-default@npm:2.1.0" - checksum: 2b2df4622b6a07a3e91893987be8f060dc553f7736b67e72aa2312041c450a6fa8371733d03c42f45a02e47ec824e961c2fba63a3d94fc59cbd669220a5b0d7a - languageName: node - linkType: hard - "ignore@npm:^5.2.0, ignore@npm:^5.2.4": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef + version: 5.3.0 + resolution: "ignore@npm:5.3.0" + checksum: 2736da6621f14ced652785cb05d86301a66d70248597537176612bd0c8630893564bd5f6421f8806b09e8472e75c591ef01672ab8059c07c6eb2c09cefe04bf9 languageName: node linkType: hard -"image-size@npm:^1.0.1": +"image-size@npm:^1.0.1, image-size@npm:^1.0.2": version: 1.0.2 resolution: "image-size@npm:1.0.2" dependencies: @@ -10701,6 +11797,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:^4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: 22f5e51702134aef78890156738454f620e5fe7044b204ebc057c614888a1dd6fdf2ede0fdcca44d5c173fd64f65c985f19a51775b06967ef58cc3d26898df07 + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -10715,13 +11818,6 @@ __metadata: languageName: node linkType: hard -"indent-string@npm:^5.0.0": - version: 5.0.0 - resolution: "indent-string@npm:5.0.0" - checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3 - languageName: node - linkType: hard - "infima@npm:0.2.0-alpha.43": version: 0.2.0-alpha.43 resolution: "infima@npm:0.2.0-alpha.43" @@ -10730,9 +11826,9 @@ __metadata: linkType: hard "inflation@npm:^2.0.0": - version: 2.0.0 - resolution: "inflation@npm:2.0.0" - checksum: a0494871b12275afdef9e2710ee1af1e0fc642b04613a9be69c05ef8b5e9627f3bd7d358a937fa47aa20235ee7313a4f30255048533add0ad4918beb918a586e + version: 2.1.0 + resolution: "inflation@npm:2.1.0" + checksum: 80c1b5d9ec408105a85f0623c824d668ddf0cadafd8d9716c0737990e5a712ae5f7d6bb0ff216b6648eccb9c6ac69fe06c0d8c58456d168db5bf550c89dd74ed languageName: node linkType: hard @@ -10767,7 +11863,7 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.5, ini@npm:~1.3.0": +"ini@npm:^1.3.4, ini@npm:^1.3.5, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 @@ -10781,6 +11877,13 @@ __metadata: languageName: node linkType: hard +"inline-style-parser@npm:0.2.2": + version: 0.2.2 + resolution: "inline-style-parser@npm:0.2.2" + checksum: 698893d6542d4e7c0377936a1c7daec34a197765bd77c5599384756a95ce8804e6b79347b783aa591d5e9c6f3d33dae74c6d4cad3a94647eb05f3a785e927a3f + languageName: node + linkType: hard + "integration-tests@workspace:compiler/integration-tests": version: 0.0.0-use.local resolution: "integration-tests@workspace:compiler/integration-tests" @@ -10788,7 +11891,6 @@ __metadata: "@noir-lang/backend_barretenberg": "workspace:*" "@noir-lang/noir_js": "workspace:*" "@noir-lang/noir_wasm": "workspace:*" - "@noir-lang/source-resolver": "workspace:*" "@nomicfoundation/hardhat-chai-matchers": ^2.0.0 "@nomicfoundation/hardhat-ethers": ^3.0.0 "@web/dev-server-esbuild": ^0.3.6 @@ -10858,13 +11960,6 @@ __metadata: languageName: node linkType: hard -"irregular-plurals@npm:^3.3.0": - version: 3.5.0 - resolution: "irregular-plurals@npm:3.5.0" - checksum: 5b663091dc89155df7b2e9d053e8fb11941a0c4be95c4b6549ed3ea020489fdf4f75ea586c915b5b543704252679a5a6e8c6c3587da5ac3fc57b12da90a9aee7 - languageName: node - linkType: hard - "is-alphabetical@npm:1.0.4, is-alphabetical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphabetical@npm:1.0.4" @@ -10872,6 +11967,13 @@ __metadata: languageName: node linkType: hard +"is-alphabetical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphabetical@npm:2.0.1" + checksum: 56207db8d9de0850f0cd30f4966bf731eb82cedfe496cbc2e97e7c3bacaf66fc54a972d2d08c0d93bb679cb84976a05d24c5ad63de56fabbfc60aadae312edaa + languageName: node + linkType: hard + "is-alphanumerical@npm:^1.0.0": version: 1.0.4 resolution: "is-alphanumerical@npm:1.0.4" @@ -10882,6 +11984,16 @@ __metadata: languageName: node linkType: hard +"is-alphanumerical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphanumerical@npm:2.0.1" + dependencies: + is-alphabetical: ^2.0.0 + is-decimal: ^2.0.0 + checksum: 87acc068008d4c9c4e9f5bd5e251041d42e7a50995c77b1499cf6ed248f971aadeddb11f239cabf09f7975ee58cac7a48ffc170b7890076d8d227b24a68663c9 + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -10925,12 +12037,23 @@ __metadata: languageName: node linkType: hard +"is-ci@npm:^3.0.1": + version: 3.0.1 + resolution: "is-ci@npm:3.0.1" + dependencies: + ci-info: ^3.2.0 + bin: + is-ci: bin.js + checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e + languageName: node + linkType: hard + "is-core-module@npm:^2.13.0": - version: 2.13.0 - resolution: "is-core-module@npm:2.13.0" + version: 2.13.1 + resolution: "is-core-module@npm:2.13.1" dependencies: - has: ^1.0.3 - checksum: 053ab101fb390bfeb2333360fd131387bed54e476b26860dc7f5a700bbf34a0ec4454f7c8c4d43e8a0030957e4b3db6e16d35e1890ea6fb654c833095e040355 + hasown: ^2.0.0 + checksum: 256559ee8a9488af90e4bad16f5583c6d59e92f0742e9e8bb4331e758521ee86b810b93bae44f390766ffbc518a0488b18d9dab7da9a5ff997d499efc9403f7c languageName: node linkType: hard @@ -10941,6 +12064,13 @@ __metadata: languageName: node linkType: hard +"is-decimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-decimal@npm:2.0.1" + checksum: 97132de7acdce77caa7b797632970a2ecd649a88e715db0e4dbc00ab0708b5e7574ba5903962c860cd4894a14fd12b100c0c4ac8aed445cf6f55c6cf747a4158 + languageName: node + linkType: hard + "is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": version: 2.2.1 resolution: "is-docker@npm:2.2.1" @@ -10959,13 +12089,6 @@ __metadata: languageName: node linkType: hard -"is-error@npm:^2.2.2": - version: 2.2.2 - resolution: "is-error@npm:2.2.2" - checksum: a97b39587150f0d38f9f93f64699807fe3020fe5edbd63548f234dc2ba96fd7c776d66c062bf031dfeb93c7f48db563ff6bde588418ca041da37c659a416f055 - languageName: node - linkType: hard - "is-extendable@npm:^0.1.0": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" @@ -10987,13 +12110,6 @@ __metadata: languageName: node linkType: hard -"is-fullwidth-code-point@npm:^4.0.0": - version: 4.0.0 - resolution: "is-fullwidth-code-point@npm:4.0.0" - checksum: 8ae89bf5057bdf4f57b346fb6c55e9c3dd2549983d54191d722d5c739397a903012cc41a04ee3403fd872e811243ef91a7c5196da7b5841dc6b6aae31a264a8d - languageName: node - linkType: hard - "is-generator-function@npm:^1.0.7": version: 1.0.10 resolution: "is-generator-function@npm:1.0.10" @@ -11026,6 +12142,13 @@ __metadata: languageName: node linkType: hard +"is-hexadecimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-hexadecimal@npm:2.0.1" + checksum: 66a2ea85994c622858f063f23eda506db29d92b52580709eb6f4c19550552d4dcf3fb81952e52f7cf972097237959e00adc7bb8c9400cd12886e15bf06145321 + languageName: node + linkType: hard + "is-inside-container@npm:^1.0.0": version: 1.0.0 resolution: "is-inside-container@npm:1.0.0" @@ -11068,6 +12191,13 @@ __metadata: languageName: node linkType: hard +"is-npm@npm:^6.0.0": + version: 6.0.0 + resolution: "is-npm@npm:6.0.0" + checksum: fafe1ddc772345f5460514891bb8014376904ccdbddd59eee7525c9adcc08d426933f28b087bef3e17524da7ebf35c03ef484ff3b6ba9d5fecd8c6e6a7d4bf11 + languageName: node + linkType: hard + "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -11117,6 +12247,13 @@ __metadata: languageName: node linkType: hard +"is-plain-obj@npm:^4.0.0": + version: 4.1.0 + resolution: "is-plain-obj@npm:4.1.0" + checksum: 6dc45da70d04a81f35c9310971e78a6a3c7a63547ef782e3a07ee3674695081b6ca4e977fbb8efc48dae3375e0b34558d2bcd722aec9bddfa2d7db5b041be8ce + languageName: node + linkType: hard + "is-plain-object@npm:^2.0.4": version: 2.0.4 resolution: "is-plain-object@npm:2.0.4" @@ -11133,10 +12270,19 @@ __metadata: languageName: node linkType: hard -"is-promise@npm:^4.0.0": +"is-port-reachable@npm:4.0.0": version: 4.0.0 - resolution: "is-promise@npm:4.0.0" - checksum: 0b46517ad47b00b6358fd6553c83ec1f6ba9acd7ffb3d30a0bf519c5c69e7147c132430452351b8a9fc198f8dd6c4f76f8e6f5a7f100f8c77d57d9e0f4261a8a + resolution: "is-port-reachable@npm:4.0.0" + checksum: 47b7e10db8edcef27fbf9e50f0de85ad368d35688790ca64a13db67260111ac5f4b98989b11af06199fa93f25d810bd09a5b21b2c2646529668638f7c34d3c04 + languageName: node + linkType: hard + +"is-reference@npm:^3.0.0": + version: 3.0.2 + resolution: "is-reference@npm:3.0.2" + dependencies: + "@types/estree": "*" + checksum: ac3bf5626fe9d0afbd7454760d73c47f16b9f471401b9749721ad3b66f0a39644390382acf88ca9d029c95782c1e2ec65662855e3ba91acf52d82231247a7fd3 languageName: node linkType: hard @@ -11182,13 +12328,6 @@ __metadata: languageName: node linkType: hard -"is-unicode-supported@npm:^1.2.0": - version: 1.3.0 - resolution: "is-unicode-supported@npm:1.3.0" - checksum: 20a1fc161afafaf49243551a5ac33b6c4cf0bbcce369fcd8f2951fbdd000c30698ce320de3ee6830497310a8f41880f8066d440aa3eb0a853e2aa4836dd89abc - languageName: node - linkType: hard - "is-whitespace-character@npm:^1.0.0": version: 1.0.4 resolution: "is-whitespace-character@npm:1.0.4" @@ -11219,6 +12358,13 @@ __metadata: languageName: node linkType: hard +"is-yarn-global@npm:^0.4.0": + version: 0.4.1 + resolution: "is-yarn-global@npm:0.4.1" + checksum: 79ec4e6f581c53d4fefdf5f6c237f9a3ad8db29c85cdc4659e76ae345659317552052a97b7e56952aa5d94a23c798ebec8ccad72fb14d3b26dc647ddceddd716 + languageName: node + linkType: hard + "isarray@npm:0.0.1": version: 0.0.1 resolution: "isarray@npm:0.0.1" @@ -11247,6 +12393,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e + languageName: node + linkType: hard + "isobject@npm:^3.0.1": version: 3.0.1 resolution: "isobject@npm:3.0.1" @@ -11255,9 +12408,9 @@ __metadata: linkType: hard "istanbul-lib-coverage@npm:^3.0.0": - version: 3.2.0 - resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 2367407a8d13982d8f7a859a35e7f8dd5d8f75aae4bb5484ede3a9ea1b426dc245aff28b976a2af48ee759fdd9be374ce2bd2669b644f31e76c5f46a2e29a831 languageName: node linkType: hard @@ -11282,19 +12435,6 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^2.0.3": - version: 2.3.3 - resolution: "jackspeak@npm:2.3.3" - dependencies: - "@isaacs/cliui": ^8.0.2 - "@pkgjs/parseargs": ^0.11.0 - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 4313a7c0cc44c7753c4cb9869935f0b06f4cf96827515f63f58ff46b3d2f6e29aba6b3b5151778397c3f5ae67ef8bfc48871967bd10343c27e90cff198ec7808 - languageName: node - linkType: hard - "jackspeak@npm:^2.3.5": version: 2.3.6 resolution: "jackspeak@npm:2.3.6" @@ -11345,16 +12485,16 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.18.2": - version: 1.20.0 - resolution: "jiti@npm:1.20.0" +"jiti@npm:^1.18.2, jiti@npm:^1.20.0": + version: 1.21.0 + resolution: "jiti@npm:1.21.0" bin: jiti: bin/jiti.js - checksum: 7924062b5675142e3e272a27735be84b7bfc0a0eb73217fc2dcafa034f37c4f7b4b9ffc07dd98bcff0f739a8811ce1544db205ae7e97b1c86f0df92c65ce3c72 + checksum: a7bd5d63921c170eaec91eecd686388181c7828e1fa0657ab374b9372bfc1f383cf4b039e6b272383d5cb25607509880af814a39abdff967322459cca41f2961 languageName: node linkType: hard -"joi@npm:^17.6.0": +"joi@npm:^17.6.0, joi@npm:^17.9.2": version: 17.11.0 resolution: "joi@npm:17.11.0" dependencies: @@ -11367,6 +12507,13 @@ __metadata: languageName: node linkType: hard +"js-base64@npm:^3.7.5": + version: 3.7.5 + resolution: "js-base64@npm:3.7.5" + checksum: 67a78c8b1c47b73f1c6fba1957e9fe6fd9dc78ac93ac46cc2e43472dcb9cf150d126fb0e593192e88e0497354fa634d17d255add7cc6ee3c7b4d29870faa8e18 + languageName: node + linkType: hard + "js-sdsl@npm:^4.1.4": version: 4.4.2 resolution: "js-sdsl@npm:4.4.2" @@ -11381,13 +12528,6 @@ __metadata: languageName: node linkType: hard -"js-string-escape@npm:^1.0.1": - version: 1.0.1 - resolution: "js-string-escape@npm:1.0.1" - checksum: f11e0991bf57e0c183b55c547acec85bd2445f043efc9ea5aa68b41bd2a3e7d3ce94636cb233ae0d84064ba4c1a505d32e969813c5b13f81e7d4be12c59256fe - languageName: node - linkType: hard - "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -11406,7 +12546,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1": +"js-yaml@npm:^3.13.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -11531,14 +12671,14 @@ __metadata: languageName: node linkType: hard -"katex@npm:^0.13.0": - version: 0.13.24 - resolution: "katex@npm:0.13.24" +"katex@npm:^0.16.0": + version: 0.16.9 + resolution: "katex@npm:0.16.9" dependencies: - commander: ^8.0.0 + commander: ^8.3.0 bin: katex: cli.js - checksum: 1b7c8295867073d0db4f6fb41ef1c0e3418b8e23924ff61b446b36134cb74cdadc7242dfbfb922d9c32f0b15eda6160a08cd30948c4e78141966ca2991a1726b + checksum: 861194dfd4d86505e657f688fb73048d46ac498edafce71199502a35b03c0ecc35ba930c631be79c4a09d90a0d23476673cd52f6bc367c7a161854d64005fa95 languageName: node linkType: hard @@ -11573,11 +12713,11 @@ __metadata: linkType: hard "keyv@npm:^4.5.3": - version: 4.5.3 - resolution: "keyv@npm:4.5.3" + version: 4.5.4 + resolution: "keyv@npm:4.5.4" dependencies: json-buffer: 3.0.1 - checksum: 3ffb4d5b72b6b4b4af443bbb75ca2526b23c750fccb5ac4c267c6116888b4b65681015c2833cb20d26cf3e6e32dac6b988c77f7f022e1a571b7d90f1442257da + checksum: 74a24395b1c34bd44ad5cb2b49140d087553e170625240b86755a6604cd65aa16efdbdeae5cdb17ba1284a0fbb25ad06263755dbc71b8d8b06f74232ce3cdd72 languageName: node linkType: hard @@ -11710,6 +12850,15 @@ __metadata: languageName: node linkType: hard +"latest-version@npm:^7.0.0": + version: 7.0.0 + resolution: "latest-version@npm:7.0.0" + dependencies: + package-json: ^8.1.0 + checksum: 1f0deba00d5a34394cce4463c938811f51bbb539b131674f4bb2062c63f2cc3b80bccd56ecade3bd5932d04a34cf0a5a8a2ccc4ec9e5e6b285a9a7b3e27d0d66 + languageName: node + linkType: hard + "launch-editor@npm:^2.6.0": version: 2.6.1 resolution: "launch-editor@npm:2.6.1" @@ -11788,13 +12937,6 @@ __metadata: languageName: node linkType: hard -"load-json-file@npm:^7.0.0": - version: 7.0.1 - resolution: "load-json-file@npm:7.0.1" - checksum: a560288da6891778321ef993e4bdbdf05374a4f3a3aeedd5ba6b64672798c830d748cfc59a2ec9891a3db30e78b3d04172e0dcb0d4828168289a393147ca0e74 - languageName: node - linkType: hard - "loader-runner@npm:^4.2.0": version: 4.3.0 resolution: "loader-runner@npm:4.3.0" @@ -11881,13 +13023,6 @@ __metadata: languageName: node linkType: hard -"lodash.curry@npm:^4.0.1": - version: 4.1.1 - resolution: "lodash.curry@npm:4.1.1" - checksum: 9192b70fe7df4d1ff780c0260bee271afa9168c93fe4fa24bc861900240531b59781b5fdaadf4644fea8f4fbcd96f0700539ab294b579ffc1022c6c15dcc462a - languageName: node - linkType: hard - "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" @@ -11895,34 +13030,6 @@ __metadata: languageName: node linkType: hard -"lodash.escape@npm:^4.0.1": - version: 4.0.1 - resolution: "lodash.escape@npm:4.0.1" - checksum: fcb54f457497256964d619d5cccbd80a961916fca60df3fe0fa3e7f052715c2944c0ed5aefb4f9e047d127d44aa2d55555f3350cb42c6549e9e293fb30b41e7f - languageName: node - linkType: hard - -"lodash.flatten@npm:^4.4.0": - version: 4.4.0 - resolution: "lodash.flatten@npm:4.4.0" - checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb - languageName: node - linkType: hard - -"lodash.flow@npm:^3.3.0": - version: 3.5.0 - resolution: "lodash.flow@npm:3.5.0" - checksum: a9a62ad344e3c5a1f42bc121da20f64dd855aaafecee24b1db640f29b88bd165d81c37ff7e380a7191de6f70b26f5918abcebbee8396624f78f3618a0b18634c - languageName: node - linkType: hard - -"lodash.invokemap@npm:^4.6.0": - version: 4.6.0 - resolution: "lodash.invokemap@npm:4.6.0" - checksum: 646ceebbefbcb6da301f8c2868254680fd0bcdc6ada470495d9ae49c9c32938829c1b38a38c95d0258409a9655f85db404b16e648381c7450b7ed3d9c52d8808 - languageName: node - linkType: hard - "lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" @@ -11944,13 +13051,6 @@ __metadata: languageName: node linkType: hard -"lodash.pullall@npm:^4.2.0": - version: 4.2.0 - resolution: "lodash.pullall@npm:4.2.0" - checksum: 7a5fbaedf186ec197ce1e0b9ba1d88a89773ebaf6a8291c7d273838cac59cb3b339cf36ef00e94172862ee84d2304c38face161846f08f5581d0553dcbdcd090 - languageName: node - linkType: hard - "lodash.uniq@npm:4.5.0, lodash.uniq@npm:^4.5.0": version: 4.5.0 resolution: "lodash.uniq@npm:4.5.0" @@ -11958,14 +13058,7 @@ __metadata: languageName: node linkType: hard -"lodash.uniqby@npm:^4.7.0": - version: 4.7.0 - resolution: "lodash.uniqby@npm:4.7.0" - checksum: 659264545a95726d1493123345aad8cbf56e17810fa9a0b029852c6d42bc80517696af09d99b23bef1845d10d95e01b8b4a1da578f22aeba7a30d3e0022a4938 - languageName: node - linkType: hard - -"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21": +"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -11994,6 +13087,13 @@ __metadata: languageName: node linkType: hard +"longest-streak@npm:^3.0.0": + version: 3.1.0 + resolution: "longest-streak@npm:3.1.0" + checksum: d7f952ed004cbdb5c8bcfc4f7f5c3d65449e6c5a9e9be4505a656e3df5a57ee125f284286b4bf8ecea0c21a7b3bf2b8f9001ad506c319b9815ad6a63a47d0fd0 + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -12005,12 +13105,12 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^2.3.1": - version: 2.3.6 - resolution: "loupe@npm:2.3.6" +"loupe@npm:^2.3.6": + version: 2.3.7 + resolution: "loupe@npm:2.3.7" dependencies: - get-func-name: ^2.0.0 - checksum: cc83f1b124a1df7384601d72d8d1f5fe95fd7a8185469fec48bb2e4027e45243949e7a013e8d91051a138451ff0552310c32aa9786e60b6a30d1e801bdc2163f + get-func-name: ^2.0.1 + checksum: 96c058ec7167598e238bb7fb9def2f9339215e97d6685d9c1e3e4bdb33d14600e11fe7a812cf0c003dfb73ca2df374f146280b2287cae9e8d989e9d7a69a203b languageName: node linkType: hard @@ -12037,6 +13137,20 @@ __metadata: languageName: node linkType: hard +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 67a3f81409af969bc0c4ca0e76cd7d16adb1e25aa1c197229587eaf8671275c8c067cd421795dbca4c81be0098e4c426a086a05e30de8a9c587b7a13c0c7ccc5 + languageName: node + linkType: hard + +"lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.1.0 + resolution: "lru-cache@npm:10.1.0" + checksum: 58056d33e2500fbedce92f8c542e7c11b50d7d086578f14b7074d8c241422004af0718e08a6eaae8705cee09c77e39a61c1c79e9370ba689b7010c152e6a76ab + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -12055,13 +13169,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.7.1": - version: 7.18.3 - resolution: "lru-cache@npm:7.18.3" - checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 - languageName: node - linkType: hard - "lru-cache@npm:^8.0.4": version: 8.0.5 resolution: "lru-cache@npm:8.0.5" @@ -12069,13 +13176,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.1 - resolution: "lru-cache@npm:10.0.1" - checksum: 06f8d0e1ceabd76bb6f644a26dbb0b4c471b79c7b514c13c6856113879b3bf369eb7b497dad4ff2b7e2636db202412394865b33c332100876d838ad1372f0181 - languageName: node - linkType: hard - "lru_map@npm:^0.3.3": version: 0.3.3 resolution: "lru_map@npm:0.3.3" @@ -12122,35 +13222,22 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^11.0.3": - version: 11.1.1 - resolution: "make-fetch-happen@npm:11.1.1" +"make-fetch-happen@npm:^13.0.0": + version: 13.0.0 + resolution: "make-fetch-happen@npm:13.0.0" dependencies: - agentkeepalive: ^4.2.1 - cacache: ^17.0.0 + "@npmcli/agent": ^2.0.0 + cacache: ^18.0.0 http-cache-semantics: ^4.1.1 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^5.0.0 + minipass: ^7.0.2 minipass-fetch: ^3.0.0 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 negotiator: ^0.6.3 promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 ssri: ^10.0.0 - checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 - languageName: node - linkType: hard - -"map-age-cleaner@npm:^0.1.3": - version: 0.1.3 - resolution: "map-age-cleaner@npm:0.1.3" - dependencies: - p-defer: ^1.0.0 - checksum: cb2804a5bcb3cbdfe4b59066ea6d19f5e7c8c196cd55795ea4c28f792b192e4c442426ae52524e5e1acbccf393d3bddacefc3d41f803e66453f6c4eda3650bc1 + checksum: 7c7a6d381ce919dd83af398b66459a10e2fe8f4504f340d1d090d3fa3d1b0c93750220e1d898114c64467223504bd258612ba83efbc16f31b075cd56de24b4af languageName: node linkType: hard @@ -12175,6 +13262,20 @@ __metadata: languageName: node linkType: hard +"markdown-extensions@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-extensions@npm:2.0.0" + checksum: ec4ffcb0768f112e778e7ac74cb8ef22a966c168c3e6c29829f007f015b0a0b5c79c73ee8599a0c72e440e7f5cfdbf19e80e2d77b9a313b8f66e180a330cf1b2 + languageName: node + linkType: hard + +"markdown-table@npm:^3.0.0": + version: 3.0.3 + resolution: "markdown-table@npm:3.0.3" + checksum: 8fcd3d9018311120fbb97115987f8b1665a603f3134c93fbecc5d1463380c8036f789e2a62c19432058829e594fff8db9ff81c88f83690b2f8ed6c074f8d9e10 + languageName: node + linkType: hard + "marked@npm:^4.3.0": version: 4.3.0 resolution: "marked@npm:4.3.0" @@ -12191,15 +13292,6 @@ __metadata: languageName: node linkType: hard -"matcher@npm:^5.0.0": - version: 5.0.0 - resolution: "matcher@npm:5.0.0" - dependencies: - escape-string-regexp: ^5.0.0 - checksum: 28f191c2d23fee0f6f32fd0181d9fe173b0ab815a919edba55605438a2f9fa40372e002574a1b17add981b0a8669c75bc6194318d065ed2dceffd8b160c38118 - languageName: node - linkType: hard - "mcl-wasm@npm:^0.7.1": version: 0.7.9 resolution: "mcl-wasm@npm:0.7.9" @@ -12207,15 +13299,6 @@ __metadata: languageName: node linkType: hard -"md5-hex@npm:^3.0.1": - version: 3.0.1 - resolution: "md5-hex@npm:3.0.1" - dependencies: - blueimp-md5: ^2.10.0 - checksum: 6799a19e8bdd3e0c2861b94c1d4d858a89220488d7885c1fa236797e367d0c2e5f2b789e05309307083503f85be3603a9686a5915568a473137d6b4117419cc2 - languageName: node - linkType: hard - "md5.js@npm:^1.3.4": version: 1.3.5 resolution: "md5.js@npm:1.3.5" @@ -12245,9 +13328,235 @@ __metadata: languageName: node linkType: hard -"mdast-util-to-hast@npm:10.0.1": - version: 10.0.1 - resolution: "mdast-util-to-hast@npm:10.0.1" +"mdast-util-directive@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-directive@npm:3.0.0" + dependencies: + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + parse-entities: ^4.0.0 + stringify-entities: ^4.0.0 + unist-util-visit-parents: ^6.0.0 + checksum: 593afdc4f39f99bb198f3774bf4648cb546cb99a055e40c82262a7faab10926d2529a725d0d3945300ed0a1f07c6c84215a3f76b899a89b3f410ec7375bbab17 + languageName: node + linkType: hard + +"mdast-util-find-and-replace@npm:^3.0.0, mdast-util-find-and-replace@npm:^3.0.1": + version: 3.0.1 + resolution: "mdast-util-find-and-replace@npm:3.0.1" + dependencies: + "@types/mdast": ^4.0.0 + escape-string-regexp: ^5.0.0 + unist-util-is: ^6.0.0 + unist-util-visit-parents: ^6.0.0 + checksum: 05d5c4ff02e31db2f8a685a13bcb6c3f44e040bd9dfa54c19a232af8de5268334c8755d79cb456ed4cced1300c4fb83e88444c7ae8ee9ff16869a580f29d08cd + languageName: node + linkType: hard + +"mdast-util-from-markdown@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-from-markdown@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 + decode-named-character-reference: ^1.0.0 + devlop: ^1.0.0 + mdast-util-to-string: ^4.0.0 + micromark: ^4.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-decode-string: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-stringify-position: ^4.0.0 + checksum: 4e8d8a46b4b588486c41b80c39da333a91593bc8d60cd7421c6cd3c22003b8e5a62478292fb7bc97b9255b6301a2250cca32340ef43c309156e215453c5b92be + languageName: node + linkType: hard + +"mdast-util-frontmatter@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-frontmatter@npm:2.0.1" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + escape-string-regexp: ^5.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + micromark-extension-frontmatter: ^2.0.0 + checksum: 86a7c8d9eb183be2621d6d9134b9d33df2a3647e3255f68a9796e2425e25643ffae00a501e36c57d9c10973087b94aa5a2ffd865d33cdd274cc9b88cd2d90a2e + languageName: node + linkType: hard + +"mdast-util-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + ccount: ^2.0.0 + devlop: ^1.0.0 + mdast-util-find-and-replace: ^3.0.0 + micromark-util-character: ^2.0.0 + checksum: 10322662e5302964bed7c9829c5fd3b0c9899d4f03e63fb8620ab141cf4f3de9e61fcb4b44d46aacc8a23f82bcd5d900980a211825dfe026b1dab5fdbc3e8742 + languageName: node + linkType: hard + +"mdast-util-gfm-footnote@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-footnote@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.1.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + checksum: 45d26b40e7a093712e023105791129d76e164e2168d5268e113298a22de30c018162683fb7893cdc04ab246dac0087eed708b2a136d1d18ed2b32b3e0cae4a79 + languageName: node + linkType: hard + +"mdast-util-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-strikethrough@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: fe9b1d0eba9b791ff9001c008744eafe3dd7a81b085f2bf521595ce4a8e8b1b44764ad9361761ad4533af3e5d913d8ad053abec38172031d9ee32a8ebd1c7dbd + languageName: node + linkType: hard + +"mdast-util-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-table@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + markdown-table: ^3.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 063a627fd0993548fd63ca0c24c437baf91ba7d51d0a38820bd459bc20bf3d13d7365ef8d28dca99176dd5eb26058f7dde51190479c186dfe6af2e11202957c9 + languageName: node + linkType: hard + +"mdast-util-gfm-task-list-item@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-task-list-item@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 37db90c59b15330fc54d790404abf5ef9f2f83e8961c53666fe7de4aab8dd5e6b3c296b6be19797456711a89a27840291d8871ff0438e9b4e15c89d170efe072 + languageName: node + linkType: hard + +"mdast-util-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-gfm@npm:3.0.0" + dependencies: + mdast-util-from-markdown: ^2.0.0 + mdast-util-gfm-autolink-literal: ^2.0.0 + mdast-util-gfm-footnote: ^2.0.0 + mdast-util-gfm-strikethrough: ^2.0.0 + mdast-util-gfm-table: ^2.0.0 + mdast-util-gfm-task-list-item: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 62039d2f682ae3821ea1c999454863d31faf94d67eb9b746589c7e136076d7fb35fabc67e02f025c7c26fd7919331a0ee1aabfae24f565d9a6a9ebab3371c626 + languageName: node + linkType: hard + +"mdast-util-math@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-math@npm:3.0.0" + dependencies: + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + longest-streak: ^3.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.1.0 + unist-util-remove-position: ^5.0.0 + checksum: dc7dfb14aec2ec143420f2d92f80c5e6d69293d7cfb6b8180e7f411ce4e1314b5cf4a8d3345eefe06ab0ddd95e3c7801c4174b343fd2c26741180ca4dbad5371 + languageName: node + linkType: hard + +"mdast-util-mdx-expression@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-mdx-expression@npm:2.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 4e1183000e183e07a7264e192889b4fd57372806103031c71b9318967f85fd50a5dd0f92ef14f42c331e77410808f5de3341d7bc8ad4ee91b7fa8f0a30043a8a + languageName: node + linkType: hard + +"mdast-util-mdx-jsx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx-jsx@npm:3.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 + ccount: ^2.0.0 + devlop: ^1.1.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + parse-entities: ^4.0.0 + stringify-entities: ^4.0.0 + unist-util-remove-position: ^5.0.0 + unist-util-stringify-position: ^4.0.0 + vfile-message: ^4.0.0 + checksum: 48fe1ba617205f3776ca2030d195adbdb42bb6c53326534db3f5bdd28abe7895103af8c4dfda7cbe2911e8cd71921bc8a82fe40856565e57af8b4f8a79c8c126 + languageName: node + linkType: hard + +"mdast-util-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx@npm:3.0.0" + dependencies: + mdast-util-from-markdown: ^2.0.0 + mdast-util-mdx-expression: ^2.0.0 + mdast-util-mdx-jsx: ^3.0.0 + mdast-util-mdxjs-esm: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: e2b007d826fcd49fd57ed03e190753c8b0f7d9eff6c7cb26ba609cde15cd3a472c0cd5e4a1ee3e39a40f14be22fdb57de243e093cea0c064d6f3366cff3e3af2 + languageName: node + linkType: hard + +"mdast-util-mdxjs-esm@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdxjs-esm@npm:2.0.1" + dependencies: + "@types/estree-jsx": ^1.0.0 + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 1f9dad04d31d59005332e9157ea9510dc1d03092aadbc607a10475c7eec1c158b475aa0601a3a4f74e13097ca735deb8c2d9d37928ddef25d3029fd7c9e14dc3 + languageName: node + linkType: hard + +"mdast-util-phrasing@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-phrasing@npm:4.0.0" + dependencies: + "@types/mdast": ^4.0.0 + unist-util-is: ^6.0.0 + checksum: 95d5d8e18d5ea6dbfe2ee4ed1045961372efae9077e5c98e10bfef7025ee3fd9449f9a82840068ff50aa98fa43af0a0a14898ae10b5e46e96edde01e2797df34 + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:10.0.1": + version: 10.0.1 + resolution: "mdast-util-to-hast@npm:10.0.1" dependencies: "@types/mdast": ^3.0.0 "@types/unist": ^2.0.0 @@ -12261,6 +13570,38 @@ __metadata: languageName: node linkType: hard +"mdast-util-to-hast@npm:^13.0.0": + version: 13.0.2 + resolution: "mdast-util-to-hast@npm:13.0.2" + dependencies: + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + "@ungap/structured-clone": ^1.0.0 + devlop: ^1.0.0 + micromark-util-sanitize-uri: ^2.0.0 + trim-lines: ^3.0.0 + unist-util-position: ^5.0.0 + unist-util-visit: ^5.0.0 + checksum: 8fef6c3752476461d9c00b1dea4f141bc7d980e1b3bac7bd965bc68f532b6d30fb1c9e810433327c167176e68e071b8f4ab5a45355954857dc095c878421f35e + languageName: node + linkType: hard + +"mdast-util-to-markdown@npm:^2.0.0, mdast-util-to-markdown@npm:^2.1.0": + version: 2.1.0 + resolution: "mdast-util-to-markdown@npm:2.1.0" + dependencies: + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 + longest-streak: ^3.0.0 + mdast-util-phrasing: ^4.0.0 + mdast-util-to-string: ^4.0.0 + micromark-util-decode-string: ^2.0.0 + unist-util-visit: ^5.0.0 + zwitch: ^2.0.0 + checksum: 3a2cf3957e23b34e2e092e6e76ae72ee0b8745955bd811baba6814cf3a3d916c3fd52264b4b58f3bb3d512a428f84a1e998b6fc7e28434e388a9ae8fb6a9c173 + languageName: node + linkType: hard + "mdast-util-to-string@npm:^2.0.0": version: 2.0.0 resolution: "mdast-util-to-string@npm:2.0.0" @@ -12268,6 +13609,15 @@ __metadata: languageName: node linkType: hard +"mdast-util-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-to-string@npm:4.0.0" + dependencies: + "@types/mdast": ^4.0.0 + checksum: 35489fb5710d58cbc2d6c8b6547df161a3f81e0f28f320dfb3548a9393555daf07c310c0c497708e67ed4dfea4a06e5655799e7d631ca91420c288b4525d6c29 + languageName: node + linkType: hard + "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" @@ -12289,16 +13639,6 @@ __metadata: languageName: node linkType: hard -"mem@npm:^9.0.2": - version: 9.0.2 - resolution: "mem@npm:9.0.2" - dependencies: - map-age-cleaner: ^0.1.3 - mimic-fn: ^4.0.0 - checksum: 07829bb182af0e3ecf748dc2edb1c3b10a256ef10458f7e24d06561a2adc2b3ef34d14abe81678bbcedb46faa477e7370223f118b1a5e1252da5fe43496f3967 - languageName: node - linkType: hard - "memfs@npm:^3.1.2, memfs@npm:^3.4.3": version: 3.5.3 resolution: "memfs@npm:3.5.3" @@ -12354,6 +13694,519 @@ __metadata: languageName: node linkType: hard +"micromark-core-commonmark@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-core-commonmark@npm:2.0.0" + dependencies: + decode-named-character-reference: ^1.0.0 + devlop: ^1.0.0 + micromark-factory-destination: ^2.0.0 + micromark-factory-label: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-factory-title: ^2.0.0 + micromark-factory-whitespace: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-classify-character: ^2.0.0 + micromark-util-html-tag-name: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-resolve-all: ^2.0.0 + micromark-util-subtokenize: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 9c12fb580cf4ce71f60872043bd2794efe129f44d7b2b73afa155bbc0a66b7bc35655ba8cef438a6bd068441837ed3b6dc6ad7e5a18f815462c1750793e03a42 + languageName: node + linkType: hard + +"micromark-extension-directive@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-directive@npm:3.0.0" + dependencies: + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-factory-whitespace: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + parse-entities: ^4.0.0 + checksum: 8350106bdf039a544cba64cf7932261a710e07d73d43d6c645dd2b16577f30ebd04abf762e8ca74266f5de19938e1eeff6c237d79f8244dea23aef7f90df2c31 + languageName: node + linkType: hard + +"micromark-extension-frontmatter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-frontmatter@npm:2.0.0" + dependencies: + fault: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: f68032df38c00ae47de15b63bcd72515bfcce39de4a9262a3a1ac9c5990f253f8e41bdc65fd17ec4bb3d144c32529ce0829571331e4901a9a413f1a53785d1e8 + languageName: node + linkType: hard + +"micromark-extension-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-autolink-literal@npm:2.0.0" + dependencies: + micromark-util-character: ^2.0.0 + micromark-util-sanitize-uri: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: fa16d59528239262d6d04d539a052baf1f81275954ec8bfadea40d81bfc25667d5c8e68b225a5358626df5e30a3933173a67fdad2fed011d37810a10b770b0b2 + languageName: node + linkType: hard + +"micromark-extension-gfm-footnote@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-footnote@npm:2.0.0" + dependencies: + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-sanitize-uri: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: a426fddecfac6144fc622b845cd2dc09d46faa75be5b76ff022cb76a03301b1d4929a5e5e41e071491787936be65e03d0b03c7aebc0e0136b3cdbfadadd6632c + languageName: node + linkType: hard + +"micromark-extension-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-strikethrough@npm:2.0.0" + dependencies: + devlop: ^1.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-classify-character: ^2.0.0 + micromark-util-resolve-all: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 4e35fbbf364bfce08066b70acd94b9d393a8fd09a5afbe0bae70d0c8a174640b1ba86ab6b78ee38f411a813e2a718b07959216cf0063d823ba1c569a7694e5ad + languageName: node + linkType: hard + +"micromark-extension-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-table@npm:2.0.0" + dependencies: + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 71484dcf8db7b189da0528f472cc81e4d6d1a64ae43bbe7fcb7e2e1dba758a0a4f785f9f1afb9459fe5b4a02bbe023d78c95c05204414a14083052eb8219e5eb + languageName: node + linkType: hard + +"micromark-extension-gfm-tagfilter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0" + dependencies: + micromark-util-types: ^2.0.0 + checksum: cf21552f4a63592bfd6c96ae5d64a5f22bda4e77814e3f0501bfe80e7a49378ad140f827007f36044666f176b3a0d5fea7c2e8e7973ce4b4579b77789f01ae95 + languageName: node + linkType: hard + +"micromark-extension-gfm-task-list-item@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-extension-gfm-task-list-item@npm:2.0.1" + dependencies: + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 80e569ab1a1d1f89d86af91482e9629e24b7e3f019c9d7989190f36a9367c6de723b2af48e908c1b73479f35b2215d3d38c1fdbf02ab01eb2fc90a59d1cf4465 + languageName: node + linkType: hard + +"micromark-extension-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-gfm@npm:3.0.0" + dependencies: + micromark-extension-gfm-autolink-literal: ^2.0.0 + micromark-extension-gfm-footnote: ^2.0.0 + micromark-extension-gfm-strikethrough: ^2.0.0 + micromark-extension-gfm-table: ^2.0.0 + micromark-extension-gfm-tagfilter: ^2.0.0 + micromark-extension-gfm-task-list-item: ^2.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 2060fa62666a09532d6b3a272d413bc1b25bbb262f921d7402795ac021e1362c8913727e33d7528d5b4ccaf26922ec51208c43f795a702964817bc986de886c9 + languageName: node + linkType: hard + +"micromark-extension-math@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-math@npm:3.0.0" + dependencies: + "@types/katex": ^0.16.0 + devlop: ^1.0.0 + katex: ^0.16.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 14d313ea58f711d69c567951870f8d8517384cd90318d8b608b4eabb2fea2278c7de1ca38fa86067704cba679b5a82be243680436c1bc26c4c4978b28fdf647c + languageName: node + linkType: hard + +"micromark-extension-mdx-expression@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdx-expression@npm:3.0.0" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-factory-mdx-expression: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: abd6ba0acdebc03bc0836c51a1ec4ca28e0be86f10420dd8cfbcd6c10dd37cd3f31e7c8b9792e9276e7526748883f4a30d0803d72b6285dae47d4e5348c23a10 + languageName: node + linkType: hard + +"micromark-extension-mdx-jsx@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdx-jsx@npm:3.0.0" + dependencies: + "@types/acorn": ^4.0.0 + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + micromark-factory-mdx-expression: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + vfile-message: ^4.0.0 + checksum: 5e2f45d381d1ce43afadc5376427b42ef8cd2a574ca3658473254eabe84db99ef1abc03055b3d86728fac7f1edfb1076e6f2f322ed8bfb1f2f14cafc2c8f0d0e + languageName: node + linkType: hard + +"micromark-extension-mdx-md@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-mdx-md@npm:2.0.0" + dependencies: + micromark-util-types: ^2.0.0 + checksum: 7daf03372fd7faddf3f0ac87bdb0debb0bb770f33b586f72251e1072b222ceee75400ab6194c0e130dbf1e077369a5b627be6e9130d7a2e9e6b849f0d18ff246 + languageName: node + linkType: hard + +"micromark-extension-mdxjs-esm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs-esm@npm:3.0.0" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: fb33d850200afce567b95c90f2f7d42259bd33eea16154349e4fa77c3ec934f46c8e5c111acea16321dce3d9f85aaa4c49afe8b810e31b34effc11617aeee8f6 + languageName: node + linkType: hard + +"micromark-extension-mdxjs@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs@npm:3.0.0" + dependencies: + acorn: ^8.0.0 + acorn-jsx: ^5.0.0 + micromark-extension-mdx-expression: ^3.0.0 + micromark-extension-mdx-jsx: ^3.0.0 + micromark-extension-mdx-md: ^2.0.0 + micromark-extension-mdxjs-esm: ^3.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 7da6f0fb0e1e0270a2f5ad257e7422cc16e68efa7b8214c63c9d55bc264cb872e9ca4ac9a71b9dfd13daf52e010f730bac316086f4340e4fcc6569ec699915bf + languageName: node + linkType: hard + +"micromark-factory-destination@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-factory-destination@npm:2.0.0" + dependencies: + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: d36e65ed1c072ff4148b016783148ba7c68a078991154625723e24bda3945160268fb91079fb28618e1613c2b6e70390a8ddc544c45410288aa27b413593071a + languageName: node + linkType: hard + +"micromark-factory-label@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-factory-label@npm:2.0.0" + dependencies: + devlop: ^1.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: c021dbd0ed367610d35f2bae21209bc804d1a6d1286ffce458fd6a717f4d7fe581a7cba7d5c2d7a63757c44eb927c80d6a571d6ea7969fae1b48ab6461d109c4 + languageName: node + linkType: hard + +"micromark-factory-mdx-expression@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-mdx-expression@npm:2.0.1" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: 2ba0ae939d0174a5e5331b1a4c203b96862ccf06e8903d6bdcc2d51f75515e52d407cd394afcd182f9ff0e877dc2a14e3fa430ced0131e156650d45104de8311 + languageName: node + linkType: hard + +"micromark-factory-space@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-space@npm:1.1.0" + dependencies: + micromark-util-character: ^1.0.0 + micromark-util-types: ^1.0.0 + checksum: b58435076b998a7e244259a4694eb83c78915581206b6e7fc07b34c6abd36a1726ade63df8972fbf6c8fa38eecb9074f4e17be8d53f942e3b3d23d1a0ecaa941 + languageName: node + linkType: hard + +"micromark-factory-space@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-factory-space@npm:2.0.0" + dependencies: + micromark-util-character: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 4ffdcdc2f759887bbb356500cb460b3915ecddcb5d85c3618d7df68ad05d13ed02b1153ee1845677b7d8126df8f388288b84fcf0d943bd9c92bcc71cd7222e37 + languageName: node + linkType: hard + +"micromark-factory-title@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-factory-title@npm:2.0.0" + dependencies: + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 39e1ac23af3554e6e652e56065579bc7faf21ade7b8704b29c175871b4152b7109b790bb3cae0f7e088381139c6bac9553b8400772c3d322e4fa635f813a3578 + languageName: node + linkType: hard + +"micromark-factory-whitespace@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-factory-whitespace@npm:2.0.0" + dependencies: + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 9587c2546d1a58b4d5472b42adf05463f6212d0449455285662d63cd8eaed89c6b159ac82713fcee5f9dd88628c24307d9533cccd8971a2f3f4d48702f8f850a + languageName: node + linkType: hard + +"micromark-util-character@npm:^1.0.0, micromark-util-character@npm:^1.1.0": + version: 1.2.0 + resolution: "micromark-util-character@npm:1.2.0" + dependencies: + micromark-util-symbol: ^1.0.0 + micromark-util-types: ^1.0.0 + checksum: 089e79162a19b4a28731736246579ab7e9482ac93cd681c2bfca9983dcff659212ef158a66a5957e9d4b1dba957d1b87b565d85418a5b009f0294f1f07f2aaac + languageName: node + linkType: hard + +"micromark-util-character@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-character@npm:2.0.1" + dependencies: + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 318d6e16fdcbe9d89e18b8e7796568d986abbb10a9f3037b7ac9b92a236bcc962f3cd380e26a7c49df40fd1d9ca33eb546268956345b662f4c4ca4962c7695f2 + languageName: node + linkType: hard + +"micromark-util-chunked@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-chunked@npm:2.0.0" + dependencies: + micromark-util-symbol: ^2.0.0 + checksum: 324f95cccdae061332a8241936eaba6ef0782a1e355bac5c607ad2564fd3744929be7dc81651315a2921535747a33243e6a5606bcb64b7a56d49b6d74ea1a3d4 + languageName: node + linkType: hard + +"micromark-util-classify-character@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-classify-character@npm:2.0.0" + dependencies: + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 086e52904deffebb793fb1c08c94aabb8901f76958142dfc3a6282890ebaa983b285e69bd602b9d507f1b758ed38e75a994d2ad9fbbefa7de2584f67a16af405 + languageName: node + linkType: hard + +"micromark-util-combine-extensions@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-combine-extensions@npm:2.0.0" + dependencies: + micromark-util-chunked: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 107c47700343f365b4ed81551e18bc3458b573c500e56ac052b2490bd548adc475216e41d2271633a8867fac66fc22ba3e0a2d74a31ed79b9870ca947eb4e3ba + languageName: node + linkType: hard + +"micromark-util-decode-numeric-character-reference@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.1" + dependencies: + micromark-util-symbol: ^2.0.0 + checksum: 9512507722efd2033a9f08715eeef787fbfe27e23edf55db21423d46d82ab46f76c89b4f960be3f5e50a2d388d89658afc0647989cf256d051e9ea01277a1adb + languageName: node + linkType: hard + +"micromark-util-decode-string@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-decode-string@npm:2.0.0" + dependencies: + decode-named-character-reference: ^1.0.0 + micromark-util-character: ^2.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-symbol: ^2.0.0 + checksum: a75daf32a4a6b549e9f19b4d833ebfeb09a32a9a1f9ce50f35dec6b6a3e4f9f121f49024ba7f9c91c55ebe792f7c7a332fc9604795181b6a612637df0df5b959 + languageName: node + linkType: hard + +"micromark-util-encode@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-encode@npm:2.0.0" + checksum: 853a3f33fce72aaf4ffa60b7f2b6fcfca40b270b3466e1b96561b02185d2bd8c01dd7948bc31a24ac014f4cc854e545ca9a8e9cf7ea46262f9d24c9e88551c66 + languageName: node + linkType: hard + +"micromark-util-events-to-acorn@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-events-to-acorn@npm:2.0.2" + dependencies: + "@types/acorn": ^4.0.0 + "@types/estree": ^1.0.0 + "@types/unist": ^3.0.0 + devlop: ^1.0.0 + estree-util-visit: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + vfile-message: ^4.0.0 + checksum: bcb3eeac52a4ae5c3ca3d8cff514de3a7d1f272d9a94cce26a08c578bef64df4d61820874c01207e92fcace9eae5c9a7ecdddef0c6e10014b255a07b7880bf94 + languageName: node + linkType: hard + +"micromark-util-html-tag-name@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-html-tag-name@npm:2.0.0" + checksum: d786d4486f93eb0ac5b628779809ca97c5dc60f3c9fc03eb565809831db181cf8cb7f05f9ac76852f3eb35461af0f89fa407b46f3a03f4f97a96754d8dc540d8 + languageName: node + linkType: hard + +"micromark-util-normalize-identifier@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-normalize-identifier@npm:2.0.0" + dependencies: + micromark-util-symbol: ^2.0.0 + checksum: b36da2d3fd102053dadd953ce5c558328df12a63a8ac0e5aad13d4dda8e43b6a5d4a661baafe0a1cd8a260bead4b4a8e6e0e74193dd651e8484225bd4f4e68aa + languageName: node + linkType: hard + +"micromark-util-resolve-all@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-resolve-all@npm:2.0.0" + dependencies: + micromark-util-types: ^2.0.0 + checksum: 31fe703b85572cb3f598ebe32750e59516925c7ff1f66cfe6afaebe0771a395a9eaa770787f2523d3c46082ea80e6c14f83643303740b3d650af7c96ebd30ccc + languageName: node + linkType: hard + +"micromark-util-sanitize-uri@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-sanitize-uri@npm:2.0.0" + dependencies: + micromark-util-character: ^2.0.0 + micromark-util-encode: ^2.0.0 + micromark-util-symbol: ^2.0.0 + checksum: ea4c28bbffcf2430e9aff2d18554296789a8b0a1f54ac24020d1dde76624a7f93e8f2a83e88cd5a846b6d2c4287b71b1142d1b89fa7f1b0363a9b33711a141fe + languageName: node + linkType: hard + +"micromark-util-subtokenize@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-subtokenize@npm:2.0.0" + dependencies: + devlop: ^1.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 77d9c7d59c05a20468d49ce2a3640e9cb268c083ccad02322f26c84e1094c25b44f4b8139ef0a247ca11a4fef7620c5bf82fbffd98acdb2989e79cbe7bd8f1db + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^1.0.0, micromark-util-symbol@npm:^1.0.1": + version: 1.1.0 + resolution: "micromark-util-symbol@npm:1.1.0" + checksum: 02414a753b79f67ff3276b517eeac87913aea6c028f3e668a19ea0fc09d98aea9f93d6222a76ca783d20299af9e4b8e7c797fe516b766185dcc6e93290f11f88 + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-symbol@npm:2.0.0" + checksum: fa4a05bff575d9fbf0ad96a1013003e3bb6087ed6b34b609a141b6c0d2137b57df594aca409a95f4c5fda199f227b56a7d8b1f82cea0768df161d8a3a3660764 + languageName: node + linkType: hard + +"micromark-util-types@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-types@npm:1.1.0" + checksum: b0ef2b4b9589f15aec2666690477a6a185536927ceb7aa55a0f46475852e012d75a1ab945187e5c7841969a842892164b15d58ff8316b8e0d6cc920cabd5ede7 + languageName: node + linkType: hard + +"micromark-util-types@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-util-types@npm:2.0.0" + checksum: 819fef3ab5770c37893d2a60381fb2694396c8d22803b6e103c830c3a1bc1490363c2b0470bb2acaaddad776dfbc2fc1fcfde39cb63c4f54d95121611672e3d0 + languageName: node + linkType: hard + +"micromark@npm:^4.0.0": + version: 4.0.0 + resolution: "micromark@npm:4.0.0" + dependencies: + "@types/debug": ^4.0.0 + debug: ^4.0.0 + decode-named-character-reference: ^1.0.0 + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-encode: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-resolve-all: ^2.0.0 + micromark-util-sanitize-uri: ^2.0.0 + micromark-util-subtokenize: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: b84ab5ab1a0b28c063c52e9c2c9d7d44b954507235c10c9492d66e0b38f7de24bf298f914a1fbdf109f2a57a88cf0412de217c84cfac5fd60e3e42a74dbac085 + languageName: node + linkType: hard + "micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" @@ -12426,7 +14279,21 @@ __metadata: languageName: node linkType: hard -"mini-css-extract-plugin@npm:^2.6.1": +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867 + languageName: node + linkType: hard + +"mimic-response@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-response@npm:4.0.0" + checksum: 33b804cc961efe206efdb1fca6a22540decdcfce6c14eb5c0c50e5ae9022267ab22ce8f5568b1f7247ba67500fe20d523d81e0e9f009b321ccd9d472e78d1850 + languageName: node + linkType: hard + +"mini-css-extract-plugin@npm:^2.6.1, mini-css-extract-plugin@npm:^2.7.6": version: 2.7.6 resolution: "mini-css-extract-plugin@npm:2.7.6" dependencies: @@ -12485,12 +14352,12 @@ __metadata: languageName: node linkType: hard -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" dependencies: - minipass: ^3.0.0 - checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 + minipass: ^7.0.3 + checksum: b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 languageName: node linkType: hard @@ -12552,10 +14419,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.3": - version: 7.0.3 - resolution: "minipass@npm:7.0.3" - checksum: 6f1614f5b5b55568a46bca5fec0e7c46dac027691db27d0e1923a8192866903144cd962ac772c0e9f89b608ea818b702709c042bce98e190d258847d85461531 +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3": + version: 7.0.4 + resolution: "minipass@npm:7.0.4" + checksum: 87585e258b9488caf2e7acea242fd7856bbe9a2c84a7807643513a338d66f368c7d518200ad7b70a508664d408aa000517647b2930c259a8b1f9f0984f344a21 languageName: node linkType: hard @@ -12651,6 +14518,34 @@ __metadata: languageName: node linkType: hard +"monaco-editor-textmate@npm:^4.0.0": + version: 4.0.0 + resolution: "monaco-editor-textmate@npm:4.0.0" + peerDependencies: + monaco-editor: 0.x.x + monaco-textmate: ^3.0.0 + checksum: 9d3f5f24982f928c5f4b7c5c5170a549cb19eb1471eb157aa07bd97cf15cd75dd941585eeb6924b05c54109a55d48adc45191eda9db5d2793b1d8c462181c100 + languageName: node + linkType: hard + +"monaco-editor@npm:^0.44.0": + version: 0.44.0 + resolution: "monaco-editor@npm:0.44.0" + checksum: 6e561b23e5e9090cbdbb820dae5895a8bf9d537acc09281756a8c428960da0481461c72f387cc9a2e14bff69ab4359186c98df2dd29d6d109f1ab7189b573a35 + languageName: node + linkType: hard + +"monaco-textmate@npm:^3.0.1": + version: 3.0.1 + resolution: "monaco-textmate@npm:3.0.1" + dependencies: + fast-plist: ^0.1.2 + peerDependencies: + onigasm: ^2.0.0 + checksum: 0f2ec07ee3e9a37bb880e2aaef802f82cb666660b40fc3c7c3e35553d740aed34ae94399b06296fddf1f96efdaf27eaf347b39cb14bc08ccfb65162c52771d56 + languageName: node + linkType: hard + "mri@npm:^1.1.0": version: 1.2.0 resolution: "mri@npm:1.2.0" @@ -12679,7 +14574,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1, ms@npm:^2.1.3": +"ms@npm:2.1.3, ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -12714,12 +14609,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.25, nanoid@npm:^3.3.6": - version: 3.3.6 - resolution: "nanoid@npm:3.3.6" +"nanoid@npm:^3.1.25, nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" bin: nanoid: bin/nanoid.cjs - checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 + checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 languageName: node linkType: hard @@ -12786,6 +14681,18 @@ __metadata: languageName: node linkType: hard +"node-emoji@npm:^2.1.0": + version: 2.1.3 + resolution: "node-emoji@npm:2.1.3" + dependencies: + "@sindresorhus/is": ^4.6.0 + char-regex: ^1.0.2 + emojilib: ^2.4.0 + skin-tone: ^2.0.0 + checksum: 9ae5a1fb12fd5ce6885f251f345986115de4bb82e7d06fdc943845fb19260d89d0aaaccbaf85cae39fe7aaa1fc391640558865ba690c9bb8a7236c3ac10bbab0 + languageName: node + linkType: hard + "node-fetch@npm:2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" @@ -12811,20 +14718,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.12": - version: 2.7.0 - resolution: "node-fetch@npm:2.7.0" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 - languageName: node - linkType: hard - "node-forge@npm:^1": version: 1.3.1 resolution: "node-forge@npm:1.3.1" @@ -12833,59 +14726,51 @@ __metadata: linkType: hard "node-gyp-build@npm:^4.2.0, node-gyp-build@npm:^4.3.0": - version: 4.6.1 - resolution: "node-gyp-build@npm:4.6.1" + version: 4.7.1 + resolution: "node-gyp-build@npm:4.7.1" bin: node-gyp-build: bin.js node-gyp-build-optional: optional.js node-gyp-build-test: build-test.js - checksum: c3676d337b36803bc7792e35bf7fdcda7cdcb7e289b8f9855a5535702a82498eb976842fefcf487258c58005ca32ce3d537fbed91280b04409161dcd7232a882 + checksum: 2ef8248021489db03be3e8098977cdc797b80a9b12b77c6dcb89b0dc89b8c62e6a482672ee298f61021740ae7f080fb33154cfec8fb158cec620f57b0fae87c0 languageName: node linkType: hard "node-gyp@npm:latest": - version: 9.4.0 - resolution: "node-gyp@npm:9.4.0" + version: 10.0.1 + resolution: "node-gyp@npm:10.0.1" dependencies: env-paths: ^2.2.0 exponential-backoff: ^3.1.1 - glob: ^7.1.4 + glob: ^10.3.10 graceful-fs: ^4.2.6 - make-fetch-happen: ^11.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 + make-fetch-happen: ^13.0.0 + nopt: ^7.0.0 + proc-log: ^3.0.0 semver: ^7.3.5 tar: ^6.1.2 - which: ^2.0.2 + which: ^4.0.0 bin: node-gyp: bin/node-gyp.js - checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.13": - version: 2.0.13 - resolution: "node-releases@npm:2.0.13" - checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + checksum: 60a74e66d364903ce02049966303a57f898521d139860ac82744a5fdd9f7b7b3b61f75f284f3bfe6e6add3b8f1871ce305a1d41f775c7482de837b50c792223f languageName: node linkType: hard -"nofilter@npm:^3.1.0": - version: 3.1.0 - resolution: "nofilter@npm:3.1.0" - checksum: 58aa85a5b4b35cbb6e42de8a8591c5e338061edc9f3e7286f2c335e9e9b9b8fa7c335ae45daa8a1f3433164dc0b9a3d187fa96f9516e04a17a1f9ce722becc4f +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 59443a2f77acac854c42d321bf1b43dea0aef55cd544c6a686e9816a697300458d4e82239e2d794ea05f7bbbc8a94500332e2d3ac3f11f52e4b16cbe638b3c41 languageName: node linkType: hard -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" +"nopt@npm:^7.0.0": + version: 7.2.0 + resolution: "nopt@npm:7.2.0" dependencies: - abbrev: ^1.0.0 + abbrev: ^2.0.0 bin: nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + checksum: a9c0f57fb8cb9cc82ae47192ca2b7ef00e199b9480eed202482c962d61b59a7fbe7541920b2a5839a97b42ee39e288c0aed770e38057a608d7f579389dfde410 languageName: node linkType: hard @@ -12917,6 +14802,13 @@ __metadata: languageName: node linkType: hard +"normalize-url@npm:^8.0.0": + version: 8.0.0 + resolution: "normalize-url@npm:8.0.0" + checksum: 24c20b75ebfd526d8453084692720b49d111c63c0911f1b7447427829597841eef5a8ba3f6bb93d6654007b991c1f5cd85da2c907800e439e2e2ec6c2abd0fc0 + languageName: node + linkType: hard + "npm-run-path@npm:^4.0.1": version: 4.0.1 resolution: "npm-run-path@npm:4.0.1" @@ -12935,18 +14827,6 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a - languageName: node - linkType: hard - "nprogress@npm:^0.2.0": version: 0.2.0 resolution: "nprogress@npm:0.2.0" @@ -12963,7 +14843,7 @@ __metadata: languageName: node linkType: hard -"object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": +"object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f @@ -12971,9 +14851,9 @@ __metadata: linkType: hard "object-inspect@npm:^1.9.0": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db + version: 1.13.1 + resolution: "object-inspect@npm:1.13.1" + checksum: 7d9fa9221de3311dcb5c7c307ee5dc011cdd31dc43624b7c184b3840514e118e05ef0002be5388304c416c0eb592feb46e983db12577fc47e47d5752fbbfb61f languageName: node linkType: hard @@ -12985,14 +14865,14 @@ __metadata: linkType: hard "object.assign@npm:^4.1.0": - version: 4.1.4 - resolution: "object.assign@npm:4.1.4" + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 + call-bind: ^1.0.5 + define-properties: ^1.2.1 has-symbols: ^1.0.3 object-keys: ^1.1.1 - checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 + checksum: f9aeac0541661370a1fc86e6a8065eb1668d3e771f7dbb33ee54578201336c057b21ee61207a186dd42db0c62201d91aac703d20d12a79fc79c353eed44d4e25 languageName: node linkType: hard @@ -13053,6 +14933,15 @@ __metadata: languageName: node linkType: hard +"onigasm@npm:^2.2.5": + version: 2.2.5 + resolution: "onigasm@npm:2.2.5" + dependencies: + lru-cache: ^5.1.1 + checksum: 97aedde610ef561f05853609d6a5b720ec1e123f867bdac1b38b5aeb3bc90ed60209678c75a5f0f9821aa793c720b6d17aabfb956e26ab115ee9b81d6e56bdf7 + languageName: node + linkType: hard + "only@npm:~0.0.2": version: 0.0.2 resolution: "only@npm:0.0.2" @@ -13136,19 +15025,10 @@ __metadata: languageName: node linkType: hard -"p-defer@npm:^1.0.0": - version: 1.0.0 - resolution: "p-defer@npm:1.0.0" - checksum: 4271b935c27987e7b6f229e5de4cdd335d808465604644cb7b4c4c95bef266735859a93b16415af8a41fd663ee9e3b97a1a2023ca9def613dba1bad2a0da0c7b - languageName: node - linkType: hard - -"p-event@npm:^5.0.1": - version: 5.0.1 - resolution: "p-event@npm:5.0.1" - dependencies: - p-timeout: ^5.0.2 - checksum: 3bdd8df6092e6b149f25e9c2eb1c0843b3b4279b07be2a2c72c02b65b267a8908c2040fefd606f2497b0f2bcefcd214f8ca5a74f0c883515d400ccf1d88d5683 +"p-cancelable@npm:^3.0.0": + version: 3.0.0 + resolution: "p-cancelable@npm:3.0.0" + checksum: 2b5ae34218f9c2cf7a7c18e5d9a726ef9b165ef07e6c959f6738371509e747334b5f78f3bcdeb03d8a12dcb978faf641fd87eb21486ed7d36fb823b8ddef3219 languageName: node linkType: hard @@ -13242,15 +15122,6 @@ __metadata: languageName: node linkType: hard -"p-map@npm:^5.5.0": - version: 5.5.0 - resolution: "p-map@npm:5.5.0" - dependencies: - aggregate-error: ^4.0.0 - checksum: 065cb6fca6b78afbd070dd9224ff160dc23eea96e57863c09a0c8ea7ce921043f76854be7ee0abc295cff1ac9adcf700e79a1fbe3b80b625081087be58e7effb - languageName: node - linkType: hard - "p-retry@npm:^4.5.0": version: 4.6.2 resolution: "p-retry@npm:4.6.2" @@ -13261,13 +15132,6 @@ __metadata: languageName: node linkType: hard -"p-timeout@npm:^5.0.2": - version: 5.1.0 - resolution: "p-timeout@npm:5.1.0" - checksum: f5cd4e17301ff1ff1d8dbf2817df0ad88c6bba99349fc24d8d181827176ad4f8aca649190b8a5b1a428dfd6ddc091af4606835d3e0cb0656e04045da5c9e270c - languageName: node - linkType: hard - "p-try@npm:^1.0.0": version: 1.0.0 resolution: "p-try@npm:1.0.0" @@ -13294,6 +15158,18 @@ __metadata: languageName: node linkType: hard +"package-json@npm:^8.1.0": + version: 8.1.1 + resolution: "package-json@npm:8.1.1" + dependencies: + got: ^12.1.0 + registry-auth-token: ^5.0.1 + registry-url: ^6.0.0 + semver: ^7.3.7 + checksum: 28bec6f42bf9fba66b7c8fea07576fc23d08ec7923433f7835d6cd8654e72169d74f9738b3785107d18a476ae76712e0daeb1dddcd6930e69f9e4b47eba7c0ca + languageName: node + linkType: hard + "param-case@npm:^3.0.4": version: 3.0.4 resolution: "param-case@npm:3.0.4" @@ -13327,6 +15203,22 @@ __metadata: languageName: node linkType: hard +"parse-entities@npm:^4.0.0": + version: 4.0.1 + resolution: "parse-entities@npm:4.0.1" + dependencies: + "@types/unist": ^2.0.0 + character-entities: ^2.0.0 + character-entities-legacy: ^3.0.0 + character-reference-invalid: ^2.0.0 + decode-named-character-reference: ^1.0.0 + is-alphanumerical: ^2.0.0 + is-decimal: ^2.0.0 + is-hexadecimal: ^2.0.0 + checksum: 32a6ff5b9acb9d2c4d71537308521fd265e685b9215691df73feedd9edfe041bb6da9f89bd0c35c4a2bc7d58e3e76e399bb6078c2fd7d2a343ff1dd46edbf1bd + languageName: node + linkType: hard + "parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -13339,13 +15231,6 @@ __metadata: languageName: node linkType: hard -"parse-ms@npm:^3.0.0": - version: 3.0.0 - resolution: "parse-ms@npm:3.0.0" - checksum: fc602bba093835562321a67a9d6c8c9687ca4f26a09459a77e07ebd7efddd1a5766725ec60eb0c83a2abe67f7a23808f7deb1c1226727776eaf7f9607ae09db2 - languageName: node - linkType: hard - "parse-numeric-range@npm:^1.3.0": version: 1.3.0 resolution: "parse-numeric-range@npm:1.3.0" @@ -13528,6 +15413,17 @@ __metadata: languageName: node linkType: hard +"periscopic@npm:^3.0.0": + version: 3.1.0 + resolution: "periscopic@npm:3.1.0" + dependencies: + "@types/estree": ^1.0.0 + estree-walker: ^3.0.0 + is-reference: ^3.0.0 + checksum: 2153244352e58a0d76e7e8d9263e66fe74509495f809af388da20045fb30aa3e93f2f94468dc0b9166ecf206fcfc0d73d2c7641c6fbedc07b1de858b710142cb + languageName: node + linkType: hard + "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -13542,16 +15438,6 @@ __metadata: languageName: node linkType: hard -"pkg-conf@npm:^4.0.0": - version: 4.0.0 - resolution: "pkg-conf@npm:4.0.0" - dependencies: - find-up: ^6.0.0 - load-json-file: ^7.0.0 - checksum: 6da0c064a74f6c7ae80d7d68c5853e14f7e762a2a80c6ca9e0aa827002b90b69c86fefe3bac830b10a6f1739e7f96a1f728637f2a141e50b0fdafe92a2c3eab6 - languageName: node - linkType: hard - "pkg-dir@npm:^4.1.0": version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" @@ -13561,6 +15447,15 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^7.0.0": + version: 7.0.0 + resolution: "pkg-dir@npm:7.0.0" + dependencies: + find-up: ^6.3.0 + checksum: 94298b20a446bfbbd66604474de8a0cdd3b8d251225170970f15d9646f633e056c80520dd5b4c1d1050c9fed8f6a9e5054b141c93806439452efe72e57562c03 + languageName: node + linkType: hard + "pkg-up@npm:^3.1.0": version: 3.1.0 resolution: "pkg-up@npm:3.1.0" @@ -13570,36 +15465,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.38.0": - version: 1.38.0 - resolution: "playwright-core@npm:1.38.0" +"playwright-core@npm:1.40.1": + version: 1.40.1 + resolution: "playwright-core@npm:1.40.1" bin: playwright-core: cli.js - checksum: 9eb43fc6c3cb392d5f35b0fd0b7291b38a8cbdc3cbb944a8261f744f30d09196dfa3b5d84aa02ffc09af87d08d31b385b007b6af20d0b6cd50a29344f3b0db8d + checksum: 84d92fb9b86e3c225b16b6886bf858eb5059b4e60fa1205ff23336e56a06dcb2eac62650992dede72f406c8e70a7b6a5303e511f9b4bc0b85022ede356a01ee0 languageName: node linkType: hard "playwright@npm:^1.22.2": - version: 1.38.0 - resolution: "playwright@npm:1.38.0" + version: 1.40.1 + resolution: "playwright@npm:1.40.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.38.0 + playwright-core: 1.40.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: c5356690a391d5dd41f814d4e2694b93ba9e79381ce63de752da1c6c59b1f9c69bc6be853d973d0542d73a44a6b15f7c0081a164a64cd27b6b31207710c0ab34 - languageName: node - linkType: hard - -"plur@npm:^5.1.0": - version: 5.1.0 - resolution: "plur@npm:5.1.0" - dependencies: - irregular-plurals: ^3.3.0 - checksum: 57e400dc4b926768fb0abab7f8688fe17e85673712134546e7beaaee188bae7e0504976e847d7e41d0d6103ff2fd61204095f03c2a45de19a8bad15aecb45cc1 + checksum: 9e36791c1b4a649c104aa365fdd9d049924eeb518c5967c0e921aa38b9b00994aa6ee54784d6c2af194b3b494b6f69772673081ef53c6c4a4b2065af9955c4ba languageName: node linkType: hard @@ -13699,7 +15585,7 @@ __metadata: languageName: node linkType: hard -"postcss-loader@npm:^7.0.0": +"postcss-loader@npm:^7.0.0, postcss-loader@npm:^7.3.3": version: 7.3.3 resolution: "postcss-loader@npm:7.3.3" dependencies: @@ -13998,7 +15884,7 @@ __metadata: languageName: node linkType: hard -"postcss-sort-media-queries@npm:^4.2.1": +"postcss-sort-media-queries@npm:^4.2.1, postcss-sort-media-queries@npm:^4.4.1": version: 4.4.1 resolution: "postcss-sort-media-queries@npm:4.4.1" dependencies: @@ -14048,14 +15934,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.3.11, postcss@npm:^8.4.14, postcss@npm:^8.4.17, postcss@npm:^8.4.21": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" +"postcss@npm:^8.4.14, postcss@npm:^8.4.17, postcss@npm:^8.4.21, postcss@npm:^8.4.26": + version: 8.4.32 + resolution: "postcss@npm:8.4.32" dependencies: - nanoid: ^3.3.6 + nanoid: ^3.3.7 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea + checksum: 220d9d0bf5d65be7ed31006c523bfb11619461d296245c1231831f90150aeb4a31eab9983ac9c5c89759a3ca8b60b3e0d098574964e1691673c3ce5c494305ae languageName: node linkType: hard @@ -14082,7 +15968,16 @@ __metadata: languageName: node linkType: hard -"prettier@npm:*, prettier@npm:3.0.3": +"prettier@npm:*": + version: 3.1.1 + resolution: "prettier@npm:3.1.1" + bin: + prettier: bin/prettier.cjs + checksum: e386855e3a1af86a748e16953f168be555ce66d6233f4ba54eb6449b88eb0c6b2ca79441b11eae6d28a7f9a5c96440ce50864b9d5f6356d331d39d6bb66c648e + languageName: node + linkType: hard + +"prettier@npm:3.0.3": version: 3.0.3 resolution: "prettier@npm:3.0.3" bin: @@ -14101,15 +15996,6 @@ __metadata: languageName: node linkType: hard -"pretty-ms@npm:^8.0.0": - version: 8.0.0 - resolution: "pretty-ms@npm:8.0.0" - dependencies: - parse-ms: ^3.0.0 - checksum: b7d2a8182887af0e5ab93f9df331f10db9b8eda86855e2de115eb01a6c501bde5631a8813b1b0abdd7d045e79b08ae875369a8fd279a3dacd6d9e572bdd3bfa6 - languageName: node - linkType: hard - "pretty-time@npm:^1.1.0": version: 1.1.0 resolution: "pretty-time@npm:1.1.0" @@ -14117,22 +16003,32 @@ __metadata: languageName: node linkType: hard -"prism-react-renderer@npm:^1.3.5": - version: 1.3.5 - resolution: "prism-react-renderer@npm:1.3.5" +"prism-react-renderer@npm:^2.1.0, prism-react-renderer@npm:^2.3.0": + version: 2.3.0 + resolution: "prism-react-renderer@npm:2.3.0" + dependencies: + "@types/prismjs": ^1.26.0 + clsx: ^2.0.0 peerDependencies: - react: ">=0.14.9" - checksum: c18806dcbc4c0b4fd6fd15bd06b4f7c0a6da98d93af235c3e970854994eb9b59e23315abb6cfc29e69da26d36709a47e25da85ab27fed81b6812f0a52caf6dfa + react: ">=16.0.0" + checksum: 29b24eb5015c09e1b7e3fa2941584ead6fceb5556fdfbe7c34548d96886e0b291290bda93a421aab8b26ce6aae677387aac294982d11349a050843f6dbbc7449 languageName: node linkType: hard -"prismjs@npm:^1.28.0": +"prismjs@npm:^1.29.0": version: 1.29.0 resolution: "prismjs@npm:1.29.0" checksum: 007a8869d4456ff8049dc59404e32d5666a07d99c3b0e30a18bd3b7676dfa07d1daae9d0f407f20983865fd8da56de91d09cb08e6aa61f5bc420a27c0beeaf93 languageName: node linkType: hard +"proc-log@npm:^3.0.0": + version: 3.0.0 + resolution: "proc-log@npm:3.0.0" + checksum: 02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02 + languageName: node + linkType: hard + "process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -14157,15 +16053,6 @@ __metadata: languageName: node linkType: hard -"promise@npm:^7.1.1": - version: 7.3.1 - resolution: "promise@npm:7.3.1" - dependencies: - asap: ~2.0.3 - checksum: 475bb069130179fbd27ed2ab45f26d8862376a137a57314cf53310bdd85cc986a826fd585829be97ebc0aaf10e9d8e68be1bfe5a4a0364144b1f9eedfa940cf1 - languageName: node - linkType: hard - "prompts@npm:^2.4.2": version: 2.4.2 resolution: "prompts@npm:2.4.2" @@ -14196,6 +16083,20 @@ __metadata: languageName: node linkType: hard +"property-information@npm:^6.0.0": + version: 6.4.0 + resolution: "property-information@npm:6.4.0" + checksum: b5aed9a40e87730995f3ceed29839f137fa73b2a4cccfb8ed72ab8bddb8881cad05c3487c4aa168d7cb49a53db8089790c9f00f59d15b8380d2bb5383cdd1f24 + languageName: node + linkType: hard + +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: 4d4826e1713cbfa0f15124ab0ae494c91b597a3c458670c9714c36e8baddf5a6aad22842776f2f5b137f259c8533e741771445eb8df82e861eea37a6eaba03f7 + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -14242,9 +16143,9 @@ __metadata: linkType: hard "punycode@npm:^2.1.0, punycode@npm:^2.1.1": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2 languageName: node linkType: hard @@ -14257,6 +16158,15 @@ __metadata: languageName: node linkType: hard +"pupa@npm:^3.1.0": + version: 3.1.0 + resolution: "pupa@npm:3.1.0" + dependencies: + escape-goat: ^4.0.0 + checksum: 0e4f4ab6bbdce600fa6d23b1833f1af57b2641246ff4cbe10f9d66e4e5479b0de2864a88d5bd629eef59524eda3c6680726acd7f3f873d9ed46b7f095d0bb5f6 + languageName: node + linkType: hard + "puppeteer-core@npm:^19.8.1": version: 19.11.1 resolution: "puppeteer-core@npm:19.11.1" @@ -14281,13 +16191,6 @@ __metadata: languageName: node linkType: hard -"pure-color@npm:^1.2.0": - version: 1.3.0 - resolution: "pure-color@npm:1.3.0" - checksum: 646d8bed6e6eab89affdd5e2c11f607a85b631a7fb03c061dfa658eb4dc4806881a15feed2ac5fd8c0bad8c00c632c640d5b1cb8b9a972e6e947393a1329371b - languageName: node - linkType: hard - "qs@npm:6.11.0": version: 6.11.0 resolution: "qs@npm:6.11.0" @@ -14322,6 +16225,13 @@ __metadata: languageName: node linkType: hard +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed + languageName: node + linkType: hard + "randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" @@ -14369,7 +16279,7 @@ __metadata: languageName: node linkType: hard -"rc@npm:1.2.8, rc@npm:^1.2.8": +"rc@npm:1.2.8, rc@npm:^1.0.1, rc@npm:^1.1.6, rc@npm:^1.2.8": version: 1.2.8 resolution: "rc@npm:1.2.8" dependencies: @@ -14383,18 +16293,6 @@ __metadata: languageName: node linkType: hard -"react-base16-styling@npm:^0.6.0": - version: 0.6.0 - resolution: "react-base16-styling@npm:0.6.0" - dependencies: - base16: ^1.0.0 - lodash.curry: ^4.0.1 - lodash.flow: ^3.3.0 - pure-color: ^1.2.0 - checksum: 00a12dddafc8a9025cca933b0dcb65fca41c81fa176d1fc3a6a9d0242127042e2c0a604f4c724a3254dd2c6aeb5ef55095522ff22f5462e419641c1341a658e4 - languageName: node - linkType: hard - "react-dev-utils@npm:^12.0.1": version: 12.0.1 resolution: "react-dev-utils@npm:12.0.1" @@ -14427,16 +16325,15 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^17.0.2": - version: 17.0.2 - resolution: "react-dom@npm:17.0.2" +"react-dom@npm:^18.2.0": + version: 18.2.0 + resolution: "react-dom@npm:18.2.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - scheduler: ^0.20.2 + scheduler: ^0.23.0 peerDependencies: - react: 17.0.2 - checksum: 1c1eaa3bca7c7228d24b70932e3d7c99e70d1d04e13bb0843bbf321582bc25d7961d6b8a6978a58a598af2af496d1cedcfb1bf65f6b0960a0a8161cb8dab743c + react: ^18.2.0 + checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc languageName: node linkType: hard @@ -14447,14 +16344,28 @@ __metadata: languageName: node linkType: hard -"react-fast-compare@npm:^3.2.0": +"react-fast-compare@npm:^3.2.0, react-fast-compare@npm:^3.2.2": version: 3.2.2 resolution: "react-fast-compare@npm:3.2.2" checksum: 2071415b4f76a3e6b55c84611c4d24dcb12ffc85811a2840b5a3f1ff2d1a99be1020d9437ee7c6e024c9f4cbb84ceb35e48cf84f28fcb00265ad2dfdd3947704 languageName: node linkType: hard -"react-helmet-async@npm:*, react-helmet-async@npm:^1.3.0": +"react-helmet-async@npm:*": + version: 2.0.3 + resolution: "react-helmet-async@npm:2.0.3" + dependencies: + invariant: ^2.2.4 + react-fast-compare: ^3.2.2 + shallowequal: ^1.1.0 + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + checksum: dfb951174c1812b1aaa8099181024ea8fbdc5cb65e5ab56e465753e2dc5a7c7756e9ab86ba382157ff27dc5b33353a2a000f7f088653815e4aa576daec01ec33 + languageName: node + linkType: hard + +"react-helmet-async@npm:^1.3.0": version: 1.3.0 resolution: "react-helmet-async@npm:1.3.0" dependencies: @@ -14477,25 +16388,12 @@ __metadata: languageName: node linkType: hard -"react-json-view@npm:^1.21.3": - version: 1.21.3 - resolution: "react-json-view@npm:1.21.3" - dependencies: - flux: ^4.0.1 - react-base16-styling: ^0.6.0 - react-lifecycles-compat: ^3.0.4 - react-textarea-autosize: ^8.3.2 +"react-json-view-lite@npm:^1.2.0": + version: 1.2.1 + resolution: "react-json-view-lite@npm:1.2.1" peerDependencies: - react: ^17.0.0 || ^16.3.0 || ^15.5.4 - react-dom: ^17.0.0 || ^16.3.0 || ^15.5.4 - checksum: 5718bcd9210ad5b06eb9469cf8b9b44be9498845a7702e621343618e8251f26357e6e1c865532cf170db6165df1cb30202787e057309d8848c220bc600ec0d1a - languageName: node - linkType: hard - -"react-lifecycles-compat@npm:^3.0.4": - version: 3.0.4 - resolution: "react-lifecycles-compat@npm:3.0.4" - checksum: a904b0fc0a8eeb15a148c9feb7bc17cec7ef96e71188280061fc340043fd6d8ee3ff233381f0e8f95c1cf926210b2c4a31f38182c8f35ac55057e453d6df204f + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + checksum: 9441260033ec07991b0121281d846f9d3e8db9061ea0dc3938f7003630f515d47870a465d90f1f9300ebe406679986657a4062c009c2a2084e2e145e6fa05a47 languageName: node linkType: hard @@ -14523,7 +16421,7 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^5.3.3": +"react-router-dom@npm:^5.3.3, react-router-dom@npm:^5.3.4": version: 5.3.4 resolution: "react-router-dom@npm:5.3.4" dependencies: @@ -14540,7 +16438,7 @@ __metadata: languageName: node linkType: hard -"react-router@npm:5.3.4, react-router@npm:^5.3.3": +"react-router@npm:5.3.4, react-router@npm:^5.3.3, react-router@npm:^5.3.4": version: 5.3.4 resolution: "react-router@npm:5.3.4" dependencies: @@ -14559,26 +16457,34 @@ __metadata: languageName: node linkType: hard -"react-textarea-autosize@npm:^8.3.2": - version: 8.5.3 - resolution: "react-textarea-autosize@npm:8.5.3" +"react-spinners@npm:^0.13.8": + version: 0.13.8 + resolution: "react-spinners@npm:0.13.8" + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: cb58f916bbf00c4f7fc33c1a75a8c0f91a98a42af26944340a0e29e4b3a97937a03f0292bc444eb5f5f0bea099344b580f9c04a81524246dadbf0571bdb57e62 + languageName: node + linkType: hard + +"react-toastify@npm:^9.1.3": + version: 9.1.3 + resolution: "react-toastify@npm:9.1.3" dependencies: - "@babel/runtime": ^7.20.13 - use-composed-ref: ^1.3.0 - use-latest: ^1.2.1 + clsx: ^1.1.1 peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: b317c3763f37a89621bbafd0e6e2d068e7876790a5ae77f497adfd6ba9334ceea138c8a0b7d907bae0f79c765cb24e8b2ca2b8033b4144c0bce28571a3658921 + react: ">=16" + react-dom: ">=16" + checksum: e8bd92c5cbf831b43a042644ab9bc69abe6ceb3ce91ba71f5cd2d8b6a2c9885ca52770e1f1ba64c5632607f6df962db344a26c7fba57606faf5aa0e7bfc8535f languageName: node linkType: hard -"react@npm:^17.0.2": - version: 17.0.2 - resolution: "react@npm:17.0.2" +"react@npm:^18.2.0": + version: 18.2.0 + resolution: "react@npm:18.2.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - checksum: b254cc17ce3011788330f7bbf383ab653c6848902d7936a87b09d835d091e3f295f7e9dd1597c6daac5dc80f90e778c8230218ba8ad599f74adcc11e33b9d61b + checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b languageName: node linkType: hard @@ -14695,6 +16601,16 @@ __metadata: languageName: node linkType: hard +"registry-auth-token@npm:3.3.2": + version: 3.3.2 + resolution: "registry-auth-token@npm:3.3.2" + dependencies: + rc: ^1.1.6 + safe-buffer: ^5.0.1 + checksum: c9d7ae160a738f1fa825556e3669e6c771d2c0239ce37679f7e8646157a97d0a76464738be075002a1f754ef9bfb913b689f4bbfd5296d28f136fbf98c8c2217 + languageName: node + linkType: hard + "registry-auth-token@npm:^4.0.0": version: 4.2.2 resolution: "registry-auth-token@npm:4.2.2" @@ -14704,6 +16620,24 @@ __metadata: languageName: node linkType: hard +"registry-auth-token@npm:^5.0.1": + version: 5.0.2 + resolution: "registry-auth-token@npm:5.0.2" + dependencies: + "@pnpm/npm-conf": ^2.1.0 + checksum: 0d7683b71ee418993e7872b389024b13645c4295eb7bb850d10728eaf46065db24ea4d47dc6cbb71a60d1aa4bef077b0d8b7363c9ac9d355fdba47bebdfb01dd + languageName: node + linkType: hard + +"registry-url@npm:3.1.0": + version: 3.1.0 + resolution: "registry-url@npm:3.1.0" + dependencies: + rc: ^1.0.1 + checksum: 6d223da41b04e1824f5faa63905c6f2e43b216589d72794111573f017352b790aef42cd1f826463062f89d804abb2027e3d9665d2a9a0426a11eedd04d470af3 + languageName: node + linkType: hard + "registry-url@npm:^5.0.0": version: 5.1.0 resolution: "registry-url@npm:5.1.0" @@ -14713,6 +16647,15 @@ __metadata: languageName: node linkType: hard +"registry-url@npm:^6.0.0": + version: 6.0.1 + resolution: "registry-url@npm:6.0.1" + dependencies: + rc: 1.2.8 + checksum: 33712aa1b489aab7aba2191c1cdadfdd71f5bf166d4792d81744a6be332c160bd7d9273af8269d8a01284b9562f14a5b31b7abcf7ad9306c44887ecff51c89ab + languageName: node + linkType: hard + "regjsparser@npm:^0.9.1": version: 0.9.1 resolution: "regjsparser@npm:0.9.1" @@ -14724,27 +16667,29 @@ __metadata: languageName: node linkType: hard -"rehype-katex@npm:^5.0.0": - version: 5.0.0 - resolution: "rehype-katex@npm:5.0.0" +"rehype-katex@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-katex@npm:7.0.0" dependencies: - "@types/katex": ^0.11.0 - hast-util-to-text: ^2.0.0 - katex: ^0.13.0 - rehype-parse: ^7.0.0 - unified: ^9.0.0 - unist-util-visit: ^2.0.0 - checksum: b20e24c5326a718581619761057a30d03615519eccd0693ada2c7c710064dceaf08f038ae3a1131550f1f7c47ca54a254ba8e45547da384867e956ceca73f6bf + "@types/hast": ^3.0.0 + "@types/katex": ^0.16.0 + hast-util-from-html-isomorphic: ^2.0.0 + hast-util-to-text: ^4.0.0 + katex: ^0.16.0 + unist-util-visit-parents: ^6.0.0 + vfile: ^6.0.0 + checksum: 3184cf7635e63039a5d455e27718cbc99998cc7bfcc15422badf5da892887f4200f3ee54a6617aa231aa15d46cb678716c112b6b7f9cef11a8653e5d518ad6f0 languageName: node linkType: hard -"rehype-parse@npm:^7.0.0": - version: 7.0.1 - resolution: "rehype-parse@npm:7.0.1" +"rehype-raw@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-raw@npm:7.0.0" dependencies: - hast-util-from-parse5: ^6.0.0 - parse5: ^6.0.0 - checksum: c3c914aa9281853290eff6b09e0bed6843934e788b957e25219e91f0bf244a183d2f5e042c7d21543276571f9b49a6bae90f4640b8f885f2773392ffa57baf4b + "@types/hast": ^3.0.0 + hast-util-raw: ^9.0.0 + vfile: ^6.0.0 + checksum: f9e28dcbf4c6c7d91a97c10a840310f18ef3268aa45abb3e0428b6b191ff3c4fa8f753b910d768588a2dac5c7da7e557b4ddc3f1b6cd252e8d20cb62d60c65ed languageName: node linkType: hard @@ -14764,6 +16709,18 @@ __metadata: languageName: unknown linkType: soft +"remark-directive@npm:^3.0.0": + version: 3.0.0 + resolution: "remark-directive@npm:3.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-directive: ^3.0.0 + micromark-extension-directive: ^3.0.0 + unified: ^11.0.0 + checksum: 744d12bbe924bd0492a2481cbaf9250aa6622c0d2cc090bb7bc39975e355c8a46ae13cc4793204ada39f0af64c953f6b730a55420a50375e0f74a5dd5d201089 + languageName: node + linkType: hard + "remark-emoji@npm:^2.2.0": version: 2.2.0 resolution: "remark-emoji@npm:2.2.0" @@ -14775,6 +16732,19 @@ __metadata: languageName: node linkType: hard +"remark-emoji@npm:^4.0.0": + version: 4.0.1 + resolution: "remark-emoji@npm:4.0.1" + dependencies: + "@types/mdast": ^4.0.2 + emoticon: ^4.0.1 + mdast-util-find-and-replace: ^3.0.1 + node-emoji: ^2.1.0 + unified: ^11.0.4 + checksum: 2c02d8c0b694535a9f0c4fe39180cb89a8fbd07eb873c94842c34dfde566b8a6703df9d28fe175a8c28584f96252121de722862baa756f2d875f2f1a4352c1f4 + languageName: node + linkType: hard + "remark-footnotes@npm:2.0.0": version: 2.0.0 resolution: "remark-footnotes@npm:2.0.0" @@ -14782,10 +16752,41 @@ __metadata: languageName: node linkType: hard -"remark-math@npm:^3.0.1": - version: 3.0.1 - resolution: "remark-math@npm:3.0.1" - checksum: 690256f27f2b42dadcf41806fec443056e09592454622ae77f03b1a8474e8c83cc7610e694be7e17de92c96cc272c61209e59a6e7a24e3af6ede47d48b185ccd +"remark-frontmatter@npm:^5.0.0": + version: 5.0.0 + resolution: "remark-frontmatter@npm:5.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-frontmatter: ^2.0.0 + micromark-extension-frontmatter: ^2.0.0 + unified: ^11.0.0 + checksum: b36e11d528d1d0172489c74ce7961bb6073f7272e71ea1349f765fc79c4246a758aef949174d371a088c48e458af776fcfbb3b043c49cd1120ca8239aeafe16a + languageName: node + linkType: hard + +"remark-gfm@npm:^4.0.0": + version: 4.0.0 + resolution: "remark-gfm@npm:4.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-gfm: ^3.0.0 + micromark-extension-gfm: ^3.0.0 + remark-parse: ^11.0.0 + remark-stringify: ^11.0.0 + unified: ^11.0.0 + checksum: 84bea84e388061fbbb697b4b666089f5c328aa04d19dc544c229b607446bc10902e46b67b9594415a1017bbbd7c811c1f0c30d36682c6d1a6718b66a1558261b + languageName: node + linkType: hard + +"remark-math@npm:^6.0.0": + version: 6.0.0 + resolution: "remark-math@npm:6.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-math: ^3.0.0 + micromark-extension-math: ^3.0.0 + unified: ^11.0.0 + checksum: fef489acb6cae6e40af05012367dc22a846ce16301e8a96006c6d78935887bdb3e6c5018b6514884ecee57f9c7a51f97a10862526ab0a0f5f7b7d339fe0eb20f languageName: node linkType: hard @@ -14805,6 +16806,16 @@ __metadata: languageName: node linkType: hard +"remark-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "remark-mdx@npm:3.0.0" + dependencies: + mdast-util-mdx: ^3.0.0 + micromark-extension-mdxjs: ^3.0.0 + checksum: 8b9b3e5297e5cb4c312553f42c3720280ada96ae60ede880606924a0aad2e773106aba1ef45a0c179c218f8da6f58dac3c789a9c4f791649ca7a183706cde5b8 + languageName: node + linkType: hard + "remark-parse@npm:8.0.3": version: 8.0.3 resolution: "remark-parse@npm:8.0.3" @@ -14829,6 +16840,31 @@ __metadata: languageName: node linkType: hard +"remark-parse@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-parse@npm:11.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-from-markdown: ^2.0.0 + micromark-util-types: ^2.0.0 + unified: ^11.0.0 + checksum: d83d245290fa84bb04fb3e78111f09c74f7417e7c012a64dd8dc04fccc3699036d828fbd8eeec8944f774b6c30cc1d925c98f8c46495ebcee7c595496342ab7f + languageName: node + linkType: hard + +"remark-rehype@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-rehype@npm:11.0.0" + dependencies: + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + mdast-util-to-hast: ^13.0.0 + unified: ^11.0.0 + vfile: ^6.0.0 + checksum: 0ff0fd948759cbde9d507ca1581028d0b89da0b5f610b35a6cb0a511f8d11621449b6eca573b11ddaea77afd37edd4755f3f1eb086ad49a6f7b970b4a4634e13 + languageName: node + linkType: hard + "remark-squeeze-paragraphs@npm:4.0.0": version: 4.0.0 resolution: "remark-squeeze-paragraphs@npm:4.0.0" @@ -14838,6 +16874,17 @@ __metadata: languageName: node linkType: hard +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-to-markdown: ^2.0.0 + unified: ^11.0.0 + checksum: 59e07460eb629d6c3b3c0f438b0b236e7e6858fd5ab770303078f5a556ec00354d9c7fb9ef6d5f745a4617ac7da1ab618b170fbb4dac120e183fecd9cc86bce6 + languageName: node + linkType: hard + "renderkid@npm:^3.0.0": version: 3.0.0 resolution: "renderkid@npm:3.0.0" @@ -14851,7 +16898,7 @@ __metadata: languageName: node linkType: hard -"repeat-string@npm:^1.0.0, repeat-string@npm:^1.5.4": +"repeat-string@npm:^1.5.4": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 @@ -14886,12 +16933,10 @@ __metadata: languageName: node linkType: hard -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: ^5.0.0 - checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 +"resolve-alpn@npm:^1.2.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0 languageName: node linkType: hard @@ -14902,13 +16947,6 @@ __metadata: languageName: node linkType: hard -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf - languageName: node - linkType: hard - "resolve-path@npm:^1.4.0": version: 1.4.0 resolution: "resolve-path@npm:1.4.0" @@ -14926,6 +16964,13 @@ __metadata: languageName: node linkType: hard +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 1012afc566b3fdb190a6309cc37ef3b2dcc35dff5fa6683a9d00cd25c3247edfbc4691b91078c97adc82a29b77a2660c30d791d65dab4fc78bfc473f60289977 + languageName: node + linkType: hard + "resolve@npm:1.17.0": version: 1.17.0 resolution: "resolve@npm:1.17.0" @@ -14935,7 +16980,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.3.2": +"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.3.2": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -14948,19 +16993,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.19.0": - version: 1.22.6 - resolution: "resolve@npm:1.22.6" - dependencies: - is-core-module: ^2.13.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: d13bf66d4e2ee30d291491f16f2fa44edd4e0cefb85d53249dd6f93e70b2b8c20ec62f01b18662e3cd40e50a7528f18c4087a99490048992a3bb954cf3201a5b - languageName: node - linkType: hard - "resolve@patch:resolve@1.17.0#~builtin": version: 1.17.0 resolution: "resolve@patch:resolve@npm%3A1.17.0#~builtin::version=1.17.0&hash=c3c19d" @@ -14970,7 +17002,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.3.2#~builtin": +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.3.2#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -14983,19 +17015,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.19.0#~builtin": - version: 1.22.6 - resolution: "resolve@patch:resolve@npm%3A1.22.6#~builtin::version=1.22.6&hash=c3c19d" - dependencies: - is-core-module: ^2.13.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: 9d3b3c67aefd12cecbe5f10ca4d1f51ea190891096497c43f301b086883b426466918c3a64f1bbf1788fabb52b579d58809614006c5d0b49186702b3b8fb746a - languageName: node - linkType: hard - "responselike@npm:^1.0.2": version: 1.0.2 resolution: "responselike@npm:1.0.2" @@ -15005,6 +17024,15 @@ __metadata: languageName: node linkType: hard +"responselike@npm:^3.0.0": + version: 3.0.0 + resolution: "responselike@npm:3.0.0" + dependencies: + lowercase-keys: ^3.0.0 + checksum: e0cc9be30df4f415d6d83cdede3c5c887cd4a73e7cc1708bcaab1d50a28d15acb68460ac5b02bcc55a42f3d493729c8856427dcf6e57e6e128ad05cba4cfb95e + languageName: node + linkType: hard + "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -15094,23 +17122,23 @@ __metadata: linkType: hard "rtl-detect@npm:^1.0.4": - version: 1.0.4 - resolution: "rtl-detect@npm:1.0.4" - checksum: d562535baa0db62f57f0a1d4676297bff72fd6b94e88f0f0900d5c3e810ab512c5c4cadffd3e05fbe8d9c74310c919afa3ea8c1001c244e5555e8eef12d02d6f + version: 1.1.2 + resolution: "rtl-detect@npm:1.1.2" + checksum: 4a43a1e5df0617eb86d5485640b318787d12b86acf53d840a3b2ff701ee941e95479d4e9ae97e907569ec763d1c47218cb87639bc87bcdad60a85747e5270cf0 languageName: node linkType: hard -"rtlcss@npm:^3.5.0": - version: 3.5.0 - resolution: "rtlcss@npm:3.5.0" +"rtlcss@npm:^4.1.0": + version: 4.1.1 + resolution: "rtlcss@npm:4.1.1" dependencies: - find-up: ^5.0.0 + escalade: ^3.1.1 picocolors: ^1.0.0 - postcss: ^8.3.11 + postcss: ^8.4.21 strip-json-comments: ^3.1.1 bin: rtlcss: bin/rtlcss.js - checksum: a3763cad2cb58ce1b950de155097c3c294e7aefc8bf328b58d0cc8d5efb88bf800865edc158a78ace6d1f7f99fea6fd66fb4a354d859b172dadd3dab3e0027b3 + checksum: dcf37d76265b5c84d610488afa68a2506d008f95feac968b35ccae9aa49e7019ae0336a80363303f8f8bbf60df3ecdeb60413548b049114a24748319b68aefde languageName: node linkType: hard @@ -15194,13 +17222,12 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.20.2": - version: 0.20.2 - resolution: "scheduler@npm:0.20.2" +"scheduler@npm:^0.23.0": + version: 0.23.0 + resolution: "scheduler@npm:0.23.0" dependencies: loose-envify: ^1.1.0 - object-assign: ^4.1.1 - checksum: c4b35cf967c8f0d3e65753252d0f260271f81a81e427241295c5a7b783abf4ea9e905f22f815ab66676f5313be0a25f47be582254db8f9241b259213e999b8fc + checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a languageName: node linkType: hard @@ -15286,11 +17313,12 @@ __metadata: linkType: hard "selfsigned@npm:^2.1.1": - version: 2.1.1 - resolution: "selfsigned@npm:2.1.1" + version: 2.4.1 + resolution: "selfsigned@npm:2.4.1" dependencies: + "@types/node-forge": ^1.3.0 node-forge: ^1 - checksum: aa9ce2150a54838978d5c0aee54d7ebe77649a32e4e690eb91775f71fdff773874a4fbafd0ac73d8ec3b702ff8a395c604df4f8e8868528f36fd6c15076fb43a + checksum: 38b91c56f1d7949c0b77f9bbe4545b19518475cae15e7d7f0043f87b1626710b011ce89879a88969651f650a19d213bb15b7d5b4c2877df9eeeff7ba8f8b9bfa languageName: node linkType: hard @@ -15303,6 +17331,15 @@ __metadata: languageName: node linkType: hard +"semver-diff@npm:^4.0.0": + version: 4.0.0 + resolution: "semver-diff@npm:4.0.0" + dependencies: + semver: ^7.3.5 + checksum: 4a958d6f76c7e7858268e1e2cf936712542441c9e003e561b574167279eee0a9bd55cc7eae1bfb31d3e7ad06a9fc370e7dd412fcfefec8c0daf1ce5aea623559 + languageName: node + linkType: hard + "semver@npm:^5.4.1, semver@npm:^5.5.0": version: 5.7.2 resolution: "semver@npm:5.7.2" @@ -15353,15 +17390,6 @@ __metadata: languageName: node linkType: hard -"serialize-error@npm:^7.0.1": - version: 7.0.1 - resolution: "serialize-error@npm:7.0.1" - dependencies: - type-fest: ^0.13.1 - checksum: e0aba4dca2fc9fe74ae1baf38dbd99190e1945445a241ba646290f2176cdb2032281a76443b02ccf0caf30da5657d510746506368889a593b9835a497fc0732e - languageName: node - linkType: hard - "serialize-javascript@npm:6.0.0": version: 6.0.0 resolution: "serialize-javascript@npm:6.0.0" @@ -15380,7 +17408,7 @@ __metadata: languageName: node linkType: hard -"serve-handler@npm:^6.1.3": +"serve-handler@npm:6.1.5, serve-handler@npm:^6.1.3, serve-handler@npm:^6.1.5": version: 6.1.5 resolution: "serve-handler@npm:6.1.5" dependencies: @@ -15423,10 +17451,36 @@ __metadata: languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 +"serve@npm:^14.2.1": + version: 14.2.1 + resolution: "serve@npm:14.2.1" + dependencies: + "@zeit/schemas": 2.29.0 + ajv: 8.11.0 + arg: 5.0.2 + boxen: 7.0.0 + chalk: 5.0.1 + chalk-template: 0.4.0 + clipboardy: 3.0.0 + compression: 1.7.4 + is-port-reachable: 4.0.0 + serve-handler: 6.1.5 + update-check: 1.5.4 + bin: + serve: build/main.js + checksum: c39a517b5d795a0a5c2f9fb9ff088b7e4962c579e34ace5b85dd62f93e0eacbc8a90359792c153c444a83258ffda392113dff7bfd10d41ced574a2d1886c2994 + languageName: node + linkType: hard + +"set-function-length@npm:^1.1.1": + version: 1.1.1 + resolution: "set-function-length@npm:1.1.1" + dependencies: + define-data-property: ^1.1.1 + get-intrinsic: ^1.2.1 + gopd: ^1.0.1 + has-property-descriptors: ^1.0.0 + checksum: c131d7569cd7e110cafdfbfbb0557249b538477624dfac4fc18c376d879672fa52563b74029ca01f8f4583a8acb35bb1e873d573a24edb80d978a7ee607c6e06 languageName: node linkType: hard @@ -15516,14 +17570,14 @@ __metadata: linkType: hard "shiki@npm:^0.14.1": - version: 0.14.5 - resolution: "shiki@npm:0.14.5" + version: 0.14.6 + resolution: "shiki@npm:0.14.6" dependencies: ansi-sequence-parser: ^1.1.0 jsonc-parser: ^3.2.0 vscode-oniguruma: ^1.7.0 vscode-textmate: ^8.0.0 - checksum: 41d847817cfc9bb6d8bf190316896698d250303656546446659cc02caed8dcc171b10cd113bb5da82425b51d0032e87aafcdc36c3dd61dadc123170b438da736 + checksum: 24d9e29f93546118f1c07659e8a38f7dbf57b06479a0a9245e0823f7c988c825be53ad0b83a820e2eda5edbf3f0c6d17fad398b825130de1c11973e0bd7075fc languageName: node linkType: hard @@ -15584,6 +17638,15 @@ __metadata: languageName: node linkType: hard +"skin-tone@npm:^2.0.0": + version: 2.0.0 + resolution: "skin-tone@npm:2.0.0" + dependencies: + unicode-emoji-modifier-base: ^1.0.0 + checksum: 19de157586b8019cacc55eb25d9d640f00fc02415761f3e41a4527142970fd4e7f6af0333bc90e879858766c20a976107bb386ffd4c812289c01d51f2c8d182c + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -15603,19 +17666,9 @@ __metadata: resolution: "slice-ansi@npm:4.0.0" dependencies: ansi-styles: ^4.0.0 - astral-regex: ^2.0.0 - is-fullwidth-code-point: ^3.0.0 - checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 - languageName: node - linkType: hard - -"slice-ansi@npm:^5.0.0": - version: 5.0.0 - resolution: "slice-ansi@npm:5.0.0" - dependencies: - ansi-styles: ^6.0.0 - is-fullwidth-code-point: ^4.0.0 - checksum: 7e600a2a55e333a21ef5214b987c8358fe28bfb03c2867ff2cbf919d62143d1812ac27b4297a077fdaf27a03da3678e49551c93e35f9498a3d90221908a1180e + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 languageName: node linkType: hard @@ -15627,9 +17680,9 @@ __metadata: linkType: hard "smol-toml@npm:^1.1.2": - version: 1.1.2 - resolution: "smol-toml@npm:1.1.2" - checksum: aa984b8d7aadb9c7db601533f81bcc0e7b6773fe56b69e87fb06224ac0c22702900b927becf0f5af0250b29746648344b57ecbcc203e82d667d46a19e1a61d77 + version: 1.1.3 + resolution: "smol-toml@npm:1.1.3" + checksum: 7948c0823b3d8db9ebf7d6dc706f75ea2bc55fa0233e6fccabc2ae3be0f1410da4617d9e3db0708a6434cfd35e13c2bc453300fa4ab11dde3da5df1c166feb39 languageName: node linkType: hard @@ -15644,18 +17697,18 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" +"socks-proxy-agent@npm:^8.0.1": + version: 8.0.2 + resolution: "socks-proxy-agent@npm:8.0.2" dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 + agent-base: ^7.0.2 + debug: ^4.3.4 + socks: ^2.7.1 + checksum: 4fb165df08f1f380881dcd887b3cdfdc1aba3797c76c1e9f51d29048be6e494c5b06d68e7aea2e23df4572428f27a3ec22b3d7c75c570c5346507433899a4b6d languageName: node linkType: hard -"socks@npm:^2.6.2": +"socks@npm:^2.7.1": version: 2.7.1 resolution: "socks@npm:2.7.1" dependencies: @@ -15722,7 +17775,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.7.3": +"source-map@npm:^0.7.0, source-map@npm:^0.7.3": version: 0.7.4 resolution: "source-map@npm:0.7.4" checksum: 01cc5a74b1f0e1d626a58d36ad6898ea820567e87f18dfc9d24a9843a351aaa2ec09b87422589906d6ff1deed29693e176194dc88bcae7c9a852dc74b311dbf5 @@ -15736,6 +17789,13 @@ __metadata: languageName: node linkType: hard +"space-separated-tokens@npm:^2.0.0": + version: 2.0.2 + resolution: "space-separated-tokens@npm:2.0.2" + checksum: 202e97d7ca1ba0758a0aa4fe226ff98142073bcceeff2da3aad037968878552c3bbce3b3231970025375bbba5aee00c5b8206eda408da837ab2dc9c0f26be990 + languageName: node + linkType: hard + "spdy-transport@npm:^3.0.0": version: 3.0.0 resolution: "spdy-transport@npm:3.0.0" @@ -15779,6 +17839,13 @@ __metadata: languageName: node linkType: hard +"srcset@npm:^4.0.0": + version: 4.0.0 + resolution: "srcset@npm:4.0.0" + checksum: aceb898c9281101ef43bfbf96bf04dfae828e1bf942a45df6fad74ae9f8f0a425f4bca1480e0d22879beb40dd2bc6947e0e1e5f4d307a714666196164bc5769d + languageName: node + linkType: hard + "ssri@npm:^10.0.0": version: 10.0.5 resolution: "ssri@npm:10.0.5" @@ -15795,15 +17862,6 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.6": - version: 2.0.6 - resolution: "stack-utils@npm:2.0.6" - dependencies: - escape-string-regexp: ^2.0.0 - checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 - languageName: node - linkType: hard - "stacktrace-parser@npm:^0.1.10": version: 0.1.10 resolution: "stacktrace-parser@npm:0.1.10" @@ -15813,6 +17871,13 @@ __metadata: languageName: node linkType: hard +"state-local@npm:^1.0.6": + version: 1.0.7 + resolution: "state-local@npm:1.0.7" + checksum: d1afcf1429e7e6eb08685b3a94be8797db847369316d4776fd51f3962b15b984dacc7f8e401ad20968e5798c9565b4b377afedf4e4c4d60fe7495e1cbe14a251 + languageName: node + linkType: hard + "state-toggle@npm:^1.0.0": version: 1.0.3 resolution: "state-toggle@npm:1.0.3" @@ -15835,9 +17900,9 @@ __metadata: linkType: hard "std-env@npm:^3.0.1": - version: 3.4.3 - resolution: "std-env@npm:3.4.3" - checksum: bef186fb2baddda31911234b1e58fa18f181eb6930616aaec3b54f6d5db65f2da5daaa5f3b326b98445a7d50ca81d6fe8809ab4ebab85ecbe4a802f1b40921bf + version: 3.6.0 + resolution: "std-env@npm:3.6.0" + checksum: ec344e93af17fd1b71eb28aeb4712f72790b9f2363981fc91ad1a91c9c7967c1ab89271819242d1b3bdbd57f10ac8ef0559d561ccf081a5377f9b3cd8c9b2259 languageName: node linkType: hard @@ -15873,7 +17938,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -15884,7 +17949,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2": +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": version: 5.1.2 resolution: "string-width@npm:5.1.2" dependencies: @@ -15913,6 +17978,16 @@ __metadata: languageName: node linkType: hard +"stringify-entities@npm:^4.0.0": + version: 4.0.3 + resolution: "stringify-entities@npm:4.0.3" + dependencies: + character-entities-html4: ^2.0.0 + character-entities-legacy: ^3.0.0 + checksum: 59e8f523b403bf7d415690e72ae52982decd6ea5426bd8b3f5c66225ddde73e766c0c0d91627df082d0794e30b19dd907ffb5864cef3602e4098d6777d7ca3c2 + languageName: node + linkType: hard + "stringify-object@npm:^3.3.0": version: 3.3.0 resolution: "stringify-object@npm:3.3.0" @@ -15995,6 +18070,24 @@ __metadata: languageName: node linkType: hard +"style-to-object@npm:^0.4.0": + version: 0.4.4 + resolution: "style-to-object@npm:0.4.4" + dependencies: + inline-style-parser: 0.1.1 + checksum: 41656c06f93ac0a7ac260ebc2f9d09a8bd74b8ec1836f358cc58e169235835a3a356977891d2ebbd76f0e08a53616929069199f9cce543214d3dc98346e19c9a + languageName: node + linkType: hard + +"style-to-object@npm:^1.0.0": + version: 1.0.5 + resolution: "style-to-object@npm:1.0.5" + dependencies: + inline-style-parser: 0.2.2 + checksum: 6201063204b6a94645f81b189452b2ca3e63d61867ec48523f4d52609c81e96176739fa12020d97fbbf023efb57a6f7ec3a15fb3a7fb7eb3ffea0b52b9dd6b8c + languageName: node + linkType: hard + "stylehacks@npm:^5.1.1": version: 5.1.1 resolution: "stylehacks@npm:5.1.1" @@ -16014,18 +18107,6 @@ __metadata: languageName: node linkType: hard -"supertap@npm:^3.0.1": - version: 3.0.1 - resolution: "supertap@npm:3.0.1" - dependencies: - indent-string: ^5.0.0 - js-yaml: ^3.14.1 - serialize-error: ^7.0.1 - strip-ansi: ^7.0.1 - checksum: ee3d71c1d25f7f15d4a849e72b0c5f430df7cd8f702cf082fdbec5642a9546be6557766745655fa3a3e9c88f7c7eed849f2d74457b5b72cb9d94a779c0c8a948 - languageName: node - linkType: hard - "supports-color@npm:8.1.1, supports-color@npm:^8.0.0": version: 8.1.1 resolution: "supports-color@npm:8.1.1" @@ -16085,12 +18166,12 @@ __metadata: linkType: hard "synckit@npm:^0.8.5": - version: 0.8.5 - resolution: "synckit@npm:0.8.5" + version: 0.8.6 + resolution: "synckit@npm:0.8.6" dependencies: - "@pkgr/utils": ^2.3.1 - tslib: ^2.5.0 - checksum: 8a9560e5d8f3d94dc3cf5f7b9c83490ffa30d320093560a37b88f59483040771fd1750e76b9939abfbb1b5a23fd6dfbae77f6b338abffe7cae7329cd9b9bb86b + "@pkgr/utils": ^2.4.2 + tslib: ^2.6.2 + checksum: 7c1f4991d0afd63c090c0537f1cf8619dd5777a40cf83bf46beadbf4eb0f9e400d92044e90a177a305df4bcb56efbaf1b689877f301f2672d865b6eecf1be75a languageName: node linkType: hard @@ -16176,14 +18257,7 @@ __metadata: languageName: node linkType: hard -"temp-dir@npm:^3.0.0": - version: 3.0.0 - resolution: "temp-dir@npm:3.0.0" - checksum: 577211e995d1d584dd60f1469351d45e8a5b4524e4a9e42d3bdd12cfde1d0bb8f5898311bef24e02aaafb69514c1feb58c7b4c33dcec7129da3b0861a4ca935b - languageName: node - linkType: hard - -"terser-webpack-plugin@npm:^5.3.3, terser-webpack-plugin@npm:^5.3.7": +"terser-webpack-plugin@npm:^5.3.3, terser-webpack-plugin@npm:^5.3.7, terser-webpack-plugin@npm:^5.3.9": version: 5.3.9 resolution: "terser-webpack-plugin@npm:5.3.9" dependencies: @@ -16205,9 +18279,9 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.10.0, terser@npm:^5.16.8": - version: 5.21.0 - resolution: "terser@npm:5.21.0" +"terser@npm:^5.10.0, terser@npm:^5.15.1, terser@npm:^5.16.8": + version: 5.26.0 + resolution: "terser@npm:5.26.0" dependencies: "@jridgewell/source-map": ^0.3.3 acorn: ^8.8.2 @@ -16215,7 +18289,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 130f1567af1ffa4ddb067651bb284a01b45b5c83e82b3a072a5ff94b0b00ac35090f89c8714631a4a45972f65187bc149fc7144380611f437e1e3d9e174b136b + checksum: 02a9bb896f04df828025af8f0eced36c315d25d310b6c2418e7dad2bed19ddeb34a9cea9b34e7c24789830fa51e1b6a9be26679980987a9c817a7e6d9cd4154b languageName: node linkType: hard @@ -16240,13 +18314,6 @@ __metadata: languageName: node linkType: hard -"time-zone@npm:^1.0.0": - version: 1.0.0 - resolution: "time-zone@npm:1.0.0" - checksum: e46f5a69b8c236dcd8e91e29d40d4e7a3495ed4f59888c3f84ce1d9678e20461421a6ba41233509d47dd94bc18f1a4377764838b21b584663f942b3426dcbce8 - languageName: node - linkType: hard - "tiny-invariant@npm:^1.0.2": version: 1.3.1 resolution: "tiny-invariant@npm:1.3.1" @@ -16337,6 +18404,13 @@ __metadata: languageName: node linkType: hard +"trim-lines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-lines@npm:3.0.1" + checksum: e241da104682a0e0d807222cc1496b92e716af4db7a002f4aeff33ae6a0024fef93165d49eab11aa07c71e1347c42d46563f91dfaa4d3fb945aa535cdead53ed + languageName: node + linkType: hard + "trim-trailing-lines@npm:^1.0.0": version: 1.1.4 resolution: "trim-trailing-lines@npm:1.1.4" @@ -16358,6 +18432,13 @@ __metadata: languageName: node linkType: hard +"trough@npm:^2.0.0": + version: 2.1.0 + resolution: "trough@npm:2.1.0" + checksum: a577bb561c2b401cc0e1d9e188fcfcdf63b09b151ff56a668da12197fe97cac15e3d77d5b51f426ccfd94255744a9118e9e9935afe81a3644fa1be9783c82886 + languageName: node + linkType: hard + "ts-api-utils@npm:^1.0.1": version: 1.0.3 resolution: "ts-api-utils@npm:1.0.3" @@ -16382,8 +18463,8 @@ __metadata: linkType: hard "ts-node@npm:^10.9.1": - version: 10.9.1 - resolution: "ts-node@npm:10.9.1" + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" dependencies: "@cspotcode/source-map-support": ^0.8.0 "@tsconfig/node10": ^1.0.7 @@ -16415,7 +18496,7 @@ __metadata: ts-node-script: dist/bin-script.js ts-node-transpile-only: dist/bin-transpile.js ts-script: dist/bin-script-deprecated.js - checksum: 090adff1302ab20bd3486e6b4799e90f97726ed39e02b39e566f8ab674fd5bd5f727f43615debbfc580d33c6d9d1c6b1b3ce7d8e3cca3e20530a145ffa232c35 + checksum: fde256c9073969e234526e2cfead42591b9a2aec5222bac154b0de2fa9e4ceb30efcd717ee8bc785a56f3a119bdd5aa27b333d9dbec94ed254bd26f8944c67ac languageName: node linkType: hard @@ -16455,7 +18536,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0": +"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad @@ -16483,6 +18564,22 @@ __metadata: languageName: node linkType: hard +"tsx@npm:^4.6.2": + version: 4.6.2 + resolution: "tsx@npm:4.6.2" + dependencies: + esbuild: ~0.18.20 + fsevents: ~2.3.3 + get-tsconfig: ^4.7.2 + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: a9f13bdb67bfb316bbfc92303d8464323ab1b673aa93ea97271c211a8ba7c59274d4b32eeec5ad8fbd0b04260a092a3ad2116abeb6913254ba456010ff685743 + languageName: node + linkType: hard + "tweetnacl-util@npm:^0.15.1": version: 0.15.1 resolution: "tweetnacl-util@npm:0.15.1" @@ -16506,20 +18603,13 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": +"type-detect@npm:^4.0.0, type-detect@npm:^4.0.8": version: 4.0.8 resolution: "type-detect@npm:4.0.8" checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 languageName: node linkType: hard -"type-fest@npm:^0.13.1": - version: 0.13.1 - resolution: "type-fest@npm:0.13.1" - checksum: e6bf2e3c449f27d4ef5d56faf8b86feafbc3aec3025fc9a5fbe2db0a2587c44714521f9c30d8516a833c8c506d6263f5cc11267522b10c6ccdb6cc55b0a9d1c4 - languageName: node - linkType: hard - "type-fest@npm:^0.20.2": version: 0.20.2 resolution: "type-fest@npm:0.20.2" @@ -16541,7 +18631,14 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^2.5.0": +"type-fest@npm:^1.0.1": + version: 1.4.0 + resolution: "type-fest@npm:1.4.0" + checksum: b011c3388665b097ae6a109a437a04d6f61d81b7357f74cbcb02246f2f5bd72b888ae33631b99871388122ba0a87f4ff1c94078e7119ff22c70e52c0ff828201 + languageName: node + linkType: hard + +"type-fest@npm:^2.13.0, type-fest@npm:^2.5.0": version: 2.19.0 resolution: "type-fest@npm:2.19.0" checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 @@ -16595,28 +18692,18 @@ __metadata: linkType: hard "typedoc@npm:^0.25.0": - version: 0.25.2 - resolution: "typedoc@npm:0.25.2" + version: 0.25.4 + resolution: "typedoc@npm:0.25.4" dependencies: lunr: ^2.3.9 marked: ^4.3.0 minimatch: ^9.0.3 shiki: ^0.14.1 peerDependencies: - typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x bin: typedoc: bin/typedoc - checksum: 5b6e24bae7498bb542aaba495378ed5a3e13c76eb04a1ae95b506f76bda4d517847101fb05a7eab3f6b79357d1e2ac6f4747d39792395329b72e463f7effda65 - languageName: node - linkType: hard - -"typescript@npm:4.9.4": - version: 4.9.4 - resolution: "typescript@npm:4.9.4" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: e782fb9e0031cb258a80000f6c13530288c6d63f1177ed43f770533fdc15740d271554cdae86701c1dd2c83b082cea808b07e97fd68b38a172a83dbf9e0d0ef9 + checksum: 6d441baa277c0db4d577db2932a7af316d175415841e2faf2e68e3eda6ad60356c54f56374f89c5233d7bd5c057b0337455e5d484d8463e1445e67c37a6d94eb languageName: node linkType: hard @@ -16631,22 +18718,22 @@ __metadata: linkType: hard "typescript@npm:^5.0.4, typescript@npm:^5.2.2": - version: 5.2.2 - resolution: "typescript@npm:5.2.2" + version: 5.3.3 + resolution: "typescript@npm:5.3.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c + checksum: 2007ccb6e51bbbf6fde0a78099efe04dc1c3dfbdff04ca3b6a8bc717991862b39fd6126c0c3ebf2d2d98ac5e960bcaa873826bb2bb241f14277034148f41f6a2 languageName: node linkType: hard -"typescript@patch:typescript@4.9.4#~builtin": - version: 4.9.4 - resolution: "typescript@patch:typescript@npm%3A4.9.4#~builtin::version=4.9.4&hash=289587" +"typescript@npm:~5.2.2": + version: 5.2.2 + resolution: "typescript@npm:5.2.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 2160f7ad975c59b2f5816817d3916be1d156c5688a7517602b3b640c5015e740f4ba933996ac85371d68f7bbdd41602150fb8b68334122ac637fdb5418085e7a + checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c languageName: node linkType: hard @@ -16661,6 +18748,16 @@ __metadata: linkType: hard "typescript@patch:typescript@^5.0.4#~builtin, typescript@patch:typescript@^5.2.2#~builtin": + version: 5.3.3 + resolution: "typescript@patch:typescript@npm%3A5.3.3#~builtin::version=5.3.3&hash=f3b441" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: f61375590b3162599f0f0d5b8737877ac0a7bc52761dbb585d67e7b8753a3a4c42d9a554c4cc929f591ffcf3a2b0602f65ae3ce74714fd5652623a816862b610 + languageName: node + linkType: hard + +"typescript@patch:typescript@~5.2.2#~builtin": version: 5.2.2 resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=f3b441" bin: @@ -16691,10 +18788,10 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^1.0.33, ua-parser-js@npm:^1.0.35": - version: 1.0.36 - resolution: "ua-parser-js@npm:1.0.36" - checksum: 5b2c8a5e3443dfbba7624421805de946457c26ae167cb2275781a2729d1518f7067c9d5c74c3b0acac4b9ff3278cae4eace08ca6eecb63848bc3b2f6a63cc975 +"ua-parser-js@npm:^1.0.33": + version: 1.0.37 + resolution: "ua-parser-js@npm:1.0.37" + checksum: 4d481c720d523366d7762dc8a46a1b58967d979aacf786f9ceceb1cd767de069f64a4bdffb63956294f1c0696eb465ddb950f28ba90571709e33521b4bd75e07 languageName: node linkType: hard @@ -16708,12 +18805,19 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 3192ef6f3fd5df652f2dc1cd782b49d6ff14dc98e5dced492aa8a8c65425227da5da6aafe22523c67f035a272c599bb89cfe803c1db6311e44bed3042fc25487 + languageName: node + linkType: hard + "undici@npm:^5.14.0": - version: 5.25.3 - resolution: "undici@npm:5.25.3" + version: 5.28.2 + resolution: "undici@npm:5.28.2" dependencies: "@fastify/busboy": ^2.0.0 - checksum: 65b814b7d8b06dab2d41c250d123663fe94edb78cf1a891cf3476569ea66dc425c7d4ba52b91d6f8ed6eba24613dd28e4a5070c372063532c3b997cd343ccc96 + checksum: f9e9335803f962fff07c3c11c6d50bbc76248bacf97035047155adb29c3622a65bd6bff23a22218189740133149d22e63b68131d8c40e78ac6cb4b6d686a6dfa languageName: node linkType: hard @@ -16734,6 +18838,13 @@ __metadata: languageName: node linkType: hard +"unicode-emoji-modifier-base@npm:^1.0.0": + version: 1.0.0 + resolution: "unicode-emoji-modifier-base@npm:1.0.0" + checksum: 6e1521d35fa69493207eb8b41f8edb95985d8b3faf07c01d820a1830b5e8403e20002563e2f84683e8e962a49beccae789f0879356bf92a4ec7a4dd8e2d16fdb + languageName: node + linkType: hard + "unicode-match-property-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-match-property-ecmascript@npm:2.0.0" @@ -16772,7 +18883,22 @@ __metadata: languageName: node linkType: hard -"unified@npm:^9.0.0, unified@npm:^9.2.2": +"unified@npm:^11.0.0, unified@npm:^11.0.3, unified@npm:^11.0.4": + version: 11.0.4 + resolution: "unified@npm:11.0.4" + dependencies: + "@types/unist": ^3.0.0 + bail: ^2.0.0 + devlop: ^1.0.0 + extend: ^3.0.0 + is-plain-obj: ^4.0.0 + trough: ^2.0.0 + vfile: ^6.0.0 + checksum: cfb023913480ac2bd5e787ffb8c27782c43e6be4a55f8f1c288233fce46a7ebe7718ccc5adb80bf8d56b7ef85f5fc32239c7bfccda006f9f2382e0cc2e2a77e4 + languageName: node + linkType: hard + +"unified@npm:^9.2.2": version: 9.2.2 resolution: "unified@npm:9.2.2" dependencies: @@ -16813,6 +18939,15 @@ __metadata: languageName: node linkType: hard +"unique-string@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-string@npm:3.0.0" + dependencies: + crypto-random-string: ^4.0.0 + checksum: 1a1e2e7d02eab1bb10f720475da735e1990c8a5ff34edd1a3b6bc31590cb4210b7a1233d779360cc622ce11c211e43afa1628dd658f35d3e6a89964b622940df + languageName: node + linkType: hard + "unist-builder@npm:2.0.3, unist-builder@npm:^2.0.0": version: 2.0.3 resolution: "unist-builder@npm:2.0.3" @@ -16820,12 +18955,13 @@ __metadata: languageName: node linkType: hard -"unist-util-find-after@npm:^3.0.0": - version: 3.0.0 - resolution: "unist-util-find-after@npm:3.0.0" +"unist-util-find-after@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-find-after@npm:5.0.0" dependencies: - unist-util-is: ^4.0.0 - checksum: daa9a28f6cdf533a72ce7ec4864dbe0f11f0fd3efd337b54c08a8a9a47cdc8d10a299cd984d7f512a57e97af012df052210a51aab7c9afd6b1e24da3b2d0a714 + "@types/unist": ^3.0.0 + unist-util-is: ^6.0.0 + checksum: e64bd5ebee7ac021cf990bf33e9ec29fc6452159187d4a7fa0f77334bea8e378fea7a7fb0bcf957300b2ffdba902ff25b62c165fc8b86309613da35ad793ada0 languageName: node linkType: hard @@ -16843,6 +18979,24 @@ __metadata: languageName: node linkType: hard +"unist-util-is@npm:^6.0.0": + version: 6.0.0 + resolution: "unist-util-is@npm:6.0.0" + dependencies: + "@types/unist": ^3.0.0 + checksum: f630a925126594af9993b091cf807b86811371e465b5049a6283e08537d3e6ba0f7e248e1e7dab52cfe33f9002606acef093441137181b327f6fe504884b20e2 + languageName: node + linkType: hard + +"unist-util-position-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "unist-util-position-from-estree@npm:2.0.0" + dependencies: + "@types/unist": ^3.0.0 + checksum: d3b3048a5727c2367f64ef6dcc5b20c4717215ef8b1372ff9a7c426297c5d1e5776409938acd01531213e2cd2543218d16e73f9f862f318e9496e2c73bb18354 + languageName: node + linkType: hard + "unist-util-position@npm:^3.0.0": version: 3.1.0 resolution: "unist-util-position@npm:3.1.0" @@ -16850,6 +19004,15 @@ __metadata: languageName: node linkType: hard +"unist-util-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-position@npm:5.0.0" + dependencies: + "@types/unist": ^3.0.0 + checksum: f89b27989b19f07878de9579cd8db2aa0194c8360db69e2c99bd2124a480d79c08f04b73a64daf01a8fb3af7cba65ff4b45a0b978ca243226084ad5f5d441dde + languageName: node + linkType: hard + "unist-util-remove-position@npm:^2.0.0": version: 2.0.1 resolution: "unist-util-remove-position@npm:2.0.1" @@ -16859,6 +19022,16 @@ __metadata: languageName: node linkType: hard +"unist-util-remove-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-remove-position@npm:5.0.0" + dependencies: + "@types/unist": ^3.0.0 + unist-util-visit: ^5.0.0 + checksum: 8aabdb9d0e3e744141bc123d8f87b90835d521209ad3c6c4619d403b324537152f0b8f20dda839b40c3aa0abfbf1828b3635a7a8bb159c3ed469e743023510ee + languageName: node + linkType: hard + "unist-util-remove@npm:^2.0.0": version: 2.1.0 resolution: "unist-util-remove@npm:2.1.0" @@ -16877,6 +19050,15 @@ __metadata: languageName: node linkType: hard +"unist-util-stringify-position@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-stringify-position@npm:4.0.0" + dependencies: + "@types/unist": ^3.0.0 + checksum: e2e7aee4b92ddb64d314b4ac89eef7a46e4c829cbd3ee4aee516d100772b490eb6b4974f653ba0717a0071ca6ea0770bf22b0a2ea62c65fcba1d071285e96324 + languageName: node + linkType: hard + "unist-util-visit-parents@npm:^3.0.0": version: 3.1.1 resolution: "unist-util-visit-parents@npm:3.1.1" @@ -16887,6 +19069,16 @@ __metadata: languageName: node linkType: hard +"unist-util-visit-parents@npm:^6.0.0": + version: 6.0.1 + resolution: "unist-util-visit-parents@npm:6.0.1" + dependencies: + "@types/unist": ^3.0.0 + unist-util-is: ^6.0.0 + checksum: 08927647c579f63b91aafcbec9966dc4a7d0af1e5e26fc69f4e3e6a01215084835a2321b06f3cbe7bf7914a852830fc1439f0fc3d7153d8804ac3ef851ddfa20 + languageName: node + linkType: hard + "unist-util-visit@npm:2.0.3, unist-util-visit@npm:^2.0.0, unist-util-visit@npm:^2.0.3": version: 2.0.3 resolution: "unist-util-visit@npm:2.0.3" @@ -16898,6 +19090,17 @@ __metadata: languageName: node linkType: hard +"unist-util-visit@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-visit@npm:5.0.0" + dependencies: + "@types/unist": ^3.0.0 + unist-util-is: ^6.0.0 + unist-util-visit-parents: ^6.0.0 + checksum: 9ec42e618e7e5d0202f3c191cd30791b51641285732767ee2e6bcd035931032e3c1b29093f4d7fd0c79175bbc1f26f24f26ee49770d32be76f8730a652a857e6 + languageName: node + linkType: hard + "universalify@npm:^0.1.0": version: 0.1.2 resolution: "universalify@npm:0.1.2" @@ -16906,9 +19109,9 @@ __metadata: linkType: hard "universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 languageName: node linkType: hard @@ -16940,6 +19143,16 @@ __metadata: languageName: node linkType: hard +"update-check@npm:1.5.4": + version: 1.5.4 + resolution: "update-check@npm:1.5.4" + dependencies: + registry-auth-token: 3.3.2 + registry-url: 3.1.0 + checksum: 2c9f7de6f030364c5ea02a341e5ae2dfe76da6559b32d40dd3b047b3ac0927408cf92d322c51cd8e009688210a85ccbf1eba449762a65a0d1b14f3cdf1ea5c48 + languageName: node + linkType: hard + "update-notifier@npm:^5.1.0": version: 5.1.0 resolution: "update-notifier@npm:5.1.0" @@ -16962,6 +19175,28 @@ __metadata: languageName: node linkType: hard +"update-notifier@npm:^6.0.2": + version: 6.0.2 + resolution: "update-notifier@npm:6.0.2" + dependencies: + boxen: ^7.0.0 + chalk: ^5.0.1 + configstore: ^6.0.0 + has-yarn: ^3.0.0 + import-lazy: ^4.0.0 + is-ci: ^3.0.1 + is-installed-globally: ^0.4.0 + is-npm: ^6.0.0 + is-yarn-global: ^0.4.0 + latest-version: ^7.0.0 + pupa: ^3.1.0 + semver: ^7.3.7 + semver-diff: ^4.0.0 + xdg-basedir: ^5.1.0 + checksum: 4bae7b3eca7b2068b6b87dde88c9dad24831fa913a5b83ecb39a7e4702c93e8b05fd9bcac5f1a005178f6e5dc859e0b3817ddda833d2a7ab92c6485e078b3cc8 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -16997,50 +19232,6 @@ __metadata: languageName: node linkType: hard -"use-composed-ref@npm:^1.3.0": - version: 1.3.0 - resolution: "use-composed-ref@npm:1.3.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: f771cbadfdc91e03b7ab9eb32d0fc0cc647755711801bf507e891ad38c4bbc5f02b2509acadf9c965ec9c5f2f642fd33bdfdfb17b0873c4ad0a9b1f5e5e724bf - languageName: node - linkType: hard - -"use-isomorphic-layout-effect@npm:^1.1.1": - version: 1.1.2 - resolution: "use-isomorphic-layout-effect@npm:1.1.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: a6532f7fc9ae222c3725ff0308aaf1f1ddbd3c00d685ef9eee6714fd0684de5cb9741b432fbf51e61a784e2955424864f7ea9f99734a02f237b17ad3e18ea5cb - languageName: node - linkType: hard - -"use-latest@npm:^1.2.1": - version: 1.2.1 - resolution: "use-latest@npm:1.2.1" - dependencies: - use-isomorphic-layout-effect: ^1.1.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: ed3f2ddddf6f21825e2ede4c2e0f0db8dcce5129802b69d1f0575fc1b42380436e8c76a6cd885d4e9aa8e292e60fb8b959c955f33c6a9123b83814a1a1875367 - languageName: node - linkType: hard - -"use-sync-external-store@npm:^1.2.0": - version: 1.2.0 - resolution: "use-sync-external-store@npm:1.2.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a - languageName: node - linkType: hard - "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -17100,13 +19291,13 @@ __metadata: linkType: hard "v8-to-istanbul@npm:^9.0.1": - version: 9.1.0 - resolution: "v8-to-istanbul@npm:9.1.0" + version: 9.2.0 + resolution: "v8-to-istanbul@npm:9.2.0" dependencies: "@jridgewell/trace-mapping": ^0.3.12 "@types/istanbul-lib-coverage": ^2.0.1 - convert-source-map: ^1.6.0 - checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 + convert-source-map: ^2.0.0 + checksum: 31ef98c6a31b1dab6be024cf914f235408cd4c0dc56a5c744a5eea1a9e019ba279e1b6f90d695b78c3186feed391ed492380ccf095009e2eb91f3d058f0b4491 languageName: node linkType: hard @@ -17131,6 +19322,16 @@ __metadata: languageName: node linkType: hard +"vfile-location@npm:^5.0.0": + version: 5.0.2 + resolution: "vfile-location@npm:5.0.2" + dependencies: + "@types/unist": ^3.0.0 + vfile: ^6.0.0 + checksum: b61c048cedad3555b4f007f390412c6503f58a6a130b58badf4ee340c87e0d7421e9c86bbc1494c57dedfccadb60f5176cc60ba3098209d99fb3a3d8804e4c38 + languageName: node + linkType: hard + "vfile-message@npm:^2.0.0": version: 2.0.4 resolution: "vfile-message@npm:2.0.4" @@ -17141,6 +19342,16 @@ __metadata: languageName: node linkType: hard +"vfile-message@npm:^4.0.0": + version: 4.0.2 + resolution: "vfile-message@npm:4.0.2" + dependencies: + "@types/unist": ^3.0.0 + unist-util-stringify-position: ^4.0.0 + checksum: 964e7e119f4c0e0270fc269119c41c96da20afa01acb7c9809a88365c8e0c64aa692fafbd952669382b978002ecd7ad31ef4446d85e8a22cdb62f6df20186c2d + languageName: node + linkType: hard + "vfile@npm:^4.0.0": version: 4.2.1 resolution: "vfile@npm:4.2.1" @@ -17153,6 +19364,17 @@ __metadata: languageName: node linkType: hard +"vfile@npm:^6.0.0, vfile@npm:^6.0.1": + version: 6.0.1 + resolution: "vfile@npm:6.0.1" + dependencies: + "@types/unist": ^3.0.0 + unist-util-stringify-position: ^4.0.0 + vfile-message: ^4.0.0 + checksum: 05ccee73aeb00402bc8a5d0708af299e9f4a33f5132805449099295085e3ca3b0d018328bad9ff44cf2e6f4cd364f1d558d3fb9b394243a25b2739207edcb0ed + languageName: node + linkType: hard + "vscode-oniguruma@npm:^1.7.0": version: 1.7.0 resolution: "vscode-oniguruma@npm:1.7.0" @@ -17208,6 +19430,13 @@ __metadata: languageName: node linkType: hard +"web-namespaces@npm:^2.0.0": + version: 2.0.1 + resolution: "web-namespaces@npm:2.0.1" + checksum: b6d9f02f1a43d0ef0848a812d89c83801d5bbad57d8bb61f02eb6d7eb794c3736f6cc2e1191664bb26136594c8218ac609f4069722c6f56d9fc2d808fa9271c6 + languageName: node + linkType: hard + "web-streams-polyfill@npm:^3.0.3": version: 3.2.1 resolution: "web-streams-polyfill@npm:3.2.1" @@ -17229,30 +19458,26 @@ __metadata: languageName: node linkType: hard -"webpack-bundle-analyzer@npm:^4.5.0": - version: 4.9.1 - resolution: "webpack-bundle-analyzer@npm:4.9.1" +"webpack-bundle-analyzer@npm:^4.5.0, webpack-bundle-analyzer@npm:^4.9.0": + version: 4.10.1 + resolution: "webpack-bundle-analyzer@npm:4.10.1" dependencies: "@discoveryjs/json-ext": 0.5.7 acorn: ^8.0.4 acorn-walk: ^8.0.0 commander: ^7.2.0 + debounce: ^1.2.1 escape-string-regexp: ^4.0.0 gzip-size: ^6.0.0 + html-escaper: ^2.0.2 is-plain-object: ^5.0.0 - lodash.debounce: ^4.0.8 - lodash.escape: ^4.0.1 - lodash.flatten: ^4.4.0 - lodash.invokemap: ^4.6.0 - lodash.pullall: ^4.2.0 - lodash.uniqby: ^4.7.0 opener: ^1.5.2 picocolors: ^1.0.0 sirv: ^2.0.3 ws: ^7.3.1 bin: webpack-bundle-analyzer: lib/bin/analyzer.js - checksum: 7e891c28d5a903242893e55ecc714fa01d7ad6bedade143235c07091b235915349812fa048968462781d59187507962f38b6c61ed7d25fb836ba0ac0ee919a39 + checksum: 77f48f10a493b1cc95674526472978a2de32412ddbf556bd3903738f14890611426f19477352993efe5a9fd6ca16711eb912d986f2221b17ba6eeca1b6f71fb6 languageName: node linkType: hard @@ -17271,7 +19496,7 @@ __metadata: languageName: node linkType: hard -"webpack-dev-server@npm:^4.9.3": +"webpack-dev-server@npm:^4.15.1, webpack-dev-server@npm:^4.9.3": version: 4.15.1 resolution: "webpack-dev-server@npm:4.15.1" dependencies: @@ -17318,13 +19543,14 @@ __metadata: languageName: node linkType: hard -"webpack-merge@npm:^5.8.0": - version: 5.9.0 - resolution: "webpack-merge@npm:5.9.0" +"webpack-merge@npm:^5.8.0, webpack-merge@npm:^5.9.0": + version: 5.10.0 + resolution: "webpack-merge@npm:5.10.0" dependencies: clone-deep: ^4.0.1 + flat: ^5.0.2 wildcard: ^2.0.0 - checksum: 64fe2c23aacc5f19684452a0e84ec02c46b990423aee6fcc5c18d7d471155bd14e9a6adb02bd3656eb3e0ac2532c8e97d69412ad14c97eeafe32fa6d10050872 + checksum: 1fe8bf5309add7298e1ac72fb3f2090e1dfa80c48c7e79fa48aa60b5961332c7d0d61efa8851acb805e6b91a4584537a347bc106e05e9aec87fa4f7088c62f2f languageName: node linkType: hard @@ -17335,7 +19561,7 @@ __metadata: languageName: node linkType: hard -"webpack@npm:^5.73.0": +"webpack@npm:^5.73.0, webpack@npm:^5.88.1": version: 5.89.0 resolution: "webpack@npm:5.89.0" dependencies: @@ -17404,13 +19630,6 @@ __metadata: languageName: node linkType: hard -"well-known-symbols@npm:^2.0.0": - version: 2.0.0 - resolution: "well-known-symbols@npm:2.0.0" - checksum: 4f54bbc3012371cb4d228f436891b8e7536d34ac61a57541890257e96788608e096231e0121ac24d08ef2f908b3eb2dc0adba35023eaeb2a7df655da91415402 - languageName: node - linkType: hard - "whatwg-url@npm:^11.0.0": version: 11.0.0 resolution: "whatwg-url@npm:11.0.0" @@ -17453,12 +19672,14 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 languageName: node linkType: hard @@ -17551,7 +19772,7 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^3.0.0": +"write-file-atomic@npm:^3.0.0, write-file-atomic@npm:^3.0.3": version: 3.0.3 resolution: "write-file-atomic@npm:3.0.3" dependencies: @@ -17563,16 +19784,6 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^5.0.1": - version: 5.0.1 - resolution: "write-file-atomic@npm:5.0.1" - dependencies: - imurmurhash: ^0.1.4 - signal-exit: ^4.0.1 - checksum: 8dbb0e2512c2f72ccc20ccedab9986c7d02d04039ed6e8780c987dc4940b793339c50172a1008eed7747001bfacc0ca47562668a069a7506c46c77d7ba3926a9 - languageName: node - linkType: hard - "ws@npm:7.4.6": version: 7.4.6 resolution: "ws@npm:7.4.6" @@ -17634,8 +19845,8 @@ __metadata: linkType: hard "ws@npm:^8.13.0": - version: 8.14.2 - resolution: "ws@npm:8.14.2" + version: 8.15.0 + resolution: "ws@npm:8.15.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -17644,7 +19855,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b + checksum: ca15c590aa49bc0197223b8ab7d15e7362ae6c4011d91ed0e5cd5867cdd5497fd71470ea36314833b4b078929fe64dc4ba7748b1e58e50a0f8e41f147db2b464 languageName: node linkType: hard @@ -17655,6 +19866,13 @@ __metadata: languageName: node linkType: hard +"xdg-basedir@npm:^5.0.1, xdg-basedir@npm:^5.1.0": + version: 5.1.0 + resolution: "xdg-basedir@npm:5.1.0" + checksum: b60e8a2c663ccb1dac77c2d913f3b96de48dafbfa083657171d3d50e10820b8a04bb4edfe9f00808c8c20e5f5355e1927bea9029f03136e29265cb98291e1fea + languageName: node + linkType: hard + "xml-js@npm:^1.6.11": version: 1.6.11 resolution: "xml-js@npm:1.6.11" @@ -17701,17 +19919,10 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.1.1": - version: 2.3.2 - resolution: "yaml@npm:2.3.2" - checksum: acd80cc24df12c808c6dec8a0176d404ef9e6f08ad8786f746ecc9d8974968c53c6e8a67fdfabcc5f99f3dc59b6bb0994b95646ff03d18e9b1dcd59eccc02146 - languageName: node - linkType: hard - -"yaml@npm:^2.2.2": - version: 2.3.3 - resolution: "yaml@npm:2.3.3" - checksum: cdfd132e7e0259f948929efe8835923df05c013c273c02bb7a2de9b46ac3af53c2778a35b32c7c0f877cc355dc9340ed564018c0242bfbb1278c2a3e53a0e99e +"yaml@npm:^2.1.1, yaml@npm:^2.2.2": + version: 2.3.4 + resolution: "yaml@npm:2.3.4" + checksum: e6d1dae1c6383bcc8ba11796eef3b8c02d5082911c6723efeeb5ba50fc8e881df18d645e64de68e421b577296000bea9c75d6d9097c2f6699da3ae0406c030d8 languageName: node linkType: hard @@ -17778,7 +19989,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.7.1, yargs@npm:^17.7.2": +"yargs@npm:^17.7.1": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: @@ -17838,6 +20049,13 @@ __metadata: languageName: node linkType: hard +"zwitch@npm:^2.0.0": + version: 2.0.4 + resolution: "zwitch@npm:2.0.4" + checksum: f22ec5fc2d5f02c423c93d35cdfa83573a3a3bd98c66b927c368ea4d0e7252a500df2a90a6b45522be536a96a73404393c958e945fdba95e6832c200791702b6 + languageName: node + linkType: hard + "zx@npm:7.1.1": version: 7.1.1 resolution: "zx@npm:7.1.1" diff --git a/yarn-project/aztec.js/src/artifacts/ecdsa_account_contract.json b/yarn-project/aztec.js/src/artifacts/ecdsa_account_contract.json index e07487ffe04..d2498f18ede 100644 --- a/yarn-project/aztec.js/src/artifacts/ecdsa_account_contract.json +++ b/yarn-project/aztec.js/src/artifacts/ecdsa_account_contract.json @@ -48,7 +48,7 @@ } } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -84,7 +84,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -167,7 +167,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -184,7 +184,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -491,7 +491,7 @@ ] } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -805,7 +805,7 @@ ] } ], - "bytecode": "H4sIAAAAAAAA/+3dB5wV1b0H8Ht3acNlARWpy3KXDiLuLtgLKxbAAjbAAipd6lIWARuiYsFCE0E6FhB7wxoVuyYmpryYF415yYt58cW8FPOSl/7e/8w9//Dbw8l9e+I52bnZ/3w+f+/Mf2bO+Z45M3OnXNwdqVQqncoNxRTtUvsPPL9af1Z8saEy7a+sipDOogJxFheIs0mBOJsWiLNZgTibF4izRYE4owJxtiwQZ6ZAnK0KxFlSIM7WBeJsUyDOtgXiPKBAnAcWiPOgAnG28+jsBM6D9Wd7/dlBf3bUn7xsZ/3ZRX+W6jY20dNdKcooulFk9TzeIOUU3Sl6UPSk6EXRm6IPRV+KfhT9KQ6hGEBxKMVAisN0GZUUVRSDKAZTHE5xBMWRFEdRHE1xDMWxFMdRHE9xAsUQvc1OpBhKcRLFyRSnUJxKMYxiOMUIitMoTqc4g+JMipEUoyjO0m3J6racTXEOxbkU51GMphhDMZbifIoLKC6kuIhiHMV4iospLqG4lGICxUSKSRSTKaZQTKWYRnEZxXSKGRQzKWZRzKaYQ1FDMdfY5vMo5lMsoKjV89rqeQspLqdYRLGYYgnFFRRXUlxFcTXFNRRLKa6lWEZxHcX1FDcYZS2nuJHiJoqbKW6hWEFxK8VtFLdT3EGxkmIVxWqKNRRrKe7UZRXpstZR3GXk1lNs0ON368+N+nOT/tysP7foz636c5v+3K4/d1D8siQ3rq41zWcCKsf7fBpyvP8XQY6PhWLI8XHRBHJ8jDSFHB8vzSDHx05zyJXq8RaQ6wrj/Fmmx1tCrpsez0Auq8dbQa5cj5dArrsebw25Hnq8DeR66vG2kOulxw+AXG89fiDk+ujxg/Qnbws1VOvPii84qDI9n2srlJ33g3bQHt4PDoYc7wftIcf7QQfIcds7Qo73g06Q4/2gM+R4P+gCOd4PSiHH+wHuP7wflEGO94NukOP9IAs53g/KIcf7QXfI8X7QA3K8H/SEHO8HvSDH27c35Hj78v6jtucpMJ8HPFbxOSDneD4eq8VQJud4Ph6rPB+PVZ6PxyrO50+ej8cqz8fjkufjMch9iMcbr4PHFvch7p9cDu6L3Ie433HZuI9xH+I+xvXhPsZ9iPsYG3Af4z7EfYxdWcjxMYL7GFvxHNUMvNX6s+KLDZV47uYhbUxXwzie00v9Wgbh90N9LNgn3BcHg6/Mr68qA9uqDOrJeq4Hv9fqsx2yYCn3a4mfUXb3W2Z8SdwD/NxWricD89tB23p4blsa6uRyeRp99bV2bWCrsnQxnHid0yUBPs5lwdfD4uvp11eVTtXtx2qY7gk+zpWDxfP+XxUZFjXkO767g6W3V0tlBV7f1sfSGyy9vFpy55o+fsuMr437ei5TldEPtglvP7ZnYH5f2F79PG+vNNTJ5fI0+sQqVrGKVaxiFatYxdq4rXifg88mebkeCfBxrhdYfN8b4PM4Lls9B90Ddfp9nlJZgffJ/OyIDVxXMSzzWqt9rud1rmVq/3vrKLXvnhr7r5tXf67/uB4ul6e7gY/bkjXa6ttSblj+eeutmuT/mWZlhdq91LN63p/KjHbgc6QORk7tk29De5PybBqf0xaBz/Pz6sq/93k1PqcrBp/n59WV+Fy8Pr4y8PF6+F4oG8D39zznzsB6TcHn+Tld7Ct38OEzYXx+yJ+en2lWuj5HtD3nbA4+v88Wc75eDr7e4OP1WoDP83O8SrzmqY+vL/h4vQh8/QP4+jn4+oOP12sJvgEBfIc4+AaA7xAYZ9/AAL5DHXwDwcTrtQJfRQDfYQ6+CvDxeiXgqwrgq3TwVYGP12sNvsEBfIMcfIPBx+u1Ad8RAXyHO/iOAB+v1xZ8RwXwHengOwp8vN4B4DsmgO9oB98x4OP1DgTfcQF8xzr4jgMfr4e/CzshgO94B98J4OP1OoCv2q8vfg86xMFXDZaT/FoGK8uJDpaTwDLUryV+D3qy3zLj96CneC5TlXEqbBPefmzPwPxTYHud6nl7paFOLpen0SfWxm1VliGGM4LlhiTAx7mhAS2RYVFDvnOdzYd9OdyvL/5eGObgGw6W071aBsXPiEc4WE4Hy2leLbnvhTP8lhmfw88EP7eV68nAfOzzMz23LQ11crk8jT6xilWsYhWrWMUqVrGKVaxiFatYxSpWsYpVrGIVq1jFKlaxilWsYhWrWMXq36oswwxnBMsNS4CPc6cFtESGRQ35fidi82FfjvLri39TM9LBNwos53i1VMW/qTnLwXIOWM72asn9puZcv2XGv6k5D/zcVq4nA/Oxz8/z3LY01Mnl8jT6xCpWsYpVrGIVq1jFKlaxilWsYhWrWMUqVrGKtVCsyjLScEaw3MgE+Dh3dkBLZFjUkO85u82HfTnGry9+JzHawTcGLBf4tcT//4exDpYLwHK+X0v8TuJCv2XG7yQuAj+3levJwHzs84s8ty0NdXK5PI0+sTZuq7KMNpwRLDc6AT7OnR/QEhkWNeQ7L9l82Jfj/fric/g4B994sFzq1ZL7WyYXO1guBcslXi25c/gEv2XG5/CJ4Oe2cj0ZmI99PtFz29JQJ5fL0+gTq1jFKlaxilWsYhVr47YqyzjDGcFy4xLg49wlAS2RYVFD2piuhnGbD/tysl9ffE83ycE3GSzTvFpy93RTHCzTwDLVqyV3T3eZ3zLje7rp4Oe2cj0ZmI99Pt1z29JQJ5fL0+gTq1jFKlaxilWsYhVr47YqyyTDGcFykxLg49zUgJbIsKgh332KzYd9OdOvL76nm+HgmwmWOQEssxwsc8Ay268lvqer8VtmfE83F/zcVq4nA/Oxz+d6blsa6uRyeRp9hWJVlhmGM4LlZiTAx7nZAS2RYVFDvuPH5sO+nO/XFx/f8xx888GyMIBlgYNlIVhq/Vric83lfsuMzzWLwM9t5XoyMB/7fJHntqWhTi6Xp9FXKFZlmWc4I1huXgJ8nKsNaIkMixryHT82H/blkgC+xQ6+JeBbbPFdGcB3hYPvSvDxehH4rg7gu8rBdzX4eD38G6NLA/iucfAtBd81MM6+ZQF81zr4loGJ12sFvusD+K5z8F0PPl6vBHzLA/hucPAtBx+vh39j9KYAvhsdfDeBj9fDvzF6SwDfzQ6+W8DH6+H579YAvhUOvlvBt8Liuz2A7zYH3+3gu83iWxnAd4eDbyX47rD4VgfwrXLwrQbLGr+WigxY1kA9dwZo89pU/dt8J1jWBWgzW9ZBPesDtPmuVP3bzPVnYD303R3At8HBdzf4Nlh8mwL4Njr4NoGP18PjeEsA32YH3xbwbbb4tgXwbXXwbQPfVotvRwDfdgffDvBtt/juDeC7x8F3L/jusfjuD+C7z8F3P/jus/h2BfDtdPDtAt9Oi293AN8DDr7d4HvA4nsogO9BB99D4HvQ4nskgO9hB98j4HvY4nssgO9RB99j4HvU4nsigO9xB98T4Hvc4nsqgO9JB99T4HvS4tsTwPe0g28P+J62+J4N4HvGwfcs+J6x+J4P4HvOwfc8+J6z+F7064vfQ7zg4HsRLC/7tcT/1v1LDpaXwfKSX0v8TuQVv2XG70T2gp/byvVkYD72+V7PbUtDnVwuT++FvFgbt1VZXjCcESz3QgJ8nHspoCUyLGrId17aa/FhX77m1xefw1918L0Glje9WnL/D/XXHSxvguUNr5bcOfwtv2XG5/C3wc9t5XoyMB/7/G3PbUtDnVwuT6NPrGIVq1jFKlaxilWsYhWrWMUqVrGKVaxiFatYC8WqLK8azgiWezUBPs69EdASGRY15HvObvNhX77r1xe/k3jHwfcuWN7zasm9k/iyg+U9sHzFqyX3TuKrfsuM30l8DfzcVq4nA/Oxz7/muW1pqJPL5Wn0iVWsYhWrWMUqVrGKVaxiFatYxSpWsYpVrGIVa6FYleUdwxnBcu8kwMe5rwS0RIZFDfmes9t82Jdf9+uL30m87+D7Oli+5dWS+/sR33CwfAss3/Rqyb2T+Be/ZcbvJL4Nfm4r15OB+djn3/bctjTUyeXyNPrEKlaxilWsYhWrWMXauK3K8r7hjGC59xPg49w3A1oiw6KGfPcpNh/25Xf8+uJ7ug8cfN8By4deLbl7un91sHwIlu96teTu6T7yW2Z8T/c98HNbuZ4MzMc+/57ntqWhTi6Xp9EnVrGKVaxiFatYxSrWxm1Vlg8MZwTLfZAAH+e+G9ASGRY15LtPsfmwL7/v1xff033s4Ps+WH7o1ZK7p/s3B8sPwfIDr5bcPd2/+y0zvqf7Efi5rVxPBuZjn//Ic9vSUCeXy9PoE6tYxSpWsYpVrGIVa+O2KsvHhjOC5T5OgI9zPwhoiQyLGvLdp9h82Jc/9uuL7+k+cfD9GCyf+rXEf2fgPxwsn4LlJ34t8T3df/otM76n+yn4ua1cTwbmY5//1HPb0lAnl8vT6BNr47YqyyeGM4LlPkmAj3M/CWiJDIsa8p2XbD7sy5/59cXn8M8cfD8Dyy/8WuJz+H85WH4Blp/7tcTn8F/6LTM+h/8K/NxWricD87HPf+W5bWmok8vlafSJtXFbleUzwxnBcp8lwMe5nwe0RIZFDfnOSzYf9uWv/fric/jnDr5fg+W3ASz/7WD5LVh+49cSn8P/x2+Z8Tn8d+DntnI9GZiPff47z21LQ51cLk+jr1CsyvK54Yxguc8T4OPcbwJaIsOihnzHj82HffmHAL7fO/j+AL7fW3x/CuD7o4PvT+D7o8X3lwC+Pzv4/gK+P1t8vLJP3/+m6u/jmRlYD31FAXzpdP19ReDj9dDXJICv2MHXBHzFFl+zAL6mDr5m4Gtq8bUI4Gvu4GsBvuYWX8sAvsjB1xJ8kcXXKoAv4+BrBb6Mxdc6gK/EwdcafLzeGvC1DeBr4+BrCz5ebx34DgzgO8DBdyD4DrD42gXwHeTgawe+gyy+9gF8Bzv42oPvYMvx0TGAr4ODryP4Olh8nQP4Ojn4OoOvk8VXGsDXxcFXCr4uFl9ZAF9XB18Z+LpafNkAvm4Oviz4ull83QP4yh183cFXbvH1DODr4eDrCb4eFl/vAL5eDr7e4Otl8fUN4Ovj4OsLvj4WX/8Avn4Ovv7g62fxDQjgO8TBNwB8h1h8AwP4DnXwDQTfoRZfRQDfYQ6+CvAdZvFVBfBVOviqwFdp8Q0O4Bvk4BsMvkEW3xF+ffHz6cMdfFy/shzt1xK/7zzSwXI0WI7y3G+qzGP8lhk/Kz8WGsRtPQb6/FhLnx/ruW1pqJPL5Wn0ibVxW5WFzw3sjGC5w9MN7+PcUQEtkWFRQ77zks2HfXl8gHP4cQ6+42FbVXu15P4O1QkOlmqwDAlwDj8xwDl8KDSI23oi9PlQS58PDXB8nGgcHzyNPrGKVaxiFatYxSpWsYpVrGIVq1jFKlaxilWsYi0Uq7Lws252RrAcz2tIH+eGBLREhkUNxmSd5+w2H/blyX598TuJkxx8J8O2GubVknsncYqDZRhYTvXcb6rM4X7LjN9JjIAGcVuHQ5+PsPT5iADHx3Dj+OBp9IlVrGIVq1jFKlaxilWsYhWrWMUqVrGKVaxiFWuhWJWFn3WzM4LleF5D+jh3akBLZFjUYEzWec5u82Ffnu7XF7+TOM3Bdzpsq5FeLbm/uXOGg2UkWM703G+qzFF+y4zfSZwFDeK2joI+P8vS52cFOD5GGccHT6NPrGIVq1jFKlaxilWsjduqLHyvwM4IluN5Denj3JkBLZFhUYMxWec+xebDvjzHry++pzvbwXcObKvRXi25e7pzHSyjwXKe535TZY7xW2Z8TzcWGsRtHQN9PtbS52MDHB9jjOODp9EnVrGKVaxiFatYxSrWxm1VFr5XYGcEy/G8hvRx7ryAlsiwqMGYrHOfYvNhX17g1xff053v4LsAttU4r5bcPd2FDpZxYLnIc7+pMsf7LTO+p7sYGsRtHQ99frGlzy8OcHyMN44PnkafWMUqVrGKVaxiFatYG7dVWfhegZ0RLMfzGtLHuYsCWiLDogZjss59is2HfXmpX198T3eJg+9S2FaT/FrivzMwwcEyCSwTPfebKnOy3zLje7op0CBu62To8ymWPp8S4PiYbBwfPI0+sTZuq7LwuWECnMN5uUvSDe/j3MSAlsiwqCHfecnmw76cFuAcPtXBNw221YwA5/DLHCwzwDI9wDl8ZoBz+CxoELd1JvT5LEufzwpwfMw0jg+eRp9YG7dVWfjccBmcw3m5qemG93FuekBLZFjUkO+8ZPNhX84JcA6f7eCbA9tqXgBLjYNlHljmBjiHzw9wDl8ADeK2zoc+X2Dp8wUBjo/5xvHB0+grFKuy8D5cA+caXm52uuF9nJsb0BIZFjXkO35sPuzLhQF8tQ6+heCrtfgWBfBd7uBbBL7LLb4lAXyLHXxLwLfY4rsygO8KB9+V4LvC4rs6gO8qB9/V4LvK4lsawHeNg28p+K6x+JYF8F3r4FsGvmstvhsCXD9c5+C7Ac7F1we4fljut8wKVeaNnreZKuMm2Ei8/ZZD3/H8G2F73RTge3S58T3K0+irr7VdqmGtAeqtakVltIB2c/lrUnW3gxpu1uNNII/H3ooA2+QWXWZaB9dxM2yTWwPUy/U01fWyg+sqhmU+inKfJancNSLnD4Ztc0eA8+ZtDuelO2B73R7gvLTS83lJlbEKGsRtXQnHJc9fAW1bFWBfWGkclzy9Ciw8FKX2WVYGsOBQDeMrLZaOCbJgHzW0ZXmCLG1SybG0SpAlSpClWYIsxQmydEiQpX2CLCUJsrRMkKV5gixNEmRpnSBLJkGWFgmyNE2QJd3Alii1/71GBPOXw3J8jXwb5Fbr8dshV2Spg7/rVkGOj9vVcH/2acn+ZeM2CnFPgPVUwzTX1RIMqwPfn9TH0jRBlhYJsmQSZGmdIEuTBFmaJ8jSMkGWkgRZ2ifI0iFBluIEWZolyBIlyNIqQZY2CbLwdVwSLCsSZOmYoD4qsljW+LUMxut4HozJOvcJa8Di+/5ElbnWb5nxO9A7PZepylgHG4m3H9szMP9O2F7rAuxHa9N1+4mn0SfWxm1V9d7ltd5B8f/XYq3DeeOugNtAlbk+wDG+ARrEbV0P/bvB0r8bAvTveqN/eRp9YhWrWMUqVrGKVaxiFatYxSpWsYpVrGIVq1jFKlaxilWsYhWrWMUqVrGK1b9V1Xu313qr4t9cYL1qMCb/WlcK6g+xDVSZG/2WGf/mYhM0iNu6Efp3k6V/NwXo341G//I0+sQqVrGKVaxiFatYxSpWsYpVrGIVq1jFKlaxirVQrKrezX7rjf99MdarBmOyzjPrzQG3gSpzi98y42fWW6FB3NYt0L9bLf27NUD/bjH6l6fRJ9bGbVX1bvNab+5v3G9xOMa3BdwGqsztAY7xHdAgbut26N8dlv7dEaB/txv9y9PoE6tYxSpWsYpVrGIVa+O2qnrv8Vpv7pof61WDMVnnmv+egNtAlXmv3zLja/77oEHc1nuhf++z9O99Afr3XqN/eRp9YhWrWMUqVrGKVaxibdxWVe/9fuuN/14q1qsGY7LONf/9AbeBKnOn3zLja/5d0CBu607o312W/t0VoH93Gv3L0+grFKuq94EA++JOh33xgYDbQJW5O8C++CA0iNu6G/r3QUv/Phigf3cb/cvT6CsUawS5otS+HM8vhtxDOtcEcg/rXFPIPQJt4tyjOtccco/pXAvIPa5zHSD3hM7h30Z6Uo/j31B6So+vhdzTenwd5Pbo8fWQe0aPb4Dcs3p8I+Se0+ObIPe8Ht8CuRf0+FbIvajHt0PuS3p8B+ReMr5HVe5l4/tM5V4xznEqt9c416jcq8a+pnKvwTh/vq5zLSH3BuyznHtT51pB7i2dK4Hc2zrXGnLv6FwbyL1r8fG+uBtyvC/ivsv74kOQ433xYcjxvvgI5HhffBRyvC8+BjneRo9DjrfRE5DjbfQk5HgbPQU53kZPQ4630R7I8TZ6BnJtde5ZyB2gc89B7kCdex5yB+ncC5Djv/P9IuT4bzl/CXL8N29eghwfoy9Djv9exCuQ66RzeyHXWedehVwXncN9s1TnXodcV517A3JlOvcm5Lrp3FuQy+rc25Ar17l3INdd596F81YzWLZaf1Z8saES6+IhbUxXwzjX3wza4slSkQFLFuop81pPVYVqH/dNka6L968yqLfUT72VPKLq7QLll4OD6yqGZb6qD94SvXwXr9uhoioN9XJ/sqcLeHiZb2iPOufVltRdz6cLjwke8u2TWWiDpz5jSgUex/Wx4Pb0u9/mrms97wPx32Pp7LlMVUYn2CbmPpWB+Z1he3XyvL3weONyeRp9YhWrWMUqVrGKVaxiFatYxSpWsYpVrGIVq1jFWihWZSk3nPh+qzwBPs7h+xbfz7bxfSCXrd5dTIR3F9281pl7t5SFNmXBwHUVwzKbS/a5purxljCf+wrfMWL/+X3fkes/rofL5WmuqyW0BfvP9/sOfE/H5f7z1ls1yf8xUFWhXtmp3xRkdXnmccd9iu9eOYfv+VSf837XQ3/iu7EewbZL/foDj5lukOPx7uDzu40rQ7xDq1RldIJ+yOpxrqcY5i+Fc8iykn19Y54v1PxVlvk85Huvie+te/lta3zO7A3lV0MdWG8fv/VWYr1pHVwH54thfCX/cAaWUwNvXzar/a6nZTkcLzPWycD8noHb3Asc1TDNdan95AbYp1bB96Xv7xtsL26X9rBdeH432C6+jze1XfD6LguGzmDpYTjxugrPgT0D+P7WdVVP8HGuFHzcDjyf7AFryGsg8/c12Ieevifq/L4Gf39RDg6uC3/Pco/er9WHed2ThXU7Qpn/iN8Emd/N+JugXWD+R/0miD223wQ9BOeJT/6f69dSIxfAX4l+LrfU8ON1QWk4S722Zah7MD5nqd+iooPrKoZlnjH2Kc/f7/HvufAcn0rlv9boBdumt+dtE+A7Nf69U1/wm9/9GZjfDtrW13Pb8PqFy+Vp9NXX2jUB1j4WK17zdzaWU9Z+Xq1V8fV9f69l5q57DtFlqXMnn4+4nmKY/2U4x74H1+/c5iyU85FlPg/5jrl+sP0O9dvW+DtuIJRfDXVgvYf5rbcS6+Xre66D88Uw/iFc3x+2b/Sv25fNar8bYFkOx/sY62Rg/oDAbT4UHNUwzXWp/eR92Kc+gut738c5the3S0fYLjwfr7PLjeXV/szHA14/+D4u01APl8vT/cHHub6wTT8J9lwx58qCK5va/7kiPu/MggufdzYN4GqSqru9eJrrUvU291wv/jsbHvKd35qDpZlni3q+xv/OZkFtzfwJ06aMnT+9dkoaXE0NYxHYimBesbFc89T+7fIGbweVFenKm2gsd5pqHP+Do4xuqNqf1D8YUv9ASP2DIPUPgNQ/+FH/wKcdOG/Xn+of9KgbQPUPdtQOqi5C1cGuLoLVham60FBf6mpHzqZyB7h6YKduqNWXvrogVBeC6mSgDjj1paEORnUQqpOHOsGpk7g6wamrMXXWqaIYRDGY4nCKIyiOpDiK4miKYyiOpTiO4niKEyiG6G17IsVQipMoTqY4heJUimEUwylGUJxGcTrFGRRnUoykGEVxFsXZFOdQnEtxHsVoijEUYynOp7iA4kKKiyjGUYynuJjiEopLKSZQTKSYRDGZYgrFVIppFJdRTKeYQTGTYhbFbIo5FDUUcynmUcynWEBRS7GQ4nKKRRSLKZZQXEFxJcVVFFdTXEOxlOJaimUU11FcT3EDxXKKGyluoriZ4haKFRS3UtyWyvXzHRQrKVZRrKZYQ7GW4k6KdRR3Uayn2EBxN8VGik0Umym2UGyl2EaxnWJHav8DRg0f6n8Jd5yePjd3sGUXzKqpzVZk59B/J8yaVbNoyuSBWZy3IDt74YLa7ILaCfNrs1Pn18zOVg7Ect/TRy9/sUyorZ0ye25ttraGVpxVO33urCXZRdNrL8vWXD5l/lSqAFfeUfIFVt6pVy7df+UJkyf/7fX26PX4n9SNmDN5yuJszcLabM3U7MSahXMmL/g/0ZCDk85mAgA=", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ], diff --git a/yarn-project/aztec.js/src/artifacts/schnorr_account_contract.json b/yarn-project/aztec.js/src/artifacts/schnorr_account_contract.json index 116928067b9..04d59da83b8 100644 --- a/yarn-project/aztec.js/src/artifacts/schnorr_account_contract.json +++ b/yarn-project/aztec.js/src/artifacts/schnorr_account_contract.json @@ -48,7 +48,7 @@ } } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -72,7 +72,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -155,7 +155,7 @@ } ], "returnTypes": [], - "bytecode": "H4sIAAAAAAAA/+1dB5gURdMebi+Sg+R0ZCS5c3EPRA9QFBOIIiiKXlQQQREwJ8w555xzwoQJc84555xzVvyrz2pohhXvvn1r/u5nZp6n7t2dnaupqq7qfqe3d+bY5p63d4HXsDUjySLJJin0VuxTWyVjMrPNzyEdOWn0FifLSkrqyovq/GK/KllUUZ0qTZaUVpel/JRfmiqtLUoVF9elSlLlFdUV5ckKv6S4zq8vrSiuZ8U5OBuTEn7nko5cAb9zLfc7j3TkCfidB/Rb530XwbzvRjq6CcShm0AcegjGoRfp6CUQh14CcSgUjENf0tFXIA59BeLQXzAOA0nHQIE4DPSw/aL3L/5naudgcHvlGW3VmWSZ90+/prArYzfG7ow9GHsy9mLszVjI2IexL2M/xv6MAxgHMg5iHPz/hMNI1uQ2U3Fpy3FZ0wK7hhh2tbOsvdTxQ0kSJPnev2+VjMnMNl9Od1mtoO46Qd31crrLk4K6BduyvEhQd3GeoXMY43DGEYxr6XMxameVYY8k/nmtLqWCNVPAorZmxr7m/DrL2NeCXyeMfS35dbaxrxW/zjH2tebXuca+Nvw6L/CZ2ioZkxlu6a5rkhluBUZc8g1/zLho1HFpbuzTcWlh7NO+tzT26bi0Mvbp87U29unz6Xgq/d2Nz/VmtqWOiWmz/jw7jU85aXzKTeNTXhqfTJvVPh2LSsZkhluuESOUTjPf9dYs8L7SeN3KiElLrC0N1+etsTobYtZWIGatvcbHrK0RszYCMWuH1dkQsw4CMWvnNT5mHYyYtReI2RpYnQ0x6yQQszW8xseskxGzjgIx64zVmRTQ2WBnFwE7u2N1plTbdvUa37bdjbbtJhCzHlidDTHrCdapdPQyYqLjp21vYXze04hXL3C8mhnn1Hr1+15y523wv/d/+N87jR29Q/TftC+2NbY1tvX/19ae/8+2qvMWQs/rlxcEzqu21Y2dhYIxUDr7YHU29PN9Dfu1r/o8LYzPzVzsC/atmXFOrVe/N+2LbY1tjW2NbY1tjW2NbY1tjW2NbY1tjW2NbY1tdcVW8zvQLMMW8LV9gy1ewBYvTVz0VmCRLbkW2ZKwyJY8i2zJtsiWfItsybHIlmb/z7aY62I8Y5/+PMvYp/tHc/1MP35trp/pz6/N9TMDDD/1voH82lw/M4hfm2uMBhuvNa7Jr801RkP4tbnGaCi/NtcY6fVk5noivbasjbFPrzNrZ+zTa87aG/v0+rM1jH16LVpHY59eMNfZ2FfMr7sY+0r4dVdjXym/7mbsK+PXPYx95fy6t7FPt6HZ5roN+xr7dBv2M/bpNuxv7NNtOMDYp9twoLFPt+EgY59uQ7NNdRuuaezTbTjE2KfbcKixT69BGmbs0+063Nin23WEsU+vxVnL2KfbOmns023tG/v0mpQiY59u/2Jjn27/EmOfXptRauzTOVFm7NM5odtUtcWkZis+1/9v1qg+j1mj5WnOV5bGLv3a7JP0/1QyJjPbGvok8zyVxnt9ruaGDSUW2JJjkS35FtmSbZEteRbZkrDIllyLbCmwyJasNLYUY21pGELMRfK6Hy427NA2FRl2+OCYNOhIY4dv2KHPnzTsWAtrR8MpRqSxYy3DDn3+EYYdw7F2NIR/WBo7hht26PMPM+wYirWjIfWGpLFjqGGHPv8Qw441sXY0pODgNHaYHFuff7BhxyCsHQ2UZGAaOwYZdujzDzTsGIC1o+G0/dPYMcCwQ5+/v2FHP6wdDX2ZeS2l3uv+Qp8rYRwzhkmT4sTmdZjJUTXfN/mtvi4wuXGKX5u8uoJfm5x8JL82+fwofm1eC+j+1ryOWN01iHmtovlXytinx7UKY5/mACONfZovaZvy+H/Ba1yL1Ln0uly9re7621yfpf/PvFbUa7XMtb4Sa1d7BuzT73sZ9ul95ppy8HreBltaBmzR73sKn7d14LytQzpv28B524Z03vaB87YP6bxdAuftEjjvv827S9jiBWzxVmPLGhbZ0sYiW9paZEtzi2zJs8iWbIts6WaRLd0tsqWzRbZ0sciWDhbZ0soiW1pbZEuBRbbkWmRLwiJbulpkS0eLbJG+nmmKLe0ssqW9Rba0sMiWlhbZkm+RLTkW2dLs/9mWf1tPoT83v6vVcyzmGobeAZ/UvkJ+ba5h0PNj5n1S9Dyaua5BzxOa6xr0HFxbY5+e2zTXOuj5O3Otg56L7WDs03N/5voHPXdsrnXQ84bmWgcdDzN+euzsZezT1zHmugadd4XGPs0BzPlDfT1mzjPq+jHXOmguY85R6rYx1zrotjHnN3XbmGsddNuYc6O6bcy1DrptdHyUXzcY9y/S/2/mjj6P+T3/kDTnWzONXfq1WSv6fyoZk5ltDbVinqfSeK/PZX7PP8gCW3IssiXfIltaWmRLC4tsaW+RLe0ssqWTRbZ0tMiWrhbZkrDIllyLbCmwyJbWFtnSyiJbOlhkSxeLbOlskS3dLbKlm0W2ZFtkS55FtjS3yJa2FtnSxiJb1rDIlqyQbNHXz1rvmgFb1HkHYs/bsDRrgHFefV0/0PBfn9/8XU1/sB3NAnYUGueVXPemdPRN438/w399/r6GHX3Bdij/Oxl2VBrvzbkkzet1+6g+vjRrhV3gdZINdpn5d4C36rVFwjhmXNYKuyqyVsRQr0Ez75vcK7BP6Ze4V1ivQFz1e30uZV9wLZppn/mbp+D9zcx5RfN/E4Fz5Hki7ZM020dthd6q7WP2c7neyrWlay5hHLOh0YaLEiv+D2z7SmuBs7z016zgem9YnqprxzP0mzHsY7xO1x/2DRynYwq00w/aoc9faOzrlcbOPoad6e4biL43arC+mnmr1kjwtfaln2EXeI3sasfTHsZ5wevsi5p6j8Chhi0jsLYUm78/bYwtgr+D8AV+49Fwr98kWKfSYT7IQsdP297C+Nz8/Qr6dzTNjHNqvfq9aV9sK95WZUuPgJ3m77F7WGCf3mf+7rhbIH5q/N5djhsWp+OGwfkPkxsellhh1x4GNxwciKv5fbAZa4nfvJhcoNJbdWxqbvhi/g4IfB220rWo1mvTecGxb0hRk98MThN3fX5pntU7jR2Fhh36/Oa9hcE8qoGXDk1jR0/DDn1+kzMMA8ejIGCH2lbHGczfLIL5i2/eK6Mxtpj8BcwLfLP/b4wt5hhWJGCL3wRbzN/7lgjYUtwEW8zfQJcJ2FLaBFvKDFtSAraUN8EWfX41tuv6G2js03XQx9in89Fcx6Xzor+xT7dPX2Nf8H4eLQx7zbVi+jeP5rzNqMA+Fb+1Az4lM9saxiV9Hq1Xv1/bsE///nKUnC0pU785T7G2cc7RYP9zDV0oP5TOMWA7lY6xrCvbaA99noTx+WJjXulmfq3yaR3+vMLQ80Caz/W2ujqqNNpkPayvDXMd6xv6K9OcQ+0fjz2vb563GYs+h96fMF7fr4vaOE5tOr7aZlU/49IcZ75eJ/A/LYzPxwn7vJ5hR6XxXp9L5cltRk49YFzrrAu2x/TXjMsoIy7689HGcWON1/rYQiNu47B2pgTyvsH39Y2Y69jq85i596TRHk8bNTwmEDf1+VtpPtfb6mrczLsNsL421PiGhv5K4xzmeSdgz+ub59U1rs+h9yeM128aNT5hxcvl8dU2qxofn+Y48/WYwP+0MD4fL+zzBoYdlcZ7fS6VJ88ZOfWWUeOVYHtMf824jDXioj835w3WN17rYwuNuIH7xpRA3jf4vqERc61Xn8fMvY+N9vjUqOH1AnFTn/+S5nO9ra7GzbzbCOtrQ41vbOivNM5hnncT7Hl987y6xvU59P6E8fpno8Y3WfFyeXy1zarGJ6Q5zny9XuB/WhifTxD2eSPDjkrjvT6XypMvjJz6xahx8Pjom/6acVnfiIv+3Jyf2tB4rY8tNOIG7htTAnnf4PvGRsx1bPV5zNzzjLnaLOP3IRsE4qY+b5fmc72trsbNvNsU62tDjW9m6K80zmGedyL2vL55Xl3j+hybGaHVr9vqhQLGcWrT8dU2qxrfJM1x5usNAv/Twvh8E2GfNzXsqDTe63OpPMkxcqqdsa4Afe1g+mvGZUMjLvpzc+53Y+O1PrbQiBu4b0wJ5H2D75sZMdex1ecxc6+b0R49jBreKBA39fnQNJ/rbXU1bubdJKyvDTW+uaG/0jiHed7J2PP65nl1jetz6P0J4/UQo8Ynr3i5PL7aZlXjE9McZ77eKPA/LYzPJwr7PMmwo9J4r8+l8qS3kVNDjRpHXzuY/ppx2diIi/68v3HcZsZrfWyhETdw35gSyPsG3zc3Yq5jq89j5l6J0R5lRg1vGoib+nz9NJ/rbXU1bubdFlhfG2p8S0N/pXEO87xTsOf1zfPqGtfn0PsTxuv1jBqfsuLl8vhqm1WNT05znPl608D/tDA+nyzs8xaGHZXGe32uhnWdRk6tb9Q4+trB9NeMy2ZGXPTnfY3jNjde62MLjbiB+8aUQN43+L6lEXMdW30eM/c2M9pjklHDkwJxU59vn+Zzva2uxs282wrra0ONTzX0VxrnMM87DXte3zyvrnF9Dr0/YbyeYdT4tBUvl8dX26xqfEqa48zXkwL/08L4fIqwz1sZdlQa7/W5VJ5sYeTU9kaNo68dTH/NuGxuxEV/bkyHLM9989hCI27gvjElkPcNvk81Yq5jq89j5t5ORnvMMmp4i0Dc1Od7pflcb6urcTPvtsb62lDj2xj6K41zmOedjj2vb55X17g+h96fMF7vadT49BUvl8dX26xqfFqa48zXWwT+p4Xx+TRhn7c27Kg03utzqTzZxcipvYwaR187mP6acdnSiIv+3LwXcPfA8SqfdT2Yaw/QdWmOC1qvfm/213qfef0j+HuJhjiav1MI/l7C/H3QYMMm/fsgF9daBl/r9aXm7wnMedp0v9foFzhO+Qf+nVGxwG8JGtpbr6/LNmKjz5MwPj/ZqOVTjf5f+2zmwyVpPtfb6sYHc/0jeK1f0lz3rMeHEWnOi17XZ55Xjw/6HHp/wnh9sTE+mM+50PHVNqu8G57mOPN1n8D/tDA+Hy7ss/lsjErjvbl2/Awjpy4x+rVCsD2mv2Zcuhlx0Z+bvxmSrDfz/EMNO4LPEjV/E2j2n+jfz5i/q9J69fvhhn16X6Fhn/bD7EvM3wW0FbC1TcBW/d68j7fEeXMC580J6bx5gfPmhXTegsB5C0I6b4vAeVuEdN7w88ovVzo7gHWqdmrnrbytbuw170/dHmpL0s/3VtwDbse6+ZvNnV+3ezPDJm2nvudLc8Mu85o8YfxPtreqb7lp9uWn2dfcW3Uzn9fRynjd1vi/1gE7VYz1fSTMe03q+3SZ95rUfpj3ldT+6OPzvFXbCDr46C0B1p1l6CpOlpWU1JUX1fnFflWyqKI6VZosKa0uS/kpvzRVWluUKi6uS5WkyiuqK8qTFX5JcZ1fX1pRXM/K1gLqKsb5mEykaxxjHyqWSJtNe9UPI3TRpCuqXAFfvMB5gvFr7QknvETjlAjoLfVwSS/ldym+jcyLFetjKmWnD7RTM0Vd1IqRL/P+YfAKRzCqrcxbeQv6lakt5R6WmSm/dMdVzn6UGf6kvPSdjESbJT2ZTlr9giLupDPUmeRAovWO9OzupJXSkfg2WqnzywrozjQORUBdozx8h9OYjnRtbst0HdTaxnGj0xy3Fn8+mlEVf/DnaOiYI/N43f+nmFeuJuaVxnFjVhPzMUbMx6Y5Lsmfj2VUdo3jzyT6lnU8/CDcvgDbD6D9Xpdjiva7Q4FM/5cA27keMJbAtvaR8QuLlA3F6Uqa01Nap/pZxnjvn2W1avm2Whaplt+pZZ5q+ZRapqOWg6llFurrfLVsRH11q75eVl9Fq2UI6utd9bWu+jpafWWulgWor8y3JdmOZAbJ9iQ7kFSRVJPUkNSS1JHUk+xIshPJTJJZJDuTzCbZhWQOyVySXUl2I5lHsjvJfJIFJAtJ9iDZk2Qvkr1J9iHZl2Q/kv29f26zcyDJQSSLSA4mOcRbeYrLJKdqM6feKkFtIEB2k6btGtUUfp7hmxf4vDX7lwO1pSRpTgHqbXVTtOajibKhtvwzRaunN2mKdsyC+TtNnTl/Tt3uK03UBnu/ZmmiZT64xnygi45wtrEvy/BI79P/k2eg2OVHwls1lU3HUOdZ35MZjqDx8JNJMxaHMh7mrUi9Zka8VEP+nSZmzYzXWXxM1mqOafYvev6tFMWSQTunHP/ZcFYFIPg1AnoG3UyQ/5VT1NWrLekf6uH4yWGeTOJmgeOH9PnwlXTRsVVFJWV1pcmyulRFqq6ivL60PFlTVV9fW54sqalOVleXlCWL/eL66vKiZHVRBZ22oq60xm+wKyzuczhO10oTUkd48YQUpHGOENB7pGf3hJTy+0h8G6W1FdHRHSmg9ygPW5iqCJVOTZXCYC/jPZlBAJoXAfZyNOMxXsTYi3LcZC8qANLsxUyQTNnL0R6u+I7x3GAvSJ+P9dxjL8d62E5Sb8d5MXuBNM5xAnqP9+xmL8rv4/FtJMJejmFb0XpP8LCFqYpQ6QyTvWzgyQwC0LwIsJcTGU/yIsZelOMme1EBkGYvZoJkyl5O9HDFd5LnBntB+nyy5x57OdnDdpJ6O8WL2QukcU4R0HuqZzd7UX6fim8jEfZyEtuK1nuahy1MVYRKZ5jsZUNPZhCA5kWAvZzOeIYXMfaiHDfZiwqANHsxEyRT9nK6hyu+Mzw32AvS5zM999jLmR62k9TbWV7MXiCNc5aA3rM9u9mL8vtsfBuJsJcz2Fa03nM8bGGqIlQ6w2QvEzyZQQCaFwH2ci7jeV7E2Ity3GQvKgDS7MVMkEzZy7kervjO89xgL0ifz/fcYy/ne9hOUm8XeDF7gTTOBQJ6L/TsZi/K7wvxbSTCXs5jW9F6L/KwhamKUOkMk71s5MkMAtC8CLCXixkv8SLGXpTjJntRAZBmL2aCZMpeLvZwxXeJ5wZ7Qfp8qecee7nUw3aServMi9kLpHEuE9B7uWc3e1F+X45vIxH2cgnbitZ7hYctTFWESmeY7GVjT2YQgOZFgL1cyXiVFzH2ohw32YsKgDR7MRMkU/ZypYcrvqs8N9gL0uerPffYy9UetpPU2zVezF4gjXONgN5rPbvZi/L7WnwbibCXq9hWtN7rPGxhqiJUOsNkL5t4MoMANC8C7OV6xhu8iLEX5bjJXlQApNmLmSCZspfrPVzx3eC5wV6QPt/oucdebvSwnaTeFnsxe4E0zmIBvTd5drMX5fdN+DYSYS83sK1ovTd72MJURah0hsleNvVkBgFoXgTYyy2Mt3oRYy/KcZO9qABIsxczQTJlL7d4uOK71XODvSB9vs1zj73c5mE7Sb0t8WL2AmmcJQJ6b/fsZi/K79vxbSTCXm5lW9F67/CwhamKUOkMk71s5skMAtC8CLCXOxnv8iLGXpTjJntRAZBmL2aCZMpe7vRwxXeX5wZ7Qfp8t+cee7nbw3aSelvqxewF0jhLBfTe49nNXpTf9+DbSIS93MW2ovXe62ELUxWh0hkme5noyQwC0LwIsJf7GO/3IsZelOMme1EBkGYvZoJkyl7u83DFd7/nBntB+vyA5x57ecDDdpJ6e9CL2QukcR4U0PuQZzd7UX4/hG8jEfZyP9uK1vuwhy1MVYRKZ5jsZZInMwhA8yLAXh5hfNSLGHtRjpvsRQVAmr2YCZIpe3nEwxXfo54b7AXp82Oee+zlMQ/bSertcS9mL5DGeVxA7xOe3exF+f0Evo1E2MujbCta75MetjBVESqdYbKXzT2ZQQCaFwH28hTj017E2Ity3GQvKgDS7MVMkEzZy1Mervie9txgL0ifn/HcYy/PeNhOUm/PejF7gTTOswJ6n/PsZi/K7+fwbSTCXp5mW9F6n/ewhamKUOkMk71M9mQGAWheBNjLC4wvehFjL8pxk72oAEizFzNBMmUvL3i44nvRc4O9IH1+yXOPvbzkYTtJvb3sxewF0jgvC+h9xbObvSi/X8G3kQh7eZFtRet91cMWpipCpTNM9rKFJzMIQPMiwF5eY3zdixh7UY6b7EUFQJq9mAmSKXt5zcMV3+ueG+wF6fMbnnvs5Q0P20nq7U0vZi+QxnlTQO9bnt3sRfn9Fr6NRNjL62wrWu/bHrYwVREqnWGyly09mUEAmhcB9vIO47texNiLctxkL+968uzFTJBM2cs7Hq743vXcYC9In9/z3GMv73nYTlJv73sxe4E0zvsCej/w7GYvyu8P8G0kwl7eZVvRej/0sIWpilDpDJO9TPFkBgFoXgTYy0eMH3sRYy/KcZO9qABIsxczQTJlLx95uOL72HODvSB9/sRzj7184mE7Sb196sXsBdI4nwro/cyzm70ovz/Dt5EIe/mYbUXr/dzDFqYqQqUzTPaylSczCEDzIsBevmD80osYe1GOm+xFBUCavZgJkil7+cLDFd+XnhvsBenzV5577OUrD9tJ6u1rL2YvkMb5WkDvN57d7EX5/Q2+jUTYy5dsK1rvtx62MFURKp1hspepnswgAM2LAHv5jvF7L2LsRTlushcVAGn2YiZIpuzlOw9XfN97brAXpM8/eO6xlx88bCeptx+9mL1AGudHAb0/eXazF+X3T/g2EmEv37OtaL0/e9jCVEWodIbJXqZ5MoMANC8C7OUXxl+9iLEX5bjJXlQApNmLmSCZspdfPFzx/eq5wV6QPv/mucdefvOwnaTefvdi9gJpnN8F9P7h2c1elN9/4NtIhL38yrai9f7pYQtTFaHSGSZ72dqTGQSgeRFgL38xLvMixl6U4yZ7UQGQZi9mgmTKXv7ycMW3zHODvSB9/ttzj7387WE7SdPQmL1kqPNvVorW26yZ3exF+d2sGbyNRNjLMrYVrTerGZ69KJ1hspdtPJlBAJoXAfaS4CBkN4sYe1GOm+xFBUCavZgJkil7SQA7texmMomLZi9In3OaucdecsCdpN5yY/aCaZxcAfaSZzl7UX7nOcJestlWtN58AfaSHzJ7me7JDALQvAiwlwIOQvOosZeCAHtpHgJ7MRMkU/ZSAOzUmjvCXpA+t3CQvbQQYi8tY/aCaZyWAuylleXsRfndyhH20pxtRettLcBeWofMXrb1ZAYBaF4E2EsbDkLbqLGXNgH20jYE9mImSKbspQ2wU2vrCHtB+tzOQfbSToi9tI/ZC6Zx2guwlw6WsxfldwdH2EtbthWtdw0B9rJGyOxlO09mEIDmRYC9dOQgdIoae+kYYC+dQmAvZoJkyl46Aju1To6wF6TPnR1kL52F2EuXmL1gGqeLAHvpajl7UX53dYS9dGJb0Xq7CbCXbiGzlxmezCAAzYsAe+nOQegRNfbSPcBeeoTAXswEyZS9dAd2aj0cYS9In3s6yF56CrGXXjF7wTROLwH20tty9qL87u0Ie+nBtqL1Fgqwl8KQ2cv2nswgAM2LAHvpw0HoGzX20ifAXvqGwF7MBMmUvfQBdmp9HWEvSJ/7Oche+gmxl/4xe8E0Tn8B9jLAcvai/B7gCHvpy7ai9Q4UYC8DQ2YvO3gygwA0LwLsZRAHYXDU2MugAHsZHAJ72cHDsZdBwE5tsCPsBenzmg6ylzWF2MuQmL1gGmeIAHsZajl7UX4PdYS9DGZb0XqHCbCXYSGzlypPZhCA5kWAvQznIIyIGnsZHmAvI0JgL2aCZMpehgM7tRGOsBekz2s5yF7WEmIvyZi9YBonKcBefMvZi/Lbd4S9jGBb0XqLBNhLUcjspdqTGQSgeRFgL8UchJKosZfiAHspCYG9mAmSKXspBnZqJY6wF6TPpQ6yl1Ih9lIWsxdM45QJsJdyy9mL8rvcEfZSwrai9aYE2EsqZPZS48kMAtC8CLCXCg7CyKixl4oAexkZAnsxEyRT9lIB7NRGOsJekD6PcpC9jBJiL2vH7AXTOGsLsJfRlrMX5fdoR9jLSLYVrXcdAfayTsjspdaTGQSgeRFgL+tyECqjxl7WDbCXyhDYi5kgmbKXdYGdWqUj7AXp8xgH2csYIfYyNmYvmMYZK8BexlnOXpTf4xxhL5VsK1rvegLsZb2Q2UudJzMIQPMiwF7W5yCMjxp7WT/AXsaHwF7MBMmUvawP7NTGO8JekD5v4CB72UCIvWwYsxdM42wowF4mWM5elN8THGEv49lWtN6NBNjLRiGzl3pPZhCA5kWAvWzMQdgkauxl4wB72SQE9mImSKbsZWNgp7aJI+wF6fOmDrKXTYXYy2Yxe8E0zmYC7GWi5exF+T3REfayCduK1jtJgL1MCpm97OjJDALQvAiwl805CJOjxl42D7CXySGwFzNBMmUvmwM7tcmOsBekz1s4yF62EGIvW8bsBdM4WwqwlymWsxfl9xRH2MtkthWtdysB9rJVyOxlJ09mEIDmRYC9TOUgTIsae5kaYC/TQmAvZoJkyl6mAju1aY6wF6TPWzvIXrYWYi/bxOwF0zjbCLCX6ZazF+X3dEfYyzS2Fa13WwH2sm3I7GWmJzMIQPMiwF624yDMiBp72S7AXmaEwF7MBMmUvWwH7NRmOMJekD5v7yB72V6IvewQsxdM4+wgwF6qLGcvyu8qR9jLDLYVrbdagL1Uh8xeZnkygwA0LwLspYaDUBs19lITYC+1IbAXM0EyZS81wE6t1hH2gvS5zkH2UifEXupj9oJpnHoB9rKj5exF+b2jI+yllm1F691JgL3sFDJ72dmTGQSgeRFgLzM5CLOixl5mBtjLrBDYi5kgmbKXmcBObZYj7AXp884OspedhdjL7Ji9YBpntgB72cVy9qL83sUR9jKLbUXrnSPAXuaEzF5mezKDADQvAuxlLgdh16ixl7kB9rJrCOzFTJBM2ctcYKe2qyPsBenzbg6yl92E2Mu8mL1gGmeeAHvZ3XL2ovze3RH2sivbitY7X4C9zA+ZveziyQwC0LwIsJcFHISFUWMvCwLsZWEI7MVMkEzZywJgp7bQEfaC9HkPB9nLHkLsZc+YvWAaZ08B9rKX5exF+b2XI+xlIduK1ru3AHvZO2T2MseTGQSgeRFgL/twEPaNGnvZJ8Be9g2BvZgJkil72QfYqe3rCHtB+ryfg+xlPyH2sn/MXjCNs78AeznAcvai/D7AEfayL9uK1nugAHs5MGT2MteTGQSgeRFgLwdxEBZFjb0cFGAvi0JgL2aCZMpeDgJ2aoscYS9Inw92kL0cLMReDonZC6ZxDhFgL4dazl6U34c6wl4Wsa1ovYcJsJfDQmYvu3oygwA0LwLs5XAOwhFRYy+HB9jLESGwFzNBMmUvhwM7tSMcYS9In490kL0cKcRejorZC6ZxjhJgL0dbzl6U30c7wl6OYFvReo8RYC/HhMxedvNkBgFoXgTYy7EchOOixl6ODbCX40JgL2aCZMpejgV2asc5wl6QPh/vIHs5Xoi9nBCzF0zjnCDAXk60nL0ov090hL0cx7ai9Z4kwF5OCpm9zPNkBgFoXgTYy8kchFOixl5ODrCXU0JgL2aCZMpeTgZ2aqc4wl6QPp/qIHs5VYi9nBazF0zjnCbAXk63nL0ov093hL2cwrai9Z4hwF7OCJm97O7JDALQvAiwlzM5CGdFjb2cGWAvZ4XAXswEyZS9nAns1M5yhL0gfT7bQfZythB7OSdmL5jGOUeAvZxrOXtRfp/rCHs5i21F6z1PgL2cFzJ7me/JDALQvAiwl/M5CBdEjb2cH2AvF4TAXswEyZS9nA/s1C5whL0gfb7QQfZyoRB7uShmL5jGuUiAvVxsOXtRfl/sCHu5gG1F671EgL1cEjJ7WeDJDALQvAiwl0s5CJdFjb1cGmAvl4XAXswEyZS9XArs1C5zhL0gfb7cQfZyuRB7uSJmL5jGuUKAvVxpOXtRfl/pCHu5jG1F671KgL1cFTJ7WejJDALQvAiwl6s5CNdEjb1cHWAv14TAXswEyZS9XA3s1K5xhL0gfb7WQfZyrRB7uS5mL5jGuU6AvVxvOXtRfl/vCHu5hm1F671BgL3cEDJ72cOTGQSgeRFgLzdyEBZHjb3cGGAvi0NgL2aCZMpebgR2aosdYS9In29ykL3cJMRebo7ZC6ZxbhZgL7dYzl6U37c4wl4Ws61ovbcKsJdbQ2Yve3oygwA0LwLs5TYOwpKosZfbAuxlSQjsxUyQTNnLbcBObYkj7AXp8+0OspfbhdjLHTF7wTTOHQLs5U7L2Yvy+05H2MsSthWt9y4B9nJXyOxlL09mEIDmRYC93M1BWBo19nJ3gL0sDYG9mAmSKXu5G9ipLXWEvSB9vsdB9nKPEHu5N2YvmMa5V4C93Gc5e1F+3+cIe1nKtqL13i/AXu4Pmb3s7ckMAtC8CLCXBzgID0aNvTwQYC8PhsBezATJlL08AOzUHnSEvSB9fshB9vKQEHt5OGYvmMZ5WIC9PGI5e1F+P+IIe3mQbUXrfVSAvTwaMnvZx5MZBKB5EWAvj3EQHo8ae3kswF4eD4G9mAmSKXt5DNipPe4Ie0H6/ISD7OUJIfbyZMxeMI3zpAB7ecpy9qL8fsoR9vI424rW+7QAe3k6ZPayryczCEDzIsBenuEgPBs19vJMgL08GwJ7MRMkU/byDLBTe9YR9oL0+TkH2ctzQuzl+Zi9YBrneQH28oLl7EX5/YIj7OVZthWt90UB9vJiyOxlP09mEIDmRYC9vMRBeDlq7OWlAHt5OQT2YiZIpuzlJWCn9rIj7AXp8ysOspdXhNjLqzF7wTTOqwLs5TXL2Yvy+zVH2MvLbCta7+sC7OX1kNnL/p7MIADNiwB7eYOD8GbU2MsbAfbyZgjsxUyQTNnLG8BO7U1H2AvS57ccZC9vCbGXt2P2gmmctwXYyzuWsxfl9zuOsJc32Va03ncF2Mu7IbOXAzyZQQCaFwH28h4H4f2osZf3Auzl/RDYi5kgmbKX94Cd2vuOsBekzx84yF4+EGIvH8bsBdM4Hwqwl48sZy/K748cYS/vs61ovR8LsJePQ2YvB3oygwA0LwLs5RMOwqdRYy+fBNjLpyGwlwM9HHv5BNipfeoIe0H6/JmD7OUzIfbyecxeMI3zuQB7+cJy9qL8/sIR9vIp24rW+6UAe/kyZPZykCczCEDzIsBevuIgfB019vJVgL18HQJ7MRMkU/byFbBT+9oR9oL0+RsH2cs3Quzl25i9YBrnWwH28p3l7EX5/Z0j7OVrthWt93sB9vJ9yOxlkSczCEDzIsBefuAg/Bg19vJDgL38GAJ7MRMkU/byA7BT+9ER9oL0+ScH2ctPQuzl55i9YBrnZwH28ovl7EX5/Ysj7OVHthWt91cB9vJryOzlYE9mEIDmRYC9/MZB+D1q7OW3AHv5PQT2YiZIpuzlN2Cn9rsj7AXp8x8Ospc/hNjLnzF7wTTOnwLs5S/L2Yvy+y9H2MvvbCta7zIB9rIsZPZyiCczCEDzIsBe/jYoSKTYy98B9qL+SLMXM0EyZS9/Izu1LDfYC9LnZlnusZdmWdhOcnk7ZcXsBdI4KpBovYksu9mL8juRBW8jEfbisa1ovdngwlThVDoL+LVZCOj2Gwpss0LWk0NG55LkqUFV+UHSnKQFSUuSViStSdqQtCVpR9KepAPJGiQdSTqRdCbpQtKVpBtJd5IeJD1JepH0Jikk6UPSl6QfSX8OmI5jDg/s+n1u4H1e4H1+4H1B4H3zwPsWgfctA+9bBd63DrxvE3jfNvC+XeB9+8D7DoH3awTedwy87xR43znwvkvgfdfA+26B990D73sE3vcMvO8VeN878L4w8L5P4H3fwPt+gff9s+SJnFkzmfYdOcD+vVOBDJELxi9T8pqbhdGl2iIPGL/O1sevQbWfn7nPReyzXwCMXxeb41ey3E6/eWY+Jw2f/RbA+HW1NX5FK9npt/zffU4GfPZbAePXzcL4ldWvYqff+n/zOZXGZ78NMH7dbYtfKq2dftum+1z+Lz777YDx62FT/Mr/1U6/fdN8LlqNz34HYPx62hK/8tXa6a/ReJ9r/sNnvyMwfr1siF/5f9rpd2qcz8lG+Ox3Bsav9/93/JKNstPv8t8+lzbSZ78rMH6F/5/xK2m0nX631fpcUt8En/3uwPj1+f+KX3mT7PR7/LvPqSb67PcExq/v/0P8KuqbbKffK73Pyf/BZ783MH79wo5f8n+y0y9c1Wf/f/TZ7wOMX/8w41f7P9vp913Z5+IMfPb7AeM3IKT4FdVnZKffPws3l2jO2WUav4EhxS+Z2eYD59n8LsD4DXIkfsB5Ir8bMH6DHYkfcJ7D7wGM35qOxA94ne73AsZviCPxA15n+oXA+A11JH7A6yS/LzB+wxyJH5Dn+/2B8RvuSPyAPNUfCIzfCEfiB+RZ/mBg/NZyJH5AnuAPAcYv6Uj8gOOcPwwYP9+R+AH7aX8EMH5FjsQP2M/4SWD8ih2JH7BOfGDO+Mj4qfVs6hcZw0iWkQxn1PoP8/5Z53YM40mMZzCex3gJ41WMNzDeyngX4/2MjzI+zfgi4+uM7zJ+zPgl4/eMvzIuY8zmn4U2Z2zL2ImxB2NfxsGMIxhLGEcyVjKOZ9yEcTLjNMYZjLWMsxh3ZVzIuC/jIsYjGI9jPIXxLMYLGC9jvIZxMeMSxqWMDzI+zqgfLKwf0acfdqNvG69vwKpvZaZvCrL857VZ/2Ah54Fe76jXQer1kXrdZCGjXmep11/qdZl6vaZex6nXd+p1n3o9qF4nqteP6nWler2pXoeq16fqdat6Pate56rXv+p1sXq9rF5Hq9fX6nW3ej2uXqer1+/qdb0DsryVNvT66AHA+e2wfijS1cP2Q3obmBX/UATSOCqQaL2DgIkq5fegLHgbrfYXZxl/IQCM6WDgl0YJb0XRmZvNHYmknV0csbOzh++YFbbi12tSjg0hGUoyjGQ4yQiStUjU7359kiKSYpISklKSjvy/+qfS5qb2ZQdiofbpnwrress1/qcS5J/AYJIsMGxOpPE7O43fOQa2MD73AjFozXHIw9pca8bbC7RFMOaecf5cb0W7gGzxG4gh66qbs9uCugV1kxZUz55ZM37BnJr5M+fOGVc1e7aZmNpwnaCJNIEL7jcbQf+SJ8fYV2A4qPdpXfnGPrOBdWCaoSta9erdDONBepNh3bRgSJZMzwmKh69fmLEo4zflWRG7aYFy/G3DWRWAwsA50XMtQzKnQMt/a1QGpFPlQombBY4f0udUGl3VyZraUr+6rLbcr6sqTdXUVBT7flFVWVVZdVGqvq661E+VpkhnTVVRik5XVFXj1yWryurCuhZNZeEpj9oq4mtRTONUCFyLjrT8WlT5PVLoWhR9c4FythWtd7Llk/3aTmQujQJeg08GT/ardFT29fHCu2XVULvZn96KzFiszW9GR439Kcf/ChiDOocK5miBTmZ0lt2dDG8rFUJmdzeor187y/74oVku0ud1DF1+qrioqLxYHZeqTfoltTVFqaKi2uqSZE2yqqaorqLEr6gvKSoprqmtqSadVX59sr6qpqI+9Y9dYbHcdYRY7roxy8U0zroCLLfScpbbkJSOsNzRbCta7xhwYapwKp1ZXngsbZiDLG0svxkXNZY2VpClqWCOEyiScY6wtGFAljY2y/74oVka0uf1HGRp6wmxtPVjloZpnPUFWNp4y1ma8nu8IyxtHNuK1ruBAEvbIGSWNtxBlrYhv5kQNZa2oSBLU8GcIFAkExxhacOBLG3DLPvjh2ZpSJ83cpClbSTE0jaOWRqmcTYWYGmbWM7SlN+bOMLSJrCtaL2bCrC0TUNmab7dLC3terfN+M3EqLE05bi53k0FoDBwTvhvCzPviJavd9sM2KlNdIS9IH2elEaX7evdJgmxl81j9oJpnM0F2Mtky9mL8nuyI+xlItuK1rulI+vdkLm0Ba4z8rcUWO+m7Ovjhcf+iuxmf3pbaY5uS34zJWrsb0vBOToVzCkCncwUR+boioBzdFtm2R8/NMtF+ryVg3N0Wwmx3Kkxy8U0zlQBljvNcpar/J7mCMudwrai9W4tMEe3dchzdMUOsrRt+M30qLG0bQRZmgrmdIEime4ISysGsrRtsuyPH5qlIX3e1kGWtq0QS9suZmmYxtlOgKXNsJylKb9nOMLSprOtaL3bC7C07UNmaSUOsrQd+E1V1FjaDoIsTQWzSqBIqhxhaSVAlrZDlv3xQ7M0pM/VDrK0aiGWVhOzNEzj1AiwtFrLWZryu9YRllbFtqL11gmwtLqsVdlZAmw38K6d/prAPK0HxjOszrk+S6Zz3jHunDGNs6NA57yT5Z2z8nunkDrnZGabr26OOVigc56ZZbffqn1mOuC33tBXRV2APpcD63GWg4MQ0mbT3p3jQQjTODsLDEKzLR+ElN+zHRmEZrKtURuE1P3mJQahrQpk/c7UvlKhwXeq0Bpi9JQasH38qQV25/gUbmsPq1fE1ukO2VolaKve0KQzy8PV+gjg+LuLg6QTabNp75yYdGIaZ44A6ZxrOelUfs91iHTOjfAMQFegz2sB83JXBzvjXYU6493izhjTOLsJdMbzLO+Mld/zHOqM51neGSvb1EOqdEGqaU/1GN3RjOMYJzA2J9mdfcrzVjz5awR/vhZjknEi4xTG6YxVjO1I5hv6dCcw2Pvn8yCq1UwLmnj8wiYev0cTj9+zicfv1cTj927i8fs08fh9m3j8fk08fv8mHn9AE48/sInHH9TE4xc18fiDm3j8IcbxWf9yfD7JoY087rBGHnd4I487opHHHdnI445q5HFHN/K4Yxp53LGNPO64Rh53fCOPO6GRx53YyONOauRxJzfyuFOM46bycfO5fy7NSp+3QVzAxy1k3INxT8a9GPdm3IdxX8b9GPdnPIDxQMaDGBcxHsx4COOhjIcxHs54BOORjEcxHs14DOOxjMcxHs94AuOJjCcxnsx4SiPjE2M4OJTk1DT975rcTrsznsrYnuQ0g0+qTb+tZMyUr3UD6jodx/3iJzoH7Iz6E50v5NdnUI6dSXIWydkk55CcS3IeyfkkF5BcSHIRycUkl5BcSnIZyeUkV5BcSXIVydUk15BcS3IdyfUkN5DcSLKY5CaSm0luIbmV5DaSJSS3k9xBcifJXSR3kywluYfkXpL7SO4neYDkQZKHSB4meYTkUZLHSB4neYLkSZKnSJ4meYbkWZLnSJ4neYHkRZKXSF4meYXkVZLXSF4neYPkTZK3SN4meYfkXZL3SN4n+YDkQ5KPSD4m+YTkU5LPSD4n+YLkS5KvSL4m+YbkW5LvSL4n+YHkR5KfSH4m+YXkV5LfSH4n+YPkT5K/VH9F8nfWP0XbjCSLJEGSTZJDkkuSR5JPUkDSnKQFSUuSViStSdqQtCVpR9KepAPJGiQdSTqRdCbpQtKVpBtJd5IeJD1JepH0Jikk6UPSl6QfSX+SASQDSQaRDCZZk2QIyVCSYSTDSUaQrEWiZrBU51NEUkxSQlJKUkZSTpJKxE8It/sJ4VW+bU8I78C6aqpmz540b+bCqvl1+vngZhenTdZdXSJNyIL7nXs2+OmGJyC9oT0b/MwsmTEYFI+090qt4JYdmYjYL/yU428bzqoAFAbOif6Gx0yQTO+VquzPUNdyYj4y4cYyHaTPo9Losv1eqaOA7WTau3Yi/lYL0jgqkGi9o4FJL+X36AS8jUTWOY5kW9F6t3HkXqnIXFoH1xn5yPjpAV3Z18cL7/4OZ9nN/vS20v0d1uUEq4wa+1OOS93fQQWzUqCTqUzY3cnwtlIhZHp/h3UT9scPzXKRPo8xdLlyf4cxQix3bMxyMY0zVoDljrOc5Sq/xznCcivZVrTe9cCFqYpQ6eSvBUJhaWc7yNLW57wbHzWWtr4gS1PBHC9QJOMdYWlnA1na+gn744dmaUifN3CQpW0gxNI2jFkapnE2FGBpEyxnacrvCY6wtPFsK1rvRgIsbaOQWdo5DrK0jTnvNokaS9tYkKWpYG4iUCSbOMLSzgGytI0T9scPzdKQPm/qIEvbVIilbRazNEzjbCbA0iZaztKU3xMdYWmbsK1ovZMEWNqkkFnaBXaztLTr3TbnvJscNZa2eWC92+QQ1rtdkDl7Wb7ebXNgpzbZEfaC9HkLB9e7bSHEXraM2QumcbYUYC9TLGcvyu8pjrCXyWwrWu+2jqx3Q+bSVsD1btsKrHfbKuT1bhc6OEc3lRNsWtTY31TBOToVzGkCncw0R+boLgTO0U1N2B8/NMtF+ry1g3N0Wwux3G1ilotpnG0EWO50y1mu8nu6Iyx3GtsKZ7kCc3TbhjxHd5GDLG07zrsZUWNp2wmyNBXMGQJFMsMRlnYRkKVtl7A/fmiWhvR5ewdZ2vZCLG2HmKVhGmcHAZZWZTlLU35XOcLSZrCtaL3VAiytOmSWdrGDLK2G8642aiytRpClqWDWChRJrSMs7WIgS6tJ2B8/NEtD+lznIEurE2Jp9TFLwzROvQBL29Fylqb83tERllbLtqL17iTA0nYKmaWlhAYBcF6sxNJmct7NihpLmynI0lQwZwkUySxHWFoK0OFqljYzYX/80CwN6fPODrK0nYVY2uyYpWEaZ7YAS9vFcpam/N7FEZY2i21F650jwNLmJFZlZwmw3cC79PtnZOHsmguMZ1id81yhznnXuHPGNM6uAp3zbpZ3zsrv3ULqnJOZbctvY47unOcl7PZbtc+8hP1+6w19VdQF6PNIYD3u7uAgtLvQIDQ/HoQwjTNfYBBaYPkgpPxe4MggNI9tjdogpJ4vJTEIzSiQ9TtT+9RzrCT83l7ol17oKTVg+/jbF9id47OYaHlYvSK2TnPI1hkO2VoraKve0AQ5y8P1S+cCZ2kWOkiQFwoR5D1igoxpnD0ECPKelhNk5feeDhHkPSM8W9EV6PN5wM54Lwc7472EOuO9484Y0zh7C3TG+1jeGSu/93GoM97H8s5Y2aYee6oLUk3RqqewVzKOZ9yEsTnJvuxTnrfiKbKKuarPz2M8n3Ey/980xhmMtYztSPYz9OlHtib5c5+xiLGYsYSxlLElyf6GnhNYz378+SVsz6WMlzFezngF45WMVzFezXgN47WM1zFez3gD442MixlvYryZ8RbGWxlvY1zCeDvjHYx3Mt7FeDfjUsZ7GO9lvI/xfsYHGB9kfIjxYcZHGB9lfIzxccYnGJ9kfIrxacZnGJ9lfI7xecYXGF9kfInxZcZXGF9lfI3xdcY3GN9kfIvxbcZ3GN9lfI/xfcYPGD9k/IjxY8ZPGD9l/Izxc8YvGL9k/Irxa8ZvGL9l/I7xe8YfGH9k/InxZ8ZfGH9l/I3xd8Y/GP9k/ItxGePfjB7neTPGLMYEYzZjDmMuYx5jPmOBrnPGFrq+GFsxtmZsw9hW1zNje8YOjGswdmTsxNiZsQtjV8ZujN0ZezD2ZOzF2JuxkLEPY1/Gfoz9GQcwDmQcxDiYcU3GIYxDGYcxDmccwbgW4/6MZYzlWg/JAUa/pIeuM7jd9uXjDtBxIzmQD0KPR+rr2wMFxqODLJ8970Y6TsvC+73IQVLf05Mh9QfHpB7TOAcLkPpDLCf1yu9DhEi93rICujONAzKmh+I6kobVzglv1c3mjkTSzh6O2Nndw3fMClvx68MoKQ4nOYLkSJKjSI4mOYbkWJLjSI4nOYHkRJKTSDry/xakySm1LzsQC7VP/xxH11uu8T+VIP8EBpNkgWFzIo3f2Wn8zjGwhfG5F4hBa45DHtbmWjPeXqAtgjH3jPPneivaBWSLn086urKuujm7LahbUDdpQfXsmTXjF8ypmT9z7pxxVbNnm4mpDdcJmkgTuOB+sxHy+XWOsa/AcFDv07ryjX1mA+vANENXtOrVexnGg/Q2UEUzQHpD2394QqbnBMUj7Y3wT+aWPSURsR8GKsffNpxVASgMnDMBPvfhmVOg5TfCPxlIp04RStwscPyQPp+aRpftN8I/FTyPrbfT4mtRTOOcJnAterrl16LK79OFrkXRE1CnsK1ovdWO3AgfmUtnAK/BqwVuhK/s6+OFd1uII+xmf3pb6bYQZ3KCnRU19qccl7othArmWQKdzFkJuzsZ3lYqhExvC3Fmwv74oVku0uezDV2u3BbibCGWe07McjGNc44Ayz3Xcpar/D7XEZZ7FtuK1nseuDBVESqdWV54LO1IB1na+Zx3F0SNpZ0vyNJUMC8QKJILHGFpRwJZ2vkJ++OHZmlIny90kKVdKMTSLopZGqZxLhJgaRdbztKU3xc7wtIuYFvRei8RYGmXhMzSjnKQpV3KeXdZ1FjapYIsTQXzMoEiucwRlnYUkKVdmrA/fmiWhvT5cgdZ2uVCLO2KmKVhGucKAZZ2peUsTfl9pSMs7TK2Fa33KgGWdlXILO04B9e7Xc15d03UWNrVgfVu14Sw3u044Hq3q4Gd2jWOsBekz9c6uN7tWiH2cl3MXjCNc50Ae7necvai/L7eEfZyDduK1lvryHo3ZC7dAFzvViuw3u2GkNe7He/gHN2NnGCLo8b+bhSco1PBXCzQySx2ZI7ueOAc3Y0J++OHZrlIn29ycI7uJiGWe3PMcjGNc7MAy73Fcpar/L7FEZa7mG1F671VYI7u1pDn6E5wkKXdxnm3JGos7TZBlqaCuUSgSJY4wtJOALK02xL2xw/N0pA+3+4gS7tdiKXdEbM0TOPcIcDS7rScpSm/73SEpS1hW9F67xJgaXeFzNJOdJCl3c15tzRqLO1uQZamgrlUoEiWOsLSTgSytLsT9scPzdKQPt/jIEu7R4il3RuzNEzj3CvA0u6znKUpv+9zhKUtZVvReu8XYGn3J+QfKQ68a6d/GDBPHwDGM6zO+QGhzvnBuHPGNM6DAp3zQ5Z3zsrvh0LqnJOZbb66OeahAp3zwwm7/Vbt87ADfusNfVXUA+jzKcB6fMTBQegRoUHo0XgQwjTOowKD0GOWD0LK78ccGYQeZlujNgip+81LDEL1lj9S/CShwXdHRx4pDmwff0fLHym+mNvaw+oVsXWJQ7YuFbRVb2jSmeXhav1o4Pj7uIOk83Eh0vlETDoxjfOEAOl80nLSqfx+0iHS+WSEZwB6An0+BpiXTznYGT8l1Bk/HXfGmMZ5WqAzfsbyzlj5/YxDnfEzlnfGyjbzMd1q2lM9LvYsxgsYL2NUj+l+ln0yH9N9NH9+DOOxjNcwLmZcwriUUT2m+zlDn27awR4/PjeAajXT8008/oUmHv9iE49/qYnHv9zE419p4vGvNvH415p4/OtNPP6NJh7/ZhOPf6uJx7/dxOPfaeLx7zbx+PeM47P+5fh8kvcbedwHjTzuw0Ye91Ejj/u4kcd90sjjPm3kcZ818rjPG3ncF4087stGHvdVI4/7upHHfdPI475t5HHfGcdN5eOe4/75pET6vA3i83zcC4wvMr7E+DLjK4yvMr7G+DrjG4xvMr7F+DbjO4zvMr7H+D7jB4wfMn7E+DHjJ4yfMn7G+DnjF4xfMn7F+DXjN4zfMn7XyPjEGA4OJfk+Tf97GLfTs4zfM7Yn+SGx6gp2NBccTMq7GfpBepGr2P3gDjMeP3Igf0pEbBW7cnyp4exPBvlGJ4lKEJUo6AuGWSHdhqaJdiYDdvo/Ai8+f8JdJPmzHPkKDhm/n1ejK1VeV11fXlJclSypryY9ZfV1xVVFFX59qpjUF5f41VV1ydqS6vKykrJUfXloM1Y/49p8pRmrX+IZK0zj/JLA6/0VmPRSfv+agLeRyBqGn9hWtN7Zlt4HLWgnMpd+Aw5AswXug6bsG+OF99vNTAbk+pW3mjTmirDe3znB/lgN6x2bJmZB1jvW+2/Wm07Pf7JeiSlrkC6RzlQ1yO8CHdTvCXyB/cEFZm6ZdliBDdle/h/Azu9PXLHX63j+iY/nKsX/u6Xx/Atcl3pDX4H8BPR5GXjAkPga7i+BvmiO5Ysfld/LBPye68hVNrB9/LB8Ro6Pmer6G9jHSuX33wmZ/gLZ1hJT1IsE/FYsGeW3IuFqtkXPxqgXaupfi0RcpGZlm2Xb388rG9F+ZwH9zuZ8CG7IuErENivbfhsTAjY2bOjB6WHg4JSdbf/gJFGUOQ50Rj8IDE7zLCfbqgizBdp7dzu/ElzFzlxgPQLb2kfGT3gQW/5VEjo3cxwYxHJdGcR6AXXlAYtGFXTCW3VDNxTwBkJJSTt7OGJnd6Cd5tcUF/LrfMqxApLmJC1IWpK0ImlN0oakLUk7kvYkHUjWIOlI0omkM0kXkq4k3Ui6k/Qg6UnSi6Q3SSFJH5K+JP1I+pMMIBlIMkhd9ZGsSTKEZCjJMJLhJCNI1iJRvapPUkRSTFJCUkpSRlJOkiKpIBlJMopkbZLRJOuQrKvqh2QMyViScSTrkaxPMp5kA5INSSaQbESyMckmJJuSbEYykWQSyeYkk0m2INmSZArJViRTSaaRbE2yDcl0km1JtiOZQbI9yQ4kVSTVJDUktSR1JPUkO5LsRDKTZBbJziSzSXYhmUMyl2RXkt1I5pHsTjKfZAHJQpI9SPYk2Ytkb5J9SPYl2Y9kf5IDSA4kOYhkEcnBJIeQHEpyGMnhJEeQHElyFMnRJMeQHEtyHMnxJCeQnEhyEsnJJKeQnEpyGsnpJGeQnElyFsnZJOeQnEtyHsn5JBeQXEhyEcnFJJeQXEpyGcnlJFeQdORcLEjTR6l92YHaUvv013i6/zYH3kpQvQisB0kWGDYn0vidncbvHANbGJ97gRi05jjkQW2u8s14e4G2CMbcM86f661oF4wtST+fdHRgXTVVs2dPmjdzYdX8uvEL5tTMnzl3jtnFaZN1V5dIE7LgfjP8+fw6x9hXYLim92ld+cY+s2l1SJqhxwZ1b6y87BXGg/Qmw1pKoMYdlM1pzM1Ud9oH6l7J8b4qO2ILaJXjbxvOqgAUBs6J/lrcTJBMH6h7Zea6VjzNWihx0V9xIX2+Oo0u2x+oezWwnUx7r8mOF5JCGkcFEq33WmDSS/l9rcConc5WREd3bTZe70JHHqiLzKXrcJ2Rv1BgIamyr48X3kLS5nazP72t9BCQ67lub4ga+1OOSz0ERAXzBoFO5oZsuzsZ3lYqhEwfAnJ9tv3xQ7NcpM83GrpceQjIjUIsd3HMcjGNs1iA5d5kOctVft/kCMu9gW1F670ZXJiqCJXOLC88ltbCQZZ2C+fdrVFjabcIsjQVzFsFiuRWR1haCyBLuyXb/vihWRrS59scZGm3CbG0JTFLwzTOEgGWdrvlLE35fbsjLO1WthWt9w4BlnZHyCytpYMs7U7Ou7uixtLuFGRpKph3CRTJXY6wtJZAlnZntv3xQ7M0pM93O8jS7hZiaUtjloZpnKUCLO0ey1ma8vseR1jaXWwrWu+9Aizt3pBZWlsH17vdx3l3f9RY2n2B9W73h7DerS1wvdt9wE7tfkfYC9LnBxxc7/aAEHt5MGYvmMZ5UIC9PGQ5e1F+P+QIe7mfbUXr3dOR9W7IXHoYuN5tT4H1bg+HvN6tnYNzdI9w3T4aNfb3iOAcnQrmowKdzKOOzNG1A87RPZJtf/zQLBfp82MOztE9JsRyH49ZLqZxHhdguU9YznKV3084wnIfZVvRep8UmKN7MuQ5uvYOsrSnOO+ejhpLe0qQpalgPi1QJE87wtLaA1naU9n2xw/N0pA+P+MgS3tGiKU9G7M0TOM8K8DSnrOcpSm/n3OEpT3NtqL1Pi/A0p4PmaV1cJClvcB592LUWNoLgixNBfNFgSJ50RGW1gHI0l7Itj9+aJaG9PklB1naS0Is7eWYpWEa52UBlvaK5SxN+f2KIyztRbYVrfdVAZb2asgs7QoHWdprnHevR42lvSbI0lQwXxcoktcdYWlXAFnaa9n2xw/N0pA+v+EgS3tDiKW9GbM0TOO8KcDS3rKcpSm/33KEpb3OtqL1vi3A0t7OXpWdoR/HAbxLv58PzNN3gPEMq3N+R6hzfjfunDGN865A5/ye5Z2z8vu9kDrnZGbb8tuYozvn97Pt9lu1z/sO+K039FVRD6DPVwHr8QMHB6EPhAahD+NBCNM4HwoMQh9ZPggpvz9yZBB6n22N2iCkni8lMQjtLfxAxkztW0No8N3HkaefA9vH36fA7hx/ndvaw+oVsfVRh2x92iFbXxS0VW9ogpzl4fqlVkCu8LGDBPljIYL8SUyQMY3ziQBB/tRygqz8/tQhgvxphGcregJ9bg3My88c7Iw/E+qMP487Y0zjfC7QGX9heWes/P7Coc74C8s7Y2WbeuypDqmaol3m/fOoH4W3Mt7F2JzkS/Ypz1vxFNlW/HlrxjaM9zM+yvg044uM7Ui+MvTpR7ZewJ9fyHgR48WMlzBeytiS5GtDzwms5yv+fA3GjoydGDszdmHsytiNsTtjD8aejL0YezMWMvZh7MvYj7E/4wDGgYyDGAczrsk4hHEo4zDG4YwjGNdiTDL6jEWMxYwljKWMZYzljCnGCsaRjKMY12YczbgO47qMlYxjGMcyjmNcj3F9xvGMGzBuyDiBcSPGjRk3YdyUcTPGiYyTGDdnnMy4BeOWjFMYt2KcyjiNcWvGbRinM27LuB3jDMbtGXdgrGKsZqxhrGWsY6xn3JFxJ8aZjLMYd2aczbgL4xzGuYy7Mu7GOI9xd8b5jAsYFzLuwbgn416MezPuw7gv436M+zMewHgg40GMixgPZjyE8VDGwxgPZzyC8UjGoxiPZjyG8VjG4xiPZzyB8UTGkxhPZjyF8VTG0xhPZzyD8UzGsxjPZjyH8VzG8xjPZ/ya8TLGy3Udk3yTvaJf0iQnnz//kvEbxvYk32avuvoXPTYNJuWnGycA6UWuAPaDO8x4fJf9D36fHbEVwMrxpYazKgCVAeNQ59RJgiYw+4d0o7Um2pkM2Ol/l43z2WynZGabv78jX18g4/fDanSlyuuq68tLiquSJfXVpKesvq64qqjCr08Vk/riEr+6qi5ZW1JdXlZSlqovD+0K+odsLFHX24/Z8RU0pHF+zMbr/QmY9FJ+/5QNbyOR73+/Z1vReg+09E6fQTuRufQzcAA6UOBOn8q+MV54v3vLZECuX3mrSWOuCOv9hev219Ww3rFpYhZkvWO9/2a96fT8J+uVmEID6RLpTFWD/CLQQf2SjS+wX7nAzA39/QuwvfxfgZ3fb7hir9fx/A0fz1WK/xdL4/k7uC71hr4C+R7o8x/gAUPia4HfBfqiRZYvHFN+/yHg98GOXGUD28cPy2fk+Jiprj+BfaxUfv+ZLdNfINtaYvbxoATe77+AfisSnu+tmI1Rugd7K0QqLhKzsssszweVr8sE6uBvoN/ZnA/BDRlXidj+nW2/jeqKF21jw4YenN4HDk7NcuwfnCSKMivH/s7oWwG/D7OcbKsiVDmJ9vtwO78SXMXOBLAegW3tI+MnPIgt/yoJnZtZOfYPYgmpQQxdkNk5ziSUWGNlO5BQOWgbXbmMy40TtOGmHLbbmBcWbU9mthWZwcw0OfPj5PTzHeg9CxxJzmJkcjaPk9Nv7kBytnAkOf1lwAmPluAJj39rnIx/qg0uolxv1Q2lXypBWzlQRK1d4MeLBPhxmzhBneDHbaPIj9vFyem3c6D3bB9FftwhTk6/gwPJuYYr/LgZkB93tPwLwV4q4QW+IDrK8i/G1L1xcwT8PtqRL8Y6AfMS2Nb+0Q7kTZ5A3nS2/At05XeBgN9dHPC7hYDfXS33W40LEgtFjnOgvlsKtPfxjowL3YDjArCt/eMtzxtVL60F8uYkB+qljYDfJztSL92B9QJsa/9kB+qlrUDe9HBgXG0v4HdPB/xeQ8DvXg743VHA79Msr281hyLx/JnTHRkXegPHBWBb+8j4hXVflj44XSvdl6UwJ74vC6RxCnME9ObgilHK7z458DYS/RkmMqZ9gR1cwltRdOZmc0ciaWehI3b29vAds8JW/Lof5Vh/kgEkA0kGkQwmWZNkCMlQkmEkw0lGkKxF0pH/tyBNTql92YFYqH26jHW9md8AVoL8ExhMkgWGzYk0fmen8TvHwBbG514gBq05DnlYm2vNeHuBtgjG3DPOn+utaBeQLb5aCdmVddXN2W1B3YK6SQuqZ8+sGb9gTs38mXPnjKuaPdtMTG24TtBEmsAF95uNoJde5hj7CgwH9T6tK9/YZzawDkwzdEWrXr2vYTxIbzKsu0T1l/qOGWPn8hvGmLFIcjb4ORG7N6py/G3DWRWAwsA50Xc86p85BSrS9xtNAumUL5S46LURSJ+L0uiqTtbUlvrVZbXlfl1VaaqmpqLY94uqyqrKqotS9XXVpX6qNEU6a6qKUnS6oqoavy5ZVVYX1rVoUQ6e8jT4H1+LYhqnWOBatMTya1Hld4nQtSh6As9nW9F6z7L0HqF603Yic6kUeA2OjJ8e0JV9fbzw7hE6wG72p7ciMxZlXLflUWN/yvG/AsagzqGCWS7QyZTn2N3J8LZSIfyvPtfxzQ/LcuyPH5rlIn1OGbr8VHFRUXmxOi5VS7yitqYoVVRUW12SrElW1RTVVZT4FfUlRSXFNbU11aSzyq9P1lfVVNSn/rErLJabEmK5FTHLxTROhQDLHWk5y1V+j3SE5ZazrWi9o8CFqYpQ6czywmNpAx1kaWtz3o2OGktbW5ClqWCOFiiS0Y6wtIFAlrZ2jv3xQ7M0pM/rOMjS1hFiaevGLA3TOOsKsLRKy1laQ1I6wtJGs61ovWMEWNqYkFnaIAdZ2ljOu3FRY2ljBVmaCuY4gSIZ5whLGwRkaWNz7I8fmqUhfV7PQZa2nhBLWz9maZjGWV+ApY23nKUpv8c7wtLGsa1ovRsIsLQNQmZpQx1c77Yh592EqLG0DQPr3SaEsN5tKHC924bATm2CI+wF6fNGDq5320iIvWwcsxdM42wswF42sZy9KL83cYS9TGBb0XrPcWS9GzKXNgWudztHYL3bpiGvdxvm4BzdZly3E6PG/jYTnKNTwZwo0MlMdGSObhhwjm6zHPvjh2a5SJ8nOThHN0mI5W4es1xM42wuwHInW85yld+THWG5E9lWtN4tBObotgh5jm64gyxtS867KVFjaVsKsjQVzCkCRTLFEZY2HMjStsyxP35olob0eSsHWdpWQixtaszSMI0zVYClTbOcpSm/pznC0qawrWi9WwuwtK1DZmkjHGRp23DeTY8aS9tGkKWpYE4XKJLpjrC0EUCWtk2O/fFDszSkz9s6yNK2FWJp28UsDdM42wmwtBmWszTl9wxHWNp0thWtd3sBlrZ9zqrsDH0r5T7APOgHzNMdgPEMq3PeQahzroo7Z0zjVAl0ztWWd87K7+qQOudkZpvfl3T0Feica3Ls9lu1T40DfusNfVVUCPTZB9ZjrYODUK3QIFQXD0KYxqkTGITqLR+ElN/1jgxCNWxr1AYhdb95iUHoPOGH6WRq31pCg+/5QmuI0VNqwPbxz7f8wUkTua09rF4RW6c4ZOt0QVv1hiadWR6u1gcDx98dHSSdOwqRzp1i0olpnJ0ESOdMy0mn8numQ6RzZoRnAPoAfV4TmJezHOyMZwl1xjvHnTGmcXYW6IxnW94ZK79nO9QZz7a8M1a2qYdU6YJU057LvH9uzK5wNOM4xuYku7BPed6KJ38N5s/XZBzCOIFxIuMUxumM7UjmGPp0JzDY++fzIKrVTHObePyuTTx+tyYeP6+Jx+/exOPnN/H4BU08fmETj9+jicfv2cTj92ri8Xs38fh9mnj8vk08fr8mHr+/cXzWvxyfT3JAI487sJHHHdTI4xY18riDG3ncIY087tBGHndYI487vJHHHdHI445s5HFHNfK4oxt53DGNPO7YRh53nHHcVD5uDvfPa+Wkz9sgzuXjdmXcjXEe4+6M8xkXMC5k3INxT8a9GPdm3IdxX8b9GPdnPIDxQMaDGBcxHsx4COOhjIcxHs54BOORjEcxHs14DOOxjMc1Mj4xhoNDSY5P0//243bahfF4xvYkJ+SsuoIdPTt+CJ2gWTZO36Gkr7fwTGmGuv3gDjO+J7LtJ+VEbFW8cnyp4exJBplHX4DopENfgFxk+dczujjQfl8c0u18mmhnMmCnfyLwIv4koK5LLL8dEm8+ML99YM74lzjyVTAy/05eja5UeV11fXlJcVWypL6a9JTV1xVXFVX49aliUl9c4ldX1SVrS6rLy0rKUvXloc2cniw0c3pKPHOKaZxTBGZOT7V85lT5fWpIM6eIQedUgQH8CksHoKCdyFw6DdcZ+VcI3I9P2TfGC+83xCdlEI/6lbeaNOaKXC2dznV7xmqulsamiVnwamms999XS+n0/OfVksRXJyBdIp2papDTBTqo03PwBXYGF5i5oRkzsL38M4Cd35m4Yq/X8TwTH89Viv90S+N5Frgu9Ya+AkFetZ4NHjAkvg4+S6AvusryWR7l99kCfl/tyFU2sH38sHxGjo8Z35wb2MdK5fc5OTL9BbKtJWat2wj4fZ0Ds9bdBfy+3s5Z61XsPBdYj8C29q93IG96COTNeZb3E8rvngJ+n++A370E/L4A6LeapFBLBfVstaptlU8qthcYk5BqQ/cjFwL7EUu/CRLj0xcK5NVFwLzK5rwKbsi4SsT2ohz7bbxY6NoefhFQg/xK2oGLAImivNTyQU75fYKA34st74RVEV4i4PdNjlwEXAasR2Bb+8j4CQ9iy7+yR+fmpQ4MYpe5Moj1Beq6HFg0qqAT3qobuqH6eDINhbaz0BE7ewPtNL8OvpBfX0E5diXJVSRXk1xDci3JdSTXk9xAciPJYpKbSG4muYXkVpLbSJaQ3E5yB8mdJHeR3K3WwpLcQ3IvyX0k95M8QPIgyUMkD5M8QvIoyWMkj5M8QfIkyVMkT5M8Q/IsyXMkz5O8QPIiyUskL5O8QvIqyWskr5O8QfImyVskb5O8Q/IuyXsk75N8QPIhyUckH5N8QvIpyWckn5N8QfIlyVckX5N8Q/ItyXck35P8QPIjyU8kP5P8QvIryW8kv5P8QfInyV8ky0j+VlfEuRRvkiySBEk2SQ5JLkkeST5JAUlzkhYkLUlakbQmaUPSlqQdSXuSDiRrkHQk6UTSmaQLSVeSbiTdSXqQ9CTpRdKbpJCkD0lfkn4k/UkGkAwkGUQymGRNkiEkQ0mGkQwnGUGyFkmSxCcpIikmKSEpJSkjKSdJkVSQjCQZRbI2yWiSdUjWJakkGUMylmQcyXok65OMJ9mAZEPlD+diQZo+Su3LDtSW2qcnG3T/nWv8TyWoXgTW3SULDJsTafzOTuN3joEtjM+9QAxacxzyoDZX+Wa8vUBbBGPuGefP9Va0C8aWpJ9POjqwrpqq2bMnzZu5sGp+3fgFc2rmz5w7x+zitMm6q0ukCVlwvxn+fH6dY+wrMFzT+7SufGOf2bQ6JM3QY4O6F+blRsOA9CbDWrJ1pRSpw9i5fPWGGYsJ3PIb5UbsBy7K8bcNZ1UACgPnRC8/ujLzGaEi/eMJZX+GulY8TD7XjaUESJ83TqOrOllTW+pXl9WW+3VVpamamopi3y+qKqsqqy5K1ddVl/qp0hTprKkqStHpiqpq/LpkVVldWAv2Nwa2k2nvJrnxgn1I46hAovVuCkx6Kb83zYW3kciC/Y3YVrTeWy3/xdjyh94Dc2kzXGfk3yqwYF/Z18cLb8H+VXazP72t9NCviVy3k6LG/pTjUg/9UsGcJNDJTMq1u5PhbaVCyPShXxNz7Y8fmuUifd7c0OXKQ782F2K5k2OWi2mcyQIsdwvLWa7yewtHWO4kthWtd0twYaoiVDqzvPBY2tUOsrQpnHdbRY2lTRFkaSqYWwkUyVaOsLSrgSxtSq798UOzNKTPUx1kaVOFWNq0mKVhGmeaAEvb2nKWpvze2hGWthXbita7jQBL2yZklnaNgyxtOufdtlFjadMFWZoK5rYCRbKtIyztGiBLm55rf/zQLA3p83YOsrTthFjajJilYRpnhgBL295ylqb83t4RlrYt24rWu4MAS9shZJZ2g4Pr3ao476qjxtKqAuvdqkNY73YDcL1bFbBTq3aEvSB9rnFwvVuNEHupjdkLpnFqBdhLneXsRfld5wh7qWZb0XqXOLLeDZlL9cD1bksE1rvVh7ze7UYH5+h25LrdKWrsb0fBOToVzJ0EOpmdHJmjuxE4R7djrv3xQ7NcpM8zHZyjmynEcmfFLBfTOLMEWO7OlrNc5ffOjrDcndhWtN7ZAnN0s0Oeo1vsIEvbhfNuTtRY2i6CLE0Fc45AkcxxhKUtBrK0XXLtjx+apSF9nusgS5srxNJ2jVkapnF2FWBpu1nO0pTfuznC0uawrWi98wRY2ryQWdpNDrK03Tnv5keNpe0uyNJUMOcLFMl8R1jaTUCWtnuu/fFDszSkzwscZGkLhFjawpilYRpnoQBL28Nylqb83sMRljafbUXr3VOApe0ZMkvbUGgQAOfFSixtL867vaPG0vYSZGkqmHsLFMnejrC0DQEdrmZpe+XaHz80S0P6vI+DLG0fIZa2b8zSMI2zrwBL289ylqb83s8RlrY324rWu78AS9s/d1V2hn4cRx9gHlyRg7PrAGA8w+qcDxDqnA+MO2dM4xwo0DkfZHnnrPw+KKTOOZnZtvw25ujOeVGu3X6r9lmUa7/fekNfFRUCfd4IWI8HOzgIHSw0CB0SD0KYxjlEYBA61PJBSPl9qCOD0CK2NWqDkHq+lMQgdIfwAxkztU89x0rC7zuFfumFnlIDto9/Z4HdOb43Ey0Pq1fE1p0csnWOQ7bOF7RVb2iCnOXh+qVrgbM0hzlIkA8TIsiHxwQZ0ziHCxDkIywnyMrvIxwiyEdEeLaiD9Dn64Cd8ZEOdsZHCnXGR8WdMaZxjhLojI+2vDNWfh/tUGd8tOWdsbJNPfZUF6Saol3m/fOoH4VbMW7L2JzkGPYpz1vxFFnFXNXn1zFez1jN/7cT4xzG+YztSI419OmmreTPxzCOZRzHuB7j+owtSY4z9JzAeo7lz29me25hvJXxNsYljLcz3sF4J+NdjHczLmW8h/FexvsY72d8gPFBxocYH2Z8hPFRxscYH2d8gvFJxqcYn2Z8hvFZxucYn2d8gfFFxpcYX2Z8hfFVxtcYX2d8g/FNxrcY32Z8h/FdxvcY32f8gPFDxo8YP2b8hPFTxs8YP2f8gvFLxq8Yv2b8hvFbxu8Yv2f8gfFHxp8Yf2b8hfFXxt8Yf2f8g/FPxr8YlzH+zehxnjVjzGJMMGYz5jDmMuYx5jMW6DpjbKHzm7EVY2vGNoxtdT0xtmfswLgGY0fGToydGbswdmXsxtidsQdjT8ZejL0ZCxn7MPZl7MfYn3EA40DGQYyDGddkHMI4lHEY43DGEYxrMSYZfcYixmLGEsZSxjLGcsYUYwXjSMZRjGszjmZch3FdxuMYxzNuoP0gOd7olzTJuYLz5hg+7njdbiQn5K66+hc9s3gInWBZNvBbDtLXLWeFvSC9yBXFfnCHGd8TeeA5KTdiK4qV40sNZ08yyAWaEOmkQxOipZZPbeviQPt9T0g3rGuincmAnf6JwIuKk4C67rX8hn+8+cD89oE549/ryNdoyPw7eTW6UuV11fXlJcVVyZL6atJTVl9XXFVU4denikl9cYlfXVWXrC2pLi8rKUvVl4c2k3Oy0EzOKfFMDqZxThGYyTnV8pkc5fepIc3kIAadUwVmch60dAAK2onMpdNwnZH/oMAdZ5V9Y7zwfn95UgbxqF95q0ljrsjV0ulct2es5mppbJqYBa+Wxnr/fbWUTs9/Xi1JTOWCdIl0pqpBThfooE7PxRfYGVxg5oZmzMD28s8Adn5n4oq9XsfzTHw8Vyn+0y2N51ngutQb+goEedV6NnjAkPh66iyBvuhhy2d5lN9nC/j9iCNX2cD28cPyGTk+ZqrrHGAfK5Xf5+TK9BfItpaYtc4VmL193IFZ604Cfj9h56z1KnaeC6xHYFv7TziQN50F8uY8y/sJ5XcXAb/Pd8DvrgJ+XwD0W01SqCVCerZa1bbKJxXbC4xJSLWh+5ELgf2Ipd8EifHpCwX4xkXAvMrmvApuyLhKxPaiXPttvFjo2h5+EbAIeBFwiQMXARJFeanlg5zy+wQBv5+2vBNWRXiJgN/POHIRcBmwHoFt7SPjJzyILf/KHp2blzowiF0mNYihC/LymBX5lzuQUFdIJRS657wyAtMnriZ63xz7bbwKneiuzHNd7cZ3mkV9gb+PvSYeffxrHBh9rnWhKCUmYa9zoyiLkUV5fVyU/vUOFOUNLhSlxDcENzqy+udC4AThYvAE4b8lZaZ23gTuPJp7q24o/f8Wg2Rmm3+TA53Hza5cT94CTPzrgNeT1xfEie7C9eStLoySPQRGydsieD25JB59/CUOjD63u1CUPQWK8o4IXk/eGRelf6cDRXmXC0XZS6Ao73blehJYlEstX3DSl3RcKbAA4XnLF16oZ61cIeD3C44svLgHmJfAtvZfsDxvVL1cLZA3LztQL1cJ+P2KI/VyL7BegG3tv+JAvVwnkDevO1Av1wr4/YYj9XIfsF6Abe2/4UC93CiQN287UC83CPj9jiP1cj+wXoBt7b/jQL1ILJh/34F6WSzg9weO1MsDwHoBtrX/gQP1crNA3nzsQL3cIuD3J47Uy4PAegG2tf+JA/Vyq0DefO5Avdwm4PcXjtTLQ8B6Aba1/4UD9XK7QN587UC93CHg9zeO1MvDwHoBtrX/jQP1cpdA3nzvQL3cLeD3D47UyyPAegG2tf+DA/WyVCBvfrbcb/Wd9OUC38n/4ki9PAqsF2Bb+8j4hXW/+gE4XSvdr/6x+H71mMZ5TOB+9Y8DfyQh5ffjQver11twoVDGtxgExvQJYAeX8FYUnbnZ3JFI2tnfETv7efiOWWErfv0k5dhTJE+TPEPyLMlzJM+TvEDyIslLJC+TvELyKklH/t+CNDml9mUHYqH26XvW63oz7wBXCfJPYDBJFhg2J9L4nZ3G7xwDWxife4EYtOY45GFtrjXj7QXaIhhzzzh/rmc8DRRji59POrqyrro5uy2oW1A3aUH17Jk14xfMqZk/c+6ccVWzZ5uJqQ3XCZpIE7jgfrMR8vl1jrGvwHBQ79O68o19ZgPrwDRDV7Tq1QcaxoP0JsN6esZTUj9fw9i5/Eb6Zixe45Z/PTdizxpUjr9tOKsCUBg4J/pJEE9lToGK9HPsXgPSqdcdWWuO9PmNNLqqkzW1pX51WW25X1dVmqqpqSj2/aKqsqqy6qJUfV11qZ8qTZHOmqqiFJ2uqKrGr0tWldWFdS36Ri6e8qjtzfhaFNM4bwpci75l+bWo8vstoWtR+EJYthWt93fLH96p7UTm0tvAa3Bk/PSAruzr44X37LSn7WZ/eisyY/EO1+27UWN/yvG/AsagzqGC+a5AJ/Nurt2dDG8rFcL/6nMdPxTqnVz744dmuUif3zN0+anioqLyYnVcqjbpl9TWFKWKimqrS5I1yaqaorqKEr+ivqSopLimtqaadFb59cn6qpqK+tQ/doXFct8TYrnvxywX0zjvC7DcDyxnucrvDxxhue+yrWi9H4ILUxWh0pnlhcfSnnGQpX3Eefdx1FjaR4IsTQXzY4m1/Y6wtGeALO2jXPvjh2ZpSJ8/cZClfSLE0j6NWRqmcT4VYGmfWc7SlN+fOcLSPmZb4T+WEWBpn4fM0p51kKV9wXn3ZdRY2heCLE0F80uBIvnSEZb2LJClfZFrf/zQLA3p81cOsrSvhFja1zFLwzTO1wIs7RvLWZry+xtHWNqXbCta77cCLO3bkFnaiw6ud/uO8+77qLG07wLr3b4PYb3bi8D1bt8BO7XvHWEvSJ9/cHC92w9C7OXHmL1gGudHAfbyk+XsRfn9kyPs5Xu2Fa33T0fWuyFz6Wfgerc/Bda7/RzyereXHJyj+4Xr9teosb9fBOfoVDB/FehkfnVkju4l4BzdL7n2xw/NcpE+/+bgHN1vQiz395jlYhrndwGW+4flLFf5/YcjLPdXthXOcgXm6P4MeY7uZQdZ2l+cd8uixtL+EmRpKpjLBIpkmSMs7WUgS/sr1/74oVka0ue/HWRpfwuxNHUrhZilZahTNY4KJFpvszy7WZryu1kevI1EWNoythWtNysPz9KUzjBZ2isOsrQE5112XsRYmnJciqWpYGYLFEl2nkyCoVnaK0CWlsizP35olob0OSfPPZaWAx4M9JYbszRM4+QKsLQ8y1ma8jvPEZaWzbai9eYLsLT8vFXZGfpWysC7dvpPAi+hC4DxDKtzLhDqnJvHnTOmcZoLdM4tLO+cld8tQuqck5lt/kDS8YTAHG7LPLv9Vu3TMs9+v/WGvirqD/T5deAg1MrBQaiV0CDUOh6EMI3TWmAQamP5IKT8buPIINSSbY3aINTPkxmElgk/TCdT+9R97SX8/ltoDTF6Sg3YPv7flj846Vduaw+rV8TWZQ7Zmp0nZ6ve0KQzy8PV+nNA0tnWQdLZVoh0totJJ6Zx2gmQzvaWk07ld3uHSGf7CM8ADAD6/DywM+7gYGfcQagzXiPujDGNs4ZAZ9zR8s5Y+d3Roc64o+WdsbJNhVMXpJr2XOb9c2N2hR8zfsnYnKQT+5TnrXjy13P8+fOMLzB+z/gr4zJGxfQVtiPpbOjTncBg75/Pg6hWM3Vp4vFdm3h8tyYe372Jx/do4vE9m3h8ryYe37uJxxc28fg+TTy+bxOP79fE4/s38fgBTTx+YBOPH2Qcn/Uvx+er1408bs1GHjekkccNbeRxwxp53PBGHjeikcet1cjjko08zm/kcUWNPK64kceVNPK40kYeV9bI48qN46bycZ25f341N33eBrELH9+VsRtjd8YejD0ZezH2Zixk7MPYl7EfY3/GAYwDGQcxDmZck3EI41DGYYzDGUcwrsWYZPQZixiLGUsYSxnLGMvzGhefGMPBoSSpNP3vk5zHnbi9UoztSSryVl3Bjp4d75PjeRfm4PT1JV2PCv3uNLj9j7r94A4zviOZOI7Ki9iqeOX4UsPZUQaZR1+A6KRDX4BkNbf7wksXB9rvRHOZQstwMWYyYKc/EngRPwqoKzuk+CUz23xgfvvAnPGl4oce7JD5t/ZqdKXK66rry0uKq5Il9dWkp6y+rriqqMKvTxWT+uISv7qqLllbUl1eVlKWqi8PbeZ0baGZ09HxzCmmcUbn4fWuA0x6Kb/XyYO3kchamlFsK/zXFZYOQEE7kbm0Lq4z8pHx0wRY2TfGC+83xKMyiEf9yltNGnNFrpYquW7HrOZqaWyamAWvlsZ6/321lE7Pf14tSXx1AtIl0pmqBqkU6KAq8/AFNoYLzNzQjBnYXv4YYOc3Flfs9TqeY/HxXKX4Ky2N5zhwXeoNfQWCvGpdDzxgSHwdPE6gL2pu+SyP8ns9Ab9bOHKVDWwfPyyfkeNjprrWB/axUvm9fp5Mf4Fsa4lZ61sEZm9bOzBr/aCA323snLVexc7xwHoEtrXfxvK8UfVym0DetHegXh4S8LuDI/WyAbBegG3td3CgXu4QyJtODtTLwwJ+d3akXjYE1guwrf3ODtTL3QJ5082BenlEwO/ujtTLBGC9ANvaR8ZPTaariWz9rarioGpcVX3FhDzPk4zvRsD4WrpiQWzeZyOB6+KNgdfF2ZxXwQ0ZV4nYbpxnv42bCM1BwyerWgInqzZ1YLJKoig3s3yySvldIeB3L8s7YVWEmwr43dsRcjQRWI/AtvaR8RMexJYvLUPn5mYODGITXRnEBgJ1TQIWjSrohLfqhm4o4I1tk5J29nfEzn5AO81lSxfy680pxyaTbEGyJckUkq1IppJMI9maZBuS6STbkmxHMoNke5IdSKpIqklqSGpJ6kjqSXYk2YlkJskskp1JZpPsQjKHZC7JriS7kcwj2Z1kPskCkoUke5DsSbIXyd4k+5DsS7Ifyf4kB5AcSHIQySKSg0kOITmU5DCSw0mOIDmS5CiSo0mOITmW5DiS40lOIDmR5CSSk0lOITmV5DSS00nOIDmT5CySs0nOITmX5DyS80kuILmQ5CKSi0kuIbmU5DKSy0muILmS5CqSq0muIbmW5DqS60luILmRZDHJTSQ3k9xCcivJbSRLSG4nuYPkTpK7SO4mWUpyD8m9JPeR3E/yAMmDJA+RPEzyCMmjJI+RPE7yBMmTJE+RPE3yDMmzJM+RPE/yAsmLJC+RvEzyCsmrJK+RvE7yBsmbJG+RvE3yDsm7JO+RvE/yAcmHJB+RfEzyCcmnJJ+RfE7yBcmXJF+RfE3yDcm3JN+RdORcLEjTR6l92YHaUvv0sj7dfxu/7YLVi8D68GSBYXMijd/ZafzOMbCF8bkXiEFrjkMe1OYq34y3F2iLYMw94/y53op2wdiS9PNJRwfWVVM1e/akeTMXVs2vG79gTs38mXPnmF2cNll3dYk0IQvuN8Ofz69zjH0Fhmt6n9aVb+wzm1aHpBl6bFD3bJ6Ut8J4kN5kWEuL1biDsjmNuZnqXr7K0IzF9xzvH/Ii9kNM5fjbhrMqAIWBc6KXyZoJ8j+S6SL9I7/v83DE/AehxEUveUP6/GMaXdXJmtpSv7qsttyvqypN1dRUFPt+UVVZVVl1Uaq+rrrUT5WmSGdNVVGKTldUVePXJavK6sL6YdmPeXjyrLaf8uIflkEaRwUSrfdnYNJL+f2zwKidzlZER/dzHl5vX8t/2aztRObSL7jOyO8r8MMyZV8fL7wflm1hN/vT20oPp/yV6/a3qLE/5bjUwylVMH8T6GR+y7O7k+FtpULI9OGUv+bZHz80y0X6/Luhy5WHU/4uxHL/iFkupnH+EGC5f1rOcpXffzrCcn9jW9F6/wIXpipCpTPLC4+lbekgS1vGefd31FjaMkGWpoL5t0CR/O0IS9sSyNKW5dkfPzRLQ/qsvmrRulxhaabNyQw3095m+TFLgzSOCiRab1a+3SxN+Z2VD28jEZamOrqsfLzeBLgwG9hZfrgsbYqDLC2b8y4nP2IsTTkuxdIagilQJDn5MgmGZmlTgCwtO9/++KFZGtLnXAdZWq4QS8uLWRqmcfIEWFq+5SxN+Z3vCEvLYVvRegsEWFpByCxtawfXuzXnvGsRNZamHDfXu6kAFAbOiWYvWwPXuzUHdmotHGEvSJ9bptFl+3q3lkLspVXMXjCN00qAvbS2nL0ov1s7wl5asK1ovf0dWe+GzKU2uM7I7y+w3k3Z18cLj/1t4+AcXVuu23ZRY39tBefoVDDbCXQy7RyZo9sGOEfXNt/++KFZLtLn9g7O0bUXYrkdYpaLaZwOAix3DctZrvJ7DUdYbju2Fa23o8AcXceQ5+imO8jSOnHedY4aS+skyNJUMDsLFElnR1jadCBL65Rvf/zQLA3pcxcHWVoXIZbWNWZpmMbpKsDSulnO0pTf3RxhaZ3ZVrTe7gIsrXvILG1bB1laD867nlFjaT0EWZoKZk+BIunpCEvbFsjSeuTbHz80S0P63MtBltZLiKX1jlkapnF6C7C0QstZmvK70BGW1pNtRevtI8DS+oTM0r5zkKX15bzrFzWW1leQpalg9hMokn6OsLTvgCytb7798UOzNKTP/R1kaf2FWNqAmKVhGmeAAEsbaDlLU34PdISl9WNb0XoHCbC0QfmrsjP04ziAd+n3Nwf+sH8wMJ5hdc6DhTrnNePOGdM4awp0zkMs75yV30NC6pyTmW3Lb2OO7pyH5tvtt2qfofn2+6039FVRf6DPPwAHoWEODkLDhAah4fEghGmc4QKD0AjLByHl9whHBqGhbGvUBqF+nswgNFD4gYyZ2qeeYyXh9yChX3qhp9SA7eMPsvzhm/2YaHlYvSK2tnPI1s4O2dpT0Fa9oQlylofrl7YCEuS1HCTIawkR5GRMkDGNkxQgyL7lBFn57TtEkP0Iz1YMAPo8FdgZFznYGRcJdcbFcWeMaZxigc64xPLOWPld4lBnXGJ5Z6xsUzfi1wWppmiXef886kfh34zqjnEK6SLSK2Wf8rwVT5Hdio+byjiNsQX/XzvGzow99X6SMkOffmTrZ/z/nzN+wfgl41eMXzO2JCk39JzAesr4PNvxcTMYt2fcgbGKsZqxhrGWsY6xnnFHxp0YZzLOYtyZcTbjLoxzGOcy7sq4G+M8xt0Z5zMuYFzIuAfjnox7Me7NuA/jvoz7Me7PeADjgYwHMS5iPJjxEMZDGQ9jPJzxCMYjGY9iPJrxGMZjGY9jPJ7xBMYTGU9iPJnxFMZTGU9jPJ3xDMYzGc9iPJvxHMZzGc9jPJ/xAsYLGS9ivJjxEsZLGS9jvJzxCsYrGa9ivJrxGsZrGa9jvJ7xBsYbGRcz3sR4M+MtjLcy3sa4hPF2xjsY72S8i/FuxqWM9zDey3gf4/2MDzA+yPgQ48OMjzA+yvgY4+OMTzA+yfgU49OMzzA+y/gc4/OMLzC+yPgS48uMrzC+yvga4+uMbzC+yfgW49uM7zC+y/ge4/uMHzB+yPgR48eMnzB+yljO/cw3/P5bxiEkKaNf0iRnc/68lP8vxdiepCJ/1dW/6JnFPjmU87nAxX+k7wHj8e4gvcgVxX5whxnfkcwpRkVtRbFyfKnh7CiDXKAJkU46NCEaYvnUti4OOBEM6YZ1TbQzGbDTHwm8qBgF1DXM8hv+8eYD89sH5ow/zJGv0ZD5t/ZqdKXK66rry0uKq5Il9dWkp6y+rriqqMKvTxWT+uISv7qqLllbUl1eVlKWqi8PbSZnbaGZnNHxTA6mcUYLzOSsY/lMjvJ7HUdWpo9iW9F6k5YOQEE7kbm0Lq4z8pMCd5xV9o3xwvv95agM4lG/8laTxlyRq6VKrtsxq7laGpsmZsGrpbHef18tpdPzn1dLElO5IF0inalqkEqBDqpS4KczY7jAzA3NmIHt5Y8Bdn5jccVer+M5Fh/PVYq/0tJ4jhP6Xhp9BYK8al0PPGBIfD01TqAvKrJ8lkf5vZ6A38WOXGUD28cPy2fk+JiprvWBfaxUfq8fwcX3atb6SoHZ2zIHZq3vEfC73M5Z61XsHA+sR2Bb++WW542ql6sF8makA/Vyr4Dfoxyplw2A9QJsa3+UA/VynUDerONAvdwn4Pe6jtTLhsB6Aba1v64D9XKjQN6MdaBe7hfwe5wj9TIBWC/AtvaR8VOT6W29Fd+qKg6qxlXVV0zI9zzJ+G4EjK+lKxbE5n02Ergu3hh4XZzNeRXckHGViO3G+fbbuInQHDR8smoocLJqUwcmqySKcjPLJ6uU3xUCfo+3vBNWRbipgN8bOEKOJgLrEdjWPjJ+woPY8qVl6NzczIFBbKLUIIYuyEkxK/InOZBQm0slFLrnnByBaX5XE/2JXPtt3MKVRN8yIvPzegOvbygykzHTtpgSj2L+FAdGsa1cKe6pEfkyQW/g4i5GFve0uLj9aQ4U99auFPc2Efjmw4wf+ppxOrggW3urbug4oJN9ugMFua0rBbkdsCBbAwuyTfM40V24ZpzhSqJvD0z09sBE7xDBa8Yd4lHM38GBUazKleKuBhZ3J2Bxd47gNWNNXNx+jQPFXetKcdcBi7sbsLi7W76QYCDpmCywkGAjy/1Wz/baXGIVmyMLKOqB9QJsa39jB+plS4mFVg7UyxYCfk90pF52BNYLsK39iQ7Uy1SBvJnsQL1sJeD3Fo7Uy07AegG2tb+FA/WyjUDebOVAvWwt4PdUR+plJrBegG3tT3WgXrYVyJttHKiX7QT8nu5IvcwC1guwrf3pDtTLDIG8meFAvWwv4Pf2jtTLzsB6Aba1v70D9VIlkDfVDtRLtYDfNY7Uy2xgvQDb2q9xoF5qBfKm3oF6qRPwe0dH6mUXYL0A29rf0fK8KSIdKQ+fN7Ms93sU6VhPwO+dHamXOcB6Aba1v7PlefN4rsz3lXMs91stvqgX8HuuI/UyF1gvwLb25zpQLxLfV85zoF52FPB7d0fqZVdgvQDb2t/dgXqR+L5yoQP1spOA33s4Ui+7AesF2Nb+Hg7Ui8T3lXs7UC8zBfzex5F6mQesF2Bb+/s4UC8S39vt70C9zBLw+wBH6mV3YL0A29o/wIF6kfjebpED9bKzgN8HO1Iv84H1Amxr/2AH6kXie7vDHKiX2QJ+H+5IvSwA1guwrf3DHagXie/tjnKgXnYR8PtoR+plIbBegG3tS8UvC5w/zYBtsYcjTzXMAvq8pyM+J4A+7+WIz9lAn/d2xOccoM/7OOJzLtDnfR3xOQ/o836O+DwE6PP+jvg8GOjzARH0+cAI+nxQBH1e5IjPc4APMzk4gu18SAR9PjSCPh8WQZ8Pj6DPR0TQ5yMj6PNREfT56Aj6fEwEfT42gj4fF0Gfj4+gzydE0OcTI+jzSRH0+eQI+nxKBH0+NYI+nxZBn0+PoM9nRNDnMyPo81kR9PnsCPp8TgR9PjeCPp8XQZ/Pj6DPF0TQ5wsj6PNFEfT54gj6fEkEfb40gj5fFkGfL4+gz1dE0OcrI+jzVRH0+eoI+nxNBH2+NoI+XxdBn6+PoM83RNDnGyPo8+II+nxTBH2+OYI+3xJBn2+NoM+3RdDnJRH0+fYI+nxHBH2+M4I+3xVBn++OoM9LI+jzPRH0+d4I+nxfBH2+P4I+PxBBnx+MoM8PRdDnhyPo8yMR9PnRCPr8WAR9fjyCPj8RQZ+fjKDPT0XQ56cj6PMzEfT52Qj6/FwEfX4+gj6/EEGfX4ygzy9F0OeXI+jzKxH0+dUI+vxaBH1+PYI+vxFBn9+MoM9vRdDntyPo8zsR9PndCPr8XgR9fj+CPn8QQZ8/jKDPH0XQ548j6PMnEfT50wj6/FkEff48gj5/EUGfv4ygz19F0OevI+jzNxH0+dsI+vxdBH3+3hGf5+bjfP7BEZ93Bfr8oyM+7wb0+SdHfJ4H9PlnR3zeHejzL474PB/o86+O+LwA6PNvjvi8EOjz7xHkJH9E0Oc/I+jzXxH0eVkEff47gj57BdHzuVkEfc5yxOd8oM8JR3wuAPqc7YjPzYE+5zjicwugz7mO+NwS6HOeIz63Avqc74jPrYE+Fzjicxugz80d8bkt0OcWjvjcDuhzS0d8bg/0uZUjPncA+tzaEZ/XAPrcxhGfOwJ9buuIz52APrcD+tyJ9TRjnxMk2SQ5JLkkeSTqmlBdI6lrBsWhFadUHEtxDjUGqzFJ9dGqz1I1rHJatXEn3q+2ziRdSLqSdCPpTtKDpCdJL5LeJIUkfUj6kvQj6U8ygGQgySCSs1nXHmTQniR7kexNsg/JviT7kexPcgDJgSQHkSwiOZjkEJJDSQ4jOZzkCJIjSY4iOZrkGJJjSdRz49Vz1NVzxdVzttVzp9VzmNVzidVzetVza9VzXNVzTdVzPtVzL9VzINVzEdVzAtVz89Rz5NRz1dRzxtRzt9RzqNRzmdRzitRze9RzbNRzXdRzTtRzP9RzMNRzIdRzEtRzA9R99NV95dV91tV9x9V9uNV9qdV9mtV9i9V9fNV9bdV9XtV9T9V9QNV9MdV9ItV9E9V9BNV99dR95tR919R9yNR9udR9qtR9m9R9jNR9fdR9btR9X9R9UNR9QdR9MtR9I9R9FNR9BdTv7NXvztXvsNXvktXvdNXvVtXvONXvGtXv/NTv3tTvwNTvotTvhNTvZtTvSNTvKtTvDNS6e7UOXa3LVuuU1bpdtY5VretU6xzVuj+1Dk6tC1PrpNS6IbWORq0rUess1LoD9T28+l5afU+rvrdU3+Op77XU9zzqew/1PYCaF1fzxGreVM0jqoRV80xq3kXNQ6jrcnWdqq7b1HWM4vWK5yrep3iQ4gVqnFTjhupHVb+i6kxv/wc/pOMULGUJAA==", + "bytecode": "H4sIAAAAAAAA/+1dB5gURdPuu71IzjkcOYo7l09EjyBBERBBUBS9CCiCkhQT5oQJUREVARET5pxzDpizYsKIihEz/lVHNTTDindu1Xzd/+w8Tz3v7uxsTcWed2Z7Z06spVSzTFW1JIEkg6SAZKkt63ApJozGt3ipoCM1ht6caH5ubkVBdoWX45VEs4tKC/OiuXml+YVeoZdXmFeeXZiTU1GYW1hQVFpUEC3ycnMqvMq8opxKUpzKZ2NUwu800JEm4Hea5X6ng450Ab/TGf3Wdd9CsO5bgY5WAnFoJRCHNoJxaAc62gnEoZ1AHLIE49ARdHQUiENHgTh0FoxDV9DRVSAOXRXvuKj+wf947ezOnK90I1fNQTaqTeMaYkvCVoStCdsQtiVsR9ieMIuwA2FHwk6EnQm7EHYl7EbY/X+EvUF6UM4wLg0oLj0ssKunYVdDy/KF2/cCiYBkqH9eigmj8S2enO78ckHdFYK6K+V0F0QFdQvmsiBbUHdOuqGzN+EOhH0Id9T7ItTOomFPRTa9xlMpf89kkuCSZKyrRa+TjXW16XXEWFeHXqcY6+rS61RjXT16nWasq0+v032f4VJMGI1ziXVeE41zyTTikmH4Y8ZFo45LLWOdjkttY532vY6xTselrrFO76+esU7vT8cT9bc2PteLmUsdE9Nm/XlKDJ9SY/iUFsOn9Bg+mTbjOh2LYsJonEuaESMunWa96yXJ977YeF3XiEkdXluqzs/r8eqsilkDgZjVU9WPWQMjZvUFYtaQV2dVzBoLxKyhqn7MGhsxayQQsya8Oqti1kwgZk1U9WPWzIhZU4GYNefVGRXQWWVnCwE7W/PqLMTctlTVz21rI7etBGLWhldnVczaMutEHe2MmOj4adtrG5+3NeLVjjleScY+tV79vp3cfqv8b/8v/rePYUf7AP037UvYmrA1Yev/1ta2/2Nbcb9ZrPv1CjJ9+8Vle8fOLMEYoM4OvDqrxvmOhv3aV72f2sbnZi12ZPYtydin1qvfm/YlbE3YmrA1YWvC1oStCVsTtiZsTdiasDVha8LWhK2u2Gr+Bpps2MJ8bl9li/LZomLERS+ZFtmSZpEtEYtsSbfIlhSLbMmwyJZUi2xJ+h/bYs6LUcY6/XmysU6Pj+b8mU702pw/05lem/Nnuhh+6nVd6bU5f6YbvTbnGHU3XmvsQa/NOUY96bU5x6gXvTbnGOn5ZOZ8Ij23rL6xTs8za2is03POGhnr9PyzJsY6PRetqbFOT5hrbqzLodctjHW59LqlsS6PXrcy1uXT6zbGugJ63d5Yp3No5lznsKOxTuewk7FO57CzsU7nsIuxTuewq7FO57CbsU7n0MypzmEPY53OYU9jnc5hL2OdnoPU21in87qDsU7ntY+xTs/F2dFYp3MdNdbpXHvGOj0nJdtYp/OfY6zT+c811um5GXnGOl0T+cY6XRM6p5iLUUlbPtffN3tU78fs0YIY+8uPYZd+bY5J+jvFhNH4lqoxydxPsfFe76uWYUOuBbakWmRLhkW2pFhkS7pFtkQssiXNIlsyLbIlOYYtOby2VB1CzEnyehzOMezQNmUbdnjMManSEcMOz7BD7z9q2LEjrx1Vu+gTw44dDTv0/vsYduzAa0dV+HvHsGMHww69/96GHb147agqvZ4x7Ohl2KH339OwowevHVUl2D2GHSbH1vvvbtjRjdeOKkrSNYYd3Qw79P67GnZ04bWjaredY9jRxbBD77+zYUcnXjuqxjLzXArf6/FC7ytibNOfSBNyYvM8zOSomu+b/FafF5jcuJBem7y6iF6bnHwnem3y+b702jwX0OOteR6xvXMQ81xF869CY50+rhUZ6zQH2MlYp/mStimdvss8xzUb96Xn5eple+ff5vws/T3zXFHP1TLn+krMXW3rs0+/b2fYp9eZc8qZ5/NW2VLHZ4t+31Z4v/V8+60X0H4b+PbbIKD9NvLtt1FA+23h228L337/6bq7hC3KZ4vaji1NLLKlvkW2NLDIlloW2ZJukS0pFtnSyiJbWltkS3OLbGlhkS2NLbKlrkW21LPIlkyLbEmzyJaIRba0tMiWphbZIn0+UxNbGlpkSyOLbKltkS11LLIlwyJbUi2yJel/bMs/zafQn5u/1eprLOYchvY+n3BdFr025zDo62PmfVL0dTRzXoO+TmjOa9DX4BoY6/S1TXOug75+Z8510NdiGxvr9LU/c/6DvnZsznXQ1w3NuQ46Hmb89LGznbFOn8eY8xp03WUZ6zQHMK8f6vMx8zqj7h9zroPmMuY1Sp0bc66Dzo15fVPnxpzroHNjXhvVuTHnOujc6PigXzcb9y/S3zdrR+/H/J2/Z4z99Yhhl35t9or+TjFhNL6lqlfM/RQb7/W+zN/5u1lgS6pFtmRYZEsdi2ypbZEtjSyypaFFtjSzyJamFtnS0iJbIhbZkmaRLZkW2VLPIlvqWmRLY4tsaWGRLc0tsqW1Rba0ssiWFItsSbfIlloW2dLAIlvqW2RLE4tsSQ7IFn3+rPX28NmC++3Ku9+qqVldjP3q8/quhv96/+b/ajoz25HksyPL2K/kvDfU0TGG/50M//X+Oxp2dGS2A/1vZthRbLw3ryVpXq/zg2N8XvIWu5jnSVbZZdbfPLXtuUXE2GZg8ha7ipK3xFDPQTPvm9zOtw71S9wrrJ0vrvq93hfa55+LZtpn/ufJf38z87qi+d2Ibx/pSiQ/UTM/uGSpbfNjjnNpauve0j0XMbYZauTwxMiW7zHbvtVc4GQV+5yVud+rpqfq3lGGfjOGHYzXscbDjr7tdEwZ7fT8duj9Zxnr2sWws4NhZ6z7BnLfG9XfX0lq2x7xv9a+dDLsYp4ju93jaRtjv8zz7LNreo/AXoYtfXhtyTH/f1odWwT/B+EJ/Mej6l6/UWadqMN8kIWOn7a9tvG5+f8V7v/RJBn71Hr1e9O+hK38tqItbXx2mv/HbmOBfXqd+b/jVr744fF7phw3zInFDf3XP0xueGpki11HGNywuy+u5u/BZqwl/vNicoFite2xqZbhi/k/IObzsK3ORbVem/bLHPuqEjX5TfcYcdf7l+ZZ7WPYkWXYofdv3luYmUdV8dJeMexoa9ih929yht7M8cj02YHL9jiD+Z9FZv7imffKqI4tJn9h5gWeOf5XxxbzGJYtYItXA1vM//vmCtiSUwNbzP9A5wvYklcDW/INWwoFbCmogS16/3hs1/3X1Vin+6CDsU7XozmPS9dFZ2Odzk9HY53/fh61DXvNuWL6P4/mdZu+vnUYv519PkXjW6qOS3o/Wq9+v7Nhn/7/ZV85WwpN/eZ1ip2NffZj9j/N0MXlB+rsz2wn6hhAulKMfOj9RIzPbzWuK91Or7GedqHPiww9j8X4XC/b66NiIyeDeH2tutaxm6G/OMY+cP1g3v165n6TSPQ+9PqI8fpR3dTGdrjo+GqbsX8GxtjOfL2L7zu1jc8HCvs8yLCj2Hiv94V1cpdRU48Z5zq7Mttj+mvGpa8RF/15P2O7AcZrvW2WEbeBvHYWCtR9le+7GTHXsdX7MWvveSMfq40e7u+LG37+fozP9bK9Hjfrbgivr1U9PtTQX2zsw9zvMN79euZ+dY/rfej1EeP1e0aPD9vycnN8tc3Y44NjbGe+7u/7Tm3j88HCPg8x7Cg23ut9YZ28bNTU+0aPFzPbY/prxmWAERf9uXndYDfjtd42y4gb89hYKFD3Vb4PNWKu9er9mLX3mZGPL4weHuSLG37+S4zP9bK9HjfrbndeX6t6fA9Df7GxD3O/w3n365n71T2u96HXR4zXG4weH77l5eb4apuxx4fF2M58Pcj3ndrG58OEfd7dsKPYeK/3hXWyzqipX4weZz4+eqa/Zlx2M+KiPzevTw01Xutts4y4MY+NhQJ1X+X7HkbMdWz1fszaU8a12mTj/yFDfHHDzxvG+Fwv2+txs+725PW1qsdHGPqLjX2Y+x3Ju1/P3K/ucb2PEUZo9esGeqKAsR0uOr7aZuzx4TG2M18P8X2ntvH5cGGf9zTsKDbe631hnaQaNdXQmFfAfe5g+mvGZagRF/25ee13D+O13jbLiBvz2FgoUPdVvo8wYq5jq/dj1l4rIx9tjB7e3Rc3/LxXjM/1sr0eN+tuFK+vVT2+l6G/2NiHud/RvPv1zP3qHtf70OsjxuueRo+P3vJyc3y1zdjjI2NsZ77e3fed2sbnI4V9HmXYUWy81/vCOmlv1FQvo8e5zx1Mf8247GHERX/e2dhuhPFab5tlxI15bCwUqPsq3/cyYq5jq/dj1l6ukY98o4f39MUNP98txud62V6Pm3W3N6+vVT0+xtBfbOzD3O9Y3v165n51j+t96PUR4/Ugo8fHbnm5Ob7aZuzx0TG2M1/v6ftObePz0cI+723YUWy81/uqmtdp1NRuRo9znzuY/ppxGWHERX/e0dhuL+O13jbLiBvz2FgoUPdVvo8xYq5jq/dj1t4IIx+jjB4e5Ysbfn5gjM/1sr0eN+tuH15fq3p8nKG/2NiHud/xvPv1zP3qHtf70OsjxuuJRo+P3/Jyc3y1zdjjY2NsZ74e5ftObePzscI+72PYUWy81/vCOtnbqKkDjR7nPncw/TXjspcRF/25cTlkc+2b22YZcWMeGwsF6r7K93FGzHVs9X7M2pts5ONgo4f39sUNP58b43O9bK/Hzbrbl9fXqh7fz9BfbOzD3O8E3v165n51j+t96PUR4/WRRo9P2PJyc3y1zdjj42NsZ77e2/ed2sbn44V93tewo9h4r/eFdXKoUVNzjR7nPncw/TXjMsaIi/7cvBdwa9/2WM+6H8y5B9x9aR4XtF793hyv9Trz/Efw/xJVcTT/p+D/v4T5/6Duhk36/0EuzrX0v9bzS83/E5jXaWP9X6OTbzv0j/l/RjkC/yWoyreeX5dixEbvJ2J8vtDo5QuN8V/7bNbDlTE+18v2jg/m/EfmuX5Rc96zPj70ibFf7nl95n718UHvQ6+PGK9XGMcH8zkXOr7aZqy7HWJsZ77u4PtObePzHYR9Np+NUWy8N+eOX2zU1JXGuJbFbI/prxmXVkZc9Ofmf4Yk+83cfy/DDv+zRM3/BJrjJ/f/Z8z/VWm9+v0Ohn16XZZhn/bDHEvM/wU0ELC1vs9W/d68j7fEflN9+00NaL/pvv2mB7TfTN9+MwPab23ffmsHtN/g68orQJ2NmXVinhqqrZftHXvN+1M3YrUl6mWoLfeAm1Qxa8T0WRUzkwybtJ36ni+1DLvMc/KI8Z0Uta1vaTHWZcRYV0ttu5jP66hrvG5gfK+ez06Msb6PhHmvSX2fLvNek9oP876S2h+9fbraNkesBx+9JPt050Tzc3MrCrIrvByvJJpdVFqYF83NK80v9Aq9vMK88uzCnJyKwtzCgqLSooJokZebU+FV5hXlVJLyZEY7d+TTZXKhzYHlstNjjJ8e4HVB4IF0o9p04EXsQ1i1L7X1ksScy1zFf+DS9ZZLfuQY/uSR39sUvkDOony6oqa9+EcPPSDFGrDSBHxRvv3441dPCQ8mEsnJF9BboPiaQ8rvAv4cbTX4cQ/42Yy6ChX/gFOdgbSIchlrgCoyttspxnbJ9PlOhNj85r+JJGLOWcc7/49i3m87Me9nbLfLdmK+ixHzXWNsF6XPdyWMGL5KjC19Ff9BeFEG7zjA7beuH26/L86QGf8izHb2Z4wlY649zvgFRcp68emKmmeVWucAtWkmMs54xZnVg9WmmXE4AxNnNuEMGpyphTMg8Jd2nNGBv5TiL3L4yy/++oK/EOGvSfhLIv5Cg7/M4C9K+KsX/rKHv3rtD3IAyESQA0EOAikBKQUpAykHqQCpBJkEMhlkCsjBIIeATAU5FGQayHSQw0AOB5kBMhNkFshskDkgR4AcCTIX5CiQo0GOATkW5Di16U4Zx4OcoLY+MzXJKS7mGXMxUw4EyG7UtF0jXnlLN3xTvs/rkX+prLbkRs0zd71s78qK+USRFFZbNl1Z0Vcl4MpK/9mzJo+bMmtaxcytrq/4R7+kGNEynzdhPodBRzjFWJdseKTX6e+kGyh2+hFR25ay6RjXfgYomcMRazy8Tddf9HIi4UlqS+klGfHCRP4dI2ZJxutk2iZ5O9sk/YOef2pFsWLQzqHjGwxnMQD+q38R5n2bBfJfOUVFJS5R70TFx09OUjKFm8wcP06fT95KF2xbkp2bX5EXza8oLCqsKCqozCuIlpVUVpYXRHPLSqOlpbn50Rwvp7K0IDtaml0Euy2qyCvzquwKivuczKdrqwtSp6jEBSmW5JwioPdUZfcFKfT7VP4cxbSVY6A7VUDvaYq3MbEJUaemSkGwl4FK5iDAWhc+9nI64RkqZOwFHTfZCwZAmr2YBRIvezld8TXfGcoN9sLp85nKPfZypuIdJPUyXyXYC0ty5gvoPUvZzV7Q77P4cyTCXs4gW7n1nq14GxObEHUGyV4GKZmDAGtd+NjLOYTnqpCxF3TcZC8YAGn2YhZIvOzlHMXXfOcqN9gLp8/nKffYy3mKd5DUywKVYC8syVkgoPd8ZTd7Qb/P58+RCHs5l2zl1rtQ8TYmNiHqDJK97KZkDgKsdeFjLxcQXqhCxl7QcZO9YACk2YtZIPGylwsUX/NdqNxgL5w+X6TcYy8XKd5BUi+LVIK9sCRnkYDei5Xd7AX9vpg/RyLs5UKylVvvYsXbmNiEqDNI9jJYyRwEWOvCx14uIbxUhYy9oOMme8EASLMXs0DiZS+XKL7mu1S5wV44fb5MucdeLlO8g6RelqgEe2FJzhIBvZcru9kL+n05f45E2MulZCu33qWKtzGxCVFnkOxliJI5CLDWhY+9LCNcrkLGXpaprdkLBkCavZgFEi97Wab4mm+5coO9cPp8hXKPvVyheAdJvaxQCfbCkpwVAnqvVHazF/T7Sv4cibCX5WQrt96VircxsQlRZ5DsZaiSOQiw1oWPvVxFeLUKGXtBx032ggGQZi9mgcTLXq5SfM13tXKDvXD6fI1yj71co3gHSb1cqxLshSU51wrovU7ZzV7Q7+v4cyTCXq4mW7n1rlK8jYlNiDqDZC/DlMxBgLUufOzlesIbVMjYCzpushcMgDR7MQskXvZyveJrvhuUG+yF0+cblXvs5UbFO0jq5SaVYC8syblJQO/Nym72gn7fzJ8jEfZyA9nKrfcWxduY2ISoM0j2sruSOQiw1oWPvdxKeJsKGXtBx032ggGQZi9mgcTLXm5VfM13m3KDvXD6fLtyj73crngHSb3coRLshSU5dwjovVPZzV7Q7zv5cyTCXm4jW7n13qV4GxObEHUGyV72UDIHAda68LGXuwnvUSFjL+i4yV4wANLsxSyQeNnL3Yqv+e5RbrAXTp/vVe6xl3sV7yCpl/tUgr2wJOc+Ab33K7vZC/p9P3+ORNjLPWQrt94HFG9jYhOiziDZy3AlcxBgrQsfe3mQ8CEVMvaCjpvsBQMgzV7MAomXvTyo+JrvIeUGe+H0+WHlHnt5WPEOknp5RCXYC0tyHhHQ+6iym72g34/y50iEvTxEtnLrfUzxNiY2IeoMkr3sqWQOAqx14WMvjxM+oULGXtBxk71gAKTZi1kg8bKXxxVf8z2h3GAvnD4/qdxjL08q3kFSL0+pBHthSc5TAnqfVnazF/T7af4cibCXJ8hWbr3PKN7GxCZEnUGylxFK5iDAWhc+9vIs4XMqZOwFHTfZCwZAmr2YBRIve3lW8TXfc8oN9sLp8/PKPfbyvOIdJPXygkqwF5bkvCCgd7Wym72g36v5cyTCXp4jW7n1vqh4GxObEHUGyV5GKpmDAGtd+NjLS4Qvq5CxF3TcZC8YAGn2YhZIvOzlJcXXfC8rN9gLp8+vKPfYyyuKd5DUy6sqwV5YkvOqgN7XlN3sBf1+jT9HIuzlZbKVW+/rircxsQlRZ5DsZZSSOQiw1oWPvbxB+KYKGXtBx032ggGQZi9mgcTLXt5QfM33pnKDvXD6/JZyj728pXgHSb28rRLshSU5bwvofUfZzV7Q73f4cyTCXt4kW7n1vqt4GxObEHUGyV72UjIHAda68LGX9wjfVyFjL+i4yV4wANLsxSyQeNnLe4qv+d5XbrAXTp/XKPfYyxrFO0jq5QOVYC8syflAQO+Hym72gn5/yJ8jEfbyPtnKrfcjxduY2ISoM0j2MlrJHARY68LHXj4m/ESFjL2g4yZ7wQBIsxezQOJlLx8rvub7RLnBXjh9XqvcYy9rFe8gqZdPVYK9sCTnUwG9nym72Qv6/Rl/jkTYyydkK7fezxVvY2ITos4g2cveSuYgwFoXPvbyBeGXKmTsBR032QsGQJq9mAUSL3v5QvE135fKDfbC6fNXyj328pXiHST1sk4l2AtLctYJ6P1a2c1e0O+v+XMkwl6+JFu59X6jeBsTmxB1BslexiiZgwBrXfjYy7eE61XI2As6brIXDIA0ezELJF728q3ia771yg32wunzd8o99vKd4h0k9fK9SrAXluR8L6D3B2U3e0G/f+DPkQh7WU+2cuv9UfE2JjYh6gySvYxVMgcB1rrwsZefCH9WIWMv6LjJXjAA0uzFLJB42ctPiq/5flZusBdOnzco99jLBsU7SOrlF5VgLyzJ+UVA76/KbvaCfv/KnyMR9vIz2cqt9zfF25jYhKgzSPayj5I5CLDWhY+9/E74hwoZe0HHTfaCAZBmL2aBxMtefld8zfeHcoO9cPr8p3KPvfypeAdJvfylEuyFJTl/CejdqOxmL+j3Rv4cibCXP8hWbr1/K97G1EfUINnLOCVzEGCtCx970UFISgoZe8E9mOwFAyDNXswCiZe9oOHx6tLNl5TkBnvh9Dk5yT32kpzEO0hurvOkBHthSQ4GkltvCmPRS/mdksSeIxH2kkS2cutNZW5MbELUGSR7Ga9kDgKsdeFjL2kUhPSwsZc0H3tJD4C9mAUSL3tJYxzU0h1hL5w+ZzjIXjKE2Etmgr3wJCdTgL3Uspy9oN+1HGEv6WQrt97aAuyldsDsZV8lcxBgrQsfe6lDQagbNvZSx8de6gbAXswCiZe91GEc1Oo6wl44fa7nIHupJ8Re6ifYC09y6guwlwaWsxf0u4Ej7KUu2cqtt6EAe2kYMHvZT8kcBFjrwsdeGlEQGoeNvTTysZfGAbAXs0DiZS+NGAe1xo6wF06fmzjIXpoIsZemCfbCk5ymAuylmeXsBf1u5gh7aUy2cuttLsBemgfMXiYomYMAa1342EsLCkLLsLGXFj720jIA9mIWSLzspQXjoNbSEfbC6XMrB9lLKyH20jrBXniS01qAvbSxnL2g320cYS8tyVZuvW0F2EvbgNnL/krmIMBaFz720o6C0D5s7KWdj720D4C9mAUSL3tpxziotXeEvXD6nOUge8kSYi8dEuyFJzkdBNhLR8vZC/rd0RH20p5s5dbbSYC9dAqYvRygZA4CrHXhYy+dKQhdwsZeOvvYS5cA2ItZIPGyl86Mg1oXR9gLp89dHWQvXYXYS7cEe+FJTjcB9tLdcvaCfnd3hL10IVu59fYQYC89AmYvE5XMQYC1LnzspScFoVfY2EtPH3vpFQB7MQskXvbSk3FQ6+UIe+H0ubeD7KW3EHvZIcFeeJKzgwB76WM5e0G/+zjCXnqRrdx6dxRgLzsGzF4OVDIHAda68LEXPYp5YWMvUR978QJgL2aBxMteooyDmucIe+H0OdtB9pItxF5yEuyFJzk5Auwl13L2gn7nOsJePLKVW2+eAHvJC5i9HKRkDgKsdeFjL/kUhIKwsZd8H3spCIC9HKT42Es+46BW4Ah74fS50EH2UijEXooS7IUnOUUC7GUny9kL+r2TI+ylgGzl1ttXgL30DZi9lCiZgwBrXfjYy84UhH5hYy87+9hLvwDYi1kg8bKXnRkHtX6OsBdOn3dxkL3sIsRedk2wF57k7CrAXootZy9VRekIe+lHtnLr7S/AXvoHzF5KlcxBgLUufOxlAAVhYNjYywAfexkYAHsxCyRe9jKAcVAb6Ah74fR5kIPsZZAQe9ktwV54krObAHsZbDl7Qb8HO8JeBpKt3HqHCLCXIQGzlzIlcxBgrQsfexlKQRgWNvYy1MdehgXAXswCiZe9DGUc1IY5wl44fd7dQfayuxB72SPBXniSs4cAexluOXtBv4c7wl6Gka3cevcUYC97BsxeypXMQYC1LnzsZQQFYWTY2MsIH3sZGQB7MQskXvYygnFQG+kIe+H0eZSD7GWUEHvZK8FeeJKzlwB7GW05e0G/RzvCXkaSrdx69xZgL3sHzF4qlMxBgLUufOxlDAVhbNjYyxgfexkbAHsxCyRe9jKGcVAb6wh74fR5HwfZyz5C7GVcgr3wJGecAHsZbzl7Qb/HO8JexpKt3Hr3FWAv+wbMXiqVzEGAtS587GU/CsKEsLGX/XzsZUIA7MUskHjZy36Mg9oER9gLp8/7O8he9hdiLwck2AtPcg4QYC8TLWcv6PdER9jLBLKVW++BAuzlwIDZyyQlcxBgrQsfezmIglASNvZykI+9lATAXswCiZe9HMQ4qJU4wl44fS51kL2UCrGXsgR74UlOmQB7KbecvaDf5Y6wlxKylVtvhQB7qQiYvUxWMgcB1rrwsZdKCsKksLGXSh97mRQAezELJF72Usk4qE1yhL1w+jzZQfYyWYi9TEmwF57kTBFgLwdbzl7Q74MdYS+TyFZuvYcIsJdDAmYvU5TMQYC1LnzsZSoF4dCwsZepPvZyaADsxSyQeNnLVMZB7VBH2Aunz9McZC/ThNjL9AR74UnOdAH2cpjl7AX9PswR9nIo2cqt93AB9nJ4wOzlYCVzEGCtCx97mUFBmBk29jLDx15mBsBezAKJl73MYBzUZjrCXjh9nuUge5klxF5mJ9gLT3JmC7CXOZazF/R7jiPsZSbZyq33CAH2ckTA7OUQJXMQYK0LH3s5koIwN2zs5Ugfe5kbAHsxCyRe9nIk46A21xH2wunzUQ6yl6OE2MvRCfbCk5yjBdjLMZazF/T7GEfYy1yylVvvsQLs5diA2ctUJXMQYK0LH3s5joIwL2zs5Tgfe5kXAHsxCyRe9nIc46A2zxH2wunz8Q6yl+OF2MsJCfbCk5wTBNjLiZazF/T7REfYyzyylVvvSQLs5aSA2cuhSuYgwFoXPvZyMgXhlLCxl5N97OWUANiLWSDxspeTGQe1UxxhL5w+n+ogezlViL2clmAvPMk5TYC9nG45e0G/T3eEvZxCtnLrPUOAvZwRMHuZpmQOAqx14WMvZ1IQ5oeNvZzpYy/zA2AvZoHEy17OZBzU5jvCXjh9PstB9nKWEHs5O8FeeJJztgB7Ocdy9oJ+n+MIe5lPtnLrPVeAvZwbMHuZrmQOAqx14WMv51EQFoSNvZznYy8LAmAvZoHEy17OYxzUFjjCXjh9Pt9B9nK+EHtZmGAvPMlZKMBeLrCcvaDfFzjCXhaQrdx6LxRgLxcGzF4OUzIHAda68LGXiygIi8LGXi7ysZdFAbAXs0DiZS8XMQ5qixxhL5w+X+wge7lYiL0sTrAXnuQsFmAvl1jOXtDvSxxhL4vIVm69lwqwl0sDZi+HK5mDAGtd+NjLZRSEJWFjL5f52MuSANiLWSDxspfLGAe1JY6wF06fL3eQvVwuxF6WJtgLT3KWCrCXZZazF/R7mSPsZQnZyq13uQB7WR4we5mhZA4CrHXhYy9XUBBWhI29XOFjLysCYC9mgcTLXq5gHNRWOMJeOH2+0kH2cqUQe1mZYC88yVkpwF6uspy9oN9XOcJeVpCt3HqvFmAvVwfMXmYqmYMAa1342Ms1FIRrw8ZervGxl2sDYC9mgcTLXq5hHNSudYS9cPp8nYPs5Toh9rIqwV54krNKgL1cbzl7Qb+vd4S9XEu2cuu9QYC93BAwe5mlZA4CrHXhYy83UhBuCht7udHHXm4KgL2YBRIve7mRcVC7yRH2wunzzQ6yl5uF2MstCfbCk5xbBNjLrZazF/T7VkfYy01kK7fe2wTYy20Bs5fZSuYgwFoXPvZyOwXhjrCxl9t97OWOANiLWSDxspfbGQe1OxxhL5w+3+kge7lTiL3clWAvPMm5S4C93G05e0G/73aEvdxBtnLrvUeAvdwTMHuZo2QOAqx14WMv91IQ7gsbe7nXx17uC4C9mAUSL3u5l3FQu88R9sLp8/0Ospf7hdjLAwn2wpOcBwTYy4OWsxf0+0FH2Mt9ZCu33ocE2MtDAbOXI5TMQYC1Lnzs5WEKwiNhYy8P+9jLIwGwF7NA4mUvDzMOao84wl44fX7UQfbyqBB7eSzBXniS85gAe3nccvaCfj/uCHt5hGzl1vuEAHt5ImD2cqSSOQiw1oWPvTxJQXgqbOzlSR97eSoA9mIWSLzs5UnGQe0pR9gLp89PO8henhZiL88k2AtPcp4RYC/PWs5e0O9nHWEvT5Gt3HqfE2AvzwXMXuYqmYMAa1342MvzFIQXwsZenvexlxcCYC9mgcTLXp5nHNRecIS9cPq82kH2slqIvbyYYC88yXlRgL28ZDl7Qb9fcoS9vEC2cut9WYC9vBwwezlKyRwEWOvCx15eoSC8Gjb28oqPvbwaAHsxCyRe9vIK46D2qiPshdPn1xxkL68JsZfXE+yFJzmvC7CXNyxnL+j3G46wl1fJVm69bwqwlzcDZi9HK5mDAGtd+NjLWxSEt8PGXt7ysZe3A2AvZoHEy17eYhzU3naEvXD6/I6D7OUdIfbyboK98CTnXQH28p7l7AX9fs8R9vI22cqt930B9vJ+wOzlGCVzEGCtCx97WUNB+CBs7GWNj718EAB7MQskXvayhnFQ+8AR9sLp84cOspcPhdjLRwn2wpOcjwTYy8eWsxf0+2NH2MsHZCu33k8E2MsnAbOXY5XMQYC1LnzsZS0F4dOwsZe1PvbyaQDsxSyQeNnLWsZB7VNH2Aunz585yF4+E2IvnyfYC09yPhdgL19Yzl7Q7y8cYS+fkq3cer8UYC9fBsxejlMyBwHWuvCxl68oCOvCxl6+8rGXdQGwF7NA4mUvXzEOauscYS+cPn/tIHv5Woi9fJNgLzzJ+UaAvXxrOXtBv791hL2sI1u59a4XYC/rA2Yv85TMQYC1Lnzs5TsKwvdhYy/f+djL9wGwF7NA4mUv3zEOat87wl44ff7BQfbygxB7+THBXniS86MAe/nJcvaCfv/kCHv5nmzl1vuzAHv5OWD2crySOQiw1oWPvWygIPwSNvaywcdefgmAvRyv+NjLBsZB7RdH2Aunz786yF5+FWIvvyXYC09yfhNgL79bzl7Q798dYS+/kK3cev8QYC9/BMxeTlAyBwHWuvCxlz8pCH+Fjb386WMvfwXAXswCiZe9/Mk4qP3lCHvh9Hmjg+xloxB7+TvBXniS87cAe8GMaF02speN5uFC8Q4k3CzjL7KVW29SMj97QZ2Z+vWW8LLnrxdjzrJITzIYHQFJAUkFSQNJB8lAn0BqgdQGqQNSF6QeSH2QBiANQRqBNAZpAtIUpBlIc5AWIC1BWoG0BmkD0hakHUh7kCyQDhQwHUe0JUNteR/xvU/xvU/1vU/zvU/3vc/wvc/0va/le1/b976O731d3/t6vvf1fe8b+N439L1v5Hvf2Pe+ie99U9/7Zr73zX3vW/jet/S9b+V739r3vo3vfVvf+3a+9+1977N87zskyxM5s2fiHTuSGcf3SzNkiJw/fvGS10gyjy7MRQpj/C6zPn5Vqr3U+H3OJp+9NMb4LbE5frmb7fTS4/M5avjsZTDG73Jb45e9lZ1e5n/3Oerz2avFGL+lFsYvv3IbO73a/83nwhg+e3UY47fMtvgVxrTTq1tznwv+wWevHmP8ltsUv4J/tNOrXzOfs7fjs9eAMX5X2BK/gu3a6TWsvs9l/+Kz14gxfitsiF/Bv9rpNa6ez9Fq+Ow1YYzflf/r+EWrZafX9N99zqumz14zxvit/F/GL7fadnrNt+tzbmUNfPZaMMbvqv9V/ApqZKfX8p99Lqyhz14rxvhd/T+IX1Flje30Wsf2OfoffPbaMMbvmqDjF/1Pdnptt/XZ+48+e+0Y43dtkPEr/892eu239jknDp+9LMb4XRdQ/LIr47LT65DMdy3RvGYXb/xWBRS/aHyLx3idzVvCGL/rHYkf43Uibylj/G5wJH6M1zm85Yzxu9GR+DGep3srGON3kyPxYzzP9FYyxu9mR+LHeJ7kXc0Yv1sciR8jz/euZYzfrY7Ej5GneqsY43ebI/Fj5FneDYzxu92R+DHyBO8mxvjd4Uj8GI9z3i2M8bvTkfgxjtPebYzxu8uR+DGOM94djPG725H4MfaJx1gzHmf8cD4b/iOjN8hGkB0Itf6T1KZ5bmcQnkt4IeGlhMsJrya8gfA2wnsIHyJ8gvA5wpcJ3yR8n/ATwi8J1xP+TPgHYRL9sSKdsC5hY8KWhO0JuxD2IvQICwj7EQ4kHEY4knAs4QTCEsJJhIcSziScSziP8BTC+YQLCBcRLiFcQXgt4U2EdxDeR/gI4VOE+sHC+hF9+mE3+rbx+gas+lZm+qYg+u+1+o8qWVQHer5jFqGeH6nnTer5lHqepZ5/qedl6vmaeh6nnt+p533q+aB6nqieP6rnler5pnoeqp6fquet6vmsep6rnv+q58Xq+bJ6Hq2eX6vn3er5uHqerp6/q+f1dkxWWy3c86M7Ml7fDuqPIi0V7zikl07JiT+KsCQHA8mttzNjoUr53TmZPUfb/cdZvHHgjGkXxh+NImpL05mLzQOJpJ0tHLGzueIfmBHr0uuuUGPdQLqD9ADpCdILpDfIDiB9QHYEwf8AeyDZIE3pu/qv0uaC61J8scB1+q/Cut/SjO8UM/kncDCJZho2R2L4nRLD71QDaxufK18M6lEc0nltLjfjrXy58MdcGftPU1vywmSLV0UYSVfFtMNnV8yuGDW7dOqUssGzp5XNmjJ92sCSqVPNwtSG6wKNxAicf72ZhAx6nWqsyzQc1Ou0rgxjnZlgHZgk7o7GUb2VYTyT3mhQNy3oliwzcjLFw9MvzFjk0Jvc5JDdtAAdX2M4iwHI8u2T+1pLt/gp0Ob/GuUw0qlcocJNZo4fp895MXSVRsvK87zS/PICr6Ikr7CsrCjH87JL8kvyS7MLKytK87zCvELQWVaSXQi7yy4p8yqiJfkVQZ2L5iXzUx5c8hPnojzJyRc4Fy2w/FwU/S4QOhflvrlALtnKrfdNyy/2azs5a6mQ8RycM376gI72dVDB3bKqu93sTy/ZZiyK6M1OYWN/6PhfPmO49oHB3ElgkNkp2e5BhpatGiG+uxtUVhYl2x8/bpbL6XNfQ5dXmJOdXZCD2xWWR73c8rLswuzs8tLcaFm0pCy7oijXK6rMzc7NKSsvKwWdJV5ltLKkrKiycJNdQbHcvkIsd+cEy+VJzs4CLLef5SwX/e7nCMvdiWzl1rsLc2NiOFFnsgqOpfVwkKXtSm+Kw8bSdhVkaRjMYoEmKXaEpfVgZGm7JtsfP26WxulzfwdZWn8hljYgwdJ4kjNAgKUNtJylod8DHWFpxWQrt95BAixtUMAsraeDLG03ejM4bCxtN0GWhsEcLNAkgx1haT0ZWdpuyfbHj5ulcfo8xEGWNkSIpQ1NsDSe5AwVYGnDLGdp6PcwR1jaYLKVW+/uAixt94BZWh+7WVrM+W570JvhYWNp6Lg53w0DkOXbJzd76RP/QLR5vtsejIPacEfYC6fPe8bQZft8tz2F2MuIBHvhSc4IAfYy0nL2gn6PdIS9DCdbufW+7ch8N85aGsU3GHlvC8x3Q/s6qODY3452sz+9bHWNbi96Mzps7G8vwWt0GMzRAoPMaEeu0e3IeI1ur2T748fNcjl93tvBa3R7C7HcMQmWy5OcMQIsd6zlLBf9HusIyx1NtnLr3UfgGt0+AV+jizrI0sbRm/FhY2njBFkaBnO8QJOMd4SlRRlZ2rhk++PHzdI4fd7XQZa2rxBL2y/B0niSs58AS5tgOUtDvyc4wtLGk63cevcXYGn7B8zSPAdZ2gH0ZmLYWNoBgiwNgzlRoEkmOsLSPEaWdkCy/fHjZmmcPh/oIEs7UIilHZRgaTzJOUiApZVYztLQ7xJHWNpEspVbb6kASytN3pY5cOUM70PXRSAOZcmy+Y/Gt1TdpbRMwO93M+yue7zbp4Tf72W4QRwY8+O9Z3muWwjV+AcZdvd2rlCNf+hIjTPmx/vQ8lw3F6rxTyzv7WyhGl/rSI0z5sdba3mNj6ZcK169IraOd8jWiQHaGm9fopkS/f655bXfS2ic+8KRcY4xP94Xlue6t1Cu1wWUa4vOHb11zDOv8Ub4+sIg8mt8rNhOhMWEgwlrgZRTHtPVlqcL9KLPexPuQDiccDTheMKJhA1BKgx9+mJkd7Xpcz/iLyaVNdx+Ug23n1zD7afUcPuDa7j9ITXcfmoNtz+0httPq+H202u4/WE13P7wGm4/o4bbz6zh9rNquP1sY/vkf9g+A2RONbc7oprbHVnN7eZWc7ujqrnd0dXc7phqbndsNbc7rprbzavmdsdXc7sTqrndidXc7qRqbndyNbc7xdhuHG1XQeNzdnLsuvVjJW03iXAy4RTCgwkPIZxKeCjhNMLphIcRHk44g3Am4SzC2YRzCI8gPJJwLuFRhEcTHkN4LOFxhPMIjyc8gfBEwpMITyY8pZrxSWAw2Avk1Bjjb1fKUznhqYSNQE7TzUELN/drxajr9GQ+Hpl4atzWdob9qXHL6fUZUGNngswHOQvkbJBzQM4FOQ9kAcj5IAtBLgC5EOQikEUgF4MsBrkE5FKQy0CWgFwOshRkGchykCtAVoBcCbIS5CqQq0GuAbkW5DqQVSDXg9wAciPITSA3g9wCcivIbSC3g9wBcifIXSB3g9wDci/IfSD3gzwA8iDIQyAPgzwC8ijIYyCPgzwB8iTIUyBPgzwD8izIcyDPg7wAshrkRZCXQF4GeQXkVZDXQF4HeQPkTZC3QN4GeQfkXZD3QN4HWQPyAciHIB+BfAzyCchakE9BPgP5HOQLkC9BvgJZB/I1yDcg34KsB/kO5HuQH0B+BPkJ5GeQDSC/gPwK8hvI7yB/gPwJ8hfIRpC/kzc1fBJIMkgEJAUkFSQNJB0kAyQTpBZIbZA6IHVB6oHUB2kA0hCkEUhjkCYgTUGagTQHaQHSEqQVSGuQNiBtQdqBtAfJAukA0hGkE0hnkC4gXUG6gXQH6RFJPIXQ7qcQlni2PYWwMekqK5k6ddSMKXNKZlXoZxCaQ5w2WQ91/y+fP3i64QmT3sCeP4jHHS6bY5gbr+6Y92PqSZntFQnZLGJ0fI3hLAYgy7dP7tm1ZoHEez8mtD9OXZuJea+IGz86cPrcO4Yu2+/H1JsxT6a9O0QSs2tZkoOB5Nbbh7HopfzuE2HPkciv1b3IVm6932TIDKDc92PirKUd+QYjjzN++oCO9nVQwf2HbL7d7E8vW/2HLEoF5oWN/aHjUv8hw2B6AoOMF7F7kNFmzo+f5W7+D1k0Yn/8uFkup8/Zhi5X/kOWLcRycxIslyc5OQIsN9dylot+5zrCcj2ylVtvHnNjYhOiTrq0HwhLO8tBlpZPdVcQNpaWL8jSMJgFAk1S4AhLO4uRpeVH7I8fN0vj9LnQQZZWKMTSihIsjSc5RQIsbSfLWRr6vZMjLK2AbOXW21eApfUNmKWd7SBL25nqrl/YWNrOgiwNg9lPoEn6OcLSzmZkaTtH7I8fN0vj9HkXB1naLkIsbdcES+NJzq4CLK3YcpZWVZSOsLR+ZCu33v4CLK1/wCxtgd0sLeZ8twFUdwPDxtIG+Oa7DQxgvtuC+NnL5vluAxgHtYGOsBdOnwc5ON9tkBB72S3BXniSs5sAexlsOXtBvwc7wl4Gkq3cetc7Mt+Ns5aGMM53Wy8w321IwPPdznfwGt1QKrBhYWN/QwWv0WEwhwkMMsMcuUZ3PuM1uqER++PHzXI5fd7dwWt0uwux3D0SLJcnOXsIsNzhlrNc9Hu4Iyx3GNnKrXdPgWt0ewZ8jW6hgyxtBNXdyLCxtBGCLA2DOVKgSUY6wtIWMrK0ERH748fN0jh9HuUgSxslxNL2SrA0nuTsJcDSRlvO0tDv0Y6wtJFkK7fevQVY2t4Bs7QLHGRpY6juxoaNpY0RZGkYzLECTTLWEZZ2ASNLGxOxP37cLI3T530cZGn7CLG0cQmWxpOccQIsbbzlLA39Hu8ISxtLtnLr3VeApe0bMEvrIXQQYK6LrVjaflR3E8LG0vYTZGkYzAkCTTLBEZbWg2HA1Sxtv4j98eNmaZw+7+8gS9tfiKUdkGBpPMk5QIClTbScpaHfEx1haRPIVm69BwqwtAMjck+J1ncM5o7DQRHZ/EfjW6qeSnCQQP6/z7C77vHu/hJ+/5DhBnFgzI/3g+W5biFU4z9n2N3beI9SCb83OFLjjPnxNlie6+ZCNf6b5b19odA4/rsjNc6YH+93y2t8Ao1nileviK3DHLJ1pEO2jg3QVo4nWkuMTX9Z3qfnCI3JGx0Zkxnz4220PNfnCuU6KTOYXFt0nutx+oz5MJ9ojecC+KRHj7CAsB8hPtG6hPJoPtEaexk/P5fwPMKB9L1hhCMJxxLiE61LDX36sVAd6POOhJ0IOxN2IexKWAekzNBzHukppc8vJHsuIlxEeDHhYsJLCC8lvIxwCeHlhEsJlxEuJ7yCcAXhlYQrCa8ivJrwGsJrCa8jXEV4PeENhDcS3kR4M+EthLcS3kZ4O+EdhHcS3kV4N+E9hPcS3kd4P+EDhA8SPkT4MOEjhI8SPkb4OOEThE8SPkX4NOEzhM8SPkf4POELhKsJXyR8ifBlwlcIXyV8jfB1wjcI3yR8i/BtwncI3yV8j/B9wjWEHxB+SPgR4ceEnxCuJfyU8DPCzwm/IPyS8CvCdYRfE35D+C3hesLvCL8n/IHwR8KfCH8m3ED4C+GvhL8R/k74B+GfhH8RbiT8m1BRfyURJhNGCFMIUwnTCNMJMwgz9fhCWFv3NWFdwnqE9Qkb6HGEsBFhY8ImhE0JmxE2J2xB2JKwFWFrwjaEbQnbEbYnzCIsI+xG2J2wJ0i5MS5pSnoGxa+EtivX9oNU0Ebcx2C8bl0hcAyutPzaNT5RGJ9azO33JEa/g/ohtK3i5Q56mZz4IZQnOZMFfgidYvkPoej3FKGTdb0k+3THGwfOmB7MN5AE9phyzoFE0s42jtjZWvEPzIh16fUhUBRTQQ4FmQYyHeQwkMNBZoDMBJkFMhtkDsgRkcRjpe1+rHS03LbHSrckXRXTDp9dMbti1OzSqVPK9IOlB5ZMnWoWpjZcF2gkRuD86516uDSO6u0M45n0BvZw6akRmZGTKR4xb7Z5JGV2biRkk4/R8TWGsxiALN8+I8z7nho/Bdp8s80jGenUXKHCTWaOH6fPR8XQZfvNNo9invunl6MT56I8yTla4Fz0GMvPRdHvY4TORbkvQM0lW7n1RoR+VOM6AGk7OWvpWM5zcOYf6HAQQ/s6qOD+enao3exPL1v99ew4KrB5YWN/6LjUX88wmPMEBpl5EbsHGVq2aoR4/3p2XMT++HGzXE6fjzd0ufLXs+OFWO4JCZbLk5wTBFjuiZazXPT7REdY7jyylVvvScyNiU2IOpNVcCxtmoMs7WSqu1PCxtJOFmRpGMxTBJrkFEdY2jRGlnZyxP74cbM0Tp9PdZClnSrE0k5LsDSe5JwmwNJOt5ylod+nO8LSTiFb2f+ALcDSzgiYpU13kKWdSXU3P2ws7UxBlobBnC/QJPMdYWnTGVnamRH748fN0jh9PstBlnaWEEs7O8HSeJJztgBLO8dyloZ+n+MIS5tPtnLrPVeApZ0bMEub6eB8t/Oo7haEjaWd55vvtiCA+W4zGee7ncc4qC1whL1w+ny+g/PdzhdiLwsT7IUnOQsF2MsFlrMX9PsCR9jLArKVW2+qI/PdOGvpQsb5bqkC890uDHi+2ywHr9FdRAW2KGzs7yLBa3QYzEUCg8wiR67RzWK8RndRxP74cbNcTp8vdvAa3cVCLHdxguXyJGexAMu9xHKWi35f4gjLXUS2cuu9VOAa3aUBX6Ob7SBLu4zqbknYWNplgiwNg7lEoEmWOMLSZjOytMsi9sePm6Vx+ny5gyztciGWtjTB0niSs1SApS2znKWh38scYWlLyFZuvcsFWNrygFnaHAdZ2hVUdyvCxtKuEGRpGMwVAk2ywhGWNoeRpV0RsT9+3CyN0+crHWRpVwqxtJUJlsaTnJUCLO0qy1ka+n2VIyxtBdnKrfdqAZZ2dUTusYV4H7qDBeJwTUQ2/9H4lqq7lF4j4Hd6pt11j3f7lPA7I6DHbUTjWzzG/HgZlue6jVCN1860u7fnCtV4HUdqnDE/Xh3Lc91aqMbrW97bRwjVeANHapwxP14Dy2t8EeVa8eoVsXWJQ7auCNBWjkcBSvR7Y8tr/zChca6JI+McY368Jpbn+nChXDd35FGAnOcmzZlnXpuPAkR+jY+kmkd4CuF8QnwU4LWUR/NRgIfR54cTziBcQLiIcAnhCkJ8FOB1hj49ZHdX9EgtH+IvJqtquP31Ndz+hhpuf2MNt7+phtvfXMPtb6nh9rfWcPvbarj97TXc/o4abn9nDbe/q4bb313D7e+p4fb3Gtsn/8P2GSD3VXO7+6u53QPV3O7Bam73UDW3e7ia2z1Sze0ereZ2j1Vzu8erud0T1dzuyWpu91Q1t3u6mts9U83tnjW2G0fbXUfj8xGR2HXrx1W03fWENxDeSHgT4c2EtxDeSngb4e2EdxDeSXgX4d2E9xDeS3gf4f2EDxA+SPgQ4cOEjxA+SvgY4eOETxA+SfgU4dOEzxA+W834JDAY7AXyXIzx9xDK07WEzxHiozefj2w7S4ab/3YB5a0M/Ux6OWfKeP4VZjxeoECujoRspgw6/qDh7Grjxy/uIsECwULhPklqGdBfXWtoZ9Rnp/dChM/n1Xw/UnotHbmgwBm/F7ejq7CgorSyIDenJJpbWQp68isrckqyi7zKwhxQn5PrlZZURMtzSwvyc/MLKwsCe87ti3w532rmzEuRxMwZluS8FOHX+zJj0Uv5/XKEPUciV6JXk63celtbeq8Fv52ctfQK4wGoNfMVPxzE0L7+Krj54fEckCu3XspimCvCel+lAnttO6x3QIyY+VnvAPXvrDeWnn9lvdxJsn1qFybkVYEB6tUIf4O9Rg1mLvEOWL6FM1/ea4yD3+t8zV6p4/k6fzy3af5XLY3nG8x9qRfuM5DVjD6/yXzAkJgG+4bAWNTW8p9y0e83Bfxu58hZNmN+vHaO/Hz9KmNfv8U4xkrV91sRmfGCM9cSl6gnCfj9NqPfSMLxaou+GoO68dK/Fom4SF2VfcfyesB6fUegHt5l9DuF6sG/cMZVIrbvRuy38T0hzsl+cLqG8eD0vgMHp+cFmrKD5aQTi/F9Ab872vnT2DZ2rmGsS8Zce5zxEx7MN/+kEsbBfI0rg3k7Rl0fMDYNNnREbbtI/HmVSVdU0s42jtjZmtFO83L9cnr9IRTFRyAfg3wCshbkU5DPQD4H+QLkS5CvQNaBfA3yDci3IOtBvgP5HuQHkB9BfgL5GWQDyC8gv4L8BvI7yB8gf4L8hZOXQP7GgoRRMwkkGSQCkgKSCpIGkg6SAZIJUgukNkgdkLog9UDqgzQAaQjSCKQxSBOQpiDNQJqDtABpCdIKpDVIG5C2IO1A2oNkgXQA6QjSCaQzSBeQriDdQLqD9ADpCdILpDfIDiB9QHYEwVHfA8kGyQHJBckDyQcpACkEKQLZCaQvyM4g/UB2AdkVpBikP8gAkIEgg0B2AxkMMgRkKMgwkN1B9gAZDrInyAiQkSCjQPYCGQ2yN8gYkLEg+4CMAxkPsi/IfiATQPYHOQBkIsiBIAeBlICUgpSBlINUgFSCTAKZDDIF5GCQQ0CmghwKMg1kOshhIIeDzACZCTILZDbIHJAjQI4EmQtyFMjRIMeAHAtyHMg8kOMxX1SLmTHGqEy15WzZ/FlJ/5ylx2/zwFvM1C8C8yKimYbNkRh+p8TwO9XA2sbnyheDehSHdFabSzwz3sqXC3/MlbH/NLUlLzy2RL0M0NGYdJWVTJ06asaUOSWzKgbPnlY2a8r0aeYQp03WQ10kRsj8683wZ9DrVGNdpuGaXqd1ZRjrzNTqkCRxHxvw5hgfCEzNCOon9Y+kSB2PnTEfXnUCVciJKSGbSIqOrzGcxQBk+fbJ/fPwR/FfGdn88Cq0P05dm4n5iSlu/NTD6fNJMXTZ/vCqkxjzZNp7ckpiQiVLcjCQ3HpPYSx6Kb9PSWHPkciEyhPJVm69XRx5eBVnLZ3KNxh5XQQmVKJ9HVRwEyo/tpv96WWrG+6eRn17etjYHzoudcNdDObpAoPM6Sl2DzK0bNUI8d5w97QU++PHzXI5fT7D0OXKDXfPEGK5ZyZYLk9yzhRgufMtZ7no93xHWO7pZCu33rOYGxObEHUmq+BY2icOsrSzqe7OCRtLO1uQpWEwzxFoknMcYWmfMLK0s1Psjx83S+P0+VwHWdq5QiztvARL40nOeQIsbYHlLA39XuAISzuHbOXWe74ASzs/YJa21kGWtpDq7oKwsbSFgiwNg3mBQJNc4AhLW8vI0ham2B8/bpbG6fOFDrK0C4VY2kUJlsaTnIsEWNoiy1ka+r3IEZZ2AdnKrfdiAZZ2ccAs7QsH57stprq7JGwsbbFvvtslAcx3+4JxvttixkHtEkfYC6fPlzo43+1SIfZyWYK98CTnMgH2ssRy9oJ+L3GEvVxCtnLr7ebIfDfOWrqccb5bN4H5bpcHPN/tSwev0S2lvl0WNva3VPAaHQZzmcAgs8yRa3RfMl6jW5pif/y4WS6nz8sdvEa3XIjlXpFguTzJuUKA5a6wnOWi3yscYbnLyFZuvVcKXKO7MuBrdF85yNJWUt1dFTaWtlKQpWEwrxJokqscYWlfMbK0lSn2x4+bpXH6fLWDLO1qIZZ2TYKl8STnGgGWdq3lLA39vtYRlnYV2cqt9zoBlnZdwCxtnYMsbRXV3fVhY2mrBFkaBvN6gSa53hGWto6Rpa1KsT9+3CyN0+cbHGRpNwixtBsTLI0nOTcKsLSbLGdp6PdNjrC068lWbr03C7C0mwNmaccLHQSY62IrlnYL1d2tYWNptwiyNAzmrQJNcqsjLO14hgFXs7RbUuyPHzdL4/T5NgdZ2m1CLO32BEvjSc7tAiztDstZGvp9hyMs7VaylVvvnQIs7c6UbZkDV870HYO543BXimz+o/EtVU8luEsg/z0y7a77DyMyfvd05FmHjPnxelqe6zZCNb6D5Y9WwnuUSvjdx5EaZ8yP18fyXLcWqnHP8t7+Wmgcz3akxhnz42VbXuO30nimePWK2LrMIVuvcsjW6wO0Nd4xBHtdYmzKs7xPPxUak/MdGZMZ8+PlW57rz4RyXeTI89M5z6OKmP/Lh49W0kMlngtsVJtuJ454DuEFhLVA7qY8pqstT6rCXsbPPyP8nPAS+t4ywqsIrydsCHKPoU8/FupI+nwu4VGERxMeQ3gsYR2Qew0955Gee+jzr8mebwi/JVxP+B3h94Q/EP5I+BPhz4QbCH8h/JXwN8LfCf8g/JPwL8KNhH8TKrIziTCZMEKYQphKmEaYTphBmKnzRFhbx4ewLmE9wvqEDXQ+CBsRNiZsQtiUsBlhc8IWhC0JWxG2JmxD2JawHWF7wizCDoQdCTsRdibsQtiVsBthd8IehD0JexH2JtyBsA/hjoRRQo8wmzCHMJcwjzCfsICwkLCIcCfCvoQ7E/Yj3IVwV8Jiwv6EAwgHEg4i3I1wMOEQwqGEwwh3J9yDcDjhnoQjCEcSjiLci3A04d6EYwjHEu5DOI5wPOG+hPsRTiDcn/AAwomEBxIeRFhCWEpYRlhOWEFYSTiJcDLhFMKDCQ8hnEp4KOE0wumEhxEeTjiDcCbhLMLZhHMIjyC8l/A4wnm6DkHuM8Yl/cPQh9T3d9N29+m+A7k/ZdsZBtzH4y6g/HRjB0x6OWcZeP4VZjweSNmED6aEbJYBOv6g4SwGoNhnHNc+dZFwk7a+dj5zPeqz03sghc9nM0/R+BavryMnOJzxe2g7ugoLKkorC3JzSqK5laWgJ7+yIqcku8irLMwB9Tm5XmlJRbQ8t7QgPze/sLIgGtSsg4dSeIm6Xh5OScw6YEnOwyn8eh9hLHopvx9JYc+RyJWxB8lWbr39LL2bkN9Ozlp6lPEA1E/gbkJoX38V3NzaeA7IlVsvZTHMFWG9j1HfPr4d1jsgRsz8rHeA+nfWG0vPv7Je7iTZPi0GE/KYwAD1WAp/gz1ODWYu3PN0GfPlPc44+D3B1+yVOp5P8Mdzm+Z/zNJ4Psncl3rhPgN5kNHnp5gPGBJTCJ8UGIt2tfynJfT7KQG/ix05y2bMj1fsyM9pjzH29dOMY6xUfT+dIjNecOZa4upjpcBU62cY/UYSnqG2XI1B3d3VFpGKi8RV2Wctrwes12cF+uA5Rr9TqB78C2dcJWL7XIr9Nj4vxDnZD053MR6cXnDg4HS/QFMOtJx0YjG+IOD3IDt/GtvGztWMdcmYa48zfsKD+eafVMI4mK+WGsy5G/LFBDvwXnSgoF7itNHVRB0csd/Gl4OicdH4luyDI3yjyCuJUcR7xYFR5FVHijOHszhfSxSn95oDxfm6I8XpPct4AvwG8wnwPyUnXjvfZG6iNLXtwqVfqkDfdKCJ3uLmiS4mygWe+HYYeeI7iVHEe8eBUeTdMPLE9xLF6b3nQHG+7wpPfIexONdY/kNJO7Xp12Fu3jnE8h9K8GZpLwn4PdSRH0o+YKxLxlx7Qx2om5cF6uZDy2c5oN+vCvj9kQN+vy7g98eW+43HBYlZLXs40N9vCPg93JHjwieMxwXGXHvDLa8b7Je3BOpmpOV+vy1049lRjvTLWsZ+Ycy1N8qBfnlboF8+deC4+q6A35854Pf7An5/7oDfawT83tvy/n5H6LgwxpHjwheMxwXGXHuc8QvqfhUd+HRtdb+KLxP3q+BJzpcC96v4ivHHeim/v0phz5Ho39M4Y7qOcYCLqC1NZy42DySSdmY5Ymd7xT8wI9al119DjX0D8i3IepDvQL4H+QHkR5CfQH4G2QDyC8ivIE3pu5kxagrXpfhigev0PSt0v5m/ABYz+SdwMIlmGjZHYvidEsPvVANrG58rXwzqURzSeW0uN+OtfLnwx1wZ+09TW/LCZIuHMwJbkq6KaYfPrphdMWp26dQpZYNnTyubNWX6tIElU6eahakN1wUaiRE4/3ozCXoKYqqxLtNwUK/TujKMdWaCdWCSuDsaR/WOhvFMeqNB3T3nG6nfmHns3HwjDTMWv1GF/J4SsntGouNrDGcxAFm+fXLfCeab+ClQtr4P42+MdOp3R+5cwunzHzF0lUbLyvO80vzyAq+iJK+wrKwox/OyS/JL8kuzCysrSvO8wrxC0FlWkl0Iu8suKfMqoiX5FUGdi/7BfAckvfyZOBflSc6fAueif1l+Lop+/yV0Lsp9Ae93spVb7zhL752oF20nZy1tZDwH54yfPqCjfR1UcPdO/NZu9qeXrZ5L/rdxYhYq9oeOSz2XvCqSqfyDDOpkslFkkKFlq0aI97nkf6fYHz9ulsvpc5LhsyvPJU9K5T0YbM5TaoLlsiQnOZVfbyTVbpaLfkdS2XMkwnIV2cqtN4W5MbEJUWeyCo6lrXeQpaVS3aWFjaWh41IsDYOZJtAkaY6wtPWMLC011f74cbM0Tp/THWRp6UIsLSPB0niSkyHA0jItZ2nod6YjLC2NbOXWW0uApdUKmKV95yBLq011VydsLK22IEvDYNYRaJI6jrC07xhZWu1U++PHzdI4fa7rIEurK8TS6iVYGk9y6gmwtPqWszT0u74jLK0O2cqtt4EAS2sQMEv7ycH5bg2p7hqFjaWh4+Z8NwxAlm+f3OzlJ8b5bg0ZB7VGjrAXTp8bx9Bl+3y3xkLspUmCvfAkp4kAe2lqOXtBv5s6wl4aka3cevd1ZL4bZy014xuMvH0F5ruhfR1UcOzvZwev0TWnvm0RNvbXXPAaHQazhcAg08KRa3Q/M16ja55qf/y4WS6nzy0dvEbXUojltkqwXJ7ktBJgua0tZ7nod2tHWG4LspVbbxuBa3RtAr5Gt8FBltaW6q5d2FhaW0GWhsFsJ9Ak7RxhaRsYWVrbVPvjx83SOH1u7yBLay/E0rISLI0nOVkCLK2D5SwN/e7gCEtrR7Zy6+0owNI6BszSfnGQpXWiuuscNpbWSZClYTA7CzRJZ0dY2i+MLK1Tqv3x42ZpnD53cZCldRFiaV0TLI0nOV0FWFo3y1ka+t3NEZbWmWzl1ttdgKV1T92WOXDlrCPoWCdwp5geqbL5j8a3VN2ltIdA/idk2l33eLdPCb/3z3SDODDmx9vf8lxnCdX4gZbfFv93oRo/yJEaZ8yPd5DluW4vVONllvf2r0I1Xu5IjTPmxyu3vMbxd98eAfHqaHxL1c9vrtjaOUBb4+1L7B+Jfp9kee1/LzTOTXZknGPMjzfZ8lz/IJTrQwLKtUXnjt4hzDOv8Ub4+sIg8uuN+CJ1E6YR1iGsBdKT8piutjxd4Hv63g+EPxI2ou+1IGxH2JmwIUgvQ5++GNldbfrcj/iLSe8abr9DDbfvU8Ptd6zh9tEabu/VcPvsGm6fU8Ptc2u4fV4Nt8+v4fYFNdy+sIbbF9Vw+51quH1fY/vkf9g+A2Tnam7Xr5rb7VLN7Xat5nbF1dyufzW3G1DN7QZWc7tB1dxut2puN7ia2w2p5nZDq7ndsGput3s1t9vD2G4cbdeLxudfU2LXrR970/Y7EPYh3JEwSugRZhPmEOYS5hHmExYQFhIWEe5E2JdwZ8J+hLsQ7kpYTNifcADhQMJBhLsRDiYcQjiUcBjh7oR7pFYvPgkMBnuBDI8x/n5NddyT8jWcsBHInqnbzpLh5vpTYAf4SE8ufQeDri+EnljgX/6jbs+/wozvCDo3Hxm2mTfo+IOGsyONH9O4T7p00XGfdB1q+cmmbg5uv6fZ+ezcqM9ObwTjZIKRjLqmW/6Xa1o8xvr2GGvGm+7IhS3O+hu1HV2FBRWllQW5OSXR3MpS0JNfWZFTkl3kVRbmgPqcXK+0pCJanltakJ+bX1hZENjzlkcJzeDaKzGDiyc5ewnM4Bpt+Qwu9Hu0I7+IjCRbufXOtPQA5LeTs5b25huMvJnMV55xEEP7+qvg/qcwMo54VG69lMUwV+RsaQz17djtnC0NiBEz/9nSAPXvZ0ux9Pzr2RJ3kmyfYogJGSMwQI0RmGI6lhrMXLgZM2O+vLGMg98+fM1eqeO5D388t2n+MZbGcxxzX+qF+wyE86x1PPMBQ2I69jiBsWi25Vd50O/xAn7PceQsmzE/3hxHplGMYezrfRnHWKn63jdVZrzgzLXEVeu3Ba5az3XgqvVagavWR9l51XobO/dj7EfGXHtHOVA3nwrUzQTLxwn0+zMBv/d3wO/PBfw+gNFvvEiBUwX11WrsbawnjO0BxkVIXLjHkYmM44ilvwSJ8emJAnzjQMa6SqG68i+ccZWI7YGp9tt4kNC5PftJQA/Gk4ASB04C9hRoymMtH4ywGEsE/D7OETJcyliXjLn2OOMnPJhv/uk6jIN5qSuDeUdGXWWMTYMNHVHbLtyJ6qBkEsVtZ5YjdrZntNP8WXQ5vS6HGqsAqQSZBDIZZArIwSCHgEwFORRkGsh0kMNADgeZATITZBbIbJA5IEeAHAkyF+QokKNBjgE5FuQ4kHkgx4OcAHIiyEkgJ4OcAnIqyGkgp4OcAXImyHyQs0DOBjkH5FyQ80AWgJwPshDkApALQS4CWQRyMchikEtALgW5DGQJyOUgS0GWgSwHuQJkBciVICtBrgK5GuQakGtBrgNZBXI9yA0gN4LcBHIzyC0gt4LcBnI7yB0gd4LcBXI3yD0g94LcB3I/yAMgD4I8BPIwyCMgj4I8BvI4yBMgT4I8BfI0yDMgz4I8B/I8yAsgq0FeBHkJ5GWQV0BeBXkN5HWQN0DeBHkL5G2Qd0DeBXkP5H2QNSAfgHwI8hHIxyCfgKwF+RTkM5DPQb4A+RLkK5B1IF+DfAPyLch6kO9Avgf5AeRHkJ9AfgbZAPILyK8gv4H8DvIHyJ8gf4FsBPkbBCd1JYEkg0RAUkCaUi1mxhijcF2Kr7dwXSq91uN3mvGdYqZ+EZh/Fs00bI7E8Dslht+pBtY2Ple+GNSjOKSz2lzimfFWvlz4Y66M/aepLXnhsSXqZYCOxqSrrGTq1FEzpswpmVUxePa0sllTpk8zhzhtsh7qIjFC5l9vhj+DXqca6zIN1/Q6rSvDWGemVockifvYgDfDKjMSw6Q3GtTUJTzucNkcw9x4dcd8WGUqZT4tLWR/9EDH1xjOYgCyfPvknoZjFki8D6tE++PUtZmYp6W58ZM6p8/pMXTZ/rDK9DR+8oxLRlpi4jpLcjCQ3HozGYteyu/MNPYciUxcTyNbufWe4MjDKjlrqRbfYOSdIDBxHe3roIKbuF5pN/vTy1Y32K9NfVsnbOwPHZe6wT4Gs47AIFMnze5BhpatGiHeG+zXTrM/ftwsl9PnuoYuV26wX1eI5dZLsFye5NQTYLn1LWe56Hd9R1huHbKVW28D5sbEJkSdySo4ljbJQZbWkOquUdhYWkNBlobBbCTQJI0cYWmTGFlawzT748fN0jh9buwgS2ssxNKaJFgaT3KaCLC0ppazNPS7qSMsrRHZyq23mQBLaxYwS5vsIEtrTnXXImwsrbkgS8NgthBokhaOsLTJjCyteZr98eNmaZw+t3SQpbUUYmmtEiyNJzmtBFhaa8tZGvrd2hGW1oJs5dbbRoCltQmYpU11cL5bW6q7dmFjaW19893aBTDfbSrjfLe2jINaO0fYC6fP7R2c79ZeiL1kJdgLT3KyBNhLB8vZC/rdwRH20o5s5dZ7kiPz3ThrqSPjfLeTBOa7dQx4vtuhDl6j60R92zls7K+T4DU6DGZngUGmsyPX6A5lvEbXKc3++HGzXE6fuzh4ja6LEMvtmmC5PMnpKsByu1nOctHvbo6w3M5kK7fe7gLX6LoHfI1umoMsrQfVXc+wsbQegiwNg9lToEl6OsLSpjGytB5p9sePm6Vx+tzLQZbWS4il9U6wNJ7k9BZgaTtYztLQ7x0cYWk9yVZuvX0EWFqfgFnadAdZ2o5Ud9GwsbQdBVkaBjMq0CRRR1jadEaWtmOa/fHjZmmcPnsOsjRPiKVlJ1gaT3KyBVhajuUsDf3OcYSlRclWbr25AiwtN2CWliJ0EGCui61YWh7VXX7YWFqeIEvDYOYLNEm+IywthWHA1SwtL83++HGzNE6fCxxkaQVCLK0wwdJ4klMowNKKLGdp6HeRIywtn2zl1ruTAEvbKW1b5sCVM33HYO449E2TzX80vqXqqQR9BfJ/SqbddY9395fw+1RHninLmB/vVMtznSVU42dY/mglvEephN9nOlLjjPnxzrQ81+2Favxsy3v7MKFx/BxHapwxP945ltd4Po1nileviK2dHbK1p0O2RgO0Nd4xBHtdYmxaYHmfThEak893ZExmzI93vuW5Plgo1xcGlGuLznO9C5n/y4ePVtIXMfFcYKPadDtxxEaELQjx8Zw7Ux7T1ZYnVWEv4+cHEx5C2I6+15mwJ2GUsCFIP0OfHrL/pO//RbiR8G9CRd9P0vaC7GLoOY/09KPPD6PvHU44g3Am4SzC2YRzCI8gPJJwLuFRhEcTHkN4LOFxhPMIjyc8gfBEwpMITyY8hfBUwtMITyc8g/BMwvmEZxGeTXgO4bmE5xEuIDyfcCHhBYQXEl5EuIjwYsLFhJcQXkp4GeESwssJlxIuI1xOeAXhCsIrCVcSXkV4NeE1hNcSXke4ivB6whsIbyS8ifBmwlsIbyW8jfB2wjsI7yS8i/BuwnsI7yW8j/B+wgcIHyR8iPBhwkcIHyV8jPBxwicInyR8ivBpwmcInyV8jvB5whcIVxO+SPgS4cuErxC+Svga4euEbxC+SfgW4duE7xC+S/ge4fuEawg/IPyQ8CPCjwk/IVxL+CnhZ4SfE35B+CXhV4TrCL8m/IbwW8L1hN8Rfk/4A+GPhD8R/ky4gfAXwl8JfyP8nfAPwl1onEkmjOjxDmRXY1zSPwyV0/d2pu121eMtSHHatjMMuLnHFNjBsymMx3fQ90nKFnuZ9HLOWvD8K8z49qcDz4CwzVpAxx80nB1g/BDBTvip6LhJ4CLbyS81B7ffF9v57Pqoz06vP+MPsQMYdS22/KYitHiM9e0x1oy32JETbc76G7gdXYUFFaWVBbk5JdHcylLQk19ZkVOSXeRVFuaA+pxcr7SkIlqeW1qQn5tfWFkQDWr2y0Ch2S+DErNfeJIzSGD2y26Wz35Bv3dz5ArtALKVW+8SSw9Afjs5a2kw32DkLRG4qxXa118FN8d7QBzxqNx6KYthrsjZ0hDq26HbOVsaECNm/rOlAerfz5Zi6fnXsyXuJNk+PQsTMkRggBoiMD1vKDWYuXAzZsZ8eUMZB79hfM1eqeM5jD+e2zT/EEvjubsj8+85z1r3YD5gSExl3V1gLFpq+VUe9HsPAb+XOXKWzZgfb5kjP+sOYezr4YxjrFR9D0+TGS84cy1x1foZgau3Kxy4av2BgN9X2nnVehs792TsR8Zce1c6UDcfCtTNCMvHCfT7IwG/Rzrg98cCfo9i9BsvUuAUIX21Gnsb6wljO8q4CIkL9ziyF+M4YukvQWJ8ei8BvjGasa5SqK78C2dcJWI7Os1+G/cWOrdnPwnoy3gSMMaBk4Bigaa82vLBCItxjIDf1zhChscy1iVjrj3O+AkP5pt/ug7jYD5WajDnbsh9EuzA28eBghrHaaOriVqXYr+N44OicdH4lmwzmPGOIvsmRhFvXwdGkf0cKc4czuKckChOb4IDxbm/I8Xp7cV4AnwA8wnwPyUnXjsnMjdRLbXtwqVfqkAnOtBEB3LzRBcT5QJPPCiMPLEkMYp4JQ6MIqVh5IllieL0yhwoznJXeOLEVL7irLD8h5KOatOvzNy8c5XlP5TgzVHHCfh9vSM/lFQy1iVjrr3rLa8b7JcRAnVzkwP9Ml7A75sd6ZdJjP3CmGvvZgf6ZaRA3dzmQL/sJ+D37Y70y2TGfmHMtXe7A/0ySqBu7nKgX/YX8PtuR/plCmO/MObau9uBfpGYfXmfA/1ygIDf9zvSLwcz9gtjrr37HeiXAwXq5iHL/d4vVeaBKA870i+HMPYLY669hx3ol4ME+uUxy/2eINQvjzvSL1MZ+4Ux197jDvRLqUC/PGW53/sL9cvTjvTLoYz9wphr72kH+qVcoF+es9zvA4T65XlH+mUaY78w5tp73oF+qRDolxct93uiUL+85Ei/TGfsF8Zce5zxC+o+q134dG11n9XDEvdZ5UnOYQL3WT2ccfKzlN+HC91nVS/+iULxxoEzpjMYB7iI2tJ05mLzQCJpZ2dH7Oyk+AdmxLr0eibU2CyQ2SBzQI4AORJkLshRIEeDHANyLMhxIPNAmtJ3M2PUFK5L8cUC1+l7rep+M+9cUszkn8DBJJpp2ByJ4XdKDL9TDaxtfK58MahHcUjntbncjLfy5cIfc2XsP01tyQuTLV4G6GhJuiqmHT67YnbFqNmlU6eUDZ49rWzWlOnTBpZMnWoWpjZcF2gkRuD8680kZNDrVGNdpuGgXqd1ZRjrzATrwCRxdzSO6l0N45n0RoO66/MsqTm7PHZuvgGsGYvjKfMnpIXsGTno+BrDWQxAlm+f3HcwnhU/BcrWz185npFOneDIHXc5fT4xhq7SaFl5nleaX17gVZTkFZaVFeV4XnZJfkl+aXZhZUVpnleYVwg6y0qyC2F32SVlXkW0JL8iqHPRE5nv3K2XkxLnojzJOUngXPRky89F0e+Thc5FuS/gnUC2cut91fKHTmk7OWvpFMZzcM746QM62tdBBffMj9l2sz+9ZJuxOJX69rSwsT90/C+fMVz7wGCeJjDInJZm9yBDy1aN8F99rqCHGZyaZn/8uFkup8+nG7q8wpzs7IIc3K6wPOrllpdlF2Znl5fmRsuiJWXZFUW5XlFlbnZuTll5WSnoLPEqo5UlZUWVhZvsCorlni7Ecs9IsFye5JwhwHLPtJzlot9nOsJyTyNbufXOZ25MbELUmayCY2lzHGRpZ1HdnR02lnaWIEvDYJ4t0CRnO8LS5jCytLPS7I8fN0vj9PkcB1naOUIs7dwES+NJzrkCLO08y1ka+n2eIyztbLKVW+8CAZa2IGCWdoSDLO18qruFYWNp5wuyNAzmQoEmWegISzuCkaWdn2Z//LhZGqfPFzjI0i4QYmkXJlgaT3IuFGBpF1nO0tDvixxhaQvJVm69iwRY2qKAWdrRDs53u5jqbnHYWNrFvvluiwOY73Y043y3ixkHtcWOsBdOny9xcL7bJULs5dIEe+FJzqUC7OUyy9kL+n2ZI+xlMdnKrfd1R+a7cdbSEsb5bq8LzHdbEvB8t2McvEZ3OfXt0rCxv8sFr9FhMJcKDDJLHblGdwzjNbrL0+yPHzfL5fR5mYPX6JYJsdzlCZbLk5zlAiz3CstZLvp9hSMsdynZyq13hcA1uhUBX6M71kGWdiXV3cqwsbQrBVkaBnOlQJOsdISlHcvI0q5Msz9+3CyN0+erHGRpVwmxtKsTLI0nOVcLsLRrLGdp6Pc1jrC0lWQrt95rBVjatQGztOMcZGnXUd2tChtLu06QpWEwVwk0ySpHWNpxjCztujT748fN0jh9vt5Blna9EEu7IcHSeJJzgwBLu9FyloZ+3+gIS1tFtnLrvUmApd2Uti1z4MpZV9AxQyAON6fJ5j8a31J1l9KbBfx+M9Puuse7fUr4/VamG8SBMT/eW5bnurNQjb9r+W3xTxCq8fccqXHG/HjvWZ7rTkI1/oHlvT1PqMY/dKTGGfPjfWh5jS+lXCtevSK2rnTI1lUB2hpvX2L/SPT7J5bX/pFC49xaR8Y5xvx4ay3P9VyhXH8eUK4tOnf0PmeeeY03wtcXBpFfb1Sbbv6IeDbhQsJaILdQHtPVlqcLHEmfzyU8inAx4VLClYSrCBuC3Gro0xcju6tNn/sRfzG5rYbb317D7e+o4fZ31nD7u2q4/d013P6eGm5/bw23v6+G299fw+0fqOH2D9Zw+4dquP3DNdz+kRpu/6ixffI/bJ8B8lg1t3u8mts9Uc3tnqzmdk9Vc7unq7ndM9Xc7tlqbvdcNbd7vprbvVDN7VZXc7sXq7ndS9Xc7uVqbveKsd042u5WGp/npcWuWz/eRtvdTngH4Z2EdxHeTXgP4b2E9xHeT/gA4YOEDxE+TPgI4aOEjxE+TvgE4ZOETxE+TfgM4bOEzxE+T/gC4WrCFwlfInyZ8JVqxieBwWAvkFdjjL8zKU+3EL5K2AjktbRtZ8lwc/2vgGDhIz259K0DfdOFzm/9y3/U7flXmPF9nWx/Iy1kM2/Q8QcNZ98wfkzjPunSRcd90vWl5Sebujm4/f7KzmfnRn12eq8zTiZ4g1HXOsv/ck2Lx1jfHmPNeOscubDFWX9vbkdXYUFFaWVBbk5JNLeyFPTkV1bklGQXeZWFOaA+J9crLamIlueWFuTn5hdWFgT2vOU3mSeK6OWttMQMLpbkvJXGr/dtxqKX8vttR34ReYNs5da73tIDkN9Ozlp6h28w8tYzX3nGQQzt66+C+5/CG3HEo3LrpSyGuSJnS+9S3763nbOlATFi5j9bGqD+/Wwplp5/PVviTpLtUwwxIe9KTL9K42+w96jBzIWbMTPmy3uPcfB7n6/ZK3U83+eP5zbN/66l8VzD3Jd64T4D4Txr/YD5gCExHXuNwFj0veVXedDvDwT8/sGRs2zG/Hg/ODKN4l3Gvv6QcYyVqu8P02TGC85cS1y13k/gqvXPDly1PkQg3xvsvGq9jZ0fMfYjY669DZbXDfbLBIF++c2Bfpkq0C+/O9IvHzP2C2Ouvd8d6Jf9BfrlLwf65VCBftnoSL98wtgvjLn2NjrQLwcI9EtSLfv7ZZpAvyTXcqNf1jL2C2OuPc744cV0vJCtf1VFDorHVRwr1qYpJRnfTxnja+mMBbHrPp8K9OVnjOfFKVRX/oUzrhKx/SzNfhs/F7oGzX6x6mbGi1VfOHCx6jWBpky1nCRgMX4h4HeaIyThS8a6ZMy1xxk/4cF88xSrMA7mX7oymHdl1PUVY9NgQ0fUtgt3oroomURx29nZETs7MdppTt9ZTq/XQY19DfINyLcg60G+A/ke5AeQH0F+AvkZZAPILyC/gvwG8jvIHyB/gvyFf5QB+RvPhtJhHyDJIBGQFJBUkDSQdJAMkEyQWiC1QeqA1AWpB1IfpAFIQ5BGII1BmoA0BWkG0hykBUhLkFYgrUHagLQFaQfSHiQLpANIR5BOIJ1BuoB0BekG0h2kB0hPkF4gvUF2AOkDsiNIFMQDyQbJAckFyQPJBykAKQQpAtkJpC/IziD9QHYB2RWkGKQ/yACQgSCDQHYDGQwyBGQoyDCQ3UH2ABkOsifICJCRIKNA9gIZDbI3yBiQsSD7gIwDGQ+yL8h+IBNA9gc5AGQiyIEgB4GUgJSClIGUg1SAVIJMApkMMgXkYJBDQKaCHAoyDWQ6yGEgh4PMAJkJMgtkNsgckCNAjgSZC3IUyNEgx4AcC3IcyDyQ40FOADkR5CSQk0FOATkV5DSQ00HOADkTZD7mlmoxM8YYhetSfL2F6/T0Nj1+myfhxUz9IjBPOppp2ByJ4XdKDL9TDaxtfK58MahHcUhntbnEM+OtfLnwx1wZ+09TW/LCY0vUywAdjUlXWcnUqaNmTJlTMqti8OxpZbOmTJ9mDnHaZD3URWKEzL/eDH8GvU411mUarul1WleGsc5MrQ5JEvexAW/a+JXAVO2gpth+LUXqeOyM+VDls6i4z04P2R8S0fE1hrMYgCzfPrmni34d/5WRzQ9VRvvj1LWZmJ+dHsw0qGh8C6vP58TQZftDlc9hzJNp77npiT9YsSQHA8mt9zzGopfy+7x09hyJ/MHqbLKVW29mQJcto/9x0XZy1tICvsHI44yfPqCjfR1UcH+w+sZu9qeXrR4Ecz717cKwsT90XOpBMBjMhQKDzMJ0uwcZWrZqhHgfBHN+uv3x42a5nD5fYOhy5UEwFwix3AsTLJcnORcKsNyLLGe56PdFjrDchWQrt95FzI2JTYg6k1VwLO1bB1naxVR3i8PG0i4WZGkYzMUCTbLYEZb2LSNLuzjd/vhxszROny9xkKVdIsTSLk2wNJ7kXCrA0i6znKWh35c5wtIWk63cepcIsLQlAbO09Q6ytMup7paGjaVdLsjSMJhLBZpkqSMsbT0jS7s83f74cbM0Tp+XOcjSlgmxtOUJlsaTnOUCLO0Ky1ka+n2FIyxtKdnKrXeFAEtbETBL+9HB+W5XUt2tDBtLu9I3321lAPPdfmSc73Yl46C20hH2wunzVQ7Od7tKiL1cnWAvPMm5WoC9XGM5e0G/r3GEvawkW7n11nZkvhtnLV3LON+ttsB8t2sDnu/2k4PX6K6jvl0VNvZ3neA1OgzmKoFBZpUj1+h+YrxGd126/fHjZrmcPl/v4DW664VY7g0JlsuTnBsEWO6NlrNc9PtGR1juKrKVW+9NAtfobgr4Gt3PDrK0m6nubgkbS7tZkKVhMG8RaJJbHGFpPzOytJvT7Y8fN0vj9PlWB1narUIs7bYES+NJzm0CLO12y1ka+n27IyztFrKVW+8dAiztjoBZ2gYHWdqdVHd3hY2l3SnI0jCYdwk0yV2OsLQNjCztznT748fN0jh9vttBlna3EEu7J8HSeJJzjwBLu9dyloZ+3+sIS7uLbOXWe58AS7svYJY2X+ggwFwXW7G0+6nuHggbS7tfkKVhMB8QaJIHHGFp8xkGXM3S7k+3P37cLI3T5wcdZGkPCrG0hxIsjSc5DwmwtIctZ2no98OOsLQHyFZuvY8IsLRH0rdlDlw503cM5o7Do+my+Y/Gt1Q9leBRgfzXrWV33ePd/SX8rlfLDeLAmB+vnuW57ixU4w0tf7QS3qNUwu9GjtQ4Y368RpbnupNQjTe1vLd/ERrHmzlS44z58ZpZXuMP0HimePWK2LrKIVtvccjWuwK0Ne7nFCuZsaml5X36ndCY3MqRMZkxP14ry3P9vVCu2waUa4vOc722zP/lw2FSX8TEc4GNatPtxBEXEy4lhF2rxyiP6WrLk6qwl/Hz7wl/IFxJ31tFeAvhXYQNQR439OmHMZ1En59MeArhqYSnEZ5OWAfkCUPPeaTncfr8F7LnV8LfCH8n/IPwT8K/CDcS/k2oSF8SYTJhhDCFMJUwjTCdMIMwU8eTsLb2g7AuYT3C+oQNdNwIGxE2JmxC2JSwGWFzwhaELQlbEbYmbEPYlrAdYXvCLMIOhB0JOxF2JuxC2JWwG2F3wh6EPQl7EfYm3IGwD+GOhFFCjzCbMIcwlzCPMJ+wgLCQsIhwJ8K+hDsT9iPchXBXwmLC/oQDCAcSDiLcjXAw4RDCoYTDCHcn3INwOOGehCMIRxKOItyLcDTh3oRjCMcS7kM4jnA84b6E+xFOINyf8ADCiYQHEh5EWEJYSlhGWE5YQVhJOIlwMuEUwoMJDyGcSngo4TTC6YSHER5OOINwJuEswtmEcwiPIDyScC7hUYRHEx5DeCzhcYTzCI8nPIHwRMInCM8gPFPXN8iT6VvGJf3D0DoaTx6j7Z7U/QzyVPq2Mwy4ucdXMODvxfh03HWg72CBJ+mpGMt/1O35V5jxfTp9Ez6THrJZC+j4g4azGIBin3Fc+9RFx00C21tOfnVzcPudZeez66M+O72n0/l8foZRVwfLbypCi8dY3x5jzXgdHDnR5qy/Z7ejq7CgorSyIDenJJpbWQp68isrckqyi7zKwhxQn5PrlZZURMtzSwvyc/MLKwuiQc1+MW2OxrmY9j6Xnpj9wpKc59L59T7PWPRSfj+fzp4jkSu0z5Ct3Hq7WHoA8tvJWUsv8A1GXheBu1qhff1VcHO8n4kjHpVbL2UxzBU5W1pNffvids6WBsSImf9saYD697OlWHr+9WyJO0m2T8/ChKwWGKBWp/M32IvUYObCzZgZ8+W9yDj4vcTX7JU6ni/xx3Ob5l9taTxfZu5LvXCfgXCetb7CfMCQmMr6ssBY1M3yqzzo9ysCfnd35CybMT9ed0d+1l3N2NevMo6xUvX9arrMeMGZa4mr1nsKXL3t5cBV60oBv3vbedV6GztfY+xHxlx7vS2vG+yXEQJ1s6MD/TJJwO+oI/3yOmO/MObaizrQLyMF6ibHgX6ZLOB3riP98gZjvzDm2st1oF9GCdRNgQP9MkXA70JH+uVNxn5hzLXHGT+8mN5AbflVFTkoHldxrHgzXSnJ+L7FGF9LZyyIXfd5S+C8+G3G8+IUqiv/whlXidi+nW6/je8IXYNmv1j1KOPFqncduFj1lEBT9rV8MMJifFfA750dIQnvMdYlY649zvgJD+abp1iFcTB/T2ow527I9xPswHvfgYJaw2mjq4makWa/jR8EReOi8S3ZM9L4RpEPE6OI96EDo8hHjhRnDmdxfpwoTu9jB4rzE1c401rmgqqn3CuotQ4U1KfcnMnFRLnAmT4LI2f6PDGKeJ87MIp8EUbO9GWiOL0vHSjOr7ht5Dawq9r06yM3B9vV9tkF0IxrBPwuduQC+jrGC+iMufaKLa8b7JfXBepmoAP98oGA34Mc6ZevGfuFMdfeIAf65Q2BuhniQL98JOD3UEf65RvGfmHMtTfUgX55U6Bu9nCgXz4R8Hu4I/3yLWO/MObaG+5Av3wqUDcjLff7I6EH1IxypF/WM/YLY669UQ70y2cC/bK35X5/LNQvYxzpl+8Y+4Ux194YB/rlC4F+GWe5358I9ct4R/rle8Z+Ycy1N96BfvlKoF8mWO73WqF+2d+RfvmBsV8Yc+3tb3ndZIOOPMVfNwda7neh2nQ3K26/D3KkX35k7BfGXHsHWV43h6fJ/F5ZZrnfOHlgnYDf5Y70y0+M/cKYa6/cgX6R+L1ykgP98rWA35Md6ZefGfuFMdfeZAf6ReL3ykMc6JdvBPye6ki/bGDsF8Zce1Md6BeJ3yunO9Av3wr4fZgj/fILY78w5to7zIF++UjgOtFMB/plvUC/zHKkX35l7BfGXHuzHOiXjwX65QgH+uU7gX450pF++Y2xXxhz7R3pQL98ItAvRzvQL98L9MsxjvTL74z9wphr7xgH+mWtQL/Mc6BffhDol+Md6Zc/GPuFMdeeVPySmesniTEXfzrydJdkRp//csTnCKPPGx3xOYXR578d8TmV0WeV4YbPaYw+Jzniczqjz8mO+NyT0eeIIz53Z/Q5JYQ+p4bQ57QQ+pzuiM8/Mt7UOSOEec4Moc+1Quhz7RD6XCeEPtcNoc/1Quhz/RD63CCEPjcMoc+NQuhz4xD63CSEPjcNoc/NQuhz8xD63CKEPrcMoc+tQuhz6xD63CaEPrcNoc/tQuhz+xD6nBVCnzuE0OeOIfS5Uwh97hxCn7uE0OeuIfS5Wwh97h5Cn3uE0OeeIfS5Vwh97h1Cn3cIoc99QujzjiH0ORpCn70Q+pwdQp9zQuhzbgh9zguhz/kh9LkghD4XhtDnohD6vFMIfe4bQp93DqHP/ULo8y4h9HnXEPpcHEKf+4fQ5wEh9HlgCH0eFEKfdwuhz4ND6POQEPo8NIQ+Dwuhz7uH0Oc9Qujz8BD6vGcIfR4RQp9HhtDnUSH0ea8Q+jw6hD7vHUKfx4TQ57Eh9HmfEPo8LoQ+jw+hz/uG0Of9QujzhBD6vH8IfT4ghD5PDKHPB4bQ54NC6HNJCH0uDaHPZSH0uTyEPleE0OfKEPo8KYQ+Tw6hz1NC6PPBIfT5kBD6PDWEPh8aQp+nhdDn6SH0+bAQ+nx4CH2eEUKfZ4bQ51kh9Hl2CH2eE0Kfj3DE558Yn191pCM+/8zo81xHfN7A6PNRjvj8C6PPRzvi86+MPh/jiM+/Mfp8rCM+/87o83GO+PwHo8/zQshJjg+hzyeE0OcTQ+jzSSH0+eQQ+nxKCH0+NYQ+n+aIzxmMPp/uiM+ZjD6f4YjPtRh9PtMRn2sz+jzfEZ/rMPp8liM+12X0+WxHfK7H6PM5jvhcn9Hncx3xuQGjz+c54nNDRp8XOOJzI0afz3fE58aMPi90xOcmjD5f4IjPTRl9vtARn5sx+nwRo8/NSE8S+RwBSQFJBUkDgUvUCs8J8RwJzxmQQyOnRI6FnAOPwXhMwjEaxyzsYaxpzHEzWo9Lc5AWIC1BWoG0BmkD0hakHUh7kCyQDiAdQTqBdAbpAtIVpBvIpaTrTzDqL5CNIH+TgUkgySARkBSQVJA0kHSQDJBMkFogtUHqgNQFqQdSH6QBSEOQRiD43Hh8jjo+Vxyfs43PncbnMONzifE5vfjcWnyOKz7XFJ/zic+9xOdA4nMR8TmB+Nw8fI4cPlcNnzOGz93C51Dhc5nwOUX43B58jg0+1wWfc4LP/cDnYOCJNz4nAZ8bgPfRx/vK433W8b7jeB9uvC813qcZ71uM9/HF+9rifV6r7nsKgvfFxPtE4n0T8T6CeF89vM8c3ncN70OG9+XC+1ThfZvwPkZ4Xx+8zw3e9wXvg4L3BcH7ZOB9I/A+CnhfAfyfPf7vHP+Hjf9Lxv/p4v9W8X+c+L9G/J8f/u8N/weG/4vC/wnh/2bwfyT4vwr8nwHOu8d56DgvG+cp47xdnMeK8zpxniPO+8N5cDgvDOdJ4bwhnEeD80pwngXOO8Df4fF3afydFn+3xN/x8Hct/J0Hf/fA3wHwujheJ8brpngdEa+r4XUmvO6C1yHwvBzPU/G8Dc9jkNcjz0XehzwIeQEeJ/G4geMojivYZ3r5PyUiW9Lz6QgA", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -172,7 +172,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -479,7 +479,7 @@ ] } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -793,7 +793,7 @@ ] } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ], diff --git a/yarn-project/aztec.js/src/artifacts/schnorr_single_key_account_contract.json b/yarn-project/aztec.js/src/artifacts/schnorr_single_key_account_contract.json index 63c310b171a..ed9b096f34d 100644 --- a/yarn-project/aztec.js/src/artifacts/schnorr_single_key_account_contract.json +++ b/yarn-project/aztec.js/src/artifacts/schnorr_single_key_account_contract.json @@ -90,7 +90,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -107,7 +107,7 @@ } ], "returnTypes": [], - "bytecode": "H4sIAAAAAAAA/+1dB1hUxxa+Sy+KivFpEpOQ3pMdWARMYtaYXk01pikICCqigmI3Jnnpvffee++9vvTee17veSXv5bXknQNnwmFYDbBnYe93Zr7v//47l2Xu/59b9+6ZmasjQfBN0FFgMcgAZAFK2DosceJocsVkQxvZCdoti46JxeoqSutMmamOllbVVJZHY+U1YypNpSmvLK8trSwrq6uMVVZU1VRVRKtMrKzO1JdXldVTw9lyGqOp8J0DbeSkwHdOmvvOhTZyU+A7V9h3sIrjPVmdowR1RiiWJdTeSMB3gFFKeSvAmrTPMC5DKS5rpoGutQCZQefxxIv0OTZSrq1oFtO5NvFo0my3sQ5gXcB6QcexuD5gA8CGgI0AGwM2AWwK2AywOWALwJYUm60B2wC2Rb0AAygFlAFigHLAGEAFoBJQBRgL2A6wPWAHwDjAjqRpPGAnwATAzoBdALsCdgPsDtgDsCdgL8DegH0A+wL2A0wE7A84AHAg4CDAwYBDAJMAhwImAw4DHA44gmJwJOBc2pH5Qcd9k5ccthwnjiZZEt0/okkWrt0y3ksLgk5vgfP3fKYjM+gegyy2LtOJRxGgMEGbOez/4jLejHvuxdmy3RbXkplGWiIDrIXv44Cts3/nx4K73/H4OZmdGzkJ/ieXljMTtJ3D1mXTcm6C/+UxynG8RJMrJuJsJ87qdlsFTENuGmjJTCMtGf2kxR4ftt1sR8tAbjdPdrul/FwK2D4IHC225DEthaJaYu33jfxeaClkWgpEtXR8txok22b7vXawcJvYRhGLiY3fIBYj+/fBLF5FwvGKsG3adm2d6/NavVav1Wv1Wr1Wr9Vr9Vq9Vq/Va/VavVav1Wv1Wr1Wr9Vr9Vq9Vq/Va/VavVav1Wv1Wr1Wr9Vr9Vq9Vq/Va/VavVav1Wv1WnVrLQy65vZbHsR0DbQ+u66AaRkkqyXK+8XYtrHvw9hI5zZlc8djP/QdtO3HmQa7rUz2mcmRTl3jUqarIyea55FnOZoKgq59P6wO6RxybKMwgY4Cxnb7hWwdz2u3Ggc761J1PA9meuOsXsT02eOLaxLOa1/tuZW6a04MuwwGQ9h2sxL4t9u3n8tny/y4GsqWLQ+j5UK2rpiWB7F1wx2vvE8U36493/i2rOZhbJ3tS1LM1tljaTjTzs8NfvzlO+tScb5Egq7nbZzV+TmTx3SlSEtpIi2ZjhaBPjDGXcGPe2x/fND9GpHJPlNL11F7nPBzhve7s7oLnc+lok+Ke+7mse3yc3eI6HZj7f1rhsp6ab+GD2PxtMfeULYv7N+b2P2tmfVVtJ5zWTvLE/zdlohTj7PlISx+w2W9tu+3NVj7cbYNvt0Rsts1fLsRgt2GXZ/JlpexAI3oXPwhvlYzHu/FCT7Hlwc7/1PI/l6cYs/DmY44q9tt4XEyjx1Ty9kzk/S9n/vlcclkcXHvU6k439DisKBrXNx7HH/m5/dHfoxaLk6BviGOPlsvZvrsuiKmz/rg1xP+fJ4tqjVWxrdpy+quLby/qXT/8DwWi+l1rePntzZMamydXdfSEmHKrNoJCdRmsEjaPcx7evOrq12XwRzZdW6PZj6STLewRJMrJsNpPJ2H6Sihdo4CTAFMBVQDagDTALWAOkA9YDqgAdAImAGYCZgFaALMBjQD5gDmAuYBWgCtgPmABYA2wELAIsBiwBLAUsAyClKEdh5qyQs661Oc+lSnXu3Ua5z6NKde69TrnHq9U5/u1BuceqNTn+HUZzr1WU69yanPdurNTn2OU5/r1Oc59Ran3urU5zv1BU69zakvdOqLnPpip77EqS916suCzkcsW+wJGyeOJle6nDPJDsV0lGBb0yOyr0BWFb++6qyrxxI1U4Tawn0xVTB+DWkfv/amTXXybZWSZ1MjGL/GdI5f7AedZlpybUWZZ1MrGL8Z6Rq/0i46TV3f24o6nk29YPxmpmH8xtR302mm962tygSeTYNg/GalW/wqE+o0jb1vq2IVns0Mwfg1pVP8Klap08zsXVulq/FsZgnGb3a6xK9itTpNU8/bmvYjns1swfg1p0P8Kn5Up2nuWVvRHng2cwTjN2eg4xftkU4z98fbKu+hZzNPMH5zBzJ+sR7rNC2rbStW3wvPplUwfvMGKn4VvdJp5q+6rcpeejYLBOPXMgDxq6rvtU7TlritaB88m4WC8Wvt7/hF+6TTLOrelumjZ7NYMH7z+zN+tX3WaZZ0bassCc9mqWD8FvRT/Errk9JplgVy7xL5O7tk49fWT/GLJleM4Hs20ygYv4UhiZ/geyIzUzB+i0ISP8H3HKZJMH6LQxI/we/pplkwfktCEj/B75lmrmD8loYkfoLfk0yLYPyWhSR+gs/5Zr5g/JaHJH6Cz6mmTTB+K0ISP8HnLLNIMH5HhyR+gs8JZolg/FaGJH6C9zmzTDB+x4QkfoLXabNCMH7HhiR+gtcZs1IwfseFJH6C54kRPGaMZPwwnw3TaXG6M5y+bTSxbR+nO8M8t3WJ1yMuIV6feAPiDYk3It6YeBPiTYk3I96ceAviLYm3It6aeBvibYmjxIa4lLiMOEZcTjyGuIK4kriKeCzxdsTbE+9API54R+I48XjinYgnEO9MvAvxrsS7Ee9OvAfxnsR7Ee9NvA/xvsT7EU8k3p/4AOIDiQ8iPpj4EOJJxIcSTyY+jPhw4iPYfsZi8x1tHqTNj7R5kzaf0uZZ2vxLm5dp8zVtHqfN77R5nzYf1OaJ2vxRm1dq801tHqrNT7V5qzaftYHY5r/avFibL2vzaG1+bQ1xNfFUYpu/a/N6lwddi3R+9PJA7vqK2jBZ3F4P3XP7SGJM/V/h+JK+hmYI+loh2NbRch6j/TXVpaRmrndl0H1qO34s5KTAS+Bsx41fUZDCzg6p2jkrU9DuMYHcQZ8q38fI76PVzkscTa6IxjTs89weS3xc0HWe258CjgecADgRcBLgZMApgFMBpwFOB5wBOBNwFuBswDmAcwHnAc4HXAC4EHAR4GLAJYBLAZcBLgdcAbgScBXgasA1gGsB1wGuB9wAuBFwE+BmwC2AWwG3AW4H3AG4E3AX4G7APYB7AfcB7gc8AHgQ8BDgYcAjgEcBjwEeBzwBeBLwFOBpwDOAZykGzwV+nlssfp7b1GiJDLAWvo8Dts7Pc+vnufXz3Pp5bvl4Kj3R4ue59fPceq1eq9fqtXqtXqvX6rV6rV6r1+q1eq1eq9fqtXqtXqvX6rV6rV6r1+q1eq1eq9fqtXqtXqvX6rV6rV6r1+q1eq1eq9fqtXqt4dLq57ntKH6e286CbfA8cj/Pbc/0RgI/zy224ee57Sj8+Mt31qXifIkEgZ/nNuh67xof+Hlue1b8PLfRJAtu189z6+e55XHx89x21+fnue193PJYLBTNc2u79eKwFzgG0nFB1/HOcNgLDM3xxCcQn0h8EvHJxKcQn0p8GvHpxGcQn0l8FvHZxOcQn0t8HvH5xBcQX0h8EfHFxJcQX0p8GfHlxFcQX0l8FfHVxNcQX0t8HfH1xDcQ30h8E/HNxLcQ30p8G/HtxHcQ30l8F/HdxPcQ30t8H/H9xA8QP0j8EPHDxI8QP0r8GPHjxE8QP0n8FPHTxM8QPxv48c74eGfPB12LPSHjxNHkinmetSU93pl7bj8XdI539oLjK53HO3tBsK2fyXnstyGPJDVzvS8GfrwzkZ3zYgrafSmQO+hT5fsl+X2U0vHOpGO6Kp3Jtv2ygOe6yjHVNbH6eq4zQzieEUHPrwSpOYakPUve2F4NiedMQc+vhcRzlqDn10PiOVvQ8xsh8Zwj6PnNkHjOFfT8Vkg8ryXo+e2QeH5Z0PM7IfE8StDzuwo9v6fQ8/sKPX+g0POHCj1/pNDzxwo9f6LQ86cKPX+m0PPnCj1/odDzlwo9f6XQ888Vev6FQs+/VOj5Vwo9/1qh598o9PxbhZ5/p9Dz7xV6/oNCz39U6PlPCj3/WaHnrxV6/otCz39V6PlvCj3/XaHnbxR6/odCz/9U6PlbhZ7/pdDzvxV6/o9Cz/9V6Pl/Cj1/p9Dz9wo9Y6cWbZ4jCj1nKPScqdBzlkLP2Qo95yj0nKvQc55Cz/kKPRco9Fyo0PMghZ4HK/RcpNDzEIWehyr0PEyh52KFnocr9LyGQs8jFHr+iULPIxV6HqXQ85oKPa+l0PPaCj2PVuh5HYWe11XoeT2FnksUel5foecNFHreUKHnjRR63lih500Uet5UoefNFHreXKHnLRR63lKh560Uet5aoedtFHreVqHnqELPRqHnUoWeyxR6jin0XK7Q8xiFnisUeq5U6LlKoeexCj1vp9Dz9go976DQ8ziFnndU6Dmu0PN4hZ53Uuh5gkLPOyv0vItCz7sq9LybQs+7K/S8h0LPeyr0vJdCz3sr9LyPQs/7KvS8n0LPExV63l+h5wMUej5QoeeDFHo+WKHnQxR6nhQSz3mCng8Nied8Qc+TQ+K5QNDzYSHxXCjo+fCQeB4k6PmIkHgeLOj5yJB4LhL0fFRIPA8R9DwlJJ6HCnqeGhLPwwQ9V4fEc7Gg55qQeB4u6HlaSDyvIei5NiSeRwh6rguJ558Ieq4X9DyS2omQ50xAFiAbkAPIBeB3QvyOhN8Z8BkanynxGQufOfAejPckvEbjNQvPYTymcR+j55EsppcQvwJ4FfAa4HXAG4A3AW8B3ga8A3gX8B7gfcAHgA8BHwE+BnwC+BTwGeBzwBeALwFfAXDed5wHHecFx3mycd5onEcZ5xXGeXZx3lmchxXnJcV5OnHeyq8BOK8hzvOH897hPHA4LxrOE4bzZn0LwHmVcJ4hnHcH56HBeVlwnpLvKXg4rwPOc4Dj/uM4+DguPI6TjuOG4zjaOK40jrOM4w7jOLw4Li2O04rjluI4njiuJY7ziOMe4jiAOC4ejhOH46bhOGI4rhaOM4XjLuE4RDguD45Tg+O24DgmOK4HjnOB4z7gOAg4LgD2k8d+49iPGvsVYz9b7HeK/TCxXyL208N+a9iPC/s1YT8f7PeC/UCwXwT2E8C8ecwjx7xqzDPGvFvMQ8W8TMxTbM/bA2BeF+Y5Yd4P5sFgXgjmSWDeAP6Ojr8r4++s+Lsj/g6Hv0vh7zT4uwW+x8f32vieF9974ntAfC+G74nwvQm+R8Dv1fg9E7934fcQfC7H51R8bsPnGLyv430Or/t4HcTrAp4nGez4zqVl/AyW0VSvbm2ta5rTWtLaXFJdW1vS1tjaUNK8oG5e/azmNvzoxD783/8BZVQQUfBgAQA=", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -414,7 +414,7 @@ ] } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -728,7 +728,7 @@ ] } ], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ], diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index 23da8c4fbf4..e3a0dae1ced 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -23,7 +23,7 @@ "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", - "remake-constants": "ts-node-esm src/scripts/constants.in.ts && prettier -w src/constants.gen.ts", + "remake-constants": "node --loader ts-node/esm src/scripts/constants.in.ts && prettier -w src/constants.gen.ts", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" }, "inherits": [ diff --git a/yarn-project/noir-compiler/package.json b/yarn-project/noir-compiler/package.json index e03849b0de2..2b2269212cd 100644 --- a/yarn-project/noir-compiler/package.json +++ b/yarn-project/noir-compiler/package.json @@ -49,7 +49,6 @@ "@aztec/foundation": "workspace:^", "@ltd/j-toml": "^1.38.0", "@noir-lang/noir_wasm": "portal:../../noir/packages/noir_wasm", - "@noir-lang/source-resolver": "portal:../../noir/packages/source-resolver", "base64-js": "^1.5.1", "commander": "^9.0.0", "fs-extra": "^11.1.1", diff --git a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts index 7dff5ecb7b1..857e39bfb43 100644 --- a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts +++ b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts @@ -47,7 +47,7 @@ export function addNoirCompilerCommanderActions(program: Command, log: LogFn = ( .action(async (projectPath: string, options) => { const { generateTypescriptInterface } = await import('./generate_typescript_interface.js'); - generateTypescriptInterface(projectPath, options, log); + await generateTypescriptInterface(projectPath, options, log); }); return program @@ -62,6 +62,6 @@ export function addNoirCompilerCommanderActions(program: Command, log: LogFn = ( .description('Generates Noir interfaces from the artifacts in the given project') .action(async (projectPath: string, options) => { const { generateNoirInterface } = await import('./generate_noir_interface.js'); - generateNoirInterface(projectPath, options, log); + await generateNoirInterface(projectPath, options, log); }); } diff --git a/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts b/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts index 4a13a1c756f..33f8926154a 100644 --- a/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts +++ b/yarn-project/noir-compiler/src/cli/generate_noir_interface.ts @@ -1,7 +1,6 @@ import { LogFn } from '@aztec/foundation/log'; -import { readFileSync, readdirSync, statSync, writeFileSync } from 'fs'; -import { mkdirpSync } from 'fs-extra'; +import { mkdir, readFile, readdir, stat, writeFile } from 'fs/promises'; import path, { resolve } from 'path'; import { generateNoirContractInterface } from '../index.js'; @@ -10,7 +9,7 @@ import { isContractArtifact } from '../utils.js'; /** * */ -export function generateNoirInterface( +export async function generateNoirInterface( projectPath: string, options: { // eslint-disable-next-line jsdoc/require-jsdoc @@ -27,10 +26,10 @@ export function generateNoirInterface( const currentDir = process.cwd(); const artifactsDir = resolve(projectPath, artifacts); - for (const artifactsDirItem of readdirSync(artifactsDir)) { + for (const artifactsDirItem of await readdir(artifactsDir)) { const artifactPath = resolve(artifactsDir, artifactsDirItem); - if (statSync(artifactPath).isFile() && artifactPath.endsWith('.json')) { - const contract = JSON.parse(readFileSync(artifactPath).toString()); + if ((await stat(artifactPath)).isFile() && artifactPath.endsWith('.json')) { + const contract = JSON.parse((await readFile(artifactPath)).toString()); if (!isContractArtifact(contract)) { continue; } @@ -38,8 +37,8 @@ export function generateNoirInterface( log(`Writing ${contract.name} Noir external interface to ${path.relative(currentDir, interfacePath)}`); try { const noirInterface = generateNoirContractInterface(contract); - mkdirpSync(path.dirname(interfacePath)); - writeFileSync(interfacePath, noirInterface); + await mkdir(path.dirname(interfacePath), { recursive: true }); + await writeFile(interfacePath, noirInterface); } catch (err) { log(`Error generating interface for ${artifactPath}: ${err}`); } diff --git a/yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts b/yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts index d004706c257..b7f9f3e74c3 100644 --- a/yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts +++ b/yarn-project/noir-compiler/src/cli/generate_typescript_interface.ts @@ -1,7 +1,6 @@ import { LogFn } from '@aztec/foundation/log'; -import { readFileSync, readdirSync, statSync, writeFileSync } from 'fs'; -import { mkdirpSync } from 'fs-extra'; +import { mkdir, readFile, readdir, stat, writeFile } from 'fs/promises'; import path, { resolve } from 'path'; import { generateTypescriptContractInterface } from '../index.js'; @@ -13,7 +12,7 @@ import { isContractArtifact } from '../utils.js'; * @param log - Optional logging function. * @returns The program with the command registered. */ -export function generateTypescriptInterface( +export async function generateTypescriptInterface( projectPath: string, options: { /* eslint-disable jsdoc/require-jsdoc */ @@ -30,10 +29,10 @@ export function generateTypescriptInterface( const currentDir = process.cwd(); const artifactsDir = resolve(projectPath, artifacts); - for (const artifactsDirItem of readdirSync(artifactsDir)) { + for (const artifactsDirItem of await readdir(artifactsDir)) { const artifactPath = resolve(artifactsDir, artifactsDirItem); - if (statSync(artifactPath).isFile() && artifactPath.endsWith('.json')) { - const contract = JSON.parse(readFileSync(artifactPath).toString()); + if ((await stat(artifactPath)).isFile() && artifactPath.endsWith('.json')) { + const contract = JSON.parse((await readFile(artifactPath)).toString()); if (!isContractArtifact(contract)) { continue; } @@ -47,8 +46,8 @@ export function generateTypescriptInterface( } try { const tsWrapper = generateTypescriptContractInterface(contract, relativeArtifactPath); - mkdirpSync(path.dirname(tsPath)); - writeFileSync(tsPath, tsWrapper); + await mkdir(path.dirname(tsPath), { recursive: true }); + await writeFile(tsPath, tsWrapper); } catch (err) { log(`Error generating interface for ${artifactPath}: ${err}`); } diff --git a/yarn-project/noir-compiler/src/compile/nargo.ts b/yarn-project/noir-compiler/src/compile/nargo.ts index 134925d0cdf..f6a296144a4 100644 --- a/yarn-project/noir-compiler/src/compile/nargo.ts +++ b/yarn-project/noir-compiler/src/compile/nargo.ts @@ -1,8 +1,8 @@ import { LogFn, createDebugLogger } from '@aztec/foundation/log'; import { execSync } from 'child_process'; -import { readFileSync, readdirSync, statSync, unlinkSync } from 'fs'; -import { emptyDirSync } from 'fs-extra'; +import { emptyDir } from 'fs-extra'; +import { readFile, readdir, stat, unlink } from 'fs/promises'; import path from 'path'; import { NoirCommit, NoirTag } from '../index.js'; @@ -31,13 +31,13 @@ export class NargoContractCompiler { * Compiles the contracts in projectPath and returns the Aztec.nr artifact. * @returns Aztec.nr artifact of the compiled contracts. */ - public compile(): Promise { + public async compile(): Promise { const stdio = this.opts.quiet ? 'ignore' : 'inherit'; const nargoBin = this.opts.nargoBin ?? 'nargo'; const version = execSync(`${nargoBin} --version`, { cwd: this.projectPath, stdio: 'pipe' }).toString(); this.checkNargoBinVersion(version.replace('\n', '')); - emptyDirSync(this.getTargetFolder()); - execSync(`${nargoBin} compile --no-backend`, { cwd: this.projectPath, stdio }); + await emptyDir(this.getTargetFolder()); + execSync(`${nargoBin} compile`, { cwd: this.projectPath, stdio }); return Promise.resolve(this.collectArtifacts()); } @@ -51,23 +51,23 @@ export class NargoContractCompiler { } } - private collectArtifacts(): NoirContractCompilationArtifacts[] { + private async collectArtifacts(): Promise { const contractArtifacts = new Map(); const debugArtifacts = new Map(); - for (const filename of readdirSync(this.getTargetFolder())) { + for (const filename of await readdir(this.getTargetFolder())) { const file = path.join(this.getTargetFolder(), filename); - if (statSync(file).isFile() && file.endsWith('.json')) { + if ((await stat(file)).isFile() && file.endsWith('.json')) { if (filename.startsWith('debug_')) { debugArtifacts.set( filename.replace('debug_', ''), - JSON.parse(readFileSync(file).toString()) as NoirDebugMetadata, + JSON.parse((await readFile(file)).toString()) as NoirDebugMetadata, ); } else { - contractArtifacts.set(filename, JSON.parse(readFileSync(file).toString()) as NoirCompiledContract); + contractArtifacts.set(filename, JSON.parse((await readFile(file)).toString()) as NoirCompiledContract); } // Delete the file as it is not needed anymore and it can cause issues with prettier - unlinkSync(file); + await unlink(file); } } diff --git a/yarn-project/noir-compiler/src/compile/noir/dependencies/dependency-manager.ts b/yarn-project/noir-compiler/src/compile/noir/dependencies/dependency-manager.ts index 44bdd25743a..cc4fc179d44 100644 --- a/yarn-project/noir-compiler/src/compile/noir/dependencies/dependency-manager.ts +++ b/yarn-project/noir-compiler/src/compile/noir/dependencies/dependency-manager.ts @@ -34,6 +34,13 @@ export class NoirDependencyManager { return this.#dependencies.get('') ?? []; } + /** + * Get transitive libraries used by the package + */ + public getLibraries() { + return Array.from(this.#libraries.entries()); + } + /** * A map of library dependencies */ diff --git a/yarn-project/noir-compiler/src/compile/noir/dependencies/github-dependency-resolver.ts b/yarn-project/noir-compiler/src/compile/noir/dependencies/github-dependency-resolver.ts index 8c9380b77ef..f7115b56258 100644 --- a/yarn-project/noir-compiler/src/compile/noir/dependencies/github-dependency-resolver.ts +++ b/yarn-project/noir-compiler/src/compile/noir/dependencies/github-dependency-resolver.ts @@ -36,7 +36,7 @@ export class GithubDependencyResolver implements NoirDependencyResolver { const libPath = await this.#extractZip(dependency, archivePath); return { version: dependency.tag, - package: NoirPackage.open(libPath, this.#fm), + package: await NoirPackage.open(libPath, this.#fm), }; } @@ -64,7 +64,7 @@ export class GithubDependencyResolver implements NoirDependencyResolver { const tmpFile = localArchivePath + '.tmp'; await this.#fm.writeFile(tmpFile, response.body); - this.#fm.moveFileSync(tmpFile, localArchivePath); + await this.#fm.moveFile(tmpFile, localArchivePath); return localArchivePath; } @@ -83,7 +83,7 @@ export class GithubDependencyResolver implements NoirDependencyResolver { return packagePath; } - const { entries } = await unzip(this.#fm.readFileSync(archivePath)); + const { entries } = await unzip(await this.#fm.readFile(archivePath)); // extract to a temporary directory, then move it to the final location // TODO empty the temp directory first @@ -99,7 +99,7 @@ export class GithubDependencyResolver implements NoirDependencyResolver { await this.#fm.writeFile(path, (await entry.blob()).stream()); } - this.#fm.moveFileSync(tmpExtractLocation, extractLocation); + await this.#fm.moveFile(tmpExtractLocation, extractLocation); return packagePath; } diff --git a/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.test.ts b/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.test.ts index bc402c67602..5538a571038 100644 --- a/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.test.ts +++ b/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.test.ts @@ -28,7 +28,7 @@ describe('DependencyResolver', () => { fm = createMemFSFileManager(memFS, '/'); - pkg = NoirPackage.open('/test_contract', fm); + pkg = await NoirPackage.open('/test_contract', fm); resolver = new LocalDependencyResolver(fm); }); diff --git a/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.ts b/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.ts index 720b7fe942f..ce86063442a 100644 --- a/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.ts +++ b/yarn-project/noir-compiler/src/compile/noir/dependencies/local-dependency-resolver.ts @@ -16,17 +16,17 @@ export class LocalDependencyResolver implements NoirDependencyResolver { this.#fm = fm; } - resolveDependency(parent: NoirPackage, config: NoirDependencyConfig): Promise { + async resolveDependency(parent: NoirPackage, config: NoirDependencyConfig): Promise { if ('path' in config) { const parentPath = parent.getPackagePath(); const dependencyPath = isAbsolute(config.path) ? config.path : join(parentPath, config.path); - return Promise.resolve({ + return { // unknown version, Nargo.toml doesn't have a version field version: undefined, - package: NoirPackage.open(dependencyPath, this.#fm), - }); + package: await NoirPackage.open(dependencyPath, this.#fm), + }; } else { - return Promise.resolve(null); + return null; } } } diff --git a/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.test.ts b/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.test.ts index e0290a5c3b4..cf039e85dca 100644 --- a/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.test.ts +++ b/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.test.ts @@ -1,5 +1,6 @@ import { Volume, createFsFromVolume } from 'memfs'; -import * as fs from 'node:fs'; +import { existsSync, mkdtempSync, rmSync } from 'node:fs'; +import * as fs from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; @@ -17,20 +18,23 @@ const memFS = (): { fm: FileManager; teardown: () => void } => { const nodeFM = (): { fm: FileManager; teardown: () => void } => { const fileSystem: FileSystem = { - existsSync: fs.existsSync, - mkdirSync: fs.mkdirSync, - writeFileSync: fs.writeFileSync, - readFileSync: fs.readFileSync, - renameSync: fs.renameSync, + existsSync: existsSync, + mkdir: async (dir: string, opts?: { recursive: boolean }) => { + await fs.mkdir(dir, opts); + }, + writeFile: fs.writeFile, + readFile: fs.readFile, + rename: fs.rename, + readdir: fs.readdir, }; - const dir = fs.mkdtempSync(join(tmpdir(), 'noir-compiler-test')); + const dir = mkdtempSync(join(tmpdir(), 'noir-compiler-test')); const fm = new FileManager(fileSystem, dir); return { fm, teardown: () => { - fs.rmSync(dir, { + rmSync(dir, { recursive: true, }); }, @@ -60,12 +64,12 @@ describe.each([memFS, nodeFM])('FileManager', setup => { it('saves files and correctly reads bytes back', async () => { await fm.writeFile('test.txt', new Blob([testFileBytes]).stream()); - expect(fm.readFileSync('test.txt')).toEqual(testFileBytes); + await expect(fm.readFile('test.txt')).resolves.toEqual(testFileBytes); }); it('saves files and correctly reads UTF-8 string back', async () => { await fm.writeFile('test.txt', new Blob([testFileBytes]).stream()); - expect(fm.readFileSync('test.txt', 'utf-8')).toEqual(testFileContent); + await expect(fm.readFile('test.txt', 'utf-8')).resolves.toEqual(testFileContent); }); it('correctly checks if file exists or not', async () => { @@ -78,7 +82,7 @@ describe.each([memFS, nodeFM])('FileManager', setup => { await fm.writeFile('test.txt.tmp', new Blob([testFileBytes]).stream()); expect(fm.hasFileSync('test.txt.tmp')).toBe(true); - fm.moveFileSync('test.txt.tmp', 'test.txt'); + await fm.moveFile('test.txt.tmp', 'test.txt'); expect(fm.hasFileSync('test.txt.tmp')).toBe(false); expect(fm.hasFileSync('test.txt')).toBe(true); diff --git a/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.ts b/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.ts index a05b6479d3f..5b502bf01bc 100644 --- a/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.ts +++ b/yarn-project/noir-compiler/src/compile/noir/file-manager/file-manager.ts @@ -1,4 +1,4 @@ -import { dirname, isAbsolute, join } from 'path'; +import path, { dirname, isAbsolute, join } from 'path'; /** * A file system interface that matches the node fs module. @@ -7,19 +7,27 @@ export interface FileSystem { /** Checks if the file exists */ existsSync: (path: string) => boolean; /** Creates a directory structure */ - mkdirSync: ( + mkdir: ( dir: string, opts?: { /** Create parent directories as needed */ recursive: boolean; }, - ) => void; + ) => Promise; /** Writes a file */ - writeFileSync: (path: string, data: Uint8Array) => void; + writeFile: (path: string, data: Uint8Array) => Promise; /** Reads a file */ - readFileSync: (path: string, encoding?: 'utf-8') => Uint8Array | string; + readFile: (path: string, encoding?: 'utf-8') => Promise; /** Renames a file */ - renameSync: (oldPath: string, newPath: string) => void; + rename: (oldPath: string, newPath: string) => Promise; + /** Reads a directory */ + readdir: ( + path: string, + options?: { + /** Traverse child directories recursively */ + recursive: boolean; + }, + ) => Promise; } /** @@ -64,8 +72,8 @@ export class FileManager { offset += chunk.length; } - this.#fs.mkdirSync(dirname(path), { recursive: true }); - this.#fs.writeFileSync(this.#getPath(path), file); + await this.#fs.mkdir(dirname(path), { recursive: true }); + await this.#fs.writeFile(this.#getPath(path), file); } /** @@ -74,7 +82,7 @@ export class FileManager { * @param oldName - File to save * @param newName - File contents */ - moveFileSync(oldName: string, newName: string) { + async moveFile(oldName: string, newName: string) { if (isAbsolute(oldName) || isAbsolute(newName)) { throw new Error("can't move absolute path"); } @@ -82,29 +90,29 @@ export class FileManager { const oldPath = this.#getPath(oldName); const newPath = this.#getPath(newName); - this.#fs.mkdirSync(dirname(newPath), { recursive: true }); - this.#fs.renameSync(oldPath, newPath); + await this.#fs.mkdir(dirname(newPath), { recursive: true }); + await this.#fs.rename(oldPath, newPath); } /** * Reads a file from the disk and returns a buffer * @param name - File to read */ - public readFileSync(name: string): Uint8Array; + public async readFile(name: string): Promise; /** * Reads a file from the filesystem as a string * @param name - File to read * @param encoding - Encoding to use */ - public readFileSync(name: string, encoding: 'utf-8'): string; + public async readFile(name: string, encoding: 'utf-8'): Promise; /** * Reads a file from the filesystem * @param name - File to read * @param encoding - Encoding to use */ - public readFileSync(name: string, encoding?: 'utf-8'): string | Uint8Array { + public async readFile(name: string, encoding?: 'utf-8'): Promise { const path = this.#getPath(name); - const data = this.#fs.readFileSync(path, encoding); + const data = await this.#fs.readFile(path, encoding); if (!encoding) { return typeof data === 'string' @@ -126,4 +134,23 @@ export class FileManager { #getPath(name: string) { return isAbsolute(name) ? name : join(this.#dataDir, name); } + + /** + * Reads a file from the filesystem + * @param dir - File to read + * @param options - Readdir options + */ + public async readdir( + dir: string, + options?: { + /** + * Traverse child directories recursively + */ + recursive: boolean; + }, + ) { + const dirPath = this.#getPath(dir); + const files = await this.#fs.readdir(dirPath, options); + return files.map(file => path.join(dirPath, file)); + } } diff --git a/yarn-project/noir-compiler/src/compile/noir/file-manager/memfs-file-manager.ts b/yarn-project/noir-compiler/src/compile/noir/file-manager/memfs-file-manager.ts index 20df80837b8..cbf46def880 100644 --- a/yarn-project/noir-compiler/src/compile/noir/file-manager/memfs-file-manager.ts +++ b/yarn-project/noir-compiler/src/compile/noir/file-manager/memfs-file-manager.ts @@ -1,4 +1,5 @@ import { IFs, fs } from 'memfs'; +import { IDirent } from 'memfs/lib/node/types/misc.js'; import { FileManager } from './file-manager.js'; @@ -8,13 +9,49 @@ import { FileManager } from './file-manager.js'; * @param dataDir - where to store files */ export function createMemFSFileManager(memFS: IFs = fs, dataDir = '/'): FileManager { + const readdirRecursive = async (dir: string): Promise => { + const contents = await memFS.promises.readdir(dir); + let files: string[] = []; + for (const handle in contents) { + if ((handle as unknown as IDirent).isFile()) { + files.push(handle.toString()); + } else { + files = files.concat(await readdirRecursive(handle.toString())); + } + } + return files; + }; return new FileManager( { existsSync: memFS.existsSync.bind(memFS), - mkdirSync: memFS.mkdirSync.bind(memFS), - writeFileSync: memFS.writeFileSync.bind(memFS), - renameSync: memFS.renameSync.bind(memFS), - readFileSync: memFS.readFileSync.bind(memFS), + mkdir: async ( + dir: string, + options?: { + /** + * Traverse child directories + */ + recursive: boolean; + }, + ) => { + await memFS.promises.mkdir(dir, options); + }, + writeFile: memFS.promises.writeFile.bind(memFS), + rename: memFS.promises.rename.bind(memFS), + readFile: memFS.promises.readFile.bind(memFS), + readdir: async ( + dir: string, + options?: { + /** + * Traverse child directories + */ + recursive: boolean; + }, + ) => { + if (options?.recursive) { + return readdirRecursive(dir); + } + return (await memFS.promises.readdir(dir)).map(handles => handles.toString()); + }, }, dataDir, ); diff --git a/yarn-project/noir-compiler/src/compile/noir/file-manager/nodejs-file-manager.ts b/yarn-project/noir-compiler/src/compile/noir/file-manager/nodejs-file-manager.ts new file mode 100644 index 00000000000..d001e0c072e --- /dev/null +++ b/yarn-project/noir-compiler/src/compile/noir/file-manager/nodejs-file-manager.ts @@ -0,0 +1,34 @@ +import { existsSync } from 'node:fs'; +import * as fs from 'node:fs/promises'; + +import { FileManager } from './file-manager.js'; + +/** + * Creates a new FileManager instance based on nodejs fs + * @param dataDir - where to store files + */ +export function createNodejsFileManager(dataDir: string): FileManager { + return new FileManager( + { + ...fs, + ...{ + // ExistsSync is not available in the fs/promises module + existsSync, + // This is added here because the node types are not compatible with the FileSystem type for mkdir + // Typescripts tries to use a different variant of the function that is not the one that has the optional options. + mkdir: async ( + dir: string, + opts?: { + /** + * Traverse child directories + */ + recursive: boolean; + }, + ) => { + await fs.mkdir(dir, opts); + }, + }, + }, + dataDir, + ); +} diff --git a/yarn-project/noir-compiler/src/compile/noir/noir-source-resolver.shim.cts b/yarn-project/noir-compiler/src/compile/noir/noir-source-resolver.shim.cts deleted file mode 100644 index 3bc79cdd664..00000000000 --- a/yarn-project/noir-compiler/src/compile/noir/noir-source-resolver.shim.cts +++ /dev/null @@ -1,13 +0,0 @@ -// Shim module to force the use of the CJS build of source-resolver & noir_wasm -/** - * Source resolver module - */ -type SourceResolver = { - /** Sets up a function to provide file contents */ - initializeResolver: (resolver: (source_id: string) => string) => void; -}; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const sourceResolver: SourceResolver = require('@noir-lang/source-resolver'); - -export const initializeResolver = sourceResolver.initializeResolver; diff --git a/yarn-project/noir-compiler/src/compile/noir/noir-wasm-compiler.ts b/yarn-project/noir-compiler/src/compile/noir/noir-wasm-compiler.ts index 30beca72558..8abd9e9471a 100644 --- a/yarn-project/noir-compiler/src/compile/noir/noir-wasm-compiler.ts +++ b/yarn-project/noir-compiler/src/compile/noir/noir-wasm-compiler.ts @@ -1,6 +1,6 @@ import { LogFn, createDebugLogger } from '@aztec/foundation/log'; -import { CompileError, compile } from '@noir-lang/noir_wasm'; +import { CompileError, PathToFileSourceMap, compile } from '@noir-lang/noir_wasm'; import { isAbsolute } from 'node:path'; import { NoirCompilationResult, NoirProgramCompilationArtifacts } from '../../noir_artifact.js'; @@ -8,7 +8,6 @@ import { NoirDependencyManager } from './dependencies/dependency-manager.js'; import { GithubDependencyResolver as GithubCodeArchiveDependencyResolver } from './dependencies/github-dependency-resolver.js'; import { LocalDependencyResolver } from './dependencies/local-dependency-resolver.js'; import { FileManager } from './file-manager/file-manager.js'; -import { initializeResolver } from './noir-source-resolver.shim.cjs'; import { NoirPackage } from './package.js'; /** Compilation options */ @@ -48,12 +47,12 @@ export class NoirWasmContractCompiler { * @param projectPath - The path to the project * @param opts - Compilation options */ - public static new(fileManager: FileManager, projectPath: string, opts: NoirWasmCompileOptions) { + public static async new(fileManager: FileManager, projectPath: string, opts: NoirWasmCompileOptions) { if (!isAbsolute(projectPath)) { throw new Error('projectPath must be an absolute path'); } - const noirPackage = NoirPackage.open(projectPath, fileManager); + const noirPackage = await NoirPackage.open(projectPath, fileManager); const dependencyManager = new NoirDependencyManager( [ @@ -101,16 +100,29 @@ export class NoirWasmContractCompiler { await this.#dependencyManager.resolveDependencies(); this.#debugLog(`Dependencies: ${this.#dependencyManager.getPackageNames().join(', ')}`); - initializeResolver(this.#resolveFile); - try { const isContract: boolean = false; - const result = compile(this.#package.getEntryPointPath(), isContract, { + + const entrypoint = this.#package.getEntryPointPath(); + const deps = { /* eslint-disable camelcase */ root_dependencies: this.#dependencyManager.getEntrypointDependencies(), library_dependencies: this.#dependencyManager.getLibraryDependencies(), /* eslint-enable camelcase */ + }; + const packageSources = await this.#package.getSources(this.#fm); + const librarySources = ( + await Promise.all( + this.#dependencyManager + .getLibraries() + .map(async ([alias, library]) => await library.package.getSources(this.#fm, alias)), + ) + ).flat(); + const sourceMap: PathToFileSourceMap = new PathToFileSourceMap(); + [...packageSources, ...librarySources].forEach(sourceFile => { + sourceMap.add_source_code(sourceFile.path, sourceFile.source); }); + const result = compile(entrypoint, isContract, deps, sourceMap); if (!('program' in result)) { throw new Error('No program found in compilation result'); @@ -119,7 +131,7 @@ export class NoirWasmContractCompiler { return [{ name: this.#package.getNoirPackageConfig().package.name, ...result }]; } catch (err) { if (err instanceof Error && err.name === 'CompileError') { - this.#processCompileError(err as CompileError); + await this.#processCompileError(err as CompileError); } throw err; @@ -140,16 +152,29 @@ export class NoirWasmContractCompiler { await this.#dependencyManager.resolveDependencies(); this.#debugLog(`Dependencies: ${this.#dependencyManager.getPackageNames().join(', ')}`); - initializeResolver(this.#resolveFile); - try { const isContract: boolean = true; - const result = compile(this.#package.getEntryPointPath(), isContract, { + + const entrypoint = this.#package.getEntryPointPath(); + const deps = { /* eslint-disable camelcase */ root_dependencies: this.#dependencyManager.getEntrypointDependencies(), library_dependencies: this.#dependencyManager.getLibraryDependencies(), /* eslint-enable camelcase */ + }; + const packageSources = await this.#package.getSources(this.#fm); + const librarySources = ( + await Promise.all( + this.#dependencyManager + .getLibraries() + .map(async ([alias, library]) => await library.package.getSources(this.#fm, alias)), + ) + ).flat(); + const sourceMap: PathToFileSourceMap = new PathToFileSourceMap(); + [...packageSources, ...librarySources].forEach(sourceFile => { + sourceMap.add_source_code(sourceFile.path, sourceFile.source); }); + const result = compile(entrypoint, isContract, deps, sourceMap); if (!('contract' in result)) { throw new Error('No contract found in compilation result'); @@ -158,7 +183,7 @@ export class NoirWasmContractCompiler { return [result]; } catch (err) { if (err instanceof Error && err.name === 'CompileError') { - this.#processCompileError(err as CompileError); + await this.#processCompileError(err as CompileError); throw new Error('Compilation failed'); } @@ -166,19 +191,19 @@ export class NoirWasmContractCompiler { } } - #resolveFile = (path: string) => { + async #resolveFile(path: string) { try { const libFile = this.#dependencyManager.findFile(path); - return this.#fm.readFileSync(libFile ?? path, 'utf-8'); + return await this.#fm.readFile(libFile ?? path, 'utf-8'); } catch (err) { return ''; } - }; + } - #processCompileError(err: CompileError): void { + async #processCompileError(err: CompileError): Promise { for (const diag of err.diagnostics) { this.#log(` ${diag.message}`); - const contents = this.#resolveFile(diag.file); + const contents = await this.#resolveFile(diag.file); const lines = contents.split('\n'); const lineOffsets = lines.reduce((accum, _, idx) => { if (idx === 0) { diff --git a/yarn-project/noir-compiler/src/compile/noir/package.ts b/yarn-project/noir-compiler/src/compile/noir/package.ts index 4c5f42f1077..559ff40b270 100644 --- a/yarn-project/noir-compiler/src/compile/noir/package.ts +++ b/yarn-project/noir-compiler/src/compile/noir/package.ts @@ -6,6 +6,21 @@ import { join } from 'node:path'; import { FileManager } from './file-manager/file-manager.js'; const CONFIG_FILE_NAME = 'Nargo.toml'; +const SOURCE_EXTENSIONS = ['.nr']; + +/** + * An array of sources for a package + */ +type SourceList = Array<{ + /** + * The source path, taking into account modules and aliases. Eg: mylib/mod/mysource.nr + */ + path: string; + /** + * Resolved source plaintext + */ + source: string; +}>; /** * A Noir package. @@ -62,7 +77,6 @@ export class NoirPackage { default: throw new Error(`Unknown package type: ${this.getType()}`); } - // TODO check that `src` exists return join(this.#srcPath, entrypoint); } @@ -81,14 +95,34 @@ export class NoirPackage { return this.#config.dependencies; } + /** + * Gets this package's sources. + * @param fm - A file manager to use + * @param alias - An alias for the sources, if this package is a dependency + */ + public async getSources(fm: FileManager, alias?: string): Promise { + const handles = await fm.readdir(this.#srcPath, { recursive: true }); + return Promise.all( + handles + .filter(handle => SOURCE_EXTENSIONS.find(ext => handle.endsWith(ext))) + .map(async file => { + const suffix = file.replace(this.#srcPath, ''); + return { + path: this.getType() === 'lib' ? `${alias ? alias : this.#config.package.name}${suffix}` : file, + source: (await fm.readFile(file, 'utf-8')).toString(), + }; + }), + ); + } + /** * Opens a path on the filesystem. * @param path - Path to the package. * @param fm - A file manager to use. * @returns The Noir package at the given location */ - public static open(path: string, fm: FileManager): NoirPackage { - const fileContents = fm.readFileSync(join(path, CONFIG_FILE_NAME), 'utf-8'); + public static async open(path: string, fm: FileManager): Promise { + const fileContents = await fm.readFile(join(path, CONFIG_FILE_NAME), 'utf-8'); const config = parseNoirPackageConfig(parse(fileContents)); return new NoirPackage(path, join(path, 'src'), config); diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts b/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts index d97f66f1a43..8ff3a43bd29 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts @@ -30,7 +30,7 @@ function generateFunctionArtifact(fn: NoirFunctionEntry): FunctionArtifact { } // If the function is secret, the return is the public inputs, which should be omitted - const returnTypes = functionType === FunctionType.SECRET ? [] : [fn.abi.return_type]; + const returnTypes = functionType === FunctionType.SECRET ? [] : [fn.abi.return_type.abi_type]; return { name: fn.name, @@ -72,7 +72,6 @@ export function generateProgramArtifact( // eslint-disable-next-line camelcase noir_version, hash: program.hash, - backend: program.backend, abi: program.abi, // TODO: should we parse and write the debug? it doesn't seem to be in the nargo output diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts index 257bc287d12..7961344b522 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts @@ -158,8 +158,8 @@ export function generateTypescriptProgramInterface(abiObj: NoirFunctionAbi): str // Generating Return type, if it exists // if (abiObj.return_type != null) { - result += generateStructInterfaces(abiObj.return_type, outputStructs); - result += `export type ReturnType = ${abiTypeToTs(abiObj.return_type)};\n`; + result += generateStructInterfaces(abiObj.return_type.abi_type, outputStructs); + result += `export type ReturnType = ${abiTypeToTs(abiObj.return_type.abi_type)};\n`; } // Generating Input type diff --git a/yarn-project/noir-compiler/src/declaration.d.ts b/yarn-project/noir-compiler/src/declaration.d.ts deleted file mode 100644 index 11de551bde2..00000000000 --- a/yarn-project/noir-compiler/src/declaration.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@noir-lang/noir-source-resolver'; diff --git a/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr b/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr index b980af369cf..95824d09f4b 100644 --- a/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr +++ b/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr @@ -8,5 +8,4 @@ contract TestContract { open fn openFunction() -> pub Field { 42 } - } diff --git a/yarn-project/noir-compiler/src/index.ts b/yarn-project/noir-compiler/src/index.ts index 768d328c8ae..976c7eaf69d 100644 --- a/yarn-project/noir-compiler/src/index.ts +++ b/yarn-project/noir-compiler/src/index.ts @@ -1,10 +1,9 @@ import { ContractArtifact } from '@aztec/foundation/abi'; -import * as fs from 'node:fs'; import { join, resolve } from 'path'; import { CompileOpts, NargoContractCompiler } from './compile/nargo.js'; -import { FileManager } from './compile/noir/file-manager/file-manager.js'; +import { createNodejsFileManager } from './compile/noir/file-manager/nodejs-file-manager.js'; import { NoirWasmCompileOptions, NoirWasmContractCompiler } from './compile/noir/noir-wasm-compiler.js'; import { generateArtifact, generateContractArtifact } from './contract-interface-gen/abi.js'; import { ProgramArtifact } from './noir_artifact.js'; @@ -41,8 +40,8 @@ export async function compileUsingNoirWasm( opts: NoirWasmCompileOptions, ): Promise<(ContractArtifact | ProgramArtifact)[]> { const cacheRoot = process.env.XDG_CACHE_HOME ?? join(process.env.HOME ?? '', '.cache'); - const fileManager = new FileManager(fs, join(cacheRoot, 'aztec-noir-compiler')); - const compiler = NoirWasmContractCompiler.new(fileManager, resolve(projectPath), opts); + const fileManager = createNodejsFileManager(join(cacheRoot, 'aztec-noir-compiler')); + const compiler = await NoirWasmContractCompiler.new(fileManager, resolve(projectPath), opts); const artifacts = await compiler.compile(); return artifacts.map(artifact => { return generateArtifact(artifact); diff --git a/yarn-project/noir-compiler/src/noir_artifact.ts b/yarn-project/noir-compiler/src/noir_artifact.ts index 38032dcef94..f8702b3ca0f 100644 --- a/yarn-project/noir-compiler/src/noir_artifact.ts +++ b/yarn-project/noir-compiler/src/noir_artifact.ts @@ -1,4 +1,11 @@ -import { ABIParameter, ABIType, DebugFileMap, DebugInfo, EventAbi } from '@aztec/foundation/abi'; +import { + ABIParameter, + ABIParameterVisibility, + ABIType, + DebugFileMap, + DebugInfo, + EventAbi, +} from '@aztec/foundation/abi'; /** The Aztec.nr function types. */ type NoirFunctionType = 'Open' | 'Secret' | 'Unconstrained'; @@ -18,7 +25,16 @@ export interface NoirFunctionAbi { }[]; }; /** The return type of the function. */ - return_type: ABIType; + return_type: { + /** + * The type of the return value. + */ + abi_type: ABIType; + /** + * The visibility of the return value. + */ + visibility: ABIParameterVisibility; + }; /** The witness indices of the return type. */ return_witnesses: number[]; } @@ -49,8 +65,6 @@ export interface NoirFunctionEntry { export interface NoirCompiledContract { /** The name of the contract. */ name: string; - /** Compilation backend. */ - backend: string; /** The functions of the contract. */ functions: NoirFunctionEntry[]; /** The events of the contract */ @@ -63,8 +77,6 @@ export interface NoirCompiledContract { export interface NoirCompiledCircuit { /** The hash of the circuit. */ hash?: number; - /** Compilation backend. */ - backend: string; /** * The ABI of the function. */ @@ -90,11 +102,6 @@ export interface ProgramArtifact { */ hash?: number; - /** - * The compilation backend of the artifact. - */ - backend: string; - /** * The abi of the program. */ diff --git a/yarn-project/noir-compiler/src/versions.ts b/yarn-project/noir-compiler/src/versions.ts index 43f9383e7d4..9cf6fd768b3 100644 --- a/yarn-project/noir-compiler/src/versions.ts +++ b/yarn-project/noir-compiler/src/versions.ts @@ -1,9 +1,9 @@ -import { readFileSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; import NoirVersion from './noir-version.json' assert { type: 'json' }; // read package.json at runtime instead of compile time so that we keep rootDir as-is in tsconfig -const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8')); +const pkg = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf-8')); export const NoirWasmVersion = pkg.dependencies['@noir-lang/noir_wasm']; export const NoirTag = NoirVersion.tag; diff --git a/yarn-project/noir-contracts/src/contracts/benchmarking_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/benchmarking_contract/src/main.nr index e128c7d7b15..611d38afaaa 100644 --- a/yarn-project/noir-contracts/src/contracts/benchmarking_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/benchmarking_contract/src/main.nr @@ -64,9 +64,11 @@ contract Benchmarking { fn increment_balance(owner: AztecAddress, value: Field) { let current = storage.balances.at(owner.to_field()).read(); storage.balances.at(owner.to_field()).write(current + value); - let _callStackItem1 = context.call_public_function(context.this_address(), + let _callStackItem1 = context.call_public_function( + context.this_address(), compute_selector("broadcast((Field))"), - [owner.to_field()]); + [owner.to_field()] + ); } // Emits a public log. @@ -75,7 +77,12 @@ contract Benchmarking { emit_unencrypted_log(&mut context, storage.balances.at(owner.to_field()).read()); } - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; VALUE_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/card_game_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/card_game_contract/src/main.nr index 088f75d9ace..31f3f431b8b 100644 --- a/yarn-project/noir-contracts/src/contracts/card_game_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/card_game_contract/src/main.nr @@ -130,9 +130,11 @@ contract CardGame { let _added_to_game_deck = game_deck.add_cards(cards, player); let selector = compute_selector("on_game_joined(u32,(Field),u32)"); let strength = compute_deck_strength(cards); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [game as Field, player.to_field(), strength]); + [game as Field, player.to_field(), strength] + ); } #[aztec(public)] @@ -163,9 +165,11 @@ contract CardGame { let selector = compute_selector("on_card_played(u32,(Field),Field)"); // docs:start:call_public_function - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [game as Field, player.to_field(), card.to_field()]); + [game as Field, player.to_field(), card.to_field()] + ); // docs:end:call_public_function } @@ -192,9 +196,11 @@ contract CardGame { let _inserted_cards = collection.add_cards(cards, player); let selector = compute_selector("on_cards_claimed(u32,(Field),Field)"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [game as Field, player.to_field(), pedersen_hash(cards_fields, 0)]); + [game as Field, player.to_field(), pedersen_hash(cards_fields, 0)] + ); } #[aztec(public)] @@ -213,26 +219,31 @@ contract CardGame { game_storage.write(game_data); } - unconstrained fn view_collection_cards(owner: AztecAddress, offset: u32) -> [Option; MAX_NOTES_PER_PAGE] { + unconstrained fn view_collection_cards(owner: AztecAddress, offset: u32) -> pub [Option; MAX_NOTES_PER_PAGE] { let collection = storage.collections.at(owner.to_field()); collection.view_cards(offset) } - unconstrained fn view_game_cards(game: u32, player: AztecAddress, offset: u32) -> [Option; MAX_NOTES_PER_PAGE] { + unconstrained fn view_game_cards(game: u32, player: AztecAddress, offset: u32) -> pub [Option; MAX_NOTES_PER_PAGE] { let game_deck = storage.game_decks.at(game as Field).at(player.to_field()); game_deck.view_cards(offset) } - unconstrained fn view_game(game: u32) -> Game { + unconstrained fn view_game(game: u32) -> pub Game { storage.games.at(game as Field).read() } // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; VALUE_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr index 9bb20c9fd20..f9a8431cd87 100644 --- a/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr @@ -109,7 +109,7 @@ contract Child { } // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> pub [Field; 4] { [0, 0, 0, 0] } } diff --git a/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr index a01a6ce0971..eb474a66c60 100644 --- a/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr @@ -60,14 +60,19 @@ contract Counter { // docs:end:increment // docs:start:get_counter - unconstrained fn get_counter(owner: AztecAddress) -> Field { + unconstrained fn get_counter(owner: AztecAddress) -> pub Field { let counters = storage.counters; balance_utils::get_balance(counters.at(owner.to_field()).set) } // docs:end:get_counter // docs:start:nullifier - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; VALUE_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr index ee74e34c7ad..c705e0f91e6 100644 --- a/yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr @@ -170,14 +170,18 @@ contract DocsExample { let legendary_card = actions::get_legendary_card(storage.legendary_card); let owner = legendary_card.owner; - let result = context.call_private_function(inputs.call_context.storage_contract_address, + let result = context.call_private_function( + inputs.call_context.storage_contract_address, FunctionSelector::from_field(GET_POINTS_OF_COMMON_CARD_FUNCTION_SELECTOR), - [owner.to_field(), 0]); + [owner.to_field(), 0] + ); let total_points = legendary_card.points + result[0] as u8; - context.call_public_function(inputs.call_context.storage_contract_address, + context.call_public_function( + inputs.call_context.storage_contract_address, FunctionSelector::from_field(REPLACE_QUEEN_FUNCTION_SELECTOR), - [owner.to_field(), total_points as Field]); + [owner.to_field(), total_points as Field] + ); } #[aztec(private)] @@ -197,7 +201,7 @@ contract DocsExample { } // docs:start:functions-UnconstrainedFunction - unconstrained fn get_total_points(account: AztecAddress) -> u8 { + unconstrained fn get_total_points(account: AztecAddress) -> pub u8 { actions::get_total_points(storage.cards, account, 0) } // docs:end:functions-UnconstrainedFunction @@ -274,7 +278,12 @@ contract DocsExample { // docs:end:l1_to_l2_cross_chain_message // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } } diff --git a/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr index 8af766921bb..64fd929a21c 100644 --- a/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/easy_private_token_contract/src/main.nr @@ -65,7 +65,7 @@ contract EasyPrivateToken { } // Helper function to get the balance of a user ("unconstrained" is a Noir alternative of Solidity's "view" function). - unconstrained fn getBalance(owner: AztecAddress) -> Field { + unconstrained fn getBalance(owner: AztecAddress) -> pub Field { let balances = storage.balances; // Return the sum of all notes in the set. @@ -75,7 +75,12 @@ contract EasyPrivateToken { // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; VALUE_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/easy_private_voting_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/easy_private_voting_contract/src/main.nr index f9685507a90..67269f2d174 100644 --- a/yarn-project/noir-contracts/src/contracts/easy_private_voting_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/easy_private_voting_contract/src/main.nr @@ -56,7 +56,7 @@ contract EasyPrivateVoting { fn constructor(admin: AztecAddress) { // called when contract is deployed context.call_public_function( // we cannot update public state directly from private function but we can call public function (which queues it) - context.this_address(), // contract address whose method we want to call + context.this_address(),// contract address whose method we want to call compute_selector("_initialize((Field))"), // function selector [admin.to_field()] // parameters ); @@ -76,9 +76,10 @@ contract EasyPrivateVoting { let nullifier = dep::std::hash::pedersen_hash([context.msg_sender().to_field(), secret.low, secret.high]); // compute nullifier with this secret key so others can't descrypt it context.push_new_nullifier(nullifier, EMPTY_NULLIFIED_COMMITMENT); // push nullifier context.call_public_function( - context.this_address(), - compute_selector("add_to_tally_public(Field)"), - [candidate]); + context.this_address(), + compute_selector("add_to_tally_public(Field)"), + [candidate] + ); } // docs:end:cast_vote @@ -99,13 +100,18 @@ contract EasyPrivateVoting { } // docs:end:end_vote // docs:start:get_vote - unconstrained fn get_vote(candidate: Field) -> Field { + unconstrained fn get_vote(candidate: Field) -> pub Field { storage.tally.at(candidate).read() } // docs:end:get_vote // docs:start:compute_note_hash_and_nullifier - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } // docs:end:compute_note_hash_and_nullifier -} \ No newline at end of file +} diff --git a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr index a4604621e7c..32c41e63d8a 100644 --- a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr @@ -42,7 +42,7 @@ contract EcdsaAccount { // Creates a new account out of an ECDSA public key to use for signature verification #[aztec(private)] - fn constructor(signing_pub_key_x: pub [u8;32], signing_pub_key_y: pub [u8;32]) { + fn constructor(signing_pub_key_x: pub [u8; 32], signing_pub_key_y: pub [u8; 32]) { let this = context.this_address(); let mut pub_key_note = EcdsaPublicKeyNote::new(signing_pub_key_x, signing_pub_key_y, this); storage.public_key.initialize(&mut pub_key_note, Option::none(), true); @@ -103,7 +103,7 @@ contract EcdsaAccount { nonce: Field, storage_slot: Field, serialized_note: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] - ) -> [Field; 4] { + ) -> pub [Field; 4] { assert(storage_slot == 1); let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); diff --git a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr index d90955cd2be..9725c31cbe4 100644 --- a/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/escrow_contract/src/main.nr @@ -60,10 +60,19 @@ contract Escrow { assert(notes[0].is_some(), "Sender is not an owner."); let selector = compute_selector("transfer((Field),(Field),Field,Field)"); - let _callStackItem = context.call_private_function(token, selector, [this.to_field(), recipient.to_field(), amount, 0]); + let _callStackItem = context.call_private_function( + token, + selector, + [this.to_field(), recipient.to_field(), amount, 0] + ); } - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; ADDRESS_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; ADDRESS_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); assert(storage_slot == 1); diff --git a/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr index 0f42396fe77..67feeceb229 100644 --- a/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr @@ -238,7 +238,7 @@ contract InclusionProofs { nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN] - ) -> [Field; 4] { + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr index 0f79bd4383a..ea9b4569d39 100644 --- a/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr @@ -103,7 +103,12 @@ contract Lending { ) {} #[aztec(public)] - fn init(oracle: AztecAddress, loan_to_value: Field, collateral_asset: AztecAddress, stable_coin: AztecAddress) { + fn init( + oracle: AztecAddress, + loan_to_value: Field, + collateral_asset: AztecAddress, + stable_coin: AztecAddress + ) { let asset_loc = storage.assets.at(0); let asset = asset_loc.read(); @@ -111,12 +116,14 @@ contract Lending { assert(asset.last_updated_ts == 0); assert(asset.interest_accumulator == 0); - asset_loc.write(Asset { - interest_accumulator: 1000000000, - last_updated_ts: context.timestamp() as u120, - loan_to_value: loan_to_value as u120, - oracle - }); + asset_loc.write( + Asset { + interest_accumulator: 1000000000, + last_updated_ts: context.timestamp() as u120, + loan_to_value: loan_to_value as u120, + oracle + } + ); storage.collateral_asset.write(collateral_asset); storage.stable_coin.write(stable_coin); @@ -148,27 +155,40 @@ contract Lending { } #[aztec(private)] - fn deposit_private(from: AztecAddress, amount: Field, nonce: Field, secret: Field, on_behalf_of: Field, collateral_asset: AztecAddress) { + fn deposit_private( + from: AztecAddress, + amount: Field, + nonce: Field, + secret: Field, + on_behalf_of: Field, + collateral_asset: AztecAddress + ) { let on_behalf_of = compute_identifier(secret, on_behalf_of, context.msg_sender().to_field()); let _res = Token::at(collateral_asset).unshield(&mut context, from, context.this_address(), amount, nonce); // _deposit(on_behalf_of, amount, collateral_asset) let selector = compute_selector("_deposit((Field),Field,(Field))"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [on_behalf_of, amount, collateral_asset.to_field()]); + [on_behalf_of, amount, collateral_asset.to_field()] + ); } #[aztec(public)] fn deposit_public(amount: Field, nonce: Field, on_behalf_of: Field, collateral_asset: AztecAddress) { - Token::at(collateral_asset).transfer_public(context, + Token::at(collateral_asset).transfer_public( + context, context.msg_sender(), context.this_address(), amount, - nonce); + nonce + ); let selector = compute_selector("_deposit((Field),Field,(Field))"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [on_behalf_of, amount, collateral_asset.to_field()]); + [on_behalf_of, amount, collateral_asset.to_field()] + ); } #[aztec(public)] @@ -187,15 +207,21 @@ contract Lending { fn withdraw_private(secret: Field, to: AztecAddress, amount: Field) { let on_behalf_of = compute_identifier(secret, 0, context.msg_sender().to_field()); let selector = compute_selector("_withdraw((Field),(Field),Field)"); - context.call_public_function(context.this_address(), selector, [on_behalf_of, to.to_field(), amount]); + context.call_public_function( + context.this_address(), + selector, + [on_behalf_of, to.to_field(), amount] + ); } #[aztec(public)] fn withdraw_public(to: AztecAddress, amount: Field) { let selector = compute_selector("_withdraw((Field),(Field),Field)"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [context.msg_sender().to_field(), to.to_field(), amount]); + [context.msg_sender().to_field(), to.to_field(), amount] + ); } #[aztec(public)] @@ -211,11 +237,13 @@ contract Lending { // debt_covered will revert if decrease would leave insufficient collateral to cover debt. // or trying to remove more collateral than available - let debt_covered = covered_by_collateral(price, + let debt_covered = covered_by_collateral( + price, asset.loan_to_value, collateral as u120, 0, - amount as u120); + amount as u120 + ); let debt_returns = debt_updates(asset.interest_accumulator, static_debt as u120, 0, 0); assert(debt_returns.debt_value < debt_covered); @@ -231,15 +259,21 @@ contract Lending { fn borrow_private(secret: Field, to: AztecAddress, amount: Field) { let on_behalf_of = compute_identifier(secret, 0, context.msg_sender().to_field()); let selector = compute_selector("_borrow((Field),(Field),Field)"); - context.call_public_function(context.this_address(), selector, [on_behalf_of, to.to_field(), amount]); + context.call_public_function( + context.this_address(), + selector, + [on_behalf_of, to.to_field(), amount] + ); } #[aztec(public)] fn borrow_public(to: AztecAddress, amount: Field) { let selector = compute_selector("_borrow((Field),(Field),Field)"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [context.msg_sender().to_field(), to.to_field(), amount]); + [context.msg_sender().to_field(), to.to_field(), amount] + ); } #[aztec(public)] @@ -264,20 +298,33 @@ contract Lending { } #[aztec(private)] - fn repay_private(from: AztecAddress, amount: Field, nonce: Field, secret: Field, on_behalf_of: Field, stable_coin: AztecAddress) { + fn repay_private( + from: AztecAddress, + amount: Field, + nonce: Field, + secret: Field, + on_behalf_of: Field, + stable_coin: AztecAddress + ) { let on_behalf_of = compute_identifier(secret, on_behalf_of, context.msg_sender().to_field()); let _res = Token::at(stable_coin).burn(&mut context, from, amount, nonce); let selector = compute_selector("_repay((Field),Field,(Field))"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [on_behalf_of, amount, stable_coin.to_field()]); + [on_behalf_of, amount, stable_coin.to_field()] + ); } #[aztec(public)] fn repay_public(amount: Field, nonce: Field, owner: AztecAddress, stable_coin: AztecAddress) { Token::at(stable_coin).burn_public(context, context.msg_sender(), amount, nonce); let selector = compute_selector("_repay((Field),Field,(Field))"); - context.call_public_function(context.this_address(), selector, [owner.to_field(), amount, stable_coin.to_field()]); + context.call_public_function( + context.this_address(), + selector, + [owner.to_field(), amount, stable_coin.to_field()] + ); } #[aztec(public)] @@ -293,11 +340,11 @@ contract Lending { storage.static_debt.at(owner.to_field()).write(debt_returns.static_debt as Field); } - unconstrained fn get_asset(assetId: Field) -> Asset { + unconstrained fn get_asset(assetId: Field) -> pub Asset { storage.assets.at(assetId).read() } - unconstrained fn get_position(owner: AztecAddress) -> Position { + unconstrained fn get_position(owner: AztecAddress) -> pub Position { let collateral = storage.collateral.at(owner.to_field()).read(); let static_debt = storage.static_debt.at(owner.to_field()).read(); let asset = storage.assets.at(0).read(); @@ -305,12 +352,17 @@ contract Lending { Position { collateral, static_debt, debt } } - unconstrained fn get_assets() -> [AztecAddress; 2] { + unconstrained fn get_assets() -> pub [AztecAddress; 2] { [storage.collateral_asset.read(), storage.stable_coin.read()] } // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } } diff --git a/yarn-project/noir-contracts/src/contracts/pending_commitments_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/pending_commitments_contract/src/main.nr index c0780c4d4c1..7d874ade505 100644 --- a/yarn-project/noir-contracts/src/contracts/pending_commitments_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/pending_commitments_contract/src/main.nr @@ -145,39 +145,58 @@ contract PendingCommitments { get_note_zero_fn_selector: FunctionSelector ) { // nested call to create/insert note - let _callStackItem1 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem1 = context.call_private_function( + inputs.call_context.storage_contract_address, insert_fn_selector, - [amount, owner.to_field()]); + [amount, owner.to_field()] + ); // nested call to read and nullify that note - let _callStackItem2 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem2 = context.call_private_function( + inputs.call_context.storage_contract_address, get_then_nullify_fn_selector, - [amount, owner.to_field()]); + [amount, owner.to_field()] + ); // nested call to confirm that balance is zero - let _callStackItem3 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem3 = context.call_private_function( + inputs.call_context.storage_contract_address, get_note_zero_fn_selector, - [owner.to_field()]); + [owner.to_field()] + ); } // same test as above, but insert 2, get 2, nullify 2 #[aztec(private)] - fn test_insert2_then_get2_then_nullify2_all_in_nested_calls(amount: Field, owner: AztecAddress, insert_fn_selector: FunctionSelector, get_then_nullify_fn_selector: FunctionSelector) { + fn test_insert2_then_get2_then_nullify2_all_in_nested_calls( + amount: Field, + owner: AztecAddress, + insert_fn_selector: FunctionSelector, + get_then_nullify_fn_selector: FunctionSelector + ) { // args for nested calls let args = [amount, owner.to_field()]; // nested call to create/insert note - let _callStackItem1 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem1 = context.call_private_function( + inputs.call_context.storage_contract_address, insert_fn_selector, - args); - let _callStackItem2 = context.call_private_function(inputs.call_context.storage_contract_address, + args + ); + let _callStackItem2 = context.call_private_function( + inputs.call_context.storage_contract_address, insert_fn_selector, - args); + args + ); // nested call to read and nullify that note - let _callStackItem3 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem3 = context.call_private_function( + inputs.call_context.storage_contract_address, get_then_nullify_fn_selector, - args); - let _callStackItem4 = context.call_private_function(inputs.call_context.storage_contract_address, + args + ); + let _callStackItem4 = context.call_private_function( + inputs.call_context.storage_contract_address, get_then_nullify_fn_selector, - args); + args + ); // nested call to confirm that balance is zero // TODO(dbanks12): once > 4 nested calls is supported, can confirm 0 balance: //let _callStackItem5 = context.call_private_function(inputs.call_context.storage_contract_address, get_note_zero_fn_selector, [owner]); @@ -185,21 +204,32 @@ contract PendingCommitments { // same test as above, but insert 2, get 1, nullify 1 #[aztec(private)] - fn test_insert2_then_get2_then_nullify1_all_in_nested_calls(amount: Field, owner: AztecAddress, insert_fn_selector: FunctionSelector, get_then_nullify_fn_selector: FunctionSelector) { + fn test_insert2_then_get2_then_nullify1_all_in_nested_calls( + amount: Field, + owner: AztecAddress, + insert_fn_selector: FunctionSelector, + get_then_nullify_fn_selector: FunctionSelector + ) { // args for nested calls let args = [amount, owner.to_field()]; // nested call to create/insert note - let _callStackItem1 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem1 = context.call_private_function( + inputs.call_context.storage_contract_address, insert_fn_selector, - args); - let _callStackItem2 = context.call_private_function(inputs.call_context.storage_contract_address, + args + ); + let _callStackItem2 = context.call_private_function( + inputs.call_context.storage_contract_address, insert_fn_selector, - args); + args + ); // nested call to read and nullify that note - let _callStackItem3 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem3 = context.call_private_function( + inputs.call_context.storage_contract_address, get_then_nullify_fn_selector, - args); + args + ); } // insert 1 note, then get 2 notes (one pending, one persistent) and nullify both. @@ -217,20 +247,28 @@ contract PendingCommitments { let args = [amount, owner.to_field()]; // nested call to create/insert note - let _callStackItem1 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem1 = context.call_private_function( + inputs.call_context.storage_contract_address, insert_fn_selector, - args); + args + ); // nested call to read and nullify that note - let _callStackItem2 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem2 = context.call_private_function( + inputs.call_context.storage_contract_address, get_then_nullify_fn_selector, - args); - let _callStackItem3 = context.call_private_function(inputs.call_context.storage_contract_address, + args + ); + let _callStackItem3 = context.call_private_function( + inputs.call_context.storage_contract_address, get_then_nullify_fn_selector, - args); + args + ); - let _callStackItem4 = context.call_private_function(inputs.call_context.storage_contract_address, + let _callStackItem4 = context.call_private_function( + inputs.call_context.storage_contract_address, get_note_zero_fn_selector, - [owner.to_field()]); + [owner.to_field()] + ); } // Confirm cannot get/read a pending commitment in a nested call @@ -251,7 +289,12 @@ contract PendingCommitments { // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; VALUE_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/price_feed_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/price_feed_contract/src/main.nr index 3573778e708..b82c4260174 100644 --- a/yarn-project/noir-contracts/src/contracts/price_feed_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/price_feed_contract/src/main.nr @@ -48,12 +48,17 @@ contract PriceFeed { storage.assets.at(asset_id).read() } - unconstrained fn fetch_price(assetId: Field) -> Asset { + unconstrained fn fetch_price(assetId: Field) -> pub Asset { storage.assets.at(assetId).read() } // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } } diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr index 4210bf8e8ba..c6135b0345b 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr @@ -91,10 +91,12 @@ contract SchnorrAccount { } // Verify signature of the payload bytes - let verification = std::schnorr::verify_signature(public_key.x, + let verification = std::schnorr::verify_signature( + public_key.x, public_key.y, signature, - message_hash.to_be_bytes(32)); + message_hash.to_be_bytes(32) + ); assert(verification == true); // docs:end:entrypoint true @@ -108,7 +110,7 @@ contract SchnorrAccount { nonce: Field, storage_slot: Field, serialized_note: [Field; PUBLIC_KEY_NOTE_LEN] - ) -> [Field; 4] { + ) -> pub [Field; 4] { assert(storage_slot == 1); let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); diff --git a/yarn-project/noir-contracts/src/contracts/slow_tree_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/slow_tree_contract/src/main.nr index 149e53966ef..1f264a1ffa1 100644 --- a/yarn-project/noir-contracts/src/contracts/slow_tree_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/slow_tree_contract/src/main.nr @@ -88,9 +88,11 @@ contract SlowTree { let expected_root = compute_merkle_root(p.value, p.index, p.sibling_path); let selector = compute_selector("_assert_current_root(Field,Field)"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [context.msg_sender().to_field(), expected_root]); + [context.msg_sender().to_field(), expected_root] + ); p.value } @@ -123,21 +125,30 @@ contract SlowTree { let new_after_root = compute_merkle_root(p.new_value, p.index, p.after.sibling_path); let selector = compute_selector("_update(Field,Field,Field,Field,Field,Field)"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, [ - context.msg_sender().to_field(), - p.index, - p.new_value, - before_root, - after_root, - new_after_root - ]); + context.msg_sender().to_field(), + p.index, + p.new_value, + before_root, + after_root, + new_after_root + ] + ); } // docs:end:update_at_private // docs:start:_update #[aztec(public)] - internal fn _update(caller: Field, index: Field, new_value: Field, before: Field, after: Field, new_root: Field) { + internal fn _update( + caller: Field, + index: Field, + new_value: Field, + before: Field, + after: Field, + new_root: Field + ) { let current_root = storage.trees.at(caller).current_root(); let after_root = storage.trees.at(caller).read_root().after; @@ -147,15 +158,20 @@ contract SlowTree { storage.trees.at(caller).update_unsafe_at(index, new_value, new_root); } // docs:end:_update - unconstrained fn un_read_leaf_at(address: AztecAddress, key: Field) -> Leaf { + unconstrained fn un_read_leaf_at(address: AztecAddress, key: Field) -> pub Leaf { storage.trees.at(address.to_field()).read_leaf_at(key) } - unconstrained fn un_read_root(address: AztecAddress) -> Leaf { + unconstrained fn un_read_root(address: AztecAddress) -> pub Leaf { storage.trees.at(address.to_field()).read_root() } - unconstrained fn compute_note_hash_and_nullifier(_contract_address: Field, _nonce: Field, _storage_slot: Field, _serialized_note: [Field; 4]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + _contract_address: Field, + _nonce: Field, + _storage_slot: Field, + _serialized_note: [Field; 4] + ) -> pub [Field; 4] { [0x0d, 0x0e, 0x0a, 0x0d] } } diff --git a/yarn-project/noir-contracts/src/contracts/stateful_test_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/stateful_test_contract/src/main.nr index abf3e95a075..99011603a61 100644 --- a/yarn-project/noir-contracts/src/contracts/stateful_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/stateful_test_contract/src/main.nr @@ -74,14 +74,19 @@ contract StatefulTest { increment(recipient_notes, amount, recipient); } - unconstrained fn summed_values(owner: AztecAddress) -> Field { + unconstrained fn summed_values(owner: AztecAddress) -> pub Field { let owner_balance = storage.notes.at(owner.to_field()); // Return the sum of all notes in the set. balance_utils::get_balance(owner_balance) } - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; VALUE_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) diff --git a/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr index d5fefddd004..0a06d12d95a 100644 --- a/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/test_contract/src/main.nr @@ -162,7 +162,13 @@ contract Test { } #[aztec(public)] - fn consume_mint_public_message(to: AztecAddress, amount: Field, canceller: EthAddress, msg_key: Field, secret: Field) { + fn consume_mint_public_message( + to: AztecAddress, + amount: Field, + canceller: EthAddress, + msg_key: Field, + secret: Field + ) { let content_hash = get_mint_public_content_hash(to, amount, canceller); // Consume message and emit nullifier context.consume_l1_to_l2_message(msg_key, content_hash, secret); @@ -187,13 +193,13 @@ contract Test { storage.example_constant.initialize(&mut note, Option::none(), false); } - unconstrained fn get_constant() -> Field { + unconstrained fn get_constant() -> pub Field { let constant = storage.example_constant.view_note(); constant.value } // Purely exists for testing - unconstrained fn get_random(kindaSeed: Field) -> Field { + unconstrained fn get_random(kindaSeed: Field) -> pub Field { kindaSeed * rand() } @@ -225,7 +231,12 @@ contract Test { // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; FIELD_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; FIELD_NOTE_LEN] + ) -> pub [Field; 4] { assert(storage_slot == 1); let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); diff --git a/yarn-project/noir-contracts/src/contracts/token_blacklist_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/token_blacklist_contract/src/main.nr index cdfafc51418..b830b5ed75b 100644 --- a/yarn-project/noir-contracts/src/contracts/token_blacklist_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/token_blacklist_contract/src/main.nr @@ -109,11 +109,13 @@ contract TokenBlacklist { fn constructor(admin: AztecAddress, slow_updates_contract: AztecAddress) { let mut slow_note = FieldNote::new(slow_updates_contract.to_field()); storage.slow_update.initialize(&mut slow_note, Option::none(), false); - // docs:end:constructor + // docs:end:constructor let selector = compute_selector("_initialize((Field),(Field))"); - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), selector, - [admin.to_field(), slow_updates_contract.to_field()]); + [admin.to_field(), slow_updates_contract.to_field()] + ); // We cannot do the following atm // let roles = UserFlags{is_admin: true, is_minter: false, is_blacklisted: false}.get_value() as Field; // SlowMap::at(slow_updates_contract).update_at_private(&mut context, admin.to_field(), roles); @@ -129,9 +131,11 @@ contract TokenBlacklist { let slow = SlowMap::at(AztecAddress::from_field(storage.slow_update.get_note().value)); slow.update_at_private(&mut context, user.to_field(), roles); // docs:end:get_and_update_private - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), compute_selector("_init_slow_tree((Field))"), - [context.msg_sender().to_field()]); + [context.msg_sender().to_field()] + ); } #[aztec(public)] @@ -150,7 +154,6 @@ contract TokenBlacklist { // docs:start:slowmap_initialize SlowMap::at(slow_updates_contract).initialize(context); // docs:end:slowmap_initialize - } #[aztec(private)] @@ -171,7 +174,7 @@ contract TokenBlacklist { // docs:end:get_public // docs:start:read_at_pub let to_roles = UserFlags::new(slow.read_at_pub(context, to.to_field()) as u120); - // docs:end:read_at_pub + // docs:end:read_at_pub assert(!to_roles.is_blacklisted, "Blacklisted: Recipient"); let caller_roles = UserFlags::new(slow.read_at_pub(context, context.msg_sender().to_field()) as u120); @@ -314,7 +317,7 @@ contract TokenBlacklist { assert(!from_roles.is_blacklisted, "Blacklisted: Sender"); let to_roles = UserFlags::new(slow.read_at(&mut context, to.to_field()) as u120); assert(!to_roles.is_blacklisted, "Blacklisted: Recipient"); - // docs:end:transfer_private + // docs:end:transfer_private if (!from.eq(context.msg_sender())) { assert_current_call_valid_authwit(&mut context, from); @@ -343,7 +346,6 @@ contract TokenBlacklist { let selector = compute_selector("_reduce_total_supply(Field)"); context.call_public_function(context.this_address(), selector, [amount]); - } /// Internal /// @@ -363,15 +365,15 @@ contract TokenBlacklist { /// Unconstrained /// - unconstrained fn total_supply() -> u120 { + unconstrained fn total_supply() -> pub u120 { storage.total_supply.read().value } - unconstrained fn balance_of_private(owner: AztecAddress) -> u120 { + unconstrained fn balance_of_private(owner: AztecAddress) -> pub u120 { storage.balances.at(owner).balance_of().value } - unconstrained fn balance_of_public(owner: AztecAddress) -> u120 { + unconstrained fn balance_of_public(owner: AztecAddress) -> pub u120 { storage.public_balances.at(owner.to_field()).read().value } @@ -381,7 +383,12 @@ contract TokenBlacklist { // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, preimage: [Field; TOKEN_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + preimage: [Field; TOKEN_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); if (storage_slot == 5) { diff --git a/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr index 78a15f3918a..f6b13fb5f02 100644 --- a/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/token_bridge_contract/src/main.nr @@ -95,18 +95,18 @@ contract TokenBridge { secret_for_L1_to_L2_message_consumption: Field // secret used to consume the L1 to L2 message ) { // Consume L1 to L2 message and emit nullifier - let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, - amount, - canceller); + let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount, canceller); context.consume_l1_to_l2_message(msg_key, content_hash, secret_for_L1_to_L2_message_consumption); // Mint tokens on L2 // `mint_private` on token is public. So we call an internal public function // which then calls the public method on the token contract. // Since the secret_hash is passed, no secret is leaked. - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), compute_selector("_call_mint_on_token(Field,Field)"), - [amount, secret_hash_for_redeeming_minted_notes]); + [amount, secret_hash_for_redeeming_minted_notes] + ); } // docs:end:claim_private @@ -127,9 +127,11 @@ contract TokenBridge { // docs:start:call_assert_token_is_same // Assert that user provided token address is same as seen in storage. - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), compute_selector("_assert_token_is_same((Field))"), - [token.to_field()]); + [token.to_field()] + ); // docs:end:call_assert_token_is_same // Burn tokens @@ -146,7 +148,7 @@ contract TokenBridge { // /// Unconstrained /// - unconstrained fn token() -> AztecAddress { + unconstrained fn token() -> pub AztecAddress { storage.token.read() } @@ -174,7 +176,12 @@ contract TokenBridge { // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented // docs:start:compute_note_hash_and_nullifier_placeholder - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } // docs:end:compute_note_hash_and_nullifier_placeholder diff --git a/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr index 80d8ff96505..f8cbaa2c87e 100644 --- a/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr @@ -339,31 +339,31 @@ contract Token { /// Unconstrained /// // docs:start:admin - unconstrained fn admin() -> Field { + unconstrained fn admin() -> pub Field { storage.admin.read().to_field() } // docs:end:admin // docs:start:is_minter - unconstrained fn is_minter(minter: AztecAddress) -> bool { + unconstrained fn is_minter(minter: AztecAddress) -> pub bool { storage.minters.at(minter.to_field()).read() } // docs:end:is_minter // docs:start:total_supply - unconstrained fn total_supply() -> u120 { + unconstrained fn total_supply() -> pub u120 { storage.total_supply.read().value } // docs:end:total_supply // docs:start:balance_of_private - unconstrained fn balance_of_private(owner: AztecAddress) -> u120 { + unconstrained fn balance_of_private(owner: AztecAddress) -> pub u120 { storage.balances.at(owner).balance_of().value } // docs:end:balance_of_private // docs:start:balance_of_public - unconstrained fn balance_of_public(owner: AztecAddress) -> u120 { + unconstrained fn balance_of_public(owner: AztecAddress) -> pub u120 { storage.public_balances.at(owner.to_field()).read().value } // docs:end:balance_of_public @@ -375,7 +375,12 @@ contract Token { // Computes note hash and nullifier. // Note 1: Needs to be defined by every contract producing logs. // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; TOKEN_NOTE_LEN]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; TOKEN_NOTE_LEN] + ) -> pub [Field; 4] { let _address = AztecAddress::from_field(contract_address); // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/3669 let note_header = NoteHeader::new(_address, nonce, storage_slot); if (storage_slot == 5) { diff --git a/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr index a40e4f12194..680ff7fd85a 100644 --- a/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr @@ -83,26 +83,35 @@ contract Uniswap { let input_asset = TokenBridge::at(input_asset_bridge).token(context); // Transfer funds to this contract - Token::at(input_asset).transfer_public(context, + Token::at(input_asset).transfer_public( + context, sender, context.this_address(), input_amount, - nonce_for_transfer_approval); + nonce_for_transfer_approval + ); // Approve bridge to burn this contract's funds and exit to L1 Uniswap Portal - let _void = context.call_public_function(context.this_address(), + let _void = context.call_public_function( + context.this_address(), compute_selector("_approve_bridge_and_exit_input_asset_to_L1((Field),(Field),Field)"), - [input_asset.to_field(), input_asset_bridge.to_field(), input_amount]); + [input_asset.to_field(), input_asset_bridge.to_field(), input_amount] + ); // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. let input_asset_bridge_portal_address = get_portal_address(input_asset_bridge); let output_asset_bridge_portal_address = get_portal_address(output_asset_bridge); // ensure portal exists - else funds might be lost - assert(!input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0"); - assert(!output_asset_bridge_portal_address.is_zero(), "L1 portal address of output_asset's bridge is 0"); + assert( + !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0" + ); + assert( + !output_asset_bridge_portal_address.is_zero(), "L1 portal address of output_asset's bridge is 0" + ); - let content_hash = compute_swap_public_content_hash(input_asset_bridge_portal_address, + let content_hash = compute_swap_public_content_hash( + input_asset_bridge_portal_address, input_amount, uniswap_fee_tier, output_asset_bridge_portal_address, @@ -111,7 +120,8 @@ contract Uniswap { secret_hash_for_L1_to_l2_message, deadline_for_L1_to_l2_message, canceller_for_L1_to_L2_message, - caller_on_L1); + caller_on_L1 + ); context.message_portal(content_hash); } // docs:end:swap_public @@ -137,31 +147,42 @@ contract Uniswap { ) { // Assert that user provided token address is same as expected by token bridge. // we can't directly use `input_asset_bridge.token` because that is a public method and public can't return data to private - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), compute_selector("_assert_token_is_same((Field),(Field))"), - [input_asset.to_field(), input_asset_bridge.to_field()]); + [input_asset.to_field(), input_asset_bridge.to_field()] + ); // Transfer funds to this contract - Token::at(input_asset).unshield(&mut context, + Token::at(input_asset).unshield( + &mut context, context.msg_sender(), context.this_address(), input_amount, - nonce_for_unshield_approval); + nonce_for_unshield_approval + ); // Approve bridge to burn this contract's funds and exit to L1 Uniswap Portal - context.call_public_function(context.this_address(), + context.call_public_function( + context.this_address(), compute_selector("_approve_bridge_and_exit_input_asset_to_L1((Field),(Field),Field)"), - [input_asset.to_field(), input_asset_bridge.to_field(), input_amount]); + [input_asset.to_field(), input_asset_bridge.to_field(), input_amount] + ); // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. let input_asset_bridge_portal_address = get_portal_address(input_asset_bridge); let output_asset_bridge_portal_address = get_portal_address(output_asset_bridge); // ensure portal exists - else funds might be lost - assert(!input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0"); - assert(!output_asset_bridge_portal_address.is_zero(), "L1 portal address of output_asset's bridge is 0"); + assert( + !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0" + ); + assert( + !output_asset_bridge_portal_address.is_zero(), "L1 portal address of output_asset's bridge is 0" + ); - let content_hash = compute_swap_private_content_hash(input_asset_bridge_portal_address, + let content_hash = compute_swap_private_content_hash( + input_asset_bridge_portal_address, input_amount, uniswap_fee_tier, output_asset_bridge_portal_address, @@ -170,7 +191,8 @@ contract Uniswap { secret_hash_for_L1_to_l2_message, deadline_for_L1_to_l2_message, canceller_for_L1_to_L2_message, - caller_on_L1); + caller_on_L1 + ); context.message_portal(content_hash); } // docs:end:swap_private @@ -197,40 +219,51 @@ contract Uniswap { // approve bridge to burn this contract's funds (required when exiting on L1, as it burns funds on L2): let nonce_for_burn_approval = storage.nonce_for_burn_approval.read(); let selector = compute_selector("burn_public((Field),Field,Field)"); - let message_hash = compute_authwit_message_hash(token_bridge, + let message_hash = compute_authwit_message_hash( + token_bridge, token, selector, - [context.this_address().to_field(), amount, nonce_for_burn_approval]); + [context.this_address().to_field(), amount, nonce_for_burn_approval] + ); storage.approved_action.at(message_hash).write(true); // increment nonce_for_burn_approval so it won't be used again storage.nonce_for_burn_approval.write(nonce_for_burn_approval + 1); // Exit to L1 Uniswap Portal ! - TokenBridge::at(token_bridge).exit_to_l1_public(context, + TokenBridge::at(token_bridge).exit_to_l1_public( + context, context.this_portal_address(), amount, context.this_portal_address(), - nonce_for_burn_approval); + nonce_for_burn_approval + ); } // docs:end:authwit_uniswap_set // docs:start:assert_token_is_same #[aztec(public)] internal fn _assert_token_is_same(token: AztecAddress, token_bridge: AztecAddress) { - assert(token.eq(TokenBridge::at(token_bridge).token(context)), "input_asset address is not the same as seen in the bridge contract"); + assert( + token.eq(TokenBridge::at(token_bridge).token(context)), "input_asset address is not the same as seen in the bridge contract" + ); } // docs:end:assert_token_is_same // /// Unconstrained /// // this method exists solely for e2e tests to test that nonce gets incremented each time. - unconstrained fn nonce_for_burn_approval() -> Field { + unconstrained fn nonce_for_burn_approval() -> pub Field { storage.nonce_for_burn_approval.read() } // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; 0]) -> [Field; 4] { + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + serialized_note: [Field; 0] + ) -> pub [Field; 4] { [0, 0, 0, 0] } } diff --git a/yarn-project/noir-protocol-circuits/package.json b/yarn-project/noir-protocol-circuits/package.json index 26096a5ecaa..292e2c73986 100644 --- a/yarn-project/noir-protocol-circuits/package.json +++ b/yarn-project/noir-protocol-circuits/package.json @@ -13,7 +13,7 @@ "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", "noir:build": "cd src && ../../../noir/target/release/nargo compile --silence-warnings && rm -rf ./target/debug_*", - "noir:types": "yarn ts-node --esm src/scripts/generate_ts_from_abi.ts && yarn formatting:fix", + "noir:types": "node --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && yarn formatting:fix", "noir:test": "cd src && ../../../noir/target/release/nargo test", "test": "yarn test:js && yarn noir:test", "test:js": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" diff --git a/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts b/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts index 2eb6fcf4cc4..bce893dba8b 100644 --- a/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts +++ b/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts @@ -167,8 +167,8 @@ function generateTsInterface(abiObj: NoirFunctionAbi): string { // Generating Return type, if it exists // if (abiObj.return_type != null) { - result += generateStructInterfaces(abiObj.return_type, outputStructs); - result += `export type ReturnType = ${abiTypeToTs(abiObj.return_type)};\n`; + result += generateStructInterfaces(abiObj.return_type.abi_type, outputStructs); + result += `export type ReturnType = ${abiTypeToTs(abiObj.return_type.abi_type)};\n`; } // Generating Input type diff --git a/yarn-project/package.json b/yarn-project/package.json index c7000b40943..acf4b1627f7 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -67,7 +67,6 @@ "@noir-lang/types": "portal:../noir/packages/types", "@noir-lang/noirc_abi": "portal:../noir/packages/noirc_abi", "@noir-lang/noir_wasm": "portal:../noir/packages/noir_wasm", - "@noir-lang/source-resolver": "portal:../noir/compiler/source-resolver", "@noir-lang/noir_js": "portal:../noir/packages/noir_js" } } diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 96be5e824c3..afc929f6ed8 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -59,10 +59,6 @@ COPY --from=noir /usr/src/noir/target/release/nargo /usr/src/noir/target/release # Copy in noir packages COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages -# TODO: FIX: For some reason the source-resolver package needs to be in compiler dir or we get errors like: -# Error: ENOENT: no such file or directory, open '/aztec/lib.nr' -RUN mkdir /usr/src/noir/compiler && mv /usr/src/noir/packages/source-resolver /usr/src/noir/compiler - # We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they # walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution # correctly for portalled packages, is to use --preserve-symlinks when running node. diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 154e5880dda..c982fd40934 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -551,7 +551,6 @@ __metadata: "@jest/globals": ^29.5.0 "@ltd/j-toml": ^1.38.0 "@noir-lang/noir_wasm": "portal:../../noir/packages/noir_wasm" - "@noir-lang/source-resolver": "portal:../../noir/packages/source-resolver" "@types/fs-extra": ^11.0.1 "@types/jest": ^29.5.0 "@types/lodash.camelcase": ^4.3.7 @@ -2751,7 +2750,7 @@ __metadata: resolution: "@noir-lang/backend_barretenberg@portal:../noir/packages/backend_barretenberg::locator=%40aztec%2Faztec3-packages%40workspace%3A." dependencies: "@aztec/bb.js": 0.16.0 - "@noir-lang/types": 0.19.4 + "@noir-lang/types": 0.22.0 fflate: ^0.8.0 languageName: node linkType: soft @@ -2760,17 +2759,15 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/noir_js@portal:../noir/packages/noir_js::locator=%40aztec%2Faztec3-packages%40workspace%3A." dependencies: - "@noir-lang/acvm_js": 0.35.0 - "@noir-lang/noirc_abi": 0.19.4 - "@noir-lang/types": 0.19.4 + "@noir-lang/acvm_js": 0.38.0 + "@noir-lang/noirc_abi": 0.22.0 + "@noir-lang/types": 0.22.0 languageName: node linkType: soft "@noir-lang/noir_wasm@portal:../noir/packages/noir_wasm::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@noir-lang/noir_wasm@portal:../noir/packages/noir_wasm::locator=%40aztec%2Faztec3-packages%40workspace%3A." - peerDependencies: - "@noir-lang/source-resolver": 0.19.4 languageName: node linkType: soft @@ -2780,17 +2777,11 @@ __metadata: languageName: node linkType: soft -"@noir-lang/source-resolver@portal:../noir/compiler/source-resolver::locator=%40aztec%2Faztec3-packages%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@noir-lang/source-resolver@portal:../noir/compiler/source-resolver::locator=%40aztec%2Faztec3-packages%40workspace%3A." - languageName: node - linkType: soft - "@noir-lang/types@portal:../noir/packages/types::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@noir-lang/types@portal:../noir/packages/types::locator=%40aztec%2Faztec3-packages%40workspace%3A." dependencies: - "@noir-lang/noirc_abi": 0.19.4 + "@noir-lang/noirc_abi": 0.22.0 languageName: node linkType: soft