diff --git a/.github/workflows/with_foundry.yaml b/.github/workflows/with_foundry.yaml index 4a0cb23c..cc36f924 100644 --- a/.github/workflows/with_foundry.yaml +++ b/.github/workflows/with_foundry.yaml @@ -31,14 +31,27 @@ jobs: - name: Set up foundry uses: ./.github/actions/setup-foundry + - name: Install bb + run: | + curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/master/barretenberg/cpp/installation/install | bash + echo "PATH=$PATH:/home/runner/.bb" >> $GITHUB_ENV + shell: bash + + - name: Use bbup + run: | + bbup -v 0.41.0 + bb --version # or any other bbup command you want to run + shell: bash + - name: Generate verifier contract run: | - nargo codegen-verifier + nargo compile && bb write_vk -b ./target/with_foundry.json && bb contract working-directory: with-foundry/circuits - name: Generate proof run: | - nargo prove + nargo execute witness + bb prove -b ./target/with_foundry.json -w ./target/witness.gz -o ./target/with_foundry.proof working-directory: with-foundry/circuits - name: Test with Foundry diff --git a/.github/workflows/with_foundry_nightly.yaml b/.github/workflows/with_foundry_nightly.yaml deleted file mode 100644 index 8e4f94f3..00000000 --- a/.github/workflows/with_foundry_nightly.yaml +++ /dev/null @@ -1,125 +0,0 @@ -name: Nightly With-Foundry drift test - -on: - # Giving ourselves a way to trigger this manually - workflow_dispatch: - schedule: - # Run a nightly release at 2 AM UTC - - cron: '0 2 * * *' - pull_request: - paths: - - 'with-foundry/**' - -jobs: - with-foundry-setup: - runs-on: ubuntu-latest - outputs: - versions: ${{ steps.set-matrix.outputs.versions }} - versions_map: ${{ steps.set-matrix.outputs.versions_map }} - steps: - - uses: actions/checkout@v4 - - - name: Get versions to test for drift - id: versions_step - run: | - output=$(node ./.github/scripts/latest.js) - echo "Output from Node.js script: $output" - echo "::set-output name=versionsMap::$output" - - - name: Set Up Matrix - id: set-matrix - run: | - VERSIONS_MAP='${{ steps.versions_step.outputs.versionsMap }}' - echo "Versions out of script: $VERSIONS_MAP" - - VERSIONS=$(echo "$VERSIONS_MAP" | jq -c '[.[]]') - echo "::set-output name=versions::$VERSIONS" - echo "::set-output name=versions_map::$VERSIONS_MAP" - - with-foundry-test-drift: - needs: with-foundry-setup - runs-on: ubuntu-latest - defaults: - run: - working-directory: with-foundry - strategy: - fail-fast: false - matrix: - version: ${{ fromJson(needs.with-foundry-setup.outputs.versions) }} - steps: - - uses: actions/checkout@v4 - - - name: Set up nargo - uses: ./.github/actions/setup-nargo - with: - version: ${{ matrix.version }} - - - name: Set up foundry - uses: ./.github/actions/setup-foundry - - - name: Get stability - id: get-stability - env: - VERSIONS_MAP: ${{ needs.with-foundry-setup.outputs.versions_map }} - run: | - VERSION="${{ matrix.version }}" - echo "Version Number: $VERSION" - - STABLE_VERSION=$(echo "$VERSIONS_MAP" | jq -r --arg VERSION "$VERSION" '.stable') - if [ "$STABLE_VERSION" == "$VERSION" ]; then - IS_STABLE="true" - else - IS_STABLE="false" - fi - echo "Is stable: $IS_STABLE" - echo "::set-output name=is_stable::$IS_STABLE" - - - name: Install test version - run: | - yarn add \ - @noir-lang/noir_js@${{ matrix.version }} \ - @noir-lang/backend_barretenberg@${{ matrix.version }} \ - @noir-lang/noir_wasm@${{ matrix.version }} \ - @noir-lang/types@${{ matrix.version }} - - - name: 'Create env file' - run: | - touch .env - echo LOCALHOST_PRIVATE_KEY="${{ secrets.LOCALHOST_PRIVATE_KEY }}" >> .env - echo ANVIL_RPC="${{ secrets.ANVIL_RPC }}" >> .env - - - name: Generate verifier contract - run: | - nargo codegen-verifier - working-directory: with-foundry/circuits - - - name: Generate proof - run: | - nargo prove - working-directory: with-foundry/circuits - - - name: Test with Foundry - run: | - forge test --optimize --optimizer-runs 5000 --evm-version london - - - name: Send GitHub Action trigger data to Slack workflow - Stable - uses: slackapi/slack-github-action@v1.24.0 - if: ${{ failure() && steps.get-stability.outputs.is_stable == 'true' }} - with: - payload: | - { - "text": "Oooops, seems like latest stable Noir breaks noir-starter! Projects needing updating: with-foundry ${{ matrix.version }}" - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - - - name: Send GitHub Action trigger data to Slack workflow - Prerelease - uses: slackapi/slack-github-action@v1.24.0 - if: ${{ failure() && steps.get-stability.outputs.is_stable == 'false' }} - with: - payload: | - { - "text": "Heads up DevRel! Once the prerelease becomes stable, the following project will break: with-foundry ${{ matrix.version }}" - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/with-foundry/README.md b/with-foundry/README.md index be39eaba..68a2aa27 100644 --- a/with-foundry/README.md +++ b/with-foundry/README.md @@ -24,12 +24,27 @@ Install [noirup](https://noir-lang.org/docs/getting_started/installation/#instal noirup ``` -3. Install foundryup and follow the instructions on screen. You should then have all the foundry tools like `forge`, `cast`, `anvil` and `chisel`. +3. Install foundryup and follow the instructions on screen. You should then have all the foundry + tools like `forge`, `cast`, `anvil` and `chisel`. ```bash curl -L https://foundry.paradigm.xyz | bash ``` +4. Install the correct version of the + [Barretenberg](https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/cpp/src/barretenberg/bb#version-compatibility-with-noir) + proving backend for Noir (bb). + + ```bash + curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/master/barretenberg/cpp/installation/install | bash + ``` + + then + + ```bash + bbup -v 0.41.0 # compatible with nargo 0.31.0 + ``` + ## Generate verifier contract and proof ### Contract @@ -38,21 +53,24 @@ The deployment assumes a verifier contract has been generated by nargo. In order ```bash cd circuits -nargo codegen-verifier +nargo compile +bb write_vk -b ./target/with_foundry.json +bb contract ``` -A file named `plonk_vk.sol` should appear in the `circuits/contracts/with_foundry` folder. +A file named `contract.sol` should appear in the `circuits/target` folder. #### Proof -You also need a proof, as this template currently doesn't employ `ffi` to call `nargo prove` by -itself. For this, ensure your prover parameters are correct in `Prover.toml` and run: +You also need a proof, as this template currently doesn't employ `ffi` to call `nargo execute` (to +generate the witness) and `bb prove` by itself. For this, ensure your prover parameters are correct +in `Prover.toml` and run: ```bash -nargo prove +bb prove -b ./target/with_foundry.json -w ./target/witness.gz -o ./target/with_foundry.proof ``` -A file named `with_foundry.proof` should appear in the `./circuits/proofs` folder. +A file named `with_foundry.proof` should appear in the `./circuits/target` folder. ### Test with Foundry diff --git a/with-foundry/circuits/Nargo.toml b/with-foundry/circuits/Nargo.toml index 3907d074..f9bc18a0 100644 --- a/with-foundry/circuits/Nargo.toml +++ b/with-foundry/circuits/Nargo.toml @@ -2,6 +2,6 @@ name="with_foundry" type="bin" authors = ["critesjosh"] -compiler_version = ">=0.27.0" +compiler_version = ">=0.31.0" [dependencies] diff --git a/with-foundry/contract/Starter.sol b/with-foundry/contract/Starter.sol index de49ac91..7359e602 100644 --- a/with-foundry/contract/Starter.sol +++ b/with-foundry/contract/Starter.sol @@ -1,6 +1,6 @@ pragma solidity ^0.8.17; -import "../circuits/contract/with_foundry/plonk_vk.sol"; +import "../circuits/target/contract.sol"; contract Starter { UltraVerifier public verifier; diff --git a/with-foundry/script/Starter.s.sol b/with-foundry/script/Starter.s.sol index 9b8e3a12..32cf575a 100644 --- a/with-foundry/script/Starter.s.sol +++ b/with-foundry/script/Starter.s.sol @@ -1,7 +1,7 @@ pragma solidity ^0.8.17; import "forge-std/Script.sol"; -import "../circuits/contract/with_foundry/plonk_vk.sol"; +import "../circuits/target/contract.sol"; import "../contract/Starter.sol"; contract StarterScript is Script { diff --git a/with-foundry/script/Verify.s.sol b/with-foundry/script/Verify.s.sol index 5f09f77b..e0ef4f47 100644 --- a/with-foundry/script/Verify.s.sol +++ b/with-foundry/script/Verify.s.sol @@ -1,7 +1,7 @@ pragma solidity ^0.8.17; import "forge-std/Script.sol"; -import "../circuits/contract/with_foundry/plonk_vk.sol"; +import "../circuits/target/contract.sol"; import "../contract/Starter.sol"; contract VerifyScript is Script { diff --git a/with-foundry/script/prove.sh b/with-foundry/script/prove.sh index beffbb58..e216e816 100755 --- a/with-foundry/script/prove.sh +++ b/with-foundry/script/prove.sh @@ -1,7 +1,6 @@ #!/bin/bash -if [ "$#" -ne 1 ] -then +if [ "$#" -ne 1 ]; then echo "Usage: ./prove.sh [TESTNAME_STRING]" exit 1 fi -cd /tmp/$1 && nargo prove && echo "Proof Generated" +cd /tmp/$1 && nargo execute witness && bb prove -b ./target/with_foundry.json -w ./target/witness.gz -o ./target/with_foundry.proof && echo "Proof Generated" diff --git a/with-foundry/test/Starter.t.sol b/with-foundry/test/Starter.t.sol index e626e54c..f93d90db 100644 --- a/with-foundry/test/Starter.t.sol +++ b/with-foundry/test/Starter.t.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.17; import "forge-std/Test.sol"; import "../contract/Starter.sol"; -import "../circuits/contract/with_foundry/plonk_vk.sol"; +import "../circuits/target/contract.sol"; +import "forge-std/console.sol"; contract StarterTest is Test { Starter public starter; @@ -21,17 +22,17 @@ contract StarterTest is Test { wrong[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000004); } - function testVerifyProof() public { - string memory proof = vm.readLine("./circuits/proofs/with_foundry.proof"); - bytes memory proofBytes = vm.parseBytes(proof); - starter.verifyEqual(proofBytes, correct); + function testVerifyProof() public view { + bytes memory proof_w_inputs = vm.readFileBinary("./circuits/target/with_foundry.proof"); + bytes memory last = sliceAfter64Bytes(proof_w_inputs); + starter.verifyEqual(last, correct); } function test_wrongProof() public { vm.expectRevert(); - string memory proof = vm.readLine("./circuits/proofs/with_foundry.proof"); - bytes memory proofBytes = vm.parseBytes(proof); - starter.verifyEqual(proofBytes, wrong); + bytes memory proof_w_inputs = vm.readFileBinary("./circuits/target/with_foundry.proof"); + bytes memory proof = sliceAfter64Bytes(proof_w_inputs); + starter.verifyEqual(proof, wrong); } function test_dynamicProof() public { @@ -47,7 +48,8 @@ contract StarterTest is Test { dynamicCorrect[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000005); dynamicCorrect[1] = dynamicCorrect[0]; bytes memory proofBytes = generateDynamicProof("test1", _fieldNames, _fieldValues); - starter.verifyEqual(proofBytes, dynamicCorrect); + bytes memory proof = sliceAfter64Bytes(proofBytes); + starter.verifyEqual(proof, dynamicCorrect); } function test_dynamicProofSecondTest() public { @@ -63,7 +65,8 @@ contract StarterTest is Test { dynamicCorrect[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000008); dynamicCorrect[1] = dynamicCorrect[0]; bytes memory proofBytes = generateDynamicProof("test2", _fieldNames, _fieldValues); - starter.verifyEqual(proofBytes, dynamicCorrect); + bytes memory proof = sliceAfter64Bytes(proofBytes); + starter.verifyEqual(proof, dynamicCorrect); } function test_dynamicProofThirdTest() public { @@ -79,7 +82,8 @@ contract StarterTest is Test { dynamicCorrect[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000007); dynamicCorrect[1] = dynamicCorrect[0]; bytes memory proofBytes = generateDynamicProof("test3", _fieldNames, _fieldValues); - starter.verifyEqual(proofBytes, dynamicCorrect); + bytes memory proof = sliceAfter64Bytes(proofBytes); + starter.verifyEqual(proof, dynamicCorrect); } /// @dev This function generates dynamic proofs using 2 scripts in the /script directory @@ -112,7 +116,18 @@ contract StarterTest is Test { ffi_command[1] = _testName; bytes memory commandResponse = vm.ffi(ffi_command); console.log(string(commandResponse)); - string memory _newProof = vm.readLine(string.concat("/tmp/", _testName, "/proofs/with_foundry.proof")); - return vm.parseBytes(_newProof); + bytes memory _newProof = vm.readFileBinary(string.concat("/tmp/", _testName, "/target/with_foundry.proof")); + return _newProof; } + + // Utility function, because the proof file includes the public inputs at the beginning + function sliceAfter64Bytes(bytes memory data) internal pure returns (bytes memory) { + uint256 length = data.length - 64; + bytes memory result = new bytes(data.length - 64); + for (uint i = 0; i < length; i++) { + result[i] = data[i + 64]; + } + return result; + } + }