diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index dfbbf2f14ac..09e54b288dc 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -7,14 +7,50 @@ on: - ./compiler/integration-tests/** schedule: - cron: "0 2 * * *" # Run nightly at 2 AM UTC + jobs: - wasm-packages-build-test: + build-nargo: + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64-unknown-linux-gnu] + + steps: + - name: Checkout Noir repo + uses: actions/checkout@v4 + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.66.0 + + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + cache-on-failure: true + save-if: ${{ github.event_name != 'merge_group' }} + + - name: Build Nargo + run: cargo build --package nargo_cli --release + + - name: Package artifacts + run: | + mkdir dist + cp ./target/release/nargo ./dist/nargo + 7z a -ttar -so -an ./dist/* | 7z a -si ./nargo-x86_64-unknown-linux-gnu.tar.gz + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: nargo + path: ./dist/* + retention-days: 3 + + build-wasm: runs-on: ubuntu-latest env: CACHED_PATH: /tmp/nix-cache steps: - - name: Checkout noir sources + - name: Checkout sources uses: actions/checkout@v4 - name: Setup Nix @@ -28,38 +64,190 @@ jobs: name: barretenberg authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - - name: Build noir_wasm package + - name: Build wasm package run: | nix build -L .#noir_wasm - echo "UPLOAD_PATH=$(readlink -f ./result/noir_wasm)" >> $GITHUB_ENV - cp -r ./result/noir_wasm/nodejs ./compiler/wasm - cp -r ./result/noir_wasm/web ./compiler/wasm - - name: Upload `noir_wasm` artifact + - name: Export cache from nix store + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} + run: | + nix copy --to "file://${{ env.CACHED_PATH }}?compression=zstd¶llel-compression=true" .#noir-wasm-cargo-artifacts + + - uses: actions/cache/save@v3 + # Don't create cache entries for the merge queue. + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} + with: + path: ${{ env.CACHED_PATH }} + key: ${{ steps.cache.outputs.cache-primary-key }} + + - name: Dereference symlink + run: echo "UPLOAD_PATH=$(readlink -f ./result/noir_wasm)" >> $GITHUB_ENV + + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: noir_wasm path: ${{ env.UPLOAD_PATH }} retention-days: 3 - - name: Build noirc_abi_wasm package + build-noirc: + runs-on: ubuntu-latest + env: + CACHED_PATH: /tmp/nix-cache + + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Setup Nix + uses: cachix/install-nix-action@v22 + with: + nix_path: nixpkgs=channel:nixos-23.05 + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: cachix/cachix-action@v12 + with: + name: barretenberg + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Restore nix store cache + uses: actions/cache/restore@v3 + id: cache + with: + path: ${{ env.CACHED_PATH }} + key: ${{ runner.os }}-flake-abi-wasm-${{ hashFiles('*.lock') }} + + # Based on https://github.com/marigold-dev/deku/blob/b5016f0cf4bf6ac48db9111b70dd7fb49b969dfd/.github/workflows/build.yml#L26 + - name: Copy cache into nix store + if: steps.cache.outputs.cache-hit == 'true' + # We don't check the signature because we're the one that created the cache + run: | + for narinfo in ${{ env.CACHED_PATH }}/*.narinfo; do + path=$(head -n 1 "$narinfo" | awk '{print $2}') + nix copy --no-check-sigs --from "file://${{ env.CACHED_PATH }}" "$path" + done + + - name: Build noirc_abi_wasm run: | nix build -L .#noirc_abi_wasm - echo "UPLOAD_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV cp -r ./result/noirc_abi_wasm/nodejs ./tooling/noirc_abi_wasm cp -r ./result/noirc_abi_wasm/web ./tooling/noirc_abi_wasm - - name: Upload `noirc_abi_wasm` artifact + - name: Export cache from nix store + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} + run: | + nix copy --to "file://${{ env.CACHED_PATH }}?compression=zstd¶llel-compression=true" .#noirc-abi-wasm-cargo-artifacts + + - uses: actions/cache/save@v3 + # Don't create cache entries for the merge queue. + if: ${{ steps.cache.outputs.cache-hit != 'true' && github.event_name != 'merge_group' }} + with: + path: ${{ env.CACHED_PATH }} + key: ${{ steps.cache.outputs.cache-primary-key }} + + - name: Dereference symlink + run: echo "UPLOAD_PATH=$(readlink -f ./result/noirc_abi_wasm)" >> $GITHUB_ENV + + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: noirc_abi_wasm path: ${{ env.UPLOAD_PATH }} - retention-days: 3 + retention-days: 10 + + test-solidity-verifier: + runs-on: ubuntu-latest + needs: [build-wasm, build-nargo, build-noirc] + env: + CACHED_PATH: /tmp/nix-cache + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download nargo binary + uses: actions/download-artifact@v3 + with: + name: nargo + path: ./nargo + + - name: Download wasm package artifact + uses: actions/download-artifact@v3 + with: + name: noir_wasm + path: ./compiler/wasm + + - name: Download noirc package artifact + uses: actions/download-artifact@v3 + with: + name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm + + - name: Set nargo on PATH + run: | + nargo_binary="${{ github.workspace }}/nargo/nargo" + chmod +x $nargo_binary + echo "$(dirname $nargo_binary)" >> $GITHUB_PATH + export PATH="$PATH:$(dirname $nargo_binary)" + nargo -V - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Install jq + run: sudo apt-get install jq + + - name: Install wasm-bindgen-cli + uses: taiki-e/install-action@v2 + with: + tool: wasm-bindgen-cli@0.2.86 + + - name: Install toml2json + uses: taiki-e/install-action@v2 + with: + tool: toml2json@1.3.1 + + - name: Install wasm-opt + run: | + npm i wasm-opt -g + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Anvil + run: | + anvil > /dev/null 2>&1 & + sleep 10 + + - name: Create new Foundry project + run: forge init --no-git --no-commit --force foundry-project + + - name: Run codegen-verifier for 1_mul + working-directory: tooling/nargo_cli/tests/execution_success/1_mul + run: nargo codegen-verifier + + - name: Run codegen-verifier for main + working-directory: compiler/integration-tests/test/circuits/main + run: nargo codegen-verifier + + - name: Copy compiled contracts + run: | + cp tooling/nargo_cli/tests/execution_success/1_mul/contract/1_mul/plonk_vk.sol foundry-project/src/1_mul.sol + cp compiler/integration-tests/test/circuits/main/contract/main/plonk_vk.sol foundry-project/src/main.sol + + - name: Forge build + working-directory: foundry-project + run: forge build + + - name: Forge deploy + working-directory: foundry-project + run: | + forge create --rpc-url http://127.0.0.1:8545 --mnemonic "test test test test test test test test test test test junk" src/1_mul.sol:UltraVerifier --json > mul_output.json + forge create --rpc-url http://127.0.0.1:8545 --mnemonic "test test test test test test test test test test test junk" src/main.sol:UltraVerifier --json > main_output.json + + - name: Setup `integration-tests` run: | yarn workspace @noir-lang/source-resolver build diff --git a/compiler/integration-tests/package.json b/compiler/integration-tests/package.json index ca5f842f5af..576cf8c5299 100644 --- a/compiler/integration-tests/package.json +++ b/compiler/integration-tests/package.json @@ -12,13 +12,14 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.7.2", + "@aztec/bb.js": "^0.7.2", "@noir-lang/noir_js": "workspace:*", "@noir-lang/noir_wasm": "workspace:*", "@noir-lang/source-resolver": "workspace:*", "@web/dev-server-esbuild": "^0.3.6", "@web/test-runner": "^0.15.3", "@web/test-runner-webdriver": "^0.7.0", + "ethers": "^6.7.1", "fflate": "^0.8.0", "smol-toml": "^1.1.2", "tslog": "^4.9.2" diff --git a/compiler/integration-tests/test/integration/browser/compile_prove_verify.test.ts b/compiler/integration-tests/test/integration/browser/compile_prove_verify.test.ts index 59ea7c45b21..ea9f4db73a9 100644 --- a/compiler/integration-tests/test/integration/browser/compile_prove_verify.test.ts +++ b/compiler/integration-tests/test/integration/browser/compile_prove_verify.test.ts @@ -6,14 +6,16 @@ import newCompiler, { compile, init_log_level as compilerLogLevel, } from "@noir-lang/noir_wasm"; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -//@ts-ignore -import { Barretenberg, RawBuffer, Crs } from "@aztec/bb.js"; import { acvm, abi } from "@noir-lang/noir_js"; +import { Barretenberg, RawBuffer, Crs } from "@aztec/bb.js"; import { decompressSync as gunzip } from "fflate"; - +import { ethers } from "ethers"; import * as TOML from "smol-toml"; +const mnemonic = "test test test test test test test test test test test junk"; +const provider = new ethers.JsonRpcProvider("http://localhost:8545"); +const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic); +const wallet = walletMnemonic.connect(provider); const logger = new Logger({ name: "test", minLevel: TEST_LOG_LEVEL }); const { default: initACVM, executeCircuit, compressWitness } = acvm; @@ -36,13 +38,20 @@ async function getFile(url: URL): Promise { } const CIRCUIT_SIZE = 2 ** 19; +const FIELD_ELEMENT_BYTES = 32; const test_cases = [ { case: "tooling/nargo_cli/tests/execution_success/1_mul", + compiled: "foundry-project/out/1_mul.sol/UltraVerifier.json", + deployInformation: "foundry-project/mul_output.json", + numPublicInputs: 0, }, { - case: "tooling/nargo_cli/tests/execution_success/double_verify_proof", + case: "compiler/integration-tests/test/circuits/main", + compiled: "foundry-project/out/main.sol/UltraVerifier.json", + deployInformation: "foundry-project/main_output.json", + numPublicInputs: 1, }, ]; @@ -71,9 +80,24 @@ test_cases.forEach((testInfo) => { `${base_relative_path}/${test_case}/Prover.toml`, import.meta.url, ); + const compiled_contract_url = new URL( + `${base_relative_path}/${testInfo.compiled}`, + import.meta.url, + ); + const deploy_information_url = new URL( + `${base_relative_path}/${testInfo.deployInformation}`, + import.meta.url, + ); const noir_source = await getFile(noir_source_url); const prover_toml = await getFile(prover_toml_url); + const compiled_contract = await getFile(compiled_contract_url); + const deploy_information = await getFile(deploy_information_url); + + const { abi } = JSON.parse(compiled_contract); + const { deployedTo } = JSON.parse(deploy_information); + + const contract = new ethers.Contract(deployedTo, abi, wallet); expect(noir_source).to.be.a.string; @@ -130,7 +154,7 @@ test_cases.forEach((testInfo) => { const acirUint8Array = gunzip(compressedByteCode); const witnessUint8Array = gunzip(compressedWitness); - const isRecursive = true; + const isRecursive = false; const api = await Barretenberg.new(numberOfThreads); await api.commonInitSlabAllocator(CIRCUIT_SIZE); @@ -159,7 +183,31 @@ test_cases.forEach((testInfo) => { isRecursive, ); - expect(verified).to.be.true; + expect(verified, "Proof fails verification in JS").to.be.true; + + try { + let result; + if (testInfo.numPublicInputs === 0) { + result = await contract.verify(proof, []); + } else { + const publicInputs = Array.from( + { length: testInfo.numPublicInputs }, + (_, i) => { + const offset = i * FIELD_ELEMENT_BYTES; + return proof.slice(offset, offset + FIELD_ELEMENT_BYTES); + }, + ); + const slicedProof = proof.slice( + testInfo.numPublicInputs * FIELD_ELEMENT_BYTES, + ); + result = await contract.verify(slicedProof, publicInputs); + } + + expect(result).to.be.true; + } catch (error) { + console.error("Error while submitting the proof:", error); + throw error; + } } catch (e) { expect(e, "Proving and Verifying").to.not.be.an("error"); throw e; diff --git a/yarn.lock b/yarn.lock index b91264ec860..9a271d83859 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,6 +22,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:1.9.2": + version: 1.9.2 + resolution: "@adraffy/ens-normalize@npm:1.9.2" + checksum: a9fdeb9e080774c19e4b7f9f60aa5b37cf23fe0e8fe80284bf8221f7396e9f78642bfd39a09a94a4dc3fb8e70f2ac81545204bdcaf222d93f4c4c2ae1f0dca0b + languageName: node + linkType: hard + "@aztec/bb.js@npm:0.7.2": version: 0.7.2 resolution: "@aztec/bb.js@npm:0.7.2" @@ -36,6 +43,20 @@ __metadata: languageName: node linkType: hard +"@aztec/bb.js@npm:^0.7.2": + version: 0.7.10 + resolution: "@aztec/bb.js@npm:0.7.10" + dependencies: + comlink: ^4.4.1 + commander: ^10.0.1 + debug: ^4.3.4 + tslib: ^2.4.0 + bin: + bb.js: dest/node/main.js + checksum: 0410278e6ec2a6ecdcbaa58633b181ec1d91e1c267c76e7e587fb69c8f2fd394e79f65bd96cfcdb2a2b20fe5abeb86ababd45bd6364ba07555fc0643bf0e4307 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.21.4": version: 7.22.13 resolution: "@babel/code-frame@npm:7.22.13" @@ -358,6 +379,20 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.1.2": + version: 1.1.2 + resolution: "@noble/hashes@npm:1.1.2" + checksum: 3c2a8cb7c2e053811032f242155d870c5eb98844d924d69702244d48804cb03b42d4a666c49c2b71164420d8229cb9a6f242b972d50d5bb2f1d673b98b041de2 + languageName: node + linkType: hard + +"@noble/secp256k1@npm:1.7.1": + version: 1.7.1 + resolution: "@noble/secp256k1@npm:1.7.1" + checksum: d2301f1f7690368d8409a3152450458f27e54df47e3f917292de3de82c298770890c2de7c967d237eff9c95b70af485389a9695f73eb05a43e2bd562d18b18cb + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -922,6 +957,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:18.15.13": + version: 18.15.13 + resolution: "@types/node@npm:18.15.13" + checksum: 79cc5a2b5f98e8973061a4260a781425efd39161a0e117a69cd089603964816c1a14025e1387b4590c8e82d05133b7b4154fa53a7dffb3877890a66145e76515 + languageName: node + linkType: hard + "@types/node@npm:^18.7.20": version: 18.17.18 resolution: "@types/node@npm:18.17.18" @@ -1606,6 +1648,13 @@ __metadata: languageName: node linkType: hard +"aes-js@npm:4.0.0-beta.5": + version: 4.0.0-beta.5 + resolution: "aes-js@npm:4.0.0-beta.5" + checksum: cc2ea969d77df939c32057f7e361b6530aa6cb93cb10617a17a45cd164e6d761002f031ff6330af3e67e58b1f0a3a8fd0b63a720afd591a653b02f649470e15b + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -3457,6 +3506,21 @@ __metadata: languageName: node linkType: hard +"ethers@npm:^6.7.1": + version: 6.7.1 + resolution: "ethers@npm:6.7.1" + dependencies: + "@adraffy/ens-normalize": 1.9.2 + "@noble/hashes": 1.1.2 + "@noble/secp256k1": 1.7.1 + "@types/node": 18.15.13 + aes-js: 4.0.0-beta.5 + tslib: 2.4.0 + ws: 8.5.0 + checksum: 07833692e3f53b18e28c4cba9f53f3d5ebff8360de02ad57b2584c00c52b88f5b790373f9b9f6b4f6b52ffa2074530a6101192b30c3260f7cdeff929d34bb88b + languageName: node + linkType: hard + "event-stream@npm:=3.3.4": version: 3.3.4 resolution: "event-stream@npm:3.3.4" @@ -4445,13 +4509,14 @@ __metadata: version: 0.0.0-use.local resolution: "integration-tests@workspace:compiler/integration-tests" dependencies: - "@aztec/bb.js": 0.7.2 + "@aztec/bb.js": ^0.7.2 "@noir-lang/noir_js": "workspace:*" "@noir-lang/noir_wasm": "workspace:*" "@noir-lang/source-resolver": "workspace:*" "@web/dev-server-esbuild": ^0.3.6 "@web/test-runner": ^0.15.3 "@web/test-runner-webdriver": ^0.7.0 + ethers: ^6.7.1 fflate: ^0.8.0 smol-toml: ^1.1.2 tslog: ^4.9.2 @@ -7346,6 +7411,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.4.0": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 + languageName: node + linkType: hard + "tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -7894,6 +7966,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.5.0": + version: 8.5.0 + resolution: "ws@npm:8.5.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 76f2f90e40344bf18fd544194e7067812fb1372b2a37865678d8f12afe4b478ff2ebc0c7c0aff82cd5e6b66fc43d889eec0f1865c2365d8f7a66d92da7744a77 + languageName: node + linkType: hard + "ws@npm:^7.4.2": version: 7.5.9 resolution: "ws@npm:7.5.9"