Skip to content

Commit

Permalink
chore: add solidity verifier workflow (#2749)
Browse files Browse the repository at this point in the history
Co-authored-by: Tom French <tom@tomfren.ch>
Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 26, 2023
1 parent 75e8581 commit 85965c3
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 21 deletions.
212 changes: 200 additions & 12 deletions .github/workflows/test-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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&parallel-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&parallel-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
Expand Down
3 changes: 2 additions & 1 deletion compiler/integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -36,13 +38,20 @@ async function getFile(url: URL): Promise<string> {
}

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,
},
];

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 85965c3

Please sign in to comment.