From 6e5e7638fbf24506f07d0f197f8443a088abf132 Mon Sep 17 00:00:00 2001 From: Savio-Sou <72797635+Savio-Sou@users.noreply.github.com> Date: Tue, 15 Aug 2023 17:23:47 +0900 Subject: [PATCH 01/10] Fix instructions to get Node.js test working --- next-hardhat/.gitignore | 9 +- next-hardhat/README.md | 77 +- .../contract/noirstarter/plonk_vk.sol | 2611 ----------------- next-hardhat/test/index.test.ts | 2 +- next-hardhat/utils/addresses.json | 2 +- next-hardhat/utils/ethers.tsx | 2 +- with-foundry/.env.example | 3 - 7 files changed, 64 insertions(+), 2642 deletions(-) delete mode 100644 next-hardhat/circuits/contract/noirstarter/plonk_vk.sol delete mode 100644 with-foundry/.env.example diff --git a/next-hardhat/.gitignore b/next-hardhat/.gitignore index 9df50f4..a769f2c 100644 --- a/next-hardhat/.gitignore +++ b/next-hardhat/.gitignore @@ -38,16 +38,19 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts -# contract - # hardhat cache + # artifacts typechain-types proofs +# noir +crs +circuits/target +circuits/contract + # other .vscode -crs .DS_Store artifacts diff --git a/next-hardhat/README.md b/next-hardhat/README.md index 80dd32a..7be3bac 100644 --- a/next-hardhat/README.md +++ b/next-hardhat/README.md @@ -10,47 +10,80 @@ It also features multiple files and different entry points by resolving multiple ## Getting Started -1. [Install nargo nightly](https://noir-lang.org/getting_started/nargo_installation#option-1-noirup), - with `noirup -n`. +1. [Install Node.js ≥v18](https://nodejs.org/en) (tested on v18.17.0) -2. Install dependencies with +2. [Install Nix](https://noir-lang.org/getting_started/nargo_installation#installing-nix) + +3. Install Nargo with + +```bash +nix profile install github:noir-lang/noir/ad118eb8165ef83402e25b3001dfe27cf3a358b1 +``` + +4. Install dependencies with ```bash yarn ``` -3. Write circuits in `./circuits/src`. +5. Write circuits in `./circuits/src`. You can read more about writing circuits in Noir on the [Noir docs](https://noir-lang.org/). -4. Create the verifier contract +6. Create the verifier contract -Navigate to the `.circuits/` directory and run `nargo codegen-verifier` +Navigate to the `.circuits/` directory and run -5. Compile your circuit +```bash +nargo codegen-verifier +``` -Compile your circuits with `nargo compile`. +7. Compile your circuit -1. Deploy +Compile your circuits with -- Start a local development EVM at , for example with `npx hardhat node` or - `anvil`. -- Copy `./.env.example` to `./.env` and add keys for alchemy (to act as a node) and the deployer's - private key. Make sure you have funds in this account. -- Run `NETWORK=localhost yarn build` to build the project and deploy contracts to the local - development chain. If the deployment fails, try removing `yarn.lock` and reinstalling dependencies with `yarn`. +```bash +nargo compile noirstarter +``` -You can choose any other network in `hardhat.config.ts` and deploy there using this `NETWORK` -environment variable. For example, `NETWORK=mumbai yarn build` or `NETWORK=sepolia yarn build`. Feel -free to contribute with other networks in `hardhat.config.ts` +## Testing locally -Once your contracts are deployed and the build is finished, start the web app with `yarn start`. +1. Copy `./.env.example` to a new file `./.env`. -## Testing +2. Start a local development EVM at , for example with `npx hardhat node` or + `anvil`. -There is a basic [example test file](./test/index.test.ts) that shows the usage of Noir in a -typescript `node.js` environment. You can run the tests with: +3. Run the [example test file](./test/index.test.ts) with ```sh yarn test ``` + +The test demonstrates basic usage of Noir in a typescript `node.js` environment. + +## Deploy locally (WIP) + +1. Copy `./.env.example` to a new file `./.env`. + +2. Start a local development EVM at , for example with `npx hardhat node` or + `anvil`. + +3. Run `NETWORK=localhost yarn build` to build the project and deploy contracts to the local + development chain. + + If the deployment fails, try removing `yarn.lock` and reinstalling dependencies with `yarn`. + +4. Once your contracts are deployed and the build is finished, start the web app with `yarn start`. + +## Deploying on other networks + +You can choose any other network in `hardhat.config.ts` and deploy there using this `NETWORK` +environment variable. For example, `NETWORK=mumbai yarn build` or `NETWORK=sepolia yarn build`. + +Make sure you: + +- Update the deployer private keys in `./.env` +- Have funds in the deployer account +- Add keys for alchemy (to act as a node) in `./.env` + +Feel free to contribute with other networks in `hardhat.config.ts` diff --git a/next-hardhat/circuits/contract/noirstarter/plonk_vk.sol b/next-hardhat/circuits/contract/noirstarter/plonk_vk.sol deleted file mode 100644 index 97fbbe3..0000000 --- a/next-hardhat/circuits/contract/noirstarter/plonk_vk.sol +++ /dev/null @@ -1,2611 +0,0 @@ -// Verification Key Hash: 5bd9df07721ff64c4d2a2dbd1f1969287d0c790df883df7af4114b5956c1e411 -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 Aztec -pragma solidity >=0.8.4; - -library UltraVerificationKey { - function verificationKeyHash() internal pure returns(bytes32) { - return 0x5bd9df07721ff64c4d2a2dbd1f1969287d0c790df883df7af4114b5956c1e411; - } - - function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { - assembly { - mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000010) // vk.circuit_size - mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000001) // vk.num_inputs - mstore(add(_vk, 0x40), 0x21082ca216cbbf4e1c6e4f4594dd508c996dfbe1174efb98b11509c6e306460b) // vk.work_root - mstore(add(_vk, 0x60), 0x2d5e098bb31e86271ccb415b196942d755b0a9c3f21dd9882fa3d63ab1000001) // vk.domain_inverse - mstore(add(_vk, 0x80), 0x17c660f12bd58e45a1161d687125bcf3e50db901cd031ae90fa0f899c5f6b0af) // vk.Q1.x - mstore(add(_vk, 0xa0), 0x18431833019d0b6edd508ef905b14dc5489f7392ae6ac1e78785eeaf36dc198e) // vk.Q1.y - mstore(add(_vk, 0xc0), 0x0e0b6d8dd8f37229da396ea6af4d0950760cb8b36391ed9babf2816005d98431) // vk.Q2.x - mstore(add(_vk, 0xe0), 0x023976dee62b72746539eca15a1b803d7aa47b5e13143d496e96b90fb399ac70) // vk.Q2.y - mstore(add(_vk, 0x100), 0x2a7e71e447b5645910a429e7f48f1a5deba7f7d446b95a5edd242b55f67993d3) // vk.Q3.x - mstore(add(_vk, 0x120), 0x2b1ea7f7453a8c80a89a675245da0c33db05ba8e95ecea432ab85f6b2d6a1e86) // vk.Q3.y - mstore(add(_vk, 0x140), 0x02d6fd9e84dbe74b7531e1801405a1c292117b1a17fefe9de0bfd9edf1a84bf9) // vk.Q4.x - mstore(add(_vk, 0x160), 0x293c6ab3c06a0669af13393a82c60a459a3b2a0b768da45ac7af7f2aec40fc42) // vk.Q4.y - mstore(add(_vk, 0x180), 0x0efe5ad29f99fce939416b6638dff26c845044cca9a2d9dbf94039a11d999aaa) // vk.Q_M.x - mstore(add(_vk, 0x1a0), 0x0a44bf49517a4b66ae6b51eee6ac68587f768022c11ac8e37cd9dce243d01ef2) // vk.Q_M.y - mstore(add(_vk, 0x1c0), 0x117d457bfb28869ab380fd6e83133eeb5b6ab48e5df1ae9bc204b60817006655) // vk.Q_C.x - mstore(add(_vk, 0x1e0), 0x2a958a537a99428a1019fd2c8d6b97c48f3e74ad77f0e2c63c9dfb6dccf9a29c) // vk.Q_C.y - mstore(add(_vk, 0x200), 0x18c3e78f81e83b52719158e4ac4c2f4b6c55389300451eb2a2deddf244129e7a) // vk.Q_ARITHMETIC.x - mstore(add(_vk, 0x220), 0x0002e9c902fe5cd49b64563cadf3bb8d7beb75f905a5894e18d27c42c62fd797) // vk.Q_ARITHMETIC.y - mstore(add(_vk, 0x240), 0x2cbce7beee3076b78dace04943d69d0d9e28aa6d00e046852781a5f20816645c) // vk.QSORT.x - mstore(add(_vk, 0x260), 0x2bc27ec2e1612ea284b08bcc55b6f2fd915d11bfedbdc0e59de09e5b28952080) // vk.QSORT.y - mstore(add(_vk, 0x280), 0x0ad34b5e8db72a5acf4427546c7294be6ed4f4d252a79059e505f9abc1bdf3ed) // vk.Q_ELLIPTIC.x - mstore(add(_vk, 0x2a0), 0x1e5b26790a26eb340217dd9ad28dbf90a049f42a3852acd45e6f521f24b4900e) // vk.Q_ELLIPTIC.y - mstore(add(_vk, 0x2c0), 0x155a0f51fec78c33ffceb7364d69d7ac27e570ae50bc180509764eb3fef94815) // vk.Q_AUX.x - mstore(add(_vk, 0x2e0), 0x1c1c4720bed44a591d97cbc72b6e44b644999713a8d3c66e9054aa5726324c76) // vk.Q_AUX.y - mstore(add(_vk, 0x300), 0x0f7261cf55a71f4d0d7b961dda9ddb058cc5ad51753faec2a5908155d472e429) // vk.SIGMA1.x - mstore(add(_vk, 0x320), 0x1b7b1a10c1e638ce11d8c84b831aca4a36df78f0d50144437ef26f8bbfe69ac1) // vk.SIGMA1.y - mstore(add(_vk, 0x340), 0x163a9c8b67447afccc64e9ccba9d9e826ba5b1d1ddd8d6bb960f01cd1321a169) // vk.SIGMA2.x - mstore(add(_vk, 0x360), 0x19256311d43dbc795f746c63b209667653a773088aba5c6b1337f435188d72c4) // vk.SIGMA2.y - mstore(add(_vk, 0x380), 0x1fa51a0d75363b3af4e259e0dbb2c5df58a7bad9afe3651be67bc6c298092e11) // vk.SIGMA3.x - mstore(add(_vk, 0x3a0), 0x21915198840ad9c3666122b2837aeac8b5836b29551d41dbc04bdb1fcf1a1868) // vk.SIGMA3.y - mstore(add(_vk, 0x3c0), 0x0cee6b75dcf02a07c50939e8ca3cf35df0e69d7efdbc7898b3762f0a0ed976ad) // vk.SIGMA4.x - mstore(add(_vk, 0x3e0), 0x27e49262bd388ce2d0f193988f3b8f66a493be1ea69d2b335152719acd54d735) // vk.SIGMA4.y - mstore(add(_vk, 0x400), 0x02c397073c8abce6d4140c9b961209dd783bff1a1cfc999bb29859cfb16c46fc) // vk.TABLE1.x - mstore(add(_vk, 0x420), 0x2b7bba2d1efffce0d033f596b4d030750599be670db593af86e1923fe8a1bb18) // vk.TABLE1.y - mstore(add(_vk, 0x440), 0x2c71c58b66498f903b3bbbda3d05ce8ffb571a4b3cf83533f3f71b99a04f6e6b) // vk.TABLE2.x - mstore(add(_vk, 0x460), 0x039dce37f94d1bbd97ccea32a224fe2afaefbcbd080c84dcea90b54f4e0a858f) // vk.TABLE2.y - mstore(add(_vk, 0x480), 0x27dc44977efe6b3746a290706f4f7275783c73cfe56847d848fd93b63bf32083) // vk.TABLE3.x - mstore(add(_vk, 0x4a0), 0x0a5366266dd7b71a10b356030226a2de0cbf2edc8f085b16d73652b15eced8f5) // vk.TABLE3.y - mstore(add(_vk, 0x4c0), 0x136097d79e1b0ae373255e8760c49900a7588ec4d6809c90bb451005a3de3077) // vk.TABLE4.x - mstore(add(_vk, 0x4e0), 0x13dd7515ccac4095302d204f06f0bff2595d77bdf72e4acdb0b0b43969860d98) // vk.TABLE4.y - mstore(add(_vk, 0x500), 0x16ff3501369121d410b445929239ba057fe211dad1b706e49a3b55920fac20ec) // vk.TABLE_TYPE.x - mstore(add(_vk, 0x520), 0x1e190987ebd9cf480f608b82134a00eb8007673c1ed10b834a695adf0068522a) // vk.TABLE_TYPE.y - mstore(add(_vk, 0x540), 0x1e44194e60f0ab4ee0f77adc50f4220944f94301aa6da3016a226de04de52f4c) // vk.ID1.x - mstore(add(_vk, 0x560), 0x2a017d0d9f40d0aeb5c8152ffddec56c2c7bea37dfbd20be6bed19efd743397a) // vk.ID1.y - mstore(add(_vk, 0x580), 0x27579be0883627093cf8bdec0b72e77f43efe5631bf48c872c317bed3b8bf12b) // vk.ID2.x - mstore(add(_vk, 0x5a0), 0x0ddb2d01ec88ed69144177a4af3850cef6108b89e89b35679431d113f3be7dff) // vk.ID2.y - mstore(add(_vk, 0x5c0), 0x0a7fe830f1cb7a5d49d71877dd226a0083e7ab1f26781948b36d131759f7c8c9) // vk.ID3.x - mstore(add(_vk, 0x5e0), 0x2db7a5185064e6501ef61e989895a01834ecd1ce1e8e80812bdd95f960a45e57) // vk.ID3.y - mstore(add(_vk, 0x600), 0x2eea648c8732596b1314fe2a4d2f05363f0c994e91cecad25835338edee2294f) // vk.ID4.x - mstore(add(_vk, 0x620), 0x0ab49886c2b94bd0bd3f6ed1dbbe2cb2671d2ae51d31c1210433c3972bb64578) // vk.ID4.y - mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof - mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices - mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 - mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 - mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 - mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 - mstore(_omegaInverseLoc, 0x02e40daf409556c02bfc85eb303402b774954d30aeb0337eb85a71e6373428de) // vk.work_root_inverse - } - } -} - -/** - * @title Ultra Plonk proof verification contract - * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified - */ -abstract contract BaseUltraVerifier { - // VERIFICATION KEY MEMORY LOCATIONS - uint256 internal constant N_LOC = 0x380; - uint256 internal constant NUM_INPUTS_LOC = 0x3a0; - uint256 internal constant OMEGA_LOC = 0x3c0; - uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0; - uint256 internal constant Q1_X_LOC = 0x400; - uint256 internal constant Q1_Y_LOC = 0x420; - uint256 internal constant Q2_X_LOC = 0x440; - uint256 internal constant Q2_Y_LOC = 0x460; - uint256 internal constant Q3_X_LOC = 0x480; - uint256 internal constant Q3_Y_LOC = 0x4a0; - uint256 internal constant Q4_X_LOC = 0x4c0; - uint256 internal constant Q4_Y_LOC = 0x4e0; - uint256 internal constant QM_X_LOC = 0x500; - uint256 internal constant QM_Y_LOC = 0x520; - uint256 internal constant QC_X_LOC = 0x540; - uint256 internal constant QC_Y_LOC = 0x560; - uint256 internal constant QARITH_X_LOC = 0x580; - uint256 internal constant QARITH_Y_LOC = 0x5a0; - uint256 internal constant QSORT_X_LOC = 0x5c0; - uint256 internal constant QSORT_Y_LOC = 0x5e0; - uint256 internal constant QELLIPTIC_X_LOC = 0x600; - uint256 internal constant QELLIPTIC_Y_LOC = 0x620; - uint256 internal constant QAUX_X_LOC = 0x640; - uint256 internal constant QAUX_Y_LOC = 0x660; - uint256 internal constant SIGMA1_X_LOC = 0x680; - uint256 internal constant SIGMA1_Y_LOC = 0x6a0; - uint256 internal constant SIGMA2_X_LOC = 0x6c0; - uint256 internal constant SIGMA2_Y_LOC = 0x6e0; - uint256 internal constant SIGMA3_X_LOC = 0x700; - uint256 internal constant SIGMA3_Y_LOC = 0x720; - uint256 internal constant SIGMA4_X_LOC = 0x740; - uint256 internal constant SIGMA4_Y_LOC = 0x760; - uint256 internal constant TABLE1_X_LOC = 0x780; - uint256 internal constant TABLE1_Y_LOC = 0x7a0; - uint256 internal constant TABLE2_X_LOC = 0x7c0; - uint256 internal constant TABLE2_Y_LOC = 0x7e0; - uint256 internal constant TABLE3_X_LOC = 0x800; - uint256 internal constant TABLE3_Y_LOC = 0x820; - uint256 internal constant TABLE4_X_LOC = 0x840; - uint256 internal constant TABLE4_Y_LOC = 0x860; - uint256 internal constant TABLE_TYPE_X_LOC = 0x880; - uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0; - uint256 internal constant ID1_X_LOC = 0x8c0; - uint256 internal constant ID1_Y_LOC = 0x8e0; - uint256 internal constant ID2_X_LOC = 0x900; - uint256 internal constant ID2_Y_LOC = 0x920; - uint256 internal constant ID3_X_LOC = 0x940; - uint256 internal constant ID3_Y_LOC = 0x960; - uint256 internal constant ID4_X_LOC = 0x980; - uint256 internal constant ID4_Y_LOC = 0x9a0; - uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0; - uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0; - uint256 internal constant G2X_X0_LOC = 0xa00; - uint256 internal constant G2X_X1_LOC = 0xa20; - uint256 internal constant G2X_Y0_LOC = 0xa40; - uint256 internal constant G2X_Y1_LOC = 0xa60; - - // ### PROOF DATA MEMORY LOCATIONS - uint256 internal constant W1_X_LOC = 0x1200; - uint256 internal constant W1_Y_LOC = 0x1220; - uint256 internal constant W2_X_LOC = 0x1240; - uint256 internal constant W2_Y_LOC = 0x1260; - uint256 internal constant W3_X_LOC = 0x1280; - uint256 internal constant W3_Y_LOC = 0x12a0; - uint256 internal constant W4_X_LOC = 0x12c0; - uint256 internal constant W4_Y_LOC = 0x12e0; - uint256 internal constant S_X_LOC = 0x1300; - uint256 internal constant S_Y_LOC = 0x1320; - uint256 internal constant Z_X_LOC = 0x1340; - uint256 internal constant Z_Y_LOC = 0x1360; - uint256 internal constant Z_LOOKUP_X_LOC = 0x1380; - uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0; - uint256 internal constant T1_X_LOC = 0x13c0; - uint256 internal constant T1_Y_LOC = 0x13e0; - uint256 internal constant T2_X_LOC = 0x1400; - uint256 internal constant T2_Y_LOC = 0x1420; - uint256 internal constant T3_X_LOC = 0x1440; - uint256 internal constant T3_Y_LOC = 0x1460; - uint256 internal constant T4_X_LOC = 0x1480; - uint256 internal constant T4_Y_LOC = 0x14a0; - - uint256 internal constant W1_EVAL_LOC = 0x1600; - uint256 internal constant W2_EVAL_LOC = 0x1620; - uint256 internal constant W3_EVAL_LOC = 0x1640; - uint256 internal constant W4_EVAL_LOC = 0x1660; - uint256 internal constant S_EVAL_LOC = 0x1680; - uint256 internal constant Z_EVAL_LOC = 0x16a0; - uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0; - uint256 internal constant Q1_EVAL_LOC = 0x16e0; - uint256 internal constant Q2_EVAL_LOC = 0x1700; - uint256 internal constant Q3_EVAL_LOC = 0x1720; - uint256 internal constant Q4_EVAL_LOC = 0x1740; - uint256 internal constant QM_EVAL_LOC = 0x1760; - uint256 internal constant QC_EVAL_LOC = 0x1780; - uint256 internal constant QARITH_EVAL_LOC = 0x17a0; - uint256 internal constant QSORT_EVAL_LOC = 0x17c0; - uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0; - uint256 internal constant QAUX_EVAL_LOC = 0x1800; - uint256 internal constant TABLE1_EVAL_LOC = 0x1840; - uint256 internal constant TABLE2_EVAL_LOC = 0x1860; - uint256 internal constant TABLE3_EVAL_LOC = 0x1880; - uint256 internal constant TABLE4_EVAL_LOC = 0x18a0; - uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0; - uint256 internal constant ID1_EVAL_LOC = 0x18e0; - uint256 internal constant ID2_EVAL_LOC = 0x1900; - uint256 internal constant ID3_EVAL_LOC = 0x1920; - uint256 internal constant ID4_EVAL_LOC = 0x1940; - uint256 internal constant SIGMA1_EVAL_LOC = 0x1960; - uint256 internal constant SIGMA2_EVAL_LOC = 0x1980; - uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0; - uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0; - uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0; - uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000; - uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020; - uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040; - uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060; - uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080; - uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0; - uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0; - uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0; - uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100; - uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120; - - uint256 internal constant PI_Z_X_LOC = 0x2300; - uint256 internal constant PI_Z_Y_LOC = 0x2320; - uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340; - uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360; - - // Used for elliptic widget. These are alias names for wire + shifted wire evaluations - uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC; - uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC; - uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC; - uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC; - uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC; - uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC; - uint256 internal constant QBETA_LOC = Q3_EVAL_LOC; - uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC; - uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC; - - // ### CHALLENGES MEMORY OFFSETS - - uint256 internal constant C_BETA_LOC = 0x2600; - uint256 internal constant C_GAMMA_LOC = 0x2620; - uint256 internal constant C_ALPHA_LOC = 0x2640; - uint256 internal constant C_ETA_LOC = 0x2660; - uint256 internal constant C_ETA_SQR_LOC = 0x2680; - uint256 internal constant C_ETA_CUBE_LOC = 0x26a0; - - uint256 internal constant C_ZETA_LOC = 0x26c0; - uint256 internal constant C_CURRENT_LOC = 0x26e0; - uint256 internal constant C_V0_LOC = 0x2700; - uint256 internal constant C_V1_LOC = 0x2720; - uint256 internal constant C_V2_LOC = 0x2740; - uint256 internal constant C_V3_LOC = 0x2760; - uint256 internal constant C_V4_LOC = 0x2780; - uint256 internal constant C_V5_LOC = 0x27a0; - uint256 internal constant C_V6_LOC = 0x27c0; - uint256 internal constant C_V7_LOC = 0x27e0; - uint256 internal constant C_V8_LOC = 0x2800; - uint256 internal constant C_V9_LOC = 0x2820; - uint256 internal constant C_V10_LOC = 0x2840; - uint256 internal constant C_V11_LOC = 0x2860; - uint256 internal constant C_V12_LOC = 0x2880; - uint256 internal constant C_V13_LOC = 0x28a0; - uint256 internal constant C_V14_LOC = 0x28c0; - uint256 internal constant C_V15_LOC = 0x28e0; - uint256 internal constant C_V16_LOC = 0x2900; - uint256 internal constant C_V17_LOC = 0x2920; - uint256 internal constant C_V18_LOC = 0x2940; - uint256 internal constant C_V19_LOC = 0x2960; - uint256 internal constant C_V20_LOC = 0x2980; - uint256 internal constant C_V21_LOC = 0x29a0; - uint256 internal constant C_V22_LOC = 0x29c0; - uint256 internal constant C_V23_LOC = 0x29e0; - uint256 internal constant C_V24_LOC = 0x2a00; - uint256 internal constant C_V25_LOC = 0x2a20; - uint256 internal constant C_V26_LOC = 0x2a40; - uint256 internal constant C_V27_LOC = 0x2a60; - uint256 internal constant C_V28_LOC = 0x2a80; - uint256 internal constant C_V29_LOC = 0x2aa0; - uint256 internal constant C_V30_LOC = 0x2ac0; - - uint256 internal constant C_U_LOC = 0x2b00; - - // ### LOCAL VARIABLES MEMORY OFFSETS - uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000; - uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020; - uint256 internal constant ZETA_POW_N_LOC = 0x3040; - uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060; - uint256 internal constant ZERO_POLY_LOC = 0x3080; - uint256 internal constant L_START_LOC = 0x30a0; - uint256 internal constant L_END_LOC = 0x30c0; - uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0; - - uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100; - uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120; - uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140; - - uint256 internal constant ACCUMULATOR_X_LOC = 0x3160; - uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180; - uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0; - uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0; - uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0; - uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200; - uint256 internal constant PAIRING_RHS_X_LOC = 0x3220; - uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240; - - // ### SUCCESS FLAG MEMORY LOCATIONS - uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300; - uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020; - uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340; - uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360; - uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380; - uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0; - uint256 internal constant RESULT_FLAG = 0x33c0; - - // misc stuff - uint256 internal constant OMEGA_INVERSE_LOC = 0x3400; - uint256 internal constant C_ALPHA_SQR_LOC = 0x3420; - uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440; - uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460; - uint256 internal constant C_ALPHA_BASE_LOC = 0x3480; - - // ### RECURSION VARIABLE MEMORY LOCATIONS - uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500; - uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520; - uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540; - uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560; - - uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580; - - // sub-identity storage - uint256 internal constant PERMUTATION_IDENTITY = 0x3600; - uint256 internal constant PLOOKUP_IDENTITY = 0x3620; - uint256 internal constant ARITHMETIC_IDENTITY = 0x3640; - uint256 internal constant SORT_IDENTITY = 0x3660; - uint256 internal constant ELLIPTIC_IDENTITY = 0x3680; - uint256 internal constant AUX_IDENTITY = 0x36a0; - uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0; - uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0; - uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700; - uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720; - uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740; - - uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760; - uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780; - - // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time - uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0; - - bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6; - bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f; - bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc; - bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369; - bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec; - - uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes - - // We need to hash 41 field elements when generating the NU challenge - // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14) - // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7) - // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9) - // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7) - // table1_omega, table2_omega, table3_omega, table4_omega (4) - uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20 - - // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over - // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4 - uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0 - - uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P = - 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; - uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68 - uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14 - - error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual); - error PUBLIC_INPUT_INVALID_BN128_G1_POINT(); - error PUBLIC_INPUT_GE_P(); - error MOD_EXP_FAILURE(); - error EC_SCALAR_MUL_FAILURE(); - error PROOF_FAILURE(); - - function getVerificationKeyHash() public pure virtual returns (bytes32); - - function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual; - - /** - * @notice Verify a Ultra Plonk proof - * @param _proof - The serialized proof - * @param _publicInputs - An array of the public inputs - * @return True if proof is valid, reverts otherwise - */ - function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) { - loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC); - - uint256 requiredPublicInputCount; - assembly { - requiredPublicInputCount := mload(NUM_INPUTS_LOC) - } - if (requiredPublicInputCount != _publicInputs.length) { - revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length); - } - - assembly { - let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order - let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order - - /** - * LOAD PROOF FROM CALLDATA - */ - { - let data_ptr := add(calldataload(0x04), 0x24) - - mstore(W1_Y_LOC, mod(calldataload(data_ptr), q)) - mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q)) - - mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q)) - mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q)) - - mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q)) - mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q)) - - mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q)) - mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q)) - - mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q)) - mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q)) - mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q)) - mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q)) - mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q)) - mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q)) - mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q)) - mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q)) - - mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q)) - mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q)) - - mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q)) - mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q)) - - mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q)) - mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q)) - - mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p)) - mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p)) - mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p)) - mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p)) - mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p)) - mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p)) - mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p)) - mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p)) - mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p)) - mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p)) - mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p)) - mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p)) - mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p)) - mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p)) - mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p)) - mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p)) - mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p)) - - mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p)) - mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p)) - - mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p)) - mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p)) - - mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p)) - mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p)) - mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p)) - mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p)) - mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p)) - - mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p)) - mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p)) - mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p)) - mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p)) - - mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p)) - mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p)) - mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p)) - mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p)) - mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p)) - - mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p)) - - mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p)) - mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p)) - mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p)) - mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p)) - mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p)) - - mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q)) - mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q)) - - mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q)) - mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q)) - } - - /** - * LOAD RECURSIVE PROOF INTO MEMORY - */ - { - if mload(CONTAINS_RECURSIVE_PROOF_LOC) { - let public_inputs_ptr := add(calldataload(0x24), 0x24) - let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr) - - let x0 := calldataload(index_counter) - x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20)))) - x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40)))) - x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60)))) - let y0 := calldataload(add(index_counter, 0x80)) - y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0)))) - y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0)))) - y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0)))) - let x1 := calldataload(add(index_counter, 0x100)) - x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120)))) - x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140)))) - x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160)))) - let y1 := calldataload(add(index_counter, 0x180)) - y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0)))) - y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0)))) - y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0)))) - mstore(RECURSIVE_P1_X_LOC, x0) - mstore(RECURSIVE_P1_Y_LOC, y0) - mstore(RECURSIVE_P2_X_LOC, x1) - mstore(RECURSIVE_P2_Y_LOC, y1) - - // validate these are valid bn128 G1 points - if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) { - mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR) - revert(0x00, 0x04) - } - } - } - - { - /** - * Generate initial challenge - */ - mstore(0x00, shl(224, mload(N_LOC))) - mstore(0x04, shl(224, mload(NUM_INPUTS_LOC))) - let challenge := keccak256(0x00, 0x08) - - /** - * Generate eta challenge - */ - mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge) - // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs - let public_inputs_start := add(calldataload(0x24), 0x24) - // copy the public inputs over - let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20) - calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size) - - // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length) - let w_start := add(calldataload(0x04), 0x24) - calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH) - - // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0) - let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH)) - - challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size) - { - let eta := mod(challenge, p) - mstore(C_ETA_LOC, eta) - mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p)) - mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p)) - } - - /** - * Generate beta challenge - */ - mstore(0x00, challenge) - mstore(0x20, mload(W4_Y_LOC)) - mstore(0x40, mload(W4_X_LOC)) - mstore(0x60, mload(S_Y_LOC)) - mstore(0x80, mload(S_X_LOC)) - challenge := keccak256(0x00, 0xa0) - mstore(C_BETA_LOC, mod(challenge, p)) - - /** - * Generate gamma challenge - */ - mstore(0x00, challenge) - mstore8(0x20, 0x01) - challenge := keccak256(0x00, 0x21) - mstore(C_GAMMA_LOC, mod(challenge, p)) - - /** - * Generate alpha challenge - */ - mstore(0x00, challenge) - mstore(0x20, mload(Z_Y_LOC)) - mstore(0x40, mload(Z_X_LOC)) - mstore(0x60, mload(Z_LOOKUP_Y_LOC)) - mstore(0x80, mload(Z_LOOKUP_X_LOC)) - challenge := keccak256(0x00, 0xa0) - mstore(C_ALPHA_LOC, mod(challenge, p)) - - /** - * Compute and store some powers of alpha for future computations - */ - let alpha := mload(C_ALPHA_LOC) - mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p)) - mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p)) - mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p)) - mstore(C_ALPHA_BASE_LOC, alpha) - - /** - * Generate zeta challenge - */ - mstore(0x00, challenge) - mstore(0x20, mload(T1_Y_LOC)) - mstore(0x40, mload(T1_X_LOC)) - mstore(0x60, mload(T2_Y_LOC)) - mstore(0x80, mload(T2_X_LOC)) - mstore(0xa0, mload(T3_Y_LOC)) - mstore(0xc0, mload(T3_X_LOC)) - mstore(0xe0, mload(T4_Y_LOC)) - mstore(0x100, mload(T4_X_LOC)) - - challenge := keccak256(0x00, 0x120) - - mstore(C_ZETA_LOC, mod(challenge, p)) - mstore(C_CURRENT_LOC, challenge) - } - - /** - * EVALUATE FIELD OPERATIONS - */ - - /** - * COMPUTE PUBLIC INPUT DELTA - * ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ) - */ - { - let beta := mload(C_BETA_LOC) // β - let gamma := mload(C_GAMMA_LOC) // γ - let work_root := mload(OMEGA_LOC) // ω - let numerator_value := 1 - let denominator_value := 1 - - let p_clone := p // move p to the front of the stack - let valid_inputs := true - - // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24]) - let public_inputs_ptr := add(calldataload(0x24), 0x24) - - // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes - let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20)) - - // root_1 = β * 0x05 - let root_1 := mulmod(beta, 0x05, p_clone) // k1.β - // root_2 = β * 0x0c - let root_2 := mulmod(beta, 0x0c, p_clone) - // @note 0x05 + 0x07 == 0x0c == external coset generator - - for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } { - /** - * input = public_input[i] - * valid_inputs &= input < p - * temp = input + gamma - * numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ - * denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ - * root_1 *= ω - * root_2 *= ω - */ - - let input := calldataload(public_inputs_ptr) - valid_inputs := and(valid_inputs, lt(input, p_clone)) - let temp := addmod(input, gamma, p_clone) - - numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone) - denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone) - - root_1 := mulmod(root_1, work_root, p_clone) - root_2 := mulmod(root_2, work_root, p_clone) - } - - // Revert if not all public inputs are field elements (i.e. < p) - if iszero(valid_inputs) { - mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR) - revert(0x00, 0x04) - } - - mstore(DELTA_NUMERATOR_LOC, numerator_value) - mstore(DELTA_DENOMINATOR_LOC, denominator_value) - } - - /** - * Compute Plookup delta factor [γ(1 + β)]^{n-k} - * k = num roots cut out of Z_H = 4 - */ - { - let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p) - let delta_numerator := delta_base - { - let exponent := mload(N_LOC) - let count := 1 - for {} lt(count, exponent) { count := add(count, count) } { - delta_numerator := mulmod(delta_numerator, delta_numerator, p) - } - } - mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator) - - let delta_denominator := mulmod(delta_base, delta_base, p) - delta_denominator := mulmod(delta_denominator, delta_denominator, p) - mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator) - } - /** - * Compute lagrange poly and vanishing poly fractions - */ - { - /** - * vanishing_numerator = zeta - * ZETA_POW_N = zeta^n - * vanishing_numerator -= 1 - * accumulating_root = omega_inverse - * work_root = p - accumulating_root - * domain_inverse = domain_inverse - * vanishing_denominator = zeta + work_root - * work_root *= accumulating_root - * vanishing_denominator *= (zeta + work_root) - * work_root *= accumulating_root - * vanishing_denominator *= (zeta + work_root) - * vanishing_denominator *= (zeta + (zeta + accumulating_root)) - * work_root = omega - * lagrange_numerator = vanishing_numerator * domain_inverse - * l_start_denominator = zeta - 1 - * accumulating_root = work_root^2 - * l_end_denominator = accumulating_root^2 * work_root * zeta - 1 - * Note: l_end_denominator term contains a term \omega^5 to cut out 5 roots of unity from vanishing poly - */ - - let zeta := mload(C_ZETA_LOC) - - // compute zeta^n, where n is a power of 2 - let vanishing_numerator := zeta - { - // pow_small - let exponent := mload(N_LOC) - let count := 1 - for {} lt(count, exponent) { count := add(count, count) } { - vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p) - } - } - mstore(ZETA_POW_N_LOC, vanishing_numerator) - vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p) - - let accumulating_root := mload(OMEGA_INVERSE_LOC) - let work_root := sub(p, accumulating_root) - let domain_inverse := mload(DOMAIN_INVERSE_LOC) - - let vanishing_denominator := addmod(zeta, work_root, p) - work_root := mulmod(work_root, accumulating_root, p) - vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p) - work_root := mulmod(work_root, accumulating_root, p) - vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p) - vanishing_denominator := - mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p) - - work_root := mload(OMEGA_LOC) - - let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p) - let l_start_denominator := addmod(zeta, sub(p, 1), p) - - accumulating_root := mulmod(work_root, work_root, p) - - let l_end_denominator := - addmod( - mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p - ) - - /** - * Compute inversions using Montgomery's batch inversion trick - */ - let accumulator := mload(DELTA_DENOMINATOR_LOC) - let t0 := accumulator - accumulator := mulmod(accumulator, vanishing_denominator, p) - let t1 := accumulator - accumulator := mulmod(accumulator, vanishing_numerator, p) - let t2 := accumulator - accumulator := mulmod(accumulator, l_start_denominator, p) - let t3 := accumulator - accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p) - let t4 := accumulator - { - mstore(0, 0x20) - mstore(0x20, 0x20) - mstore(0x40, 0x20) - mstore(0x60, mulmod(accumulator, l_end_denominator, p)) - mstore(0x80, sub(p, 2)) - mstore(0xa0, p) - if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) { - mstore(0x0, MOD_EXP_FAILURE_SELECTOR) - revert(0x00, 0x04) - } - accumulator := mload(0x00) - } - - t4 := mulmod(accumulator, t4, p) - accumulator := mulmod(accumulator, l_end_denominator, p) - - t3 := mulmod(accumulator, t3, p) - accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p) - - t2 := mulmod(accumulator, t2, p) - accumulator := mulmod(accumulator, l_start_denominator, p) - - t1 := mulmod(accumulator, t1, p) - accumulator := mulmod(accumulator, vanishing_numerator, p) - - t0 := mulmod(accumulator, t0, p) - accumulator := mulmod(accumulator, vanishing_denominator, p) - - accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p) - - mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p)) - mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p)) - mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p)) - mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p)) - mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p)) - mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p)) - } - - /** - * UltraPlonk Widget Ordering: - * - * 1. Permutation widget - * 2. Plookup widget - * 3. Arithmetic widget - * 4. Fixed base widget (?) - * 5. GenPermSort widget - * 6. Elliptic widget - * 7. Auxiliary widget - */ - - /** - * COMPUTE PERMUTATION WIDGET EVALUATION - */ - { - let alpha := mload(C_ALPHA_LOC) - let beta := mload(C_BETA_LOC) - let gamma := mload(C_GAMMA_LOC) - - /** - * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2) - * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4) - * result = alpha_base * z_eval * t1 * t2 - * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval) - * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval) - * result -= (alpha_base * z_omega_eval * t1 * t2) - */ - let t1 := - mulmod( - add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)), - add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)), - p - ) - let t2 := - mulmod( - add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)), - add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)), - p - ) - let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p) - t1 := - mulmod( - add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)), - add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)), - p - ) - t2 := - mulmod( - add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)), - add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)), - p - ) - result := - addmod( - result, - sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)), - p - ) - - /** - * alpha_base *= alpha - * result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI})) - * alpha_base *= alpha - * result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1)) - * alpha_Base *= alpha - */ - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) - result := - addmod( - result, - mulmod( - mload(C_ALPHA_BASE_LOC), - mulmod( - mload(L_END_LOC), - addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p), - p - ), - p - ), - p - ) - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) - mstore( - PERMUTATION_IDENTITY, - addmod( - result, - mulmod( - mload(C_ALPHA_BASE_LOC), - mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p), - p - ), - p - ) - ) - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) - } - - /** - * COMPUTE PLOOKUP WIDGET EVALUATION - */ - { - /** - * Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³ - * f = η.q3(z) - * f += (w3(z) + qc.w_3(zω)) - * f *= η - * f += (w2(z) + qm.w2(zω)) - * f *= η - * f += (w1(z) + q2.w1(zω)) - */ - let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p) - f := - addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p) - f := mulmod(f, mload(C_ETA_LOC), p) - f := - addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p) - f := mulmod(f, mload(C_ETA_LOC), p) - f := - addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p) - - // t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z) - let t := - addmod( - addmod( - addmod( - mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p), - mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p), - p - ), - mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p), - p - ), - mload(TABLE1_EVAL_LOC), - p - ) - - // t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw) - let t_omega := - addmod( - addmod( - addmod( - mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p), - mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p), - p - ), - mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p), - p - ), - mload(TABLE1_OMEGA_EVAL_LOC), - p - ) - - /** - * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1) - * gamma_beta_constant = γ(β + 1) - * numerator = f * TABLE_TYPE_EVAL + gamma - * temp0 = t(z) + t(zω) * β + gamma_beta_constant - * numerator *= temp0 - * numerator *= (β + 1) - * temp0 = alpha * l_1 - * numerator += temp0 - * numerator *= z_lookup(z) - * numerator -= temp0 - */ - let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p) - let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p) - let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p) - numerator := mulmod(numerator, temp0, p) - numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p) - temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p) - numerator := addmod(numerator, temp0, p) - numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p) - numerator := addmod(numerator, sub(p, temp0), p) - - /** - * Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z) - * note: delta_factor = [γ(1 + β)]^{n-k} - * denominator = s(z) + βs(zω) + γ(β + 1) - * temp1 = α²L_end(z) - * denominator -= temp1 - * denominator *= z_lookup(zω) - * denominator += temp1 * delta_factor - * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base - * alpha_base *= alpha^3 - */ - let denominator := - addmod( - addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p), - gamma_beta_constant, - p - ) - let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p) - denominator := addmod(denominator, sub(p, temp1), p) - denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p) - denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p) - - mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p)) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p)) - } - - /** - * COMPUTE ARITHMETIC WIDGET EVALUATION - */ - { - /** - * The basic arithmetic gate identity in standard plonk is as follows. - * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0 - * However, for Ultraplonk, we extend this to support "passing" wires between rows (shown without alpha scaling below): - * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) + - * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0 - * - * This formula results in several cases depending on q_arith: - * 1. q_arith == 0: Arithmetic gate is completely disabled - * - * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation - * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0 - * - * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is: - * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0 - * It allows defining w_4 at next index (w_4_omega) in terms of current wire values - * - * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split - * the equation into two: - * - * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0 - * and - * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here) - * - * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1). - * The equation can be split into two: - * - * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0 - * and - * w_1 + w_4 - w_1_omega + q_m = 0 - * - * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at - * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at - * product. - */ - - let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p) - let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p) - let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p) - let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p) - - // @todo - Add a explicit test that hits QARITH == 3 - // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2 - let w1w2qm := - mulmod( - mulmod( - mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p), - addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p), - p - ), - NEGATIVE_INVERSE_OF_2_MODULO_P, - p - ) - - // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c - let identity := - addmod( - mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p - ) - - // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where: - // w_1 + w_4 - w_1_omega + q_m = 0 - // we use this gate to save an addition gate when adding or subtracting non-native field elements - // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) - let extra_small_addition_gate_identity := - mulmod( - mload(C_ALPHA_LOC), - mulmod( - addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p), - addmod( - mload(QM_EVAL_LOC), - addmod( - sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p - ), - p - ), - p - ), - p - ) - - // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity - // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires! - // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity)) - mstore( - ARITHMETIC_IDENTITY, - mulmod( - mload(C_ALPHA_BASE_LOC), - mulmod( - mload(QARITH_EVAL_LOC), - addmod( - identity, - mulmod( - addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p), - addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p), - p - ), - p - ), - p - ), - p - ) - ) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p)) - } - - /** - * COMPUTE GENPERMSORT WIDGET EVALUATION - */ - { - /** - * D1 = (w2 - w1) - * D2 = (w3 - w2) - * D3 = (w4 - w3) - * D4 = (w1_omega - w4) - * - * α_a = alpha_base - * α_b = alpha_base * α - * α_c = alpha_base * α^2 - * α_d = alpha_base * α^3 - * - * range_accumulator = ( - * D1(D1 - 1)(D1 - 2)(D1 - 3).α_a + - * D2(D2 - 1)(D2 - 2)(D2 - 3).α_b + - * D3(D3 - 1)(D3 - 2)(D3 - 3).α_c + - * D4(D4 - 1)(D4 - 2)(D4 - 3).α_d + - * ) . q_sort - */ - let minus_two := sub(p, 2) - let minus_three := sub(p, 3) - let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p) - let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p) - let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p) - let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p) - - let range_accumulator := - mulmod( - mulmod( - mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p), - addmod(d1, minus_three, p), - p - ), - mload(C_ALPHA_BASE_LOC), - p - ) - range_accumulator := - addmod( - range_accumulator, - mulmod( - mulmod( - mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p), - addmod(d2, minus_three, p), - p - ), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), - p - ), - p - ) - range_accumulator := - addmod( - range_accumulator, - mulmod( - mulmod( - mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p), - addmod(d3, minus_three, p), - p - ), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p), - p - ), - p - ) - range_accumulator := - addmod( - range_accumulator, - mulmod( - mulmod( - mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p), - addmod(d4, minus_three, p), - p - ), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p), - p - ), - p - ) - range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p) - - mstore(SORT_IDENTITY, range_accumulator) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) - } - - /** - * COMPUTE ELLIPTIC WIDGET EVALUATION - */ - { - /** - * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta - * endo_sqr_term = x_2^2 - * endo_sqr_term *= (x_3 - x_1) - * endo_sqr_term *= q_beta^2 - * leftovers = x_2^2 - * leftovers *= x_2 - * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget - * leftovers -= (y_2^2 + y_1^2) - * sign_term = y_2 * y_1 - * sign_term += sign_term - * sign_term *= q_sign - */ - - let endo_term := - mulmod( - mulmod( - mulmod(sub(p, mload(X2_EVAL_LOC)), mload(X1_EVAL_LOC), p), - addmod(addmod(mload(X3_EVAL_LOC), mload(X3_EVAL_LOC), p), mload(X1_EVAL_LOC), p), - p - ), - mload(QBETA_LOC), - p - ) - - let endo_sqr_term := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p) - endo_sqr_term := mulmod(endo_sqr_term, addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), p) - endo_sqr_term := mulmod(endo_sqr_term, mload(QBETA_SQR_LOC), p) - - let leftovers := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p) - leftovers := mulmod(leftovers, mload(X2_EVAL_LOC), p) - leftovers := - addmod( - leftovers, - mulmod( - mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), - addmod(mload(X3_EVAL_LOC), mload(X1_EVAL_LOC), p), - p - ), - p - ) - leftovers := - addmod( - leftovers, - sub( - p, - addmod( - mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p), - mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p), - p - ) - ), - p - ) - - let sign_term := mulmod(mload(Y2_EVAL_LOC), mload(Y1_EVAL_LOC), p) - sign_term := addmod(sign_term, sign_term, p) - sign_term := mulmod(sign_term, mload(QSIGN_LOC), p) - - /** - * x_identity = endo_term + endo_sqr_term + sign_term + leftovers - * x_identity *= alpha_base - * endo_term = (x_2 * q_beta) * (y_3 + y_1) - * sign_term = -((y2 * q_sign) * (x_1 + x_3)) - * leftovers = - x1 * (y_3 + y_1) + y_1 * (x_1 - x_3) - * y_identity = (endo_term + sign_term + leftovers) * (alpha_base * α) - */ - - let x_identity := addmod(addmod(endo_term, endo_sqr_term, p), addmod(sign_term, leftovers, p), p) - x_identity := mulmod(x_identity, mload(C_ALPHA_BASE_LOC), p) - endo_term := - mulmod( - mulmod(mload(X2_EVAL_LOC), mload(QBETA_LOC), p), - addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), - p - ) - sign_term := - sub( - p, - mulmod( - mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), - addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), - p - ) - ) - leftovers := - addmod( - sub(p, mulmod(mload(X1_EVAL_LOC), addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), p)), - mulmod(mload(Y1_EVAL_LOC), addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p), - p - ) - let y_identity := - mulmod( - addmod(addmod(endo_term, sign_term, p), leftovers, p), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), - p - ) - - // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL - mstore(ELLIPTIC_IDENTITY, mulmod(addmod(x_identity, y_identity, p), mload(QELLIPTIC_EVAL_LOC), p)) - - // update alpha - // The paper says to use ALPHA^2, we use ALPHA^4 this is a small oversight in the prover protocol - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) - } - - /** - * COMPUTE AUXILIARY WIDGET EVALUATION - */ - { - { - /** - * Non native field arithmetic gate 2 - * _ _ - * / _ _ _ 14 \ - * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | - * \_ _/ - * - * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2 - * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega - * non_native_field_gate_2 = non_native_field_gate_2 * limb_size - * non_native_field_gate_2 -= w_4_omega - * non_native_field_gate_2 += limb_subproduct - * non_native_field_gate_2 *= q_4 - * limb_subproduct *= limb_size - * limb_subproduct += w_1_omega * w_2_omega - * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3 - * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m - * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2 - */ - - let limb_subproduct := - addmod( - mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), - mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p), - p - ) - - let non_native_field_gate_2 := - addmod( - addmod( - mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), - mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p), - p - ), - sub(p, mload(W3_OMEGA_EVAL_LOC)), - p - ) - non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p) - non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p) - non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p) - non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p) - limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p) - limb_subproduct := - addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p) - let non_native_field_gate_1 := - mulmod( - addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p), - mload(Q3_EVAL_LOC), - p - ) - let non_native_field_gate_3 := - mulmod( - addmod( - addmod(limb_subproduct, mload(W4_EVAL_LOC), p), - sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)), - p - ), - mload(QM_EVAL_LOC), - p - ) - let non_native_field_identity := - mulmod( - addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p), - mload(Q2_EVAL_LOC), - p - ) - - mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity) - } - - { - /** - * limb_accumulator_1 = w_2_omega; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_1_omega; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_3; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_2; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_1; - * limb_accumulator_1 -= w_4; - * limb_accumulator_1 *= q_4; - */ - let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p) - limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p) - - /** - * limb_accumulator_2 = w_3_omega; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_2_omega; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_1_omega; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_4; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_3; - * limb_accumulator_2 -= w_4_omega; - * limb_accumulator_2 *= q_m; - */ - let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p) - limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p) - - mstore( - AUX_LIMB_ACCUMULATOR_EVALUATION, - mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p) - ) - } - - { - /** - * memory_record_check = w_3; - * memory_record_check *= eta; - * memory_record_check += w_2; - * memory_record_check *= eta; - * memory_record_check += w_1; - * memory_record_check *= eta; - * memory_record_check += q_c; - * - * partial_record_check = memory_record_check; - * - * memory_record_check -= w_4; - */ - - let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p) - memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p) - memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p) - memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p) - memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p) - memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p) - - let partial_record_check := memory_record_check - memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p) - - mstore(AUX_MEMORY_EVALUATION, memory_record_check) - - // index_delta = w_1_omega - w_1 - let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p) - // record_delta = w_4_omega - w_4 - let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p) - // index_is_monotonically_increasing = index_delta * (index_delta - 1) - let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p) - - // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta) - let adjacent_values_match_if_adjacent_indices_match := - mulmod(record_delta, addmod(1, sub(p, index_delta), p), p) - - // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check - mstore( - AUX_ROM_CONSISTENCY_EVALUATION, - addmod( - mulmod( - addmod( - mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p), - index_is_monotonically_increasing, - p - ), - mload(C_ALPHA_LOC), - p - ), - memory_record_check, - p - ) - ) - - { - /** - * next_gate_access_type = w_3_omega; - * next_gate_access_type *= eta; - * next_gate_access_type += w_2_omega; - * next_gate_access_type *= eta; - * next_gate_access_type += w_1_omega; - * next_gate_access_type *= eta; - * next_gate_access_type = w_4_omega - next_gate_access_type; - */ - let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p) - next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p) - next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p) - next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p) - next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p) - next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p) - - // value_delta = w_3_omega - w_3 - let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p) - // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type); - - let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation := - mulmod( - addmod(1, sub(p, index_delta), p), - mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p), - p - ) - - // AUX_RAM_CONSISTENCY_EVALUATION - - /** - * access_type = w_4 - partial_record_check - * access_check = access_type^2 - access_type - * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type - * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - * RAM_consistency_check_identity *= alpha; - * RAM_consistency_check_identity += index_is_monotonically_increasing; - * RAM_consistency_check_identity *= alpha; - * RAM_consistency_check_identity += next_gate_access_type_is_boolean; - * RAM_consistency_check_identity *= alpha; - * RAM_consistency_check_identity += access_check; - */ - - let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p) - let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p) - let next_gate_access_type_is_boolean := - mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p) - let RAM_cci := - mulmod( - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation, - mload(C_ALPHA_LOC), - p - ) - RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p) - RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p) - RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p) - RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p) - RAM_cci := addmod(RAM_cci, access_check, p) - - mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci) - } - - { - // timestamp_delta = w_2_omega - w_2 - let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p) - - // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3 - let RAM_timestamp_check_identity := - addmod( - mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p - ) - - /** - * memory_identity = ROM_consistency_check_identity * q_2; - * memory_identity += RAM_timestamp_check_identity * q_4; - * memory_identity += memory_record_check * q_m; - * memory_identity *= q_1; - * memory_identity += (RAM_consistency_check_identity * q_arith); - * - * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; - * auxiliary_identity *= q_aux; - * auxiliary_identity *= alpha_base; - */ - let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p) - memory_identity := - addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p) - memory_identity := - addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p) - memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p) - memory_identity := - addmod( - memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p - ) - - let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p) - auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p) - auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p) - auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p) - - mstore(AUX_IDENTITY, auxiliary_identity) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p)) - } - } - } - - { - /** - * quotient = ARITHMETIC_IDENTITY - * quotient += PERMUTATION_IDENTITY - * quotient += PLOOKUP_IDENTITY - * quotient += SORT_IDENTITY - * quotient += ELLIPTIC_IDENTITY - * quotient += AUX_IDENTITY - * quotient *= ZERO_POLY_INVERSE - */ - mstore( - QUOTIENT_EVAL_LOC, - mulmod( - addmod( - addmod( - addmod( - addmod( - addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p), - mload(ARITHMETIC_IDENTITY), - p - ), - mload(SORT_IDENTITY), - p - ), - mload(ELLIPTIC_IDENTITY), - p - ), - mload(AUX_IDENTITY), - p - ), - mload(ZERO_POLY_INVERSE_LOC), - p - ) - ) - } - - /** - * GENERATE NU AND SEPARATOR CHALLENGES - */ - { - let current_challenge := mload(C_CURRENT_LOC) - // get a calldata pointer that points to the start of the data we want to copy - let calldata_ptr := add(calldataload(0x04), 0x24) - - calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH) - - mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge) - mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC)) - calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH) - - // hash length = (0x20 + num field elements), we include the previous challenge in the hash - let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40)) - - mstore(C_V0_LOC, mod(challenge, p)) - // We need THIRTY-ONE independent nu challenges! - mstore(0x00, challenge) - mstore8(0x20, 0x01) - mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x02) - mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x03) - mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x04) - mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x05) - mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x06) - mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x07) - mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x08) - mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x09) - mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0a) - mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0b) - mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0c) - mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0d) - mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0e) - mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0f) - mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x10) - mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x11) - mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x12) - mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x13) - mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x14) - mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x15) - mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x16) - mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x17) - mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x18) - mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x19) - mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1a) - mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1b) - mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1c) - mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1d) - mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p)) - - // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change? - mstore8(0x20, 0x1d) - challenge := keccak256(0x00, 0x21) - mstore(C_V30_LOC, mod(challenge, p)) - - // separator - mstore(0x00, challenge) - mstore(0x20, mload(PI_Z_Y_LOC)) - mstore(0x40, mload(PI_Z_X_LOC)) - mstore(0x60, mload(PI_Z_OMEGA_Y_LOC)) - mstore(0x80, mload(PI_Z_OMEGA_X_LOC)) - - mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p)) - } - - let success := 0 - // VALIDATE T1 - { - let x := mload(T1_X_LOC) - let y := mload(T1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) - mstore(ACCUMULATOR_X_LOC, x) - mstore(add(ACCUMULATOR_X_LOC, 0x20), y) - } - // VALIDATE T2 - { - let x := mload(T2_X_LOC) // 0x1400 - let y := mload(T2_Y_LOC) // 0x1420 - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(ZETA_POW_N_LOC)) - // accumulator_2 = [T2].zeta^n - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = [T1] + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE T3 - { - let x := mload(T3_X_LOC) - let y := mload(T3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p)) - // accumulator_2 = [T3].zeta^{2n} - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE T4 - { - let x := mload(T4_X_LOC) - let y := mload(T4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p)) - // accumulator_2 = [T4].zeta^{3n} - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W1 - { - let x := mload(W1_X_LOC) - let y := mload(W1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p)) - // accumulator_2 = v0.(u + 1).[W1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W2 - { - let x := mload(W2_X_LOC) - let y := mload(W2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p)) - // accumulator_2 = v1.(u + 1).[W2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W3 - { - let x := mload(W3_X_LOC) - let y := mload(W3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p)) - // accumulator_2 = v2.(u + 1).[W3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W4 - { - let x := mload(W4_X_LOC) - let y := mload(W4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p)) - // accumulator_2 = v3.(u + 1).[W4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE S - { - let x := mload(S_X_LOC) - let y := mload(S_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p)) - // accumulator_2 = v4.(u + 1).[S] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Z - { - let x := mload(Z_X_LOC) - let y := mload(Z_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p)) - // accumulator_2 = v5.(u + 1).[Z] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Z_LOOKUP - { - let x := mload(Z_LOOKUP_X_LOC) - let y := mload(Z_LOOKUP_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p)) - // accumulator_2 = v6.(u + 1).[Z_LOOKUP] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q1 - { - let x := mload(Q1_X_LOC) - let y := mload(Q1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V7_LOC)) - // accumulator_2 = v7.[Q1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q2 - { - let x := mload(Q2_X_LOC) - let y := mload(Q2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V8_LOC)) - // accumulator_2 = v8.[Q2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q3 - { - let x := mload(Q3_X_LOC) - let y := mload(Q3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V9_LOC)) - // accumulator_2 = v9.[Q3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q4 - { - let x := mload(Q4_X_LOC) - let y := mload(Q4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V10_LOC)) - // accumulator_2 = v10.[Q4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QM - { - let x := mload(QM_X_LOC) - let y := mload(QM_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V11_LOC)) - // accumulator_2 = v11.[Q;] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QC - { - let x := mload(QC_X_LOC) - let y := mload(QC_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V12_LOC)) - // accumulator_2 = v12.[QC] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QARITH - { - let x := mload(QARITH_X_LOC) - let y := mload(QARITH_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V13_LOC)) - // accumulator_2 = v13.[QARITH] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QSORT - { - let x := mload(QSORT_X_LOC) - let y := mload(QSORT_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V14_LOC)) - // accumulator_2 = v14.[QSORT] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QELLIPTIC - { - let x := mload(QELLIPTIC_X_LOC) - let y := mload(QELLIPTIC_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V15_LOC)) - // accumulator_2 = v15.[QELLIPTIC] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QAUX - { - let x := mload(QAUX_X_LOC) - let y := mload(QAUX_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V16_LOC)) - // accumulator_2 = v15.[Q_AUX] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA1 - { - let x := mload(SIGMA1_X_LOC) - let y := mload(SIGMA1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V17_LOC)) - // accumulator_2 = v17.[sigma1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA2 - { - let x := mload(SIGMA2_X_LOC) - let y := mload(SIGMA2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V18_LOC)) - // accumulator_2 = v18.[sigma2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA3 - { - let x := mload(SIGMA3_X_LOC) - let y := mload(SIGMA3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V19_LOC)) - // accumulator_2 = v19.[sigma3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA4 - { - let x := mload(SIGMA4_X_LOC) - let y := mload(SIGMA4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V20_LOC)) - // accumulator_2 = v20.[sigma4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE1 - { - let x := mload(TABLE1_X_LOC) - let y := mload(TABLE1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p)) - // accumulator_2 = u.[table1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE2 - { - let x := mload(TABLE2_X_LOC) - let y := mload(TABLE2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p)) - // accumulator_2 = u.[table2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE3 - { - let x := mload(TABLE3_X_LOC) - let y := mload(TABLE3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p)) - // accumulator_2 = u.[table3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE4 - { - let x := mload(TABLE4_X_LOC) - let y := mload(TABLE4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p)) - // accumulator_2 = u.[table4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE_TYPE - { - let x := mload(TABLE_TYPE_X_LOC) - let y := mload(TABLE_TYPE_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V25_LOC)) - // accumulator_2 = v25.[TableType] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID1 - { - let x := mload(ID1_X_LOC) - let y := mload(ID1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V26_LOC)) - // accumulator_2 = v26.[ID1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID2 - { - let x := mload(ID2_X_LOC) - let y := mload(ID2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V27_LOC)) - // accumulator_2 = v27.[ID2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID3 - { - let x := mload(ID3_X_LOC) - let y := mload(ID3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V28_LOC)) - // accumulator_2 = v28.[ID3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID4 - { - let x := mload(ID4_X_LOC) - let y := mload(ID4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V29_LOC)) - // accumulator_2 = v29.[ID4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - /** - * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER - */ - { - /** - * batch_evaluation = v0 * (w_1_omega * u + w_1_eval) - * batch_evaluation += v1 * (w_2_omega * u + w_2_eval) - * batch_evaluation += v2 * (w_3_omega * u + w_3_eval) - * batch_evaluation += v3 * (w_4_omega * u + w_4_eval) - * batch_evaluation += v4 * (s_omega_eval * u + s_eval) - * batch_evaluation += v5 * (z_omega_eval * u + z_eval) - * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval) - */ - let batch_evaluation := - mulmod( - mload(C_V0_LOC), - addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V1_LOC), - addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V2_LOC), - addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V3_LOC), - addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V4_LOC), - addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V5_LOC), - addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V6_LOC), - addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p), - p - ), - p - ) - - /** - * batch_evaluation += v7 * Q1_EVAL - * batch_evaluation += v8 * Q2_EVAL - * batch_evaluation += v9 * Q3_EVAL - * batch_evaluation += v10 * Q4_EVAL - * batch_evaluation += v11 * QM_EVAL - * batch_evaluation += v12 * QC_EVAL - * batch_evaluation += v13 * QARITH_EVAL - * batch_evaluation += v14 * QSORT_EVAL_LOC - * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC - * batch_evaluation += v16 * QAUX_EVAL_LOC - * batch_evaluation += v17 * SIGMA1_EVAL_LOC - * batch_evaluation += v18 * SIGMA2_EVAL_LOC - * batch_evaluation += v19 * SIGMA3_EVAL_LOC - * batch_evaluation += v20 * SIGMA4_EVAL_LOC - */ - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p) - - /** - * batch_evaluation += v21 * (table1(zw) * u + table1(z)) - * batch_evaluation += v22 * (table2(zw) * u + table2(z)) - * batch_evaluation += v23 * (table3(zw) * u + table3(z)) - * batch_evaluation += v24 * (table4(zw) * u + table4(z)) - * batch_evaluation += v25 * table_type_eval - * batch_evaluation += v26 * id1_eval - * batch_evaluation += v27 * id2_eval - * batch_evaluation += v28 * id3_eval - * batch_evaluation += v29 * id4_eval - * batch_evaluation += quotient_eval - */ - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V21_LOC), - addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V22_LOC), - addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V23_LOC), - addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V24_LOC), - addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p) - - mstore(0x00, 0x01) // [1].x - mstore(0x20, 0x02) // [1].y - mstore(0x40, sub(p, batch_evaluation)) - // accumulator_2 = -[1].(batch_evaluation) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success) - } - - /** - * PERFORM PAIRING PREAMBLE - */ - { - let u := mload(C_U_LOC) - let zeta := mload(C_ZETA_LOC) - // VALIDATE PI_Z - { - let x := mload(PI_Z_X_LOC) - let y := mload(PI_Z_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) - mstore(0x00, x) - mstore(0x20, y) - } - // compute zeta.[PI_Z] and add into accumulator - mstore(0x40, zeta) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE PI_Z_OMEGA - { - let x := mload(PI_Z_OMEGA_X_LOC) - let y := mload(PI_Z_OMEGA_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p)) - // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // PAIRING_RHS = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40)) - - mstore(0x00, mload(PI_Z_X_LOC)) - mstore(0x20, mload(PI_Z_Y_LOC)) - mstore(0x40, mload(PI_Z_OMEGA_X_LOC)) - mstore(0x60, mload(PI_Z_OMEGA_Y_LOC)) - mstore(0x80, u) - success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40)) - // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u - success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40)) - // negate lhs y-coordinate - mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC))) - - if mload(CONTAINS_RECURSIVE_PROOF_LOC) { - // VALIDATE RECURSIVE P1 - { - let x := mload(RECURSIVE_P1_X_LOC) - let y := mload(RECURSIVE_P1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - - // compute u.u.[recursive_p1] and write into 0x60 - mstore(0x40, mulmod(u, u, p)) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40)) - // VALIDATE RECURSIVE P2 - { - let x := mload(RECURSIVE_P2_X_LOC) - let y := mload(RECURSIVE_P2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - // compute u.u.[recursive_p2] and write into 0x00 - // 0x40 still contains u*u - success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40)) - - // compute u.u.[recursiveP1] + rhs and write into rhs - mstore(0xa0, mload(PAIRING_RHS_X_LOC)) - mstore(0xc0, mload(PAIRING_RHS_Y_LOC)) - success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40)) - - // compute u.u.[recursiveP2] + lhs and write into lhs - mstore(0x40, mload(PAIRING_LHS_X_LOC)) - mstore(0x60, mload(PAIRING_LHS_Y_LOC)) - success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40)) - } - - if iszero(success) { - mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR) - revert(0x00, 0x04) - } - mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success) - } - - /** - * PERFORM PAIRING - */ - { - // rhs paired with [1]_2 - // lhs paired with [x]_2 - - mstore(0x00, mload(PAIRING_RHS_X_LOC)) - mstore(0x20, mload(PAIRING_RHS_Y_LOC)) - mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2 - mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) - - mstore(0xc0, mload(PAIRING_LHS_X_LOC)) - mstore(0xe0, mload(PAIRING_LHS_Y_LOC)) - mstore(0x100, mload(G2X_X0_LOC)) - mstore(0x120, mload(G2X_X1_LOC)) - mstore(0x140, mload(G2X_Y0_LOC)) - mstore(0x160, mload(G2X_Y1_LOC)) - - success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20) - mstore(PAIRING_SUCCESS_FLAG, success) - mstore(RESULT_FLAG, mload(0x00)) - } - if iszero( - and( - and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)), - mload(OPENING_COMMITMENT_SUCCESS_FLAG) - ) - ) { - mstore(0x0, PROOF_FAILURE_SELECTOR) - revert(0x00, 0x04) - } - { - mstore(0x00, 0x01) - return(0x00, 0x20) // Proof succeeded! - } - } - } -} - -contract UltraVerifier is BaseUltraVerifier { - function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) { - return UltraVerificationKey.verificationKeyHash(); - } - - function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) { - UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc); - } -} diff --git a/next-hardhat/test/index.test.ts b/next-hardhat/test/index.test.ts index dccfcd3..41ac065 100644 --- a/next-hardhat/test/index.test.ts +++ b/next-hardhat/test/index.test.ts @@ -6,7 +6,7 @@ import { NoirNode } from '../utils/noir/noirNode'; import { execSync } from 'child_process'; const noir = new NoirNode(); -import verifier from '../artifacts/circuits/contract/noirstarter/plonk_vk.sol/UltraVerifier.json'; +import verifier from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; import { test, beforeAll, describe } from 'vitest'; diff --git a/next-hardhat/utils/addresses.json b/next-hardhat/utils/addresses.json index d2f6e46..992a9f2 100644 --- a/next-hardhat/utils/addresses.json +++ b/next-hardhat/utils/addresses.json @@ -1 +1 @@ -{"chainId":80001,"verifier":"0x75B9cBF10AeD42676465BE6552648cF02150D300"} \ No newline at end of file +{"chainId":31337,"verifier":"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"} \ No newline at end of file diff --git a/next-hardhat/utils/ethers.tsx b/next-hardhat/utils/ethers.tsx index 009d6d9..56bcbe7 100644 --- a/next-hardhat/utils/ethers.tsx +++ b/next-hardhat/utils/ethers.tsx @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; import addresses from './addresses.json'; -import artifacts from '../artifacts/circuits/contract/noirstarter/plonk_vk.sol/UltraVerifier.json'; +import artifacts from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; import { toast } from 'react-toastify'; declare global { diff --git a/with-foundry/.env.example b/with-foundry/.env.example deleted file mode 100644 index 51f4019..0000000 --- a/with-foundry/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -ANVIL_RPC= -PRIVATE_KEY= -SEPOLIA_RPC=https://rpc2.sepolia.org From a8afe608bd9d8f98eeee269d1cbd6c8ccc7d5d35 Mon Sep 17 00:00:00 2001 From: Savio-Sou <72797635+Savio-Sou@users.noreply.github.com> Date: Tue, 15 Aug 2023 17:36:06 +0900 Subject: [PATCH 02/10] Merge origin/main into branch --- next-hardhat/components/component.tsx | 6 ++-- next-hardhat/utils/addresses.json | 2 +- next-hardhat/utils/noir/noirNode.ts | 2 +- with-foundry/README.md | 45 ++++++++++++++++++--------- with-foundry/circuits/Nargo.toml | 6 ++-- with-foundry/test/Starter.t.sol | 32 +++++++++---------- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/next-hardhat/components/component.tsx b/next-hardhat/components/component.tsx index aa9002f..8ad53c5 100644 --- a/next-hardhat/components/component.tsx +++ b/next-hardhat/components/component.tsx @@ -8,7 +8,7 @@ import { NoirBrowser } from '../utils/noir/noirBrowser'; import { ThreeDots } from 'react-loader-spinner'; function Component() { - const [input, setInput] = useState({ x: '', y: '' }); + const [input, setInput] = useState({ x: 0, y: 0}); const [pending, setPending] = useState(false); const [proof, setProof] = useState(Uint8Array.from([])); const [verification, setVerification] = useState(false); @@ -89,8 +89,8 @@ function Component() {

Example starter

This circuit checks that x and y are different

Try it!

- - + + {pending && } diff --git a/next-hardhat/utils/addresses.json b/next-hardhat/utils/addresses.json index 992a9f2..7360904 100644 --- a/next-hardhat/utils/addresses.json +++ b/next-hardhat/utils/addresses.json @@ -1 +1 @@ -{"chainId":31337,"verifier":"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"} \ No newline at end of file +{"chainId":31337,"verifier":"0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"} \ No newline at end of file diff --git a/next-hardhat/utils/noir/noirNode.ts b/next-hardhat/utils/noir/noirNode.ts index a8af993..075f5a3 100644 --- a/next-hardhat/utils/noir/noirNode.ts +++ b/next-hardhat/utils/noir/noirNode.ts @@ -45,7 +45,7 @@ export class NoirNode { this.acirComposer = await this.api.acirNewAcirComposer(subgroupSize); } - async generateWitness(input: any, acirBuffer: Buffer): Promise { + async generateWitness(input: any): 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)); diff --git a/with-foundry/README.md b/with-foundry/README.md index d9674e6..197be57 100644 --- a/with-foundry/README.md +++ b/with-foundry/README.md @@ -6,7 +6,8 @@ This example uses Foundry to deploy and test a verifier. ### Install nargo -Follow the [Noir Docs](https://noir-lang.org/getting_started/nargo_installation) to install nargo. For this template, ensure you're on UltraPlonk versions (at least 0.5.0). +Follow the [Noir Docs](https://noir-lang.org/getting_started/nargo_installation) to install nargo. +For this template, ensure you're using Noir version 0.9.0. You can install with `noirup -v 0.9.0`. ### Install foundryup @@ -16,7 +17,8 @@ run curl -L https://foundry.paradigm.xyz | bash ``` -and follow the instructions on screen. You should then have all the foundry tools like `forge`, `cast`, `anvil` and `chisel`. +and follow the instructions on screen. You should then have all the foundry tools like `forge`, +`cast`, `anvil` and `chisel`. ### Generate verifier contract and proof @@ -33,7 +35,8 @@ A file named `plonk_vk.sol` should appear in the `circuits` 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 prove` by +itself. For this, ensure your prover parameters are correct in `Prover.toml` and run: ```bash nargo prove p @@ -43,9 +46,14 @@ A file named `p.proof` should appear in the `proofs` folder. ### Test with Foundry -We're ready to test with Foundry. There's a basic test inside the `test` folder that deploys the verifier contract, the `Starter` contract and two bytes32 arrays correspondent to good and bad solutions to your circuit. +We're ready to test with Foundry. There's a basic test inside the `test` folder that deploys the +verifier contract, the `Starter` contract and two bytes32 arrays correspondent to good and bad +solutions to your circuit. -By running the following command, forge will compile the contract with 5000 rounds of optimization and the London EVM version. __You need to use these optimizer settings to supress the "stack too deep" error on the solc compiler__. Then it will run the test, expecting it to pass with correct inputs, and fail with wrong inputs: +By running the following command, forge will compile the contract with 5000 rounds of optimization +and the London EVM version. **You need to use these optimizer settings to supress the "stack too +deep" error on the solc compiler**. Then it will run the test, expecting it to pass with correct +inputs, and fail with wrong inputs: ```bash forge test --optimize --optimizer-runs 5000 --evm-version london @@ -53,19 +61,23 @@ forge test --optimize --optimizer-runs 5000 --evm-version london #### Testing On-chain -You can test that the Noir Solidity verifier contract works on a given chain by running the `Verify.s.sol` script against the appropriate RPC endpoint. +You can test that the Noir Solidity verifier contract works on a given chain by running the +`Verify.s.sol` script against the appropriate RPC endpoint. ```bash -forge script script/Verify.s.sol --rpc-url $RPC_ENDPOINT --broadcast +forge script script/Verify.s.sol --rpc-url $RPC_ENDPOINT --broadcast ``` -If that doesn't work, you can add the network to Metamask and deploy and test via [Remix](https://remix.ethereum.org/). +If that doesn't work, you can add the network to Metamask and deploy and test via +[Remix](https://remix.ethereum.org/). -Note that some EVM network infrastructure may behave differently and this script may fail for reasons unrelated to the compatibility of the verifier contract. +Note that some EVM network infrastructure may behave differently and this script may fail for +reasons unrelated to the compatibility of the verifier contract. ### Deploy with Foundry -This template also has a script to help you deploy on your own network. But for that you need to run your own node or, alternatively, deploy on a testnet. +This template also has a script to help you deploy on your own network. But for that you need to run +your own node or, alternatively, deploy on a testnet. #### (Option 1) Run a local node @@ -75,7 +87,8 @@ If you want to deploy locally, run a node by opening a terminal and running anvil ``` -This should start a local node listening on `http://localhost:8545`. It will also give you many private keys. +This should start a local node listening on `http://localhost:8545`. It will also give you many +private keys. Edit your `.env` file to look like: @@ -86,7 +99,8 @@ PRIVATE_KEY= #### (Option 2) Prepare for testnet -Pick a testnet like Sepolia or Goerli. Generate a private key and use a faucet (like [this one for Sepolia](https://sepoliafaucet.com/)) to get some coins in there. +Pick a testnet like Sepolia or Goerli. Generate a private key and use a faucet (like +[this one for Sepolia](https://sepoliafaucet.com/)) to get some coins in there. Edit your `.env` file to look like: @@ -113,6 +127,9 @@ Replace `$ANVIL_RPC` with the testnet RPC, if you're deploying on a testnet. ## Developing on this template -This template doesn't include settings you may need to deal with syntax highlighting and IDE-specific settings (i.e. VScode). Please follow the instructions on the [Foundy book](https://book.getfoundry.sh/config/vscode) to set that up. +This template doesn't include settings you may need to deal with syntax highlighting and +IDE-specific settings (i.e. VScode). Please follow the instructions on the +[Foundy book](https://book.getfoundry.sh/config/vscode) to set that up. -It's __highly recommended__ you get familiar with [Foundry](https://book.getfoundry.sh) before developing on this template. +It's **highly recommended** you get familiar with [Foundry](https://book.getfoundry.sh) before +developing on this template. diff --git a/with-foundry/circuits/Nargo.toml b/with-foundry/circuits/Nargo.toml index 65ab14d..8698f93 100644 --- a/with-foundry/circuits/Nargo.toml +++ b/with-foundry/circuits/Nargo.toml @@ -1,5 +1,7 @@ [package] -authors = [""] -compiler_version = "0.4.1" +name="with_foundry" +type="bin" +authors = ["critesjosh"] +compiler_version = "~0.9.0" [dependencies] \ No newline at end of file diff --git a/with-foundry/test/Starter.t.sol b/with-foundry/test/Starter.t.sol index 57b60f5..9fbc14a 100644 --- a/with-foundry/test/Starter.t.sol +++ b/with-foundry/test/Starter.t.sol @@ -11,7 +11,6 @@ contract StarterTest is Test { bytes32[] public dynamicCorrect = new bytes32[](1); bytes32[] public correct = new bytes32[](1); bytes32[] public wrong = new bytes32[](1); - function setUp() public { verifier = new UltraVerifier(); @@ -45,7 +44,7 @@ contract StarterTest is Test { // Set expected dynamic proof outcome dynamicCorrect[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000005); - bytes memory proofBytes = generateDynamicProof("test1",_fieldNames,_fieldValues); + bytes memory proofBytes = generateDynamicProof("test1", _fieldNames, _fieldValues); starter.verifyEqual(proofBytes, dynamicCorrect); } @@ -60,7 +59,7 @@ contract StarterTest is Test { // Set expected dynamic proof outcome dynamicCorrect[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000008); - bytes memory proofBytes = generateDynamicProof("test2",_fieldNames,_fieldValues); + bytes memory proofBytes = generateDynamicProof("test2", _fieldNames, _fieldValues); starter.verifyEqual(proofBytes, dynamicCorrect); } @@ -75,30 +74,32 @@ contract StarterTest is Test { // Set expected dynamic proof outcome dynamicCorrect[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000007); - bytes memory proofBytes = generateDynamicProof("test3",_fieldNames,_fieldValues); + bytes memory proofBytes = generateDynamicProof("test3", _fieldNames, _fieldValues); starter.verifyEqual(proofBytes, dynamicCorrect); } /// @dev This function generates dynamic proofs using 2 scripts in the /script directory - /// + /// /// @param _testName a random string to identify the test by, this is used to create a unique folder name in the /tmp directory /// @param _fields The field names within the Prover.toml file /// @param _fieldValues The field values associated with fields names within the Prover.toml file - function generateDynamicProof(string memory _testName,string[] memory _fields, string[] memory _fieldValues) public returns (bytes memory) { - require(_fields.length == _fieldValues.length,"generateProof: Input arrays not the same length"); - + function generateDynamicProof(string memory _testName, string[] memory _fields, string[] memory _fieldValues) + public + returns (bytes memory) + { + require(_fields.length == _fieldValues.length, "generateProof: Input arrays not the same length"); + // Copy files and create Prover.toml in /tmp directory string[] memory filecreateCommand = new string[] (2); filecreateCommand[0] = "./script/createFile.sh"; filecreateCommand[1] = _testName; bytes memory fileCreateResponse = vm.ffi(filecreateCommand); console.log(string(fileCreateResponse)); - - string memory _file = string.concat("/tmp/",_testName,"/Prover.toml"); - vm.writeFile(_file,""); - for(uint256 i; i < _fields.length; i++) - { - vm.writeLine(_file, string.concat( _fields[i] , " = " , _fieldValues[i])); + + string memory _file = string.concat("/tmp/", _testName, "/Prover.toml"); + vm.writeFile(_file, ""); + for (uint256 i; i < _fields.length; i++) { + vm.writeLine(_file, string.concat(_fields[i], " = ", _fieldValues[i])); } // now generate the proof by calling the script using ffi @@ -107,8 +108,7 @@ 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/d.proof")); + string memory _newProof = vm.readLine(string.concat("/tmp/", _testName, "/proofs/d.proof")); return vm.parseBytes(_newProof); - } } From 7ddfcc000b20a697124aad4df4cf92a0972b9144 Mon Sep 17 00:00:00 2001 From: Savio-Sou <72797635+Savio-Sou@users.noreply.github.com> Date: Tue, 15 Aug 2023 17:44:57 +0900 Subject: [PATCH 03/10] Restore foundry's .env.example --- with-foundry/.env.example | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 with-foundry/.env.example diff --git a/with-foundry/.env.example b/with-foundry/.env.example new file mode 100644 index 0000000..26409ff --- /dev/null +++ b/with-foundry/.env.example @@ -0,0 +1,3 @@ +ANVIL_RPC= +PRIVATE_KEY= +SEPOLIA_RPC=https://rpc2.sepolia.org \ No newline at end of file From c94f38922fc51c962fa93e07ed440562339e1c07 Mon Sep 17 00:00:00 2001 From: Savio-Sou <72797635+Savio-Sou@users.noreply.github.com> Date: Tue, 15 Aug 2023 17:58:06 +0900 Subject: [PATCH 04/10] Lock bb.js and acvm_js versions --- next-hardhat/package.json | 4 ++-- next-hardhat/yarn.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/next-hardhat/package.json b/next-hardhat/package.json index ceb7624..1dfdf1d 100644 --- a/next-hardhat/package.json +++ b/next-hardhat/package.json @@ -10,8 +10,8 @@ "test": "hardhat compile && vitest" }, "dependencies": { - "@aztec/bb.js": "^0.3.5", - "@noir-lang/acvm_js": "git+https://github.com/noir-lang/acvm-simulator-wasm.git", + "@aztec/bb.js": "0.3.6", + "@noir-lang/acvm_js": "git+https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42", "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", "@nomicfoundation/hardhat-toolbox": "^2.0.1", diff --git a/next-hardhat/yarn.lock b/next-hardhat/yarn.lock index d8ce1a7..9138e20 100644 --- a/next-hardhat/yarn.lock +++ b/next-hardhat/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@aztec/bb.js@^0.3.5": +"@aztec/bb.js@0.3.6": version "0.3.6" resolved "https://registry.yarnpkg.com/@aztec/bb.js/-/bb.js-0.3.6.tgz#8865d119c0292291aef6f65250b5418d71bf12cb" integrity sha512-7s/SZ3k5R1wfnVoU6sz9BBxBaI7ubkXPnvsI2KsJso2J2pwbXGxJsfOzn+uol+v3ZPooIa84/+SHk3UaPbMJGw== @@ -790,9 +790,9 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@noir-lang/acvm_js@git+https://github.com/noir-lang/acvm-simulator-wasm.git": +"@noir-lang/acvm_js@git+https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42": version "0.0.0-d576736" - resolved "git+https://github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42" + resolved "git+https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42" "@nomicfoundation/ethereumjs-block@5.0.1": version "5.0.1" From cc77900c46b8e042e75a7e0c0f65219c53e53403 Mon Sep 17 00:00:00 2001 From: Savio-Sou <72797635+Savio-Sou@users.noreply.github.com> Date: Tue, 15 Aug 2023 18:40:25 +0900 Subject: [PATCH 05/10] Update instructions for nightly Nargo support --- next-hardhat/README.md | 23 +++++++++++++++++------ next-hardhat/test/index.test.ts | 2 +- next-hardhat/utils/ethers.tsx | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/next-hardhat/README.md b/next-hardhat/README.md index 7be3bac..a5a3bf0 100644 --- a/next-hardhat/README.md +++ b/next-hardhat/README.md @@ -12,13 +12,24 @@ It also features multiple files and different entry points by resolving multiple 1. [Install Node.js ≥v18](https://nodejs.org/en) (tested on v18.17.0) -2. [Install Nix](https://noir-lang.org/getting_started/nargo_installation#installing-nix) +2. [Install noirup](https://noir-lang.org/getting_started/nargo_installation/#option-1-noirup) -3. Install Nargo with +3. Install nightly Nargo with -```bash -nix profile install github:noir-lang/noir/ad118eb8165ef83402e25b3001dfe27cf3a358b1 -``` + ```bash + noirup -n + ``` + + > If you're later faced with Noir <> ACVM <> bb.js incomaptibility issues, install Nargo from the + > tested commit instead: + > + > 1. [Install Nix](https://noir-lang.org/getting_started/nargo_installation#installing-nix) + > + > 2. Install Nargo with + > + > ```bash + > nix profile install github:noir-lang/noir/7d0178987641f5cb8f8e95507c54c3cc367bf7d2 + > ``` 4. Install dependencies with @@ -43,7 +54,7 @@ nargo codegen-verifier Compile your circuits with ```bash -nargo compile noirstarter +nargo compile ``` ## Testing locally diff --git a/next-hardhat/test/index.test.ts b/next-hardhat/test/index.test.ts index 41ac065..dccfcd3 100644 --- a/next-hardhat/test/index.test.ts +++ b/next-hardhat/test/index.test.ts @@ -6,7 +6,7 @@ import { NoirNode } from '../utils/noir/noirNode'; import { execSync } from 'child_process'; const noir = new NoirNode(); -import verifier from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; +import verifier from '../artifacts/circuits/contract/noirstarter/plonk_vk.sol/UltraVerifier.json'; import { test, beforeAll, describe } from 'vitest'; diff --git a/next-hardhat/utils/ethers.tsx b/next-hardhat/utils/ethers.tsx index 56bcbe7..009d6d9 100644 --- a/next-hardhat/utils/ethers.tsx +++ b/next-hardhat/utils/ethers.tsx @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; import addresses from './addresses.json'; -import artifacts from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; +import artifacts from '../artifacts/circuits/contract/noirstarter/plonk_vk.sol/UltraVerifier.json'; import { toast } from 'react-toastify'; declare global { From e7684b8cdb67ac68ae2fe5f7877e16c036167321 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Tue, 15 Aug 2023 14:27:34 -0400 Subject: [PATCH 06/10] update to include files expected by tests --- next-hardhat/.gitignore | 2 - next-hardhat/README.md | 10 +- .../contract/noirstarter/plonk_vk.sol | 2611 +++++++++++++++++ 3 files changed, 2613 insertions(+), 10 deletions(-) create mode 100644 next-hardhat/circuits/contract/noirstarter/plonk_vk.sol diff --git a/next-hardhat/.gitignore b/next-hardhat/.gitignore index a769f2c..8dc8dcc 100644 --- a/next-hardhat/.gitignore +++ b/next-hardhat/.gitignore @@ -47,8 +47,6 @@ proofs # noir crs -circuits/target -circuits/contract # other .vscode diff --git a/next-hardhat/README.md b/next-hardhat/README.md index a5a3bf0..c18bf80 100644 --- a/next-hardhat/README.md +++ b/next-hardhat/README.md @@ -14,15 +14,9 @@ It also features multiple files and different entry points by resolving multiple 2. [Install noirup](https://noir-lang.org/getting_started/nargo_installation/#option-1-noirup) -3. Install nightly Nargo with +3. Install Nargo with the following instructions. We are working on a stable release that is + maintains compatibility across packages and will make it easier to install these packages. - ```bash - noirup -n - ``` - - > If you're later faced with Noir <> ACVM <> bb.js incomaptibility issues, install Nargo from the - > tested commit instead: - > > 1. [Install Nix](https://noir-lang.org/getting_started/nargo_installation#installing-nix) > > 2. Install Nargo with diff --git a/next-hardhat/circuits/contract/noirstarter/plonk_vk.sol b/next-hardhat/circuits/contract/noirstarter/plonk_vk.sol new file mode 100644 index 0000000..97fbbe3 --- /dev/null +++ b/next-hardhat/circuits/contract/noirstarter/plonk_vk.sol @@ -0,0 +1,2611 @@ +// Verification Key Hash: 5bd9df07721ff64c4d2a2dbd1f1969287d0c790df883df7af4114b5956c1e411 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +library UltraVerificationKey { + function verificationKeyHash() internal pure returns(bytes32) { + return 0x5bd9df07721ff64c4d2a2dbd1f1969287d0c790df883df7af4114b5956c1e411; + } + + function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { + assembly { + mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000010) // vk.circuit_size + mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000001) // vk.num_inputs + mstore(add(_vk, 0x40), 0x21082ca216cbbf4e1c6e4f4594dd508c996dfbe1174efb98b11509c6e306460b) // vk.work_root + mstore(add(_vk, 0x60), 0x2d5e098bb31e86271ccb415b196942d755b0a9c3f21dd9882fa3d63ab1000001) // vk.domain_inverse + mstore(add(_vk, 0x80), 0x17c660f12bd58e45a1161d687125bcf3e50db901cd031ae90fa0f899c5f6b0af) // vk.Q1.x + mstore(add(_vk, 0xa0), 0x18431833019d0b6edd508ef905b14dc5489f7392ae6ac1e78785eeaf36dc198e) // vk.Q1.y + mstore(add(_vk, 0xc0), 0x0e0b6d8dd8f37229da396ea6af4d0950760cb8b36391ed9babf2816005d98431) // vk.Q2.x + mstore(add(_vk, 0xe0), 0x023976dee62b72746539eca15a1b803d7aa47b5e13143d496e96b90fb399ac70) // vk.Q2.y + mstore(add(_vk, 0x100), 0x2a7e71e447b5645910a429e7f48f1a5deba7f7d446b95a5edd242b55f67993d3) // vk.Q3.x + mstore(add(_vk, 0x120), 0x2b1ea7f7453a8c80a89a675245da0c33db05ba8e95ecea432ab85f6b2d6a1e86) // vk.Q3.y + mstore(add(_vk, 0x140), 0x02d6fd9e84dbe74b7531e1801405a1c292117b1a17fefe9de0bfd9edf1a84bf9) // vk.Q4.x + mstore(add(_vk, 0x160), 0x293c6ab3c06a0669af13393a82c60a459a3b2a0b768da45ac7af7f2aec40fc42) // vk.Q4.y + mstore(add(_vk, 0x180), 0x0efe5ad29f99fce939416b6638dff26c845044cca9a2d9dbf94039a11d999aaa) // vk.Q_M.x + mstore(add(_vk, 0x1a0), 0x0a44bf49517a4b66ae6b51eee6ac68587f768022c11ac8e37cd9dce243d01ef2) // vk.Q_M.y + mstore(add(_vk, 0x1c0), 0x117d457bfb28869ab380fd6e83133eeb5b6ab48e5df1ae9bc204b60817006655) // vk.Q_C.x + mstore(add(_vk, 0x1e0), 0x2a958a537a99428a1019fd2c8d6b97c48f3e74ad77f0e2c63c9dfb6dccf9a29c) // vk.Q_C.y + mstore(add(_vk, 0x200), 0x18c3e78f81e83b52719158e4ac4c2f4b6c55389300451eb2a2deddf244129e7a) // vk.Q_ARITHMETIC.x + mstore(add(_vk, 0x220), 0x0002e9c902fe5cd49b64563cadf3bb8d7beb75f905a5894e18d27c42c62fd797) // vk.Q_ARITHMETIC.y + mstore(add(_vk, 0x240), 0x2cbce7beee3076b78dace04943d69d0d9e28aa6d00e046852781a5f20816645c) // vk.QSORT.x + mstore(add(_vk, 0x260), 0x2bc27ec2e1612ea284b08bcc55b6f2fd915d11bfedbdc0e59de09e5b28952080) // vk.QSORT.y + mstore(add(_vk, 0x280), 0x0ad34b5e8db72a5acf4427546c7294be6ed4f4d252a79059e505f9abc1bdf3ed) // vk.Q_ELLIPTIC.x + mstore(add(_vk, 0x2a0), 0x1e5b26790a26eb340217dd9ad28dbf90a049f42a3852acd45e6f521f24b4900e) // vk.Q_ELLIPTIC.y + mstore(add(_vk, 0x2c0), 0x155a0f51fec78c33ffceb7364d69d7ac27e570ae50bc180509764eb3fef94815) // vk.Q_AUX.x + mstore(add(_vk, 0x2e0), 0x1c1c4720bed44a591d97cbc72b6e44b644999713a8d3c66e9054aa5726324c76) // vk.Q_AUX.y + mstore(add(_vk, 0x300), 0x0f7261cf55a71f4d0d7b961dda9ddb058cc5ad51753faec2a5908155d472e429) // vk.SIGMA1.x + mstore(add(_vk, 0x320), 0x1b7b1a10c1e638ce11d8c84b831aca4a36df78f0d50144437ef26f8bbfe69ac1) // vk.SIGMA1.y + mstore(add(_vk, 0x340), 0x163a9c8b67447afccc64e9ccba9d9e826ba5b1d1ddd8d6bb960f01cd1321a169) // vk.SIGMA2.x + mstore(add(_vk, 0x360), 0x19256311d43dbc795f746c63b209667653a773088aba5c6b1337f435188d72c4) // vk.SIGMA2.y + mstore(add(_vk, 0x380), 0x1fa51a0d75363b3af4e259e0dbb2c5df58a7bad9afe3651be67bc6c298092e11) // vk.SIGMA3.x + mstore(add(_vk, 0x3a0), 0x21915198840ad9c3666122b2837aeac8b5836b29551d41dbc04bdb1fcf1a1868) // vk.SIGMA3.y + mstore(add(_vk, 0x3c0), 0x0cee6b75dcf02a07c50939e8ca3cf35df0e69d7efdbc7898b3762f0a0ed976ad) // vk.SIGMA4.x + mstore(add(_vk, 0x3e0), 0x27e49262bd388ce2d0f193988f3b8f66a493be1ea69d2b335152719acd54d735) // vk.SIGMA4.y + mstore(add(_vk, 0x400), 0x02c397073c8abce6d4140c9b961209dd783bff1a1cfc999bb29859cfb16c46fc) // vk.TABLE1.x + mstore(add(_vk, 0x420), 0x2b7bba2d1efffce0d033f596b4d030750599be670db593af86e1923fe8a1bb18) // vk.TABLE1.y + mstore(add(_vk, 0x440), 0x2c71c58b66498f903b3bbbda3d05ce8ffb571a4b3cf83533f3f71b99a04f6e6b) // vk.TABLE2.x + mstore(add(_vk, 0x460), 0x039dce37f94d1bbd97ccea32a224fe2afaefbcbd080c84dcea90b54f4e0a858f) // vk.TABLE2.y + mstore(add(_vk, 0x480), 0x27dc44977efe6b3746a290706f4f7275783c73cfe56847d848fd93b63bf32083) // vk.TABLE3.x + mstore(add(_vk, 0x4a0), 0x0a5366266dd7b71a10b356030226a2de0cbf2edc8f085b16d73652b15eced8f5) // vk.TABLE3.y + mstore(add(_vk, 0x4c0), 0x136097d79e1b0ae373255e8760c49900a7588ec4d6809c90bb451005a3de3077) // vk.TABLE4.x + mstore(add(_vk, 0x4e0), 0x13dd7515ccac4095302d204f06f0bff2595d77bdf72e4acdb0b0b43969860d98) // vk.TABLE4.y + mstore(add(_vk, 0x500), 0x16ff3501369121d410b445929239ba057fe211dad1b706e49a3b55920fac20ec) // vk.TABLE_TYPE.x + mstore(add(_vk, 0x520), 0x1e190987ebd9cf480f608b82134a00eb8007673c1ed10b834a695adf0068522a) // vk.TABLE_TYPE.y + mstore(add(_vk, 0x540), 0x1e44194e60f0ab4ee0f77adc50f4220944f94301aa6da3016a226de04de52f4c) // vk.ID1.x + mstore(add(_vk, 0x560), 0x2a017d0d9f40d0aeb5c8152ffddec56c2c7bea37dfbd20be6bed19efd743397a) // vk.ID1.y + mstore(add(_vk, 0x580), 0x27579be0883627093cf8bdec0b72e77f43efe5631bf48c872c317bed3b8bf12b) // vk.ID2.x + mstore(add(_vk, 0x5a0), 0x0ddb2d01ec88ed69144177a4af3850cef6108b89e89b35679431d113f3be7dff) // vk.ID2.y + mstore(add(_vk, 0x5c0), 0x0a7fe830f1cb7a5d49d71877dd226a0083e7ab1f26781948b36d131759f7c8c9) // vk.ID3.x + mstore(add(_vk, 0x5e0), 0x2db7a5185064e6501ef61e989895a01834ecd1ce1e8e80812bdd95f960a45e57) // vk.ID3.y + mstore(add(_vk, 0x600), 0x2eea648c8732596b1314fe2a4d2f05363f0c994e91cecad25835338edee2294f) // vk.ID4.x + mstore(add(_vk, 0x620), 0x0ab49886c2b94bd0bd3f6ed1dbbe2cb2671d2ae51d31c1210433c3972bb64578) // vk.ID4.y + mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof + mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices + mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 + mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 + mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 + mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 + mstore(_omegaInverseLoc, 0x02e40daf409556c02bfc85eb303402b774954d30aeb0337eb85a71e6373428de) // vk.work_root_inverse + } + } +} + +/** + * @title Ultra Plonk proof verification contract + * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified + */ +abstract contract BaseUltraVerifier { + // VERIFICATION KEY MEMORY LOCATIONS + uint256 internal constant N_LOC = 0x380; + uint256 internal constant NUM_INPUTS_LOC = 0x3a0; + uint256 internal constant OMEGA_LOC = 0x3c0; + uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0; + uint256 internal constant Q1_X_LOC = 0x400; + uint256 internal constant Q1_Y_LOC = 0x420; + uint256 internal constant Q2_X_LOC = 0x440; + uint256 internal constant Q2_Y_LOC = 0x460; + uint256 internal constant Q3_X_LOC = 0x480; + uint256 internal constant Q3_Y_LOC = 0x4a0; + uint256 internal constant Q4_X_LOC = 0x4c0; + uint256 internal constant Q4_Y_LOC = 0x4e0; + uint256 internal constant QM_X_LOC = 0x500; + uint256 internal constant QM_Y_LOC = 0x520; + uint256 internal constant QC_X_LOC = 0x540; + uint256 internal constant QC_Y_LOC = 0x560; + uint256 internal constant QARITH_X_LOC = 0x580; + uint256 internal constant QARITH_Y_LOC = 0x5a0; + uint256 internal constant QSORT_X_LOC = 0x5c0; + uint256 internal constant QSORT_Y_LOC = 0x5e0; + uint256 internal constant QELLIPTIC_X_LOC = 0x600; + uint256 internal constant QELLIPTIC_Y_LOC = 0x620; + uint256 internal constant QAUX_X_LOC = 0x640; + uint256 internal constant QAUX_Y_LOC = 0x660; + uint256 internal constant SIGMA1_X_LOC = 0x680; + uint256 internal constant SIGMA1_Y_LOC = 0x6a0; + uint256 internal constant SIGMA2_X_LOC = 0x6c0; + uint256 internal constant SIGMA2_Y_LOC = 0x6e0; + uint256 internal constant SIGMA3_X_LOC = 0x700; + uint256 internal constant SIGMA3_Y_LOC = 0x720; + uint256 internal constant SIGMA4_X_LOC = 0x740; + uint256 internal constant SIGMA4_Y_LOC = 0x760; + uint256 internal constant TABLE1_X_LOC = 0x780; + uint256 internal constant TABLE1_Y_LOC = 0x7a0; + uint256 internal constant TABLE2_X_LOC = 0x7c0; + uint256 internal constant TABLE2_Y_LOC = 0x7e0; + uint256 internal constant TABLE3_X_LOC = 0x800; + uint256 internal constant TABLE3_Y_LOC = 0x820; + uint256 internal constant TABLE4_X_LOC = 0x840; + uint256 internal constant TABLE4_Y_LOC = 0x860; + uint256 internal constant TABLE_TYPE_X_LOC = 0x880; + uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0; + uint256 internal constant ID1_X_LOC = 0x8c0; + uint256 internal constant ID1_Y_LOC = 0x8e0; + uint256 internal constant ID2_X_LOC = 0x900; + uint256 internal constant ID2_Y_LOC = 0x920; + uint256 internal constant ID3_X_LOC = 0x940; + uint256 internal constant ID3_Y_LOC = 0x960; + uint256 internal constant ID4_X_LOC = 0x980; + uint256 internal constant ID4_Y_LOC = 0x9a0; + uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0; + uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0; + uint256 internal constant G2X_X0_LOC = 0xa00; + uint256 internal constant G2X_X1_LOC = 0xa20; + uint256 internal constant G2X_Y0_LOC = 0xa40; + uint256 internal constant G2X_Y1_LOC = 0xa60; + + // ### PROOF DATA MEMORY LOCATIONS + uint256 internal constant W1_X_LOC = 0x1200; + uint256 internal constant W1_Y_LOC = 0x1220; + uint256 internal constant W2_X_LOC = 0x1240; + uint256 internal constant W2_Y_LOC = 0x1260; + uint256 internal constant W3_X_LOC = 0x1280; + uint256 internal constant W3_Y_LOC = 0x12a0; + uint256 internal constant W4_X_LOC = 0x12c0; + uint256 internal constant W4_Y_LOC = 0x12e0; + uint256 internal constant S_X_LOC = 0x1300; + uint256 internal constant S_Y_LOC = 0x1320; + uint256 internal constant Z_X_LOC = 0x1340; + uint256 internal constant Z_Y_LOC = 0x1360; + uint256 internal constant Z_LOOKUP_X_LOC = 0x1380; + uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0; + uint256 internal constant T1_X_LOC = 0x13c0; + uint256 internal constant T1_Y_LOC = 0x13e0; + uint256 internal constant T2_X_LOC = 0x1400; + uint256 internal constant T2_Y_LOC = 0x1420; + uint256 internal constant T3_X_LOC = 0x1440; + uint256 internal constant T3_Y_LOC = 0x1460; + uint256 internal constant T4_X_LOC = 0x1480; + uint256 internal constant T4_Y_LOC = 0x14a0; + + uint256 internal constant W1_EVAL_LOC = 0x1600; + uint256 internal constant W2_EVAL_LOC = 0x1620; + uint256 internal constant W3_EVAL_LOC = 0x1640; + uint256 internal constant W4_EVAL_LOC = 0x1660; + uint256 internal constant S_EVAL_LOC = 0x1680; + uint256 internal constant Z_EVAL_LOC = 0x16a0; + uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0; + uint256 internal constant Q1_EVAL_LOC = 0x16e0; + uint256 internal constant Q2_EVAL_LOC = 0x1700; + uint256 internal constant Q3_EVAL_LOC = 0x1720; + uint256 internal constant Q4_EVAL_LOC = 0x1740; + uint256 internal constant QM_EVAL_LOC = 0x1760; + uint256 internal constant QC_EVAL_LOC = 0x1780; + uint256 internal constant QARITH_EVAL_LOC = 0x17a0; + uint256 internal constant QSORT_EVAL_LOC = 0x17c0; + uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0; + uint256 internal constant QAUX_EVAL_LOC = 0x1800; + uint256 internal constant TABLE1_EVAL_LOC = 0x1840; + uint256 internal constant TABLE2_EVAL_LOC = 0x1860; + uint256 internal constant TABLE3_EVAL_LOC = 0x1880; + uint256 internal constant TABLE4_EVAL_LOC = 0x18a0; + uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0; + uint256 internal constant ID1_EVAL_LOC = 0x18e0; + uint256 internal constant ID2_EVAL_LOC = 0x1900; + uint256 internal constant ID3_EVAL_LOC = 0x1920; + uint256 internal constant ID4_EVAL_LOC = 0x1940; + uint256 internal constant SIGMA1_EVAL_LOC = 0x1960; + uint256 internal constant SIGMA2_EVAL_LOC = 0x1980; + uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0; + uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0; + uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0; + uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000; + uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020; + uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040; + uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060; + uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080; + uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0; + uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0; + uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0; + uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100; + uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120; + + uint256 internal constant PI_Z_X_LOC = 0x2300; + uint256 internal constant PI_Z_Y_LOC = 0x2320; + uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340; + uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360; + + // Used for elliptic widget. These are alias names for wire + shifted wire evaluations + uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC; + uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC; + uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC; + uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC; + uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC; + uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC; + uint256 internal constant QBETA_LOC = Q3_EVAL_LOC; + uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC; + uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC; + + // ### CHALLENGES MEMORY OFFSETS + + uint256 internal constant C_BETA_LOC = 0x2600; + uint256 internal constant C_GAMMA_LOC = 0x2620; + uint256 internal constant C_ALPHA_LOC = 0x2640; + uint256 internal constant C_ETA_LOC = 0x2660; + uint256 internal constant C_ETA_SQR_LOC = 0x2680; + uint256 internal constant C_ETA_CUBE_LOC = 0x26a0; + + uint256 internal constant C_ZETA_LOC = 0x26c0; + uint256 internal constant C_CURRENT_LOC = 0x26e0; + uint256 internal constant C_V0_LOC = 0x2700; + uint256 internal constant C_V1_LOC = 0x2720; + uint256 internal constant C_V2_LOC = 0x2740; + uint256 internal constant C_V3_LOC = 0x2760; + uint256 internal constant C_V4_LOC = 0x2780; + uint256 internal constant C_V5_LOC = 0x27a0; + uint256 internal constant C_V6_LOC = 0x27c0; + uint256 internal constant C_V7_LOC = 0x27e0; + uint256 internal constant C_V8_LOC = 0x2800; + uint256 internal constant C_V9_LOC = 0x2820; + uint256 internal constant C_V10_LOC = 0x2840; + uint256 internal constant C_V11_LOC = 0x2860; + uint256 internal constant C_V12_LOC = 0x2880; + uint256 internal constant C_V13_LOC = 0x28a0; + uint256 internal constant C_V14_LOC = 0x28c0; + uint256 internal constant C_V15_LOC = 0x28e0; + uint256 internal constant C_V16_LOC = 0x2900; + uint256 internal constant C_V17_LOC = 0x2920; + uint256 internal constant C_V18_LOC = 0x2940; + uint256 internal constant C_V19_LOC = 0x2960; + uint256 internal constant C_V20_LOC = 0x2980; + uint256 internal constant C_V21_LOC = 0x29a0; + uint256 internal constant C_V22_LOC = 0x29c0; + uint256 internal constant C_V23_LOC = 0x29e0; + uint256 internal constant C_V24_LOC = 0x2a00; + uint256 internal constant C_V25_LOC = 0x2a20; + uint256 internal constant C_V26_LOC = 0x2a40; + uint256 internal constant C_V27_LOC = 0x2a60; + uint256 internal constant C_V28_LOC = 0x2a80; + uint256 internal constant C_V29_LOC = 0x2aa0; + uint256 internal constant C_V30_LOC = 0x2ac0; + + uint256 internal constant C_U_LOC = 0x2b00; + + // ### LOCAL VARIABLES MEMORY OFFSETS + uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000; + uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020; + uint256 internal constant ZETA_POW_N_LOC = 0x3040; + uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060; + uint256 internal constant ZERO_POLY_LOC = 0x3080; + uint256 internal constant L_START_LOC = 0x30a0; + uint256 internal constant L_END_LOC = 0x30c0; + uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0; + + uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100; + uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120; + uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140; + + uint256 internal constant ACCUMULATOR_X_LOC = 0x3160; + uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180; + uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0; + uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0; + uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0; + uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200; + uint256 internal constant PAIRING_RHS_X_LOC = 0x3220; + uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240; + + // ### SUCCESS FLAG MEMORY LOCATIONS + uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300; + uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020; + uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340; + uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360; + uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380; + uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0; + uint256 internal constant RESULT_FLAG = 0x33c0; + + // misc stuff + uint256 internal constant OMEGA_INVERSE_LOC = 0x3400; + uint256 internal constant C_ALPHA_SQR_LOC = 0x3420; + uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440; + uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460; + uint256 internal constant C_ALPHA_BASE_LOC = 0x3480; + + // ### RECURSION VARIABLE MEMORY LOCATIONS + uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500; + uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520; + uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540; + uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560; + + uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580; + + // sub-identity storage + uint256 internal constant PERMUTATION_IDENTITY = 0x3600; + uint256 internal constant PLOOKUP_IDENTITY = 0x3620; + uint256 internal constant ARITHMETIC_IDENTITY = 0x3640; + uint256 internal constant SORT_IDENTITY = 0x3660; + uint256 internal constant ELLIPTIC_IDENTITY = 0x3680; + uint256 internal constant AUX_IDENTITY = 0x36a0; + uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0; + uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0; + uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700; + uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720; + uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740; + + uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760; + uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780; + + // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time + uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0; + + bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6; + bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f; + bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc; + bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369; + bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec; + + uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes + + // We need to hash 41 field elements when generating the NU challenge + // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14) + // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7) + // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9) + // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7) + // table1_omega, table2_omega, table3_omega, table4_omega (4) + uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20 + + // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over + // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4 + uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0 + + uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P = + 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; + uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68 + uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14 + + error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual); + error PUBLIC_INPUT_INVALID_BN128_G1_POINT(); + error PUBLIC_INPUT_GE_P(); + error MOD_EXP_FAILURE(); + error EC_SCALAR_MUL_FAILURE(); + error PROOF_FAILURE(); + + function getVerificationKeyHash() public pure virtual returns (bytes32); + + function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual; + + /** + * @notice Verify a Ultra Plonk proof + * @param _proof - The serialized proof + * @param _publicInputs - An array of the public inputs + * @return True if proof is valid, reverts otherwise + */ + function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) { + loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC); + + uint256 requiredPublicInputCount; + assembly { + requiredPublicInputCount := mload(NUM_INPUTS_LOC) + } + if (requiredPublicInputCount != _publicInputs.length) { + revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length); + } + + assembly { + let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order + let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order + + /** + * LOAD PROOF FROM CALLDATA + */ + { + let data_ptr := add(calldataload(0x04), 0x24) + + mstore(W1_Y_LOC, mod(calldataload(data_ptr), q)) + mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q)) + + mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q)) + mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q)) + + mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q)) + mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q)) + + mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q)) + mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q)) + + mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q)) + mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q)) + mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q)) + mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q)) + mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q)) + mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q)) + mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q)) + mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q)) + + mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q)) + mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q)) + + mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q)) + mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q)) + + mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q)) + mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q)) + + mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p)) + mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p)) + mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p)) + mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p)) + mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p)) + mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p)) + mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p)) + mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p)) + mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p)) + mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p)) + mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p)) + mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p)) + mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p)) + mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p)) + mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p)) + mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p)) + mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p)) + + mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p)) + mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p)) + + mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p)) + mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p)) + + mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p)) + mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p)) + mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p)) + mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p)) + mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p)) + + mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p)) + mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p)) + mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p)) + mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p)) + + mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p)) + mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p)) + mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p)) + mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p)) + mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p)) + + mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p)) + + mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p)) + mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p)) + mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p)) + mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p)) + mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p)) + + mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q)) + mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q)) + + mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q)) + mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q)) + } + + /** + * LOAD RECURSIVE PROOF INTO MEMORY + */ + { + if mload(CONTAINS_RECURSIVE_PROOF_LOC) { + let public_inputs_ptr := add(calldataload(0x24), 0x24) + let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr) + + let x0 := calldataload(index_counter) + x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20)))) + x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40)))) + x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60)))) + let y0 := calldataload(add(index_counter, 0x80)) + y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0)))) + y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0)))) + y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0)))) + let x1 := calldataload(add(index_counter, 0x100)) + x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120)))) + x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140)))) + x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160)))) + let y1 := calldataload(add(index_counter, 0x180)) + y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0)))) + y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0)))) + y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0)))) + mstore(RECURSIVE_P1_X_LOC, x0) + mstore(RECURSIVE_P1_Y_LOC, y0) + mstore(RECURSIVE_P2_X_LOC, x1) + mstore(RECURSIVE_P2_Y_LOC, y1) + + // validate these are valid bn128 G1 points + if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) { + mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR) + revert(0x00, 0x04) + } + } + } + + { + /** + * Generate initial challenge + */ + mstore(0x00, shl(224, mload(N_LOC))) + mstore(0x04, shl(224, mload(NUM_INPUTS_LOC))) + let challenge := keccak256(0x00, 0x08) + + /** + * Generate eta challenge + */ + mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge) + // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs + let public_inputs_start := add(calldataload(0x24), 0x24) + // copy the public inputs over + let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20) + calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size) + + // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length) + let w_start := add(calldataload(0x04), 0x24) + calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH) + + // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0) + let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH)) + + challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size) + { + let eta := mod(challenge, p) + mstore(C_ETA_LOC, eta) + mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p)) + mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p)) + } + + /** + * Generate beta challenge + */ + mstore(0x00, challenge) + mstore(0x20, mload(W4_Y_LOC)) + mstore(0x40, mload(W4_X_LOC)) + mstore(0x60, mload(S_Y_LOC)) + mstore(0x80, mload(S_X_LOC)) + challenge := keccak256(0x00, 0xa0) + mstore(C_BETA_LOC, mod(challenge, p)) + + /** + * Generate gamma challenge + */ + mstore(0x00, challenge) + mstore8(0x20, 0x01) + challenge := keccak256(0x00, 0x21) + mstore(C_GAMMA_LOC, mod(challenge, p)) + + /** + * Generate alpha challenge + */ + mstore(0x00, challenge) + mstore(0x20, mload(Z_Y_LOC)) + mstore(0x40, mload(Z_X_LOC)) + mstore(0x60, mload(Z_LOOKUP_Y_LOC)) + mstore(0x80, mload(Z_LOOKUP_X_LOC)) + challenge := keccak256(0x00, 0xa0) + mstore(C_ALPHA_LOC, mod(challenge, p)) + + /** + * Compute and store some powers of alpha for future computations + */ + let alpha := mload(C_ALPHA_LOC) + mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p)) + mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p)) + mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p)) + mstore(C_ALPHA_BASE_LOC, alpha) + + /** + * Generate zeta challenge + */ + mstore(0x00, challenge) + mstore(0x20, mload(T1_Y_LOC)) + mstore(0x40, mload(T1_X_LOC)) + mstore(0x60, mload(T2_Y_LOC)) + mstore(0x80, mload(T2_X_LOC)) + mstore(0xa0, mload(T3_Y_LOC)) + mstore(0xc0, mload(T3_X_LOC)) + mstore(0xe0, mload(T4_Y_LOC)) + mstore(0x100, mload(T4_X_LOC)) + + challenge := keccak256(0x00, 0x120) + + mstore(C_ZETA_LOC, mod(challenge, p)) + mstore(C_CURRENT_LOC, challenge) + } + + /** + * EVALUATE FIELD OPERATIONS + */ + + /** + * COMPUTE PUBLIC INPUT DELTA + * ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ) + */ + { + let beta := mload(C_BETA_LOC) // β + let gamma := mload(C_GAMMA_LOC) // γ + let work_root := mload(OMEGA_LOC) // ω + let numerator_value := 1 + let denominator_value := 1 + + let p_clone := p // move p to the front of the stack + let valid_inputs := true + + // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24]) + let public_inputs_ptr := add(calldataload(0x24), 0x24) + + // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes + let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20)) + + // root_1 = β * 0x05 + let root_1 := mulmod(beta, 0x05, p_clone) // k1.β + // root_2 = β * 0x0c + let root_2 := mulmod(beta, 0x0c, p_clone) + // @note 0x05 + 0x07 == 0x0c == external coset generator + + for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } { + /** + * input = public_input[i] + * valid_inputs &= input < p + * temp = input + gamma + * numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ + * denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ + * root_1 *= ω + * root_2 *= ω + */ + + let input := calldataload(public_inputs_ptr) + valid_inputs := and(valid_inputs, lt(input, p_clone)) + let temp := addmod(input, gamma, p_clone) + + numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone) + denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone) + + root_1 := mulmod(root_1, work_root, p_clone) + root_2 := mulmod(root_2, work_root, p_clone) + } + + // Revert if not all public inputs are field elements (i.e. < p) + if iszero(valid_inputs) { + mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR) + revert(0x00, 0x04) + } + + mstore(DELTA_NUMERATOR_LOC, numerator_value) + mstore(DELTA_DENOMINATOR_LOC, denominator_value) + } + + /** + * Compute Plookup delta factor [γ(1 + β)]^{n-k} + * k = num roots cut out of Z_H = 4 + */ + { + let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p) + let delta_numerator := delta_base + { + let exponent := mload(N_LOC) + let count := 1 + for {} lt(count, exponent) { count := add(count, count) } { + delta_numerator := mulmod(delta_numerator, delta_numerator, p) + } + } + mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator) + + let delta_denominator := mulmod(delta_base, delta_base, p) + delta_denominator := mulmod(delta_denominator, delta_denominator, p) + mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator) + } + /** + * Compute lagrange poly and vanishing poly fractions + */ + { + /** + * vanishing_numerator = zeta + * ZETA_POW_N = zeta^n + * vanishing_numerator -= 1 + * accumulating_root = omega_inverse + * work_root = p - accumulating_root + * domain_inverse = domain_inverse + * vanishing_denominator = zeta + work_root + * work_root *= accumulating_root + * vanishing_denominator *= (zeta + work_root) + * work_root *= accumulating_root + * vanishing_denominator *= (zeta + work_root) + * vanishing_denominator *= (zeta + (zeta + accumulating_root)) + * work_root = omega + * lagrange_numerator = vanishing_numerator * domain_inverse + * l_start_denominator = zeta - 1 + * accumulating_root = work_root^2 + * l_end_denominator = accumulating_root^2 * work_root * zeta - 1 + * Note: l_end_denominator term contains a term \omega^5 to cut out 5 roots of unity from vanishing poly + */ + + let zeta := mload(C_ZETA_LOC) + + // compute zeta^n, where n is a power of 2 + let vanishing_numerator := zeta + { + // pow_small + let exponent := mload(N_LOC) + let count := 1 + for {} lt(count, exponent) { count := add(count, count) } { + vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p) + } + } + mstore(ZETA_POW_N_LOC, vanishing_numerator) + vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p) + + let accumulating_root := mload(OMEGA_INVERSE_LOC) + let work_root := sub(p, accumulating_root) + let domain_inverse := mload(DOMAIN_INVERSE_LOC) + + let vanishing_denominator := addmod(zeta, work_root, p) + work_root := mulmod(work_root, accumulating_root, p) + vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p) + work_root := mulmod(work_root, accumulating_root, p) + vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p) + vanishing_denominator := + mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p) + + work_root := mload(OMEGA_LOC) + + let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p) + let l_start_denominator := addmod(zeta, sub(p, 1), p) + + accumulating_root := mulmod(work_root, work_root, p) + + let l_end_denominator := + addmod( + mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p + ) + + /** + * Compute inversions using Montgomery's batch inversion trick + */ + let accumulator := mload(DELTA_DENOMINATOR_LOC) + let t0 := accumulator + accumulator := mulmod(accumulator, vanishing_denominator, p) + let t1 := accumulator + accumulator := mulmod(accumulator, vanishing_numerator, p) + let t2 := accumulator + accumulator := mulmod(accumulator, l_start_denominator, p) + let t3 := accumulator + accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p) + let t4 := accumulator + { + mstore(0, 0x20) + mstore(0x20, 0x20) + mstore(0x40, 0x20) + mstore(0x60, mulmod(accumulator, l_end_denominator, p)) + mstore(0x80, sub(p, 2)) + mstore(0xa0, p) + if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) { + mstore(0x0, MOD_EXP_FAILURE_SELECTOR) + revert(0x00, 0x04) + } + accumulator := mload(0x00) + } + + t4 := mulmod(accumulator, t4, p) + accumulator := mulmod(accumulator, l_end_denominator, p) + + t3 := mulmod(accumulator, t3, p) + accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p) + + t2 := mulmod(accumulator, t2, p) + accumulator := mulmod(accumulator, l_start_denominator, p) + + t1 := mulmod(accumulator, t1, p) + accumulator := mulmod(accumulator, vanishing_numerator, p) + + t0 := mulmod(accumulator, t0, p) + accumulator := mulmod(accumulator, vanishing_denominator, p) + + accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p) + + mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p)) + mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p)) + mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p)) + mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p)) + mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p)) + mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p)) + } + + /** + * UltraPlonk Widget Ordering: + * + * 1. Permutation widget + * 2. Plookup widget + * 3. Arithmetic widget + * 4. Fixed base widget (?) + * 5. GenPermSort widget + * 6. Elliptic widget + * 7. Auxiliary widget + */ + + /** + * COMPUTE PERMUTATION WIDGET EVALUATION + */ + { + let alpha := mload(C_ALPHA_LOC) + let beta := mload(C_BETA_LOC) + let gamma := mload(C_GAMMA_LOC) + + /** + * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2) + * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4) + * result = alpha_base * z_eval * t1 * t2 + * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval) + * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval) + * result -= (alpha_base * z_omega_eval * t1 * t2) + */ + let t1 := + mulmod( + add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)), + add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)), + p + ) + let t2 := + mulmod( + add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)), + add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)), + p + ) + let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p) + t1 := + mulmod( + add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)), + add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)), + p + ) + t2 := + mulmod( + add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)), + add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)), + p + ) + result := + addmod( + result, + sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)), + p + ) + + /** + * alpha_base *= alpha + * result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI})) + * alpha_base *= alpha + * result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1)) + * alpha_Base *= alpha + */ + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) + result := + addmod( + result, + mulmod( + mload(C_ALPHA_BASE_LOC), + mulmod( + mload(L_END_LOC), + addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p), + p + ), + p + ), + p + ) + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) + mstore( + PERMUTATION_IDENTITY, + addmod( + result, + mulmod( + mload(C_ALPHA_BASE_LOC), + mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p), + p + ), + p + ) + ) + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) + } + + /** + * COMPUTE PLOOKUP WIDGET EVALUATION + */ + { + /** + * Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³ + * f = η.q3(z) + * f += (w3(z) + qc.w_3(zω)) + * f *= η + * f += (w2(z) + qm.w2(zω)) + * f *= η + * f += (w1(z) + q2.w1(zω)) + */ + let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p) + f := + addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p) + f := mulmod(f, mload(C_ETA_LOC), p) + f := + addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p) + f := mulmod(f, mload(C_ETA_LOC), p) + f := + addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p) + + // t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z) + let t := + addmod( + addmod( + addmod( + mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p), + mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p), + p + ), + mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p), + p + ), + mload(TABLE1_EVAL_LOC), + p + ) + + // t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw) + let t_omega := + addmod( + addmod( + addmod( + mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p), + mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p), + p + ), + mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p), + p + ), + mload(TABLE1_OMEGA_EVAL_LOC), + p + ) + + /** + * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1) + * gamma_beta_constant = γ(β + 1) + * numerator = f * TABLE_TYPE_EVAL + gamma + * temp0 = t(z) + t(zω) * β + gamma_beta_constant + * numerator *= temp0 + * numerator *= (β + 1) + * temp0 = alpha * l_1 + * numerator += temp0 + * numerator *= z_lookup(z) + * numerator -= temp0 + */ + let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p) + let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p) + let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p) + numerator := mulmod(numerator, temp0, p) + numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p) + temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p) + numerator := addmod(numerator, temp0, p) + numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p) + numerator := addmod(numerator, sub(p, temp0), p) + + /** + * Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z) + * note: delta_factor = [γ(1 + β)]^{n-k} + * denominator = s(z) + βs(zω) + γ(β + 1) + * temp1 = α²L_end(z) + * denominator -= temp1 + * denominator *= z_lookup(zω) + * denominator += temp1 * delta_factor + * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base + * alpha_base *= alpha^3 + */ + let denominator := + addmod( + addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p), + gamma_beta_constant, + p + ) + let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p) + denominator := addmod(denominator, sub(p, temp1), p) + denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p) + denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p) + + mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p)) + + // update alpha + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p)) + } + + /** + * COMPUTE ARITHMETIC WIDGET EVALUATION + */ + { + /** + * The basic arithmetic gate identity in standard plonk is as follows. + * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0 + * However, for Ultraplonk, we extend this to support "passing" wires between rows (shown without alpha scaling below): + * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) + + * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0 + * + * This formula results in several cases depending on q_arith: + * 1. q_arith == 0: Arithmetic gate is completely disabled + * + * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation + * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0 + * + * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is: + * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0 + * It allows defining w_4 at next index (w_4_omega) in terms of current wire values + * + * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split + * the equation into two: + * + * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0 + * and + * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here) + * + * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1). + * The equation can be split into two: + * + * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0 + * and + * w_1 + w_4 - w_1_omega + q_m = 0 + * + * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at + * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at + * product. + */ + + let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p) + let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p) + let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p) + let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p) + + // @todo - Add a explicit test that hits QARITH == 3 + // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2 + let w1w2qm := + mulmod( + mulmod( + mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p), + addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p), + p + ), + NEGATIVE_INVERSE_OF_2_MODULO_P, + p + ) + + // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c + let identity := + addmod( + mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p + ) + + // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where: + // w_1 + w_4 - w_1_omega + q_m = 0 + // we use this gate to save an addition gate when adding or subtracting non-native field elements + // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + let extra_small_addition_gate_identity := + mulmod( + mload(C_ALPHA_LOC), + mulmod( + addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p), + addmod( + mload(QM_EVAL_LOC), + addmod( + sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p + ), + p + ), + p + ), + p + ) + + // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity + // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires! + // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity)) + mstore( + ARITHMETIC_IDENTITY, + mulmod( + mload(C_ALPHA_BASE_LOC), + mulmod( + mload(QARITH_EVAL_LOC), + addmod( + identity, + mulmod( + addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p), + addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p), + p + ), + p + ), + p + ), + p + ) + ) + + // update alpha + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p)) + } + + /** + * COMPUTE GENPERMSORT WIDGET EVALUATION + */ + { + /** + * D1 = (w2 - w1) + * D2 = (w3 - w2) + * D3 = (w4 - w3) + * D4 = (w1_omega - w4) + * + * α_a = alpha_base + * α_b = alpha_base * α + * α_c = alpha_base * α^2 + * α_d = alpha_base * α^3 + * + * range_accumulator = ( + * D1(D1 - 1)(D1 - 2)(D1 - 3).α_a + + * D2(D2 - 1)(D2 - 2)(D2 - 3).α_b + + * D3(D3 - 1)(D3 - 2)(D3 - 3).α_c + + * D4(D4 - 1)(D4 - 2)(D4 - 3).α_d + + * ) . q_sort + */ + let minus_two := sub(p, 2) + let minus_three := sub(p, 3) + let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p) + let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p) + let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p) + let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p) + + let range_accumulator := + mulmod( + mulmod( + mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p), + addmod(d1, minus_three, p), + p + ), + mload(C_ALPHA_BASE_LOC), + p + ) + range_accumulator := + addmod( + range_accumulator, + mulmod( + mulmod( + mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p), + addmod(d2, minus_three, p), + p + ), + mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), + p + ), + p + ) + range_accumulator := + addmod( + range_accumulator, + mulmod( + mulmod( + mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p), + addmod(d3, minus_three, p), + p + ), + mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p), + p + ), + p + ) + range_accumulator := + addmod( + range_accumulator, + mulmod( + mulmod( + mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p), + addmod(d4, minus_three, p), + p + ), + mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p), + p + ), + p + ) + range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p) + + mstore(SORT_IDENTITY, range_accumulator) + + // update alpha + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) + } + + /** + * COMPUTE ELLIPTIC WIDGET EVALUATION + */ + { + /** + * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta + * endo_sqr_term = x_2^2 + * endo_sqr_term *= (x_3 - x_1) + * endo_sqr_term *= q_beta^2 + * leftovers = x_2^2 + * leftovers *= x_2 + * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget + * leftovers -= (y_2^2 + y_1^2) + * sign_term = y_2 * y_1 + * sign_term += sign_term + * sign_term *= q_sign + */ + + let endo_term := + mulmod( + mulmod( + mulmod(sub(p, mload(X2_EVAL_LOC)), mload(X1_EVAL_LOC), p), + addmod(addmod(mload(X3_EVAL_LOC), mload(X3_EVAL_LOC), p), mload(X1_EVAL_LOC), p), + p + ), + mload(QBETA_LOC), + p + ) + + let endo_sqr_term := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p) + endo_sqr_term := mulmod(endo_sqr_term, addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), p) + endo_sqr_term := mulmod(endo_sqr_term, mload(QBETA_SQR_LOC), p) + + let leftovers := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p) + leftovers := mulmod(leftovers, mload(X2_EVAL_LOC), p) + leftovers := + addmod( + leftovers, + mulmod( + mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), + addmod(mload(X3_EVAL_LOC), mload(X1_EVAL_LOC), p), + p + ), + p + ) + leftovers := + addmod( + leftovers, + sub( + p, + addmod( + mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p), + mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p), + p + ) + ), + p + ) + + let sign_term := mulmod(mload(Y2_EVAL_LOC), mload(Y1_EVAL_LOC), p) + sign_term := addmod(sign_term, sign_term, p) + sign_term := mulmod(sign_term, mload(QSIGN_LOC), p) + + /** + * x_identity = endo_term + endo_sqr_term + sign_term + leftovers + * x_identity *= alpha_base + * endo_term = (x_2 * q_beta) * (y_3 + y_1) + * sign_term = -((y2 * q_sign) * (x_1 + x_3)) + * leftovers = - x1 * (y_3 + y_1) + y_1 * (x_1 - x_3) + * y_identity = (endo_term + sign_term + leftovers) * (alpha_base * α) + */ + + let x_identity := addmod(addmod(endo_term, endo_sqr_term, p), addmod(sign_term, leftovers, p), p) + x_identity := mulmod(x_identity, mload(C_ALPHA_BASE_LOC), p) + endo_term := + mulmod( + mulmod(mload(X2_EVAL_LOC), mload(QBETA_LOC), p), + addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), + p + ) + sign_term := + sub( + p, + mulmod( + mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), + addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), + p + ) + ) + leftovers := + addmod( + sub(p, mulmod(mload(X1_EVAL_LOC), addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), p)), + mulmod(mload(Y1_EVAL_LOC), addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p), + p + ) + let y_identity := + mulmod( + addmod(addmod(endo_term, sign_term, p), leftovers, p), + mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), + p + ) + + // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL + mstore(ELLIPTIC_IDENTITY, mulmod(addmod(x_identity, y_identity, p), mload(QELLIPTIC_EVAL_LOC), p)) + + // update alpha + // The paper says to use ALPHA^2, we use ALPHA^4 this is a small oversight in the prover protocol + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) + } + + /** + * COMPUTE AUXILIARY WIDGET EVALUATION + */ + { + { + /** + * Non native field arithmetic gate 2 + * _ _ + * / _ _ _ 14 \ + * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | + * \_ _/ + * + * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2 + * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega + * non_native_field_gate_2 = non_native_field_gate_2 * limb_size + * non_native_field_gate_2 -= w_4_omega + * non_native_field_gate_2 += limb_subproduct + * non_native_field_gate_2 *= q_4 + * limb_subproduct *= limb_size + * limb_subproduct += w_1_omega * w_2_omega + * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3 + * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m + * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2 + */ + + let limb_subproduct := + addmod( + mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), + mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p), + p + ) + + let non_native_field_gate_2 := + addmod( + addmod( + mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), + mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p), + p + ), + sub(p, mload(W3_OMEGA_EVAL_LOC)), + p + ) + non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p) + non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p) + non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p) + non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p) + limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p) + limb_subproduct := + addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p) + let non_native_field_gate_1 := + mulmod( + addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p), + mload(Q3_EVAL_LOC), + p + ) + let non_native_field_gate_3 := + mulmod( + addmod( + addmod(limb_subproduct, mload(W4_EVAL_LOC), p), + sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)), + p + ), + mload(QM_EVAL_LOC), + p + ) + let non_native_field_identity := + mulmod( + addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p), + mload(Q2_EVAL_LOC), + p + ) + + mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity) + } + + { + /** + * limb_accumulator_1 = w_2_omega; + * limb_accumulator_1 *= SUBLIMB_SHIFT; + * limb_accumulator_1 += w_1_omega; + * limb_accumulator_1 *= SUBLIMB_SHIFT; + * limb_accumulator_1 += w_3; + * limb_accumulator_1 *= SUBLIMB_SHIFT; + * limb_accumulator_1 += w_2; + * limb_accumulator_1 *= SUBLIMB_SHIFT; + * limb_accumulator_1 += w_1; + * limb_accumulator_1 -= w_4; + * limb_accumulator_1 *= q_4; + */ + let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p) + limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p) + limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) + limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p) + limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) + limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p) + limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) + limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p) + limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p) + limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p) + + /** + * limb_accumulator_2 = w_3_omega; + * limb_accumulator_2 *= SUBLIMB_SHIFT; + * limb_accumulator_2 += w_2_omega; + * limb_accumulator_2 *= SUBLIMB_SHIFT; + * limb_accumulator_2 += w_1_omega; + * limb_accumulator_2 *= SUBLIMB_SHIFT; + * limb_accumulator_2 += w_4; + * limb_accumulator_2 *= SUBLIMB_SHIFT; + * limb_accumulator_2 += w_3; + * limb_accumulator_2 -= w_4_omega; + * limb_accumulator_2 *= q_m; + */ + let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p) + limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p) + limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) + limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p) + limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) + limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p) + limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) + limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p) + limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p) + limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p) + + mstore( + AUX_LIMB_ACCUMULATOR_EVALUATION, + mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p) + ) + } + + { + /** + * memory_record_check = w_3; + * memory_record_check *= eta; + * memory_record_check += w_2; + * memory_record_check *= eta; + * memory_record_check += w_1; + * memory_record_check *= eta; + * memory_record_check += q_c; + * + * partial_record_check = memory_record_check; + * + * memory_record_check -= w_4; + */ + + let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p) + memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p) + memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p) + memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p) + memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p) + memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p) + + let partial_record_check := memory_record_check + memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p) + + mstore(AUX_MEMORY_EVALUATION, memory_record_check) + + // index_delta = w_1_omega - w_1 + let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p) + // record_delta = w_4_omega - w_4 + let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p) + // index_is_monotonically_increasing = index_delta * (index_delta - 1) + let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p) + + // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta) + let adjacent_values_match_if_adjacent_indices_match := + mulmod(record_delta, addmod(1, sub(p, index_delta), p), p) + + // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check + mstore( + AUX_ROM_CONSISTENCY_EVALUATION, + addmod( + mulmod( + addmod( + mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p), + index_is_monotonically_increasing, + p + ), + mload(C_ALPHA_LOC), + p + ), + memory_record_check, + p + ) + ) + + { + /** + * next_gate_access_type = w_3_omega; + * next_gate_access_type *= eta; + * next_gate_access_type += w_2_omega; + * next_gate_access_type *= eta; + * next_gate_access_type += w_1_omega; + * next_gate_access_type *= eta; + * next_gate_access_type = w_4_omega - next_gate_access_type; + */ + let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p) + next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p) + next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p) + next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p) + next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p) + next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p) + + // value_delta = w_3_omega - w_3 + let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p) + // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type); + + let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation := + mulmod( + addmod(1, sub(p, index_delta), p), + mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p), + p + ) + + // AUX_RAM_CONSISTENCY_EVALUATION + + /** + * access_type = w_4 - partial_record_check + * access_check = access_type^2 - access_type + * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type + * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; + * RAM_consistency_check_identity *= alpha; + * RAM_consistency_check_identity += index_is_monotonically_increasing; + * RAM_consistency_check_identity *= alpha; + * RAM_consistency_check_identity += next_gate_access_type_is_boolean; + * RAM_consistency_check_identity *= alpha; + * RAM_consistency_check_identity += access_check; + */ + + let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p) + let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p) + let next_gate_access_type_is_boolean := + mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p) + let RAM_cci := + mulmod( + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation, + mload(C_ALPHA_LOC), + p + ) + RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p) + RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p) + RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p) + RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p) + RAM_cci := addmod(RAM_cci, access_check, p) + + mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci) + } + + { + // timestamp_delta = w_2_omega - w_2 + let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p) + + // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3 + let RAM_timestamp_check_identity := + addmod( + mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p + ) + + /** + * memory_identity = ROM_consistency_check_identity * q_2; + * memory_identity += RAM_timestamp_check_identity * q_4; + * memory_identity += memory_record_check * q_m; + * memory_identity *= q_1; + * memory_identity += (RAM_consistency_check_identity * q_arith); + * + * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; + * auxiliary_identity *= q_aux; + * auxiliary_identity *= alpha_base; + */ + let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p) + memory_identity := + addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p) + memory_identity := + addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p) + memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p) + memory_identity := + addmod( + memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p + ) + + let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p) + auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p) + auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p) + auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p) + + mstore(AUX_IDENTITY, auxiliary_identity) + + // update alpha + mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p)) + } + } + } + + { + /** + * quotient = ARITHMETIC_IDENTITY + * quotient += PERMUTATION_IDENTITY + * quotient += PLOOKUP_IDENTITY + * quotient += SORT_IDENTITY + * quotient += ELLIPTIC_IDENTITY + * quotient += AUX_IDENTITY + * quotient *= ZERO_POLY_INVERSE + */ + mstore( + QUOTIENT_EVAL_LOC, + mulmod( + addmod( + addmod( + addmod( + addmod( + addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p), + mload(ARITHMETIC_IDENTITY), + p + ), + mload(SORT_IDENTITY), + p + ), + mload(ELLIPTIC_IDENTITY), + p + ), + mload(AUX_IDENTITY), + p + ), + mload(ZERO_POLY_INVERSE_LOC), + p + ) + ) + } + + /** + * GENERATE NU AND SEPARATOR CHALLENGES + */ + { + let current_challenge := mload(C_CURRENT_LOC) + // get a calldata pointer that points to the start of the data we want to copy + let calldata_ptr := add(calldataload(0x04), 0x24) + + calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH) + + mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge) + mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC)) + calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH) + + // hash length = (0x20 + num field elements), we include the previous challenge in the hash + let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40)) + + mstore(C_V0_LOC, mod(challenge, p)) + // We need THIRTY-ONE independent nu challenges! + mstore(0x00, challenge) + mstore8(0x20, 0x01) + mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x02) + mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x03) + mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x04) + mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x05) + mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x06) + mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x07) + mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x08) + mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x09) + mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x0a) + mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x0b) + mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x0c) + mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x0d) + mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x0e) + mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x0f) + mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x10) + mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x11) + mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x12) + mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x13) + mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x14) + mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x15) + mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x16) + mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x17) + mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x18) + mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x19) + mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x1a) + mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x1b) + mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x1c) + mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p)) + mstore8(0x20, 0x1d) + mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p)) + + // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change? + mstore8(0x20, 0x1d) + challenge := keccak256(0x00, 0x21) + mstore(C_V30_LOC, mod(challenge, p)) + + // separator + mstore(0x00, challenge) + mstore(0x20, mload(PI_Z_Y_LOC)) + mstore(0x40, mload(PI_Z_X_LOC)) + mstore(0x60, mload(PI_Z_OMEGA_Y_LOC)) + mstore(0x80, mload(PI_Z_OMEGA_X_LOC)) + + mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p)) + } + + let success := 0 + // VALIDATE T1 + { + let x := mload(T1_X_LOC) + let y := mload(T1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) + mstore(ACCUMULATOR_X_LOC, x) + mstore(add(ACCUMULATOR_X_LOC, 0x20), y) + } + // VALIDATE T2 + { + let x := mload(T2_X_LOC) // 0x1400 + let y := mload(T2_Y_LOC) // 0x1420 + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(ZETA_POW_N_LOC)) + // accumulator_2 = [T2].zeta^n + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = [T1] + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE T3 + { + let x := mload(T3_X_LOC) + let y := mload(T3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p)) + // accumulator_2 = [T3].zeta^{2n} + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE T4 + { + let x := mload(T4_X_LOC) + let y := mload(T4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p)) + // accumulator_2 = [T4].zeta^{3n} + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE W1 + { + let x := mload(W1_X_LOC) + let y := mload(W1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p)) + // accumulator_2 = v0.(u + 1).[W1] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE W2 + { + let x := mload(W2_X_LOC) + let y := mload(W2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p)) + // accumulator_2 = v1.(u + 1).[W2] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE W3 + { + let x := mload(W3_X_LOC) + let y := mload(W3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p)) + // accumulator_2 = v2.(u + 1).[W3] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE W4 + { + let x := mload(W4_X_LOC) + let y := mload(W4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p)) + // accumulator_2 = v3.(u + 1).[W4] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE S + { + let x := mload(S_X_LOC) + let y := mload(S_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p)) + // accumulator_2 = v4.(u + 1).[S] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE Z + { + let x := mload(Z_X_LOC) + let y := mload(Z_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p)) + // accumulator_2 = v5.(u + 1).[Z] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE Z_LOOKUP + { + let x := mload(Z_LOOKUP_X_LOC) + let y := mload(Z_LOOKUP_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p)) + // accumulator_2 = v6.(u + 1).[Z_LOOKUP] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE Q1 + { + let x := mload(Q1_X_LOC) + let y := mload(Q1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V7_LOC)) + // accumulator_2 = v7.[Q1] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE Q2 + { + let x := mload(Q2_X_LOC) + let y := mload(Q2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V8_LOC)) + // accumulator_2 = v8.[Q2] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE Q3 + { + let x := mload(Q3_X_LOC) + let y := mload(Q3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V9_LOC)) + // accumulator_2 = v9.[Q3] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE Q4 + { + let x := mload(Q4_X_LOC) + let y := mload(Q4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V10_LOC)) + // accumulator_2 = v10.[Q4] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE QM + { + let x := mload(QM_X_LOC) + let y := mload(QM_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V11_LOC)) + // accumulator_2 = v11.[Q;] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE QC + { + let x := mload(QC_X_LOC) + let y := mload(QC_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V12_LOC)) + // accumulator_2 = v12.[QC] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE QARITH + { + let x := mload(QARITH_X_LOC) + let y := mload(QARITH_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V13_LOC)) + // accumulator_2 = v13.[QARITH] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE QSORT + { + let x := mload(QSORT_X_LOC) + let y := mload(QSORT_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V14_LOC)) + // accumulator_2 = v14.[QSORT] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE QELLIPTIC + { + let x := mload(QELLIPTIC_X_LOC) + let y := mload(QELLIPTIC_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V15_LOC)) + // accumulator_2 = v15.[QELLIPTIC] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE QAUX + { + let x := mload(QAUX_X_LOC) + let y := mload(QAUX_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V16_LOC)) + // accumulator_2 = v15.[Q_AUX] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE SIGMA1 + { + let x := mload(SIGMA1_X_LOC) + let y := mload(SIGMA1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V17_LOC)) + // accumulator_2 = v17.[sigma1] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE SIGMA2 + { + let x := mload(SIGMA2_X_LOC) + let y := mload(SIGMA2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V18_LOC)) + // accumulator_2 = v18.[sigma2] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE SIGMA3 + { + let x := mload(SIGMA3_X_LOC) + let y := mload(SIGMA3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V19_LOC)) + // accumulator_2 = v19.[sigma3] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE SIGMA4 + { + let x := mload(SIGMA4_X_LOC) + let y := mload(SIGMA4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V20_LOC)) + // accumulator_2 = v20.[sigma4] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE TABLE1 + { + let x := mload(TABLE1_X_LOC) + let y := mload(TABLE1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p)) + // accumulator_2 = u.[table1] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE TABLE2 + { + let x := mload(TABLE2_X_LOC) + let y := mload(TABLE2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p)) + // accumulator_2 = u.[table2] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE TABLE3 + { + let x := mload(TABLE3_X_LOC) + let y := mload(TABLE3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p)) + // accumulator_2 = u.[table3] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE TABLE4 + { + let x := mload(TABLE4_X_LOC) + let y := mload(TABLE4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p)) + // accumulator_2 = u.[table4] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE TABLE_TYPE + { + let x := mload(TABLE_TYPE_X_LOC) + let y := mload(TABLE_TYPE_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V25_LOC)) + // accumulator_2 = v25.[TableType] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE ID1 + { + let x := mload(ID1_X_LOC) + let y := mload(ID1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V26_LOC)) + // accumulator_2 = v26.[ID1] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE ID2 + { + let x := mload(ID2_X_LOC) + let y := mload(ID2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V27_LOC)) + // accumulator_2 = v27.[ID2] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE ID3 + { + let x := mload(ID3_X_LOC) + let y := mload(ID3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V28_LOC)) + // accumulator_2 = v28.[ID3] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE ID4 + { + let x := mload(ID4_X_LOC) + let y := mload(ID4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mload(C_V29_LOC)) + // accumulator_2 = v29.[ID4] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + /** + * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER + */ + { + /** + * batch_evaluation = v0 * (w_1_omega * u + w_1_eval) + * batch_evaluation += v1 * (w_2_omega * u + w_2_eval) + * batch_evaluation += v2 * (w_3_omega * u + w_3_eval) + * batch_evaluation += v3 * (w_4_omega * u + w_4_eval) + * batch_evaluation += v4 * (s_omega_eval * u + s_eval) + * batch_evaluation += v5 * (z_omega_eval * u + z_eval) + * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval) + */ + let batch_evaluation := + mulmod( + mload(C_V0_LOC), + addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V1_LOC), + addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V2_LOC), + addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V3_LOC), + addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V4_LOC), + addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V5_LOC), + addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V6_LOC), + addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p), + p + ), + p + ) + + /** + * batch_evaluation += v7 * Q1_EVAL + * batch_evaluation += v8 * Q2_EVAL + * batch_evaluation += v9 * Q3_EVAL + * batch_evaluation += v10 * Q4_EVAL + * batch_evaluation += v11 * QM_EVAL + * batch_evaluation += v12 * QC_EVAL + * batch_evaluation += v13 * QARITH_EVAL + * batch_evaluation += v14 * QSORT_EVAL_LOC + * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC + * batch_evaluation += v16 * QAUX_EVAL_LOC + * batch_evaluation += v17 * SIGMA1_EVAL_LOC + * batch_evaluation += v18 * SIGMA2_EVAL_LOC + * batch_evaluation += v19 * SIGMA3_EVAL_LOC + * batch_evaluation += v20 * SIGMA4_EVAL_LOC + */ + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p) + + /** + * batch_evaluation += v21 * (table1(zw) * u + table1(z)) + * batch_evaluation += v22 * (table2(zw) * u + table2(z)) + * batch_evaluation += v23 * (table3(zw) * u + table3(z)) + * batch_evaluation += v24 * (table4(zw) * u + table4(z)) + * batch_evaluation += v25 * table_type_eval + * batch_evaluation += v26 * id1_eval + * batch_evaluation += v27 * id2_eval + * batch_evaluation += v28 * id3_eval + * batch_evaluation += v29 * id4_eval + * batch_evaluation += quotient_eval + */ + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V21_LOC), + addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V22_LOC), + addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V23_LOC), + addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := + addmod( + batch_evaluation, + mulmod( + mload(C_V24_LOC), + addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p), + p + ), + p + ) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p) + batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p) + + mstore(0x00, 0x01) // [1].x + mstore(0x20, 0x02) // [1].y + mstore(0x40, sub(p, batch_evaluation)) + // accumulator_2 = -[1].(batch_evaluation) + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success) + } + + /** + * PERFORM PAIRING PREAMBLE + */ + { + let u := mload(C_U_LOC) + let zeta := mload(C_ZETA_LOC) + // VALIDATE PI_Z + { + let x := mload(PI_Z_X_LOC) + let y := mload(PI_Z_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) + mstore(0x00, x) + mstore(0x20, y) + } + // compute zeta.[PI_Z] and add into accumulator + mstore(0x40, zeta) + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) + + // VALIDATE PI_Z_OMEGA + { + let x := mload(PI_Z_OMEGA_X_LOC) + let y := mload(PI_Z_OMEGA_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p)) + // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA] + success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + // PAIRING_RHS = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40)) + + mstore(0x00, mload(PI_Z_X_LOC)) + mstore(0x20, mload(PI_Z_Y_LOC)) + mstore(0x40, mload(PI_Z_OMEGA_X_LOC)) + mstore(0x60, mload(PI_Z_OMEGA_Y_LOC)) + mstore(0x80, u) + success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40)) + // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u + success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40)) + // negate lhs y-coordinate + mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC))) + + if mload(CONTAINS_RECURSIVE_PROOF_LOC) { + // VALIDATE RECURSIVE P1 + { + let x := mload(RECURSIVE_P1_X_LOC) + let y := mload(RECURSIVE_P1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + + // compute u.u.[recursive_p1] and write into 0x60 + mstore(0x40, mulmod(u, u, p)) + success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40)) + // VALIDATE RECURSIVE P2 + { + let x := mload(RECURSIVE_P2_X_LOC) + let y := mload(RECURSIVE_P2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + // compute u.u.[recursive_p2] and write into 0x00 + // 0x40 still contains u*u + success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40)) + + // compute u.u.[recursiveP1] + rhs and write into rhs + mstore(0xa0, mload(PAIRING_RHS_X_LOC)) + mstore(0xc0, mload(PAIRING_RHS_Y_LOC)) + success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40)) + + // compute u.u.[recursiveP2] + lhs and write into lhs + mstore(0x40, mload(PAIRING_LHS_X_LOC)) + mstore(0x60, mload(PAIRING_LHS_Y_LOC)) + success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40)) + } + + if iszero(success) { + mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR) + revert(0x00, 0x04) + } + mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success) + } + + /** + * PERFORM PAIRING + */ + { + // rhs paired with [1]_2 + // lhs paired with [x]_2 + + mstore(0x00, mload(PAIRING_RHS_X_LOC)) + mstore(0x20, mload(PAIRING_RHS_Y_LOC)) + mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2 + mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) + + mstore(0xc0, mload(PAIRING_LHS_X_LOC)) + mstore(0xe0, mload(PAIRING_LHS_Y_LOC)) + mstore(0x100, mload(G2X_X0_LOC)) + mstore(0x120, mload(G2X_X1_LOC)) + mstore(0x140, mload(G2X_Y0_LOC)) + mstore(0x160, mload(G2X_Y1_LOC)) + + success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20) + mstore(PAIRING_SUCCESS_FLAG, success) + mstore(RESULT_FLAG, mload(0x00)) + } + if iszero( + and( + and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)), + mload(OPENING_COMMITMENT_SUCCESS_FLAG) + ) + ) { + mstore(0x0, PROOF_FAILURE_SELECTOR) + revert(0x00, 0x04) + } + { + mstore(0x00, 0x01) + return(0x00, 0x20) // Proof succeeded! + } + } + } +} + +contract UltraVerifier is BaseUltraVerifier { + function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) { + return UltraVerificationKey.verificationKeyHash(); + } + + function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) { + UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc); + } +} From 488a8a214571f76c78b43d89dc31e6584598707c Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Tue, 15 Aug 2023 14:30:54 -0400 Subject: [PATCH 07/10] update nargo prove command --- .github/workflows/with_foundry.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/with_foundry.yaml b/.github/workflows/with_foundry.yaml index e7596c6..1aa4244 100644 --- a/.github/workflows/with_foundry.yaml +++ b/.github/workflows/with_foundry.yaml @@ -31,7 +31,7 @@ jobs: - name: Generate proof run: | - nargo prove p + nargo prove working-directory: with-foundry/circuits - name: Test with Foundry From 5a99ccaaf8d09e9e8a4947b6528a1eeb79c4d80f Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Tue, 15 Aug 2023 14:43:32 -0400 Subject: [PATCH 08/10] fix with_foundry tests --- with-foundry/contract/Starter.sol | 2 +- with-foundry/script/Starter.s.sol | 2 +- with-foundry/script/Verify.s.sol | 8 ++++---- with-foundry/script/prove.sh | 2 +- with-foundry/test/Starter.t.sol | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/with-foundry/contract/Starter.sol b/with-foundry/contract/Starter.sol index b4db518..de49ac9 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/plonk_vk.sol"; +import "../circuits/contract/with_foundry/plonk_vk.sol"; contract Starter { UltraVerifier public verifier; diff --git a/with-foundry/script/Starter.s.sol b/with-foundry/script/Starter.s.sol index e6ab452..d29b9bb 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/plonk_vk.sol"; +import "../circuits/contract/with_foundry/plonk_vk.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 b9432db..3daf6b1 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/plonk_vk.sol"; +import "../circuits/contract/with_foundry/plonk_vk.sol"; import "../contract/Starter.sol"; contract VerifyScript is Script { @@ -10,7 +10,7 @@ contract VerifyScript is Script { function setUp() public {} - function run() public returns (bool){ + function run() public returns (bool) { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); @@ -22,8 +22,8 @@ contract VerifyScript is Script { bytes32[] memory correct = new bytes32[](1); correct[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000003); - + bool equal = starter.verifyEqual(proofBytes, correct); return equal; } -} \ No newline at end of file +} diff --git a/with-foundry/script/prove.sh b/with-foundry/script/prove.sh index bce01a9..beffbb5 100755 --- a/with-foundry/script/prove.sh +++ b/with-foundry/script/prove.sh @@ -4,4 +4,4 @@ then echo "Usage: ./prove.sh [TESTNAME_STRING]" exit 1 fi -cd /tmp/$1 && nargo prove d && echo "Proof Generated" +cd /tmp/$1 && nargo prove && echo "Proof Generated" diff --git a/with-foundry/test/Starter.t.sol b/with-foundry/test/Starter.t.sol index 9fbc14a..b5e8c78 100644 --- a/with-foundry/test/Starter.t.sol +++ b/with-foundry/test/Starter.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.17; import "forge-std/Test.sol"; import "../contract/Starter.sol"; -import "../circuits/contract/plonk_vk.sol"; +import "../circuits/contract/with_foundry/plonk_vk.sol"; contract StarterTest is Test { Starter public starter; @@ -21,14 +21,14 @@ contract StarterTest is Test { } function testVerifyProof() public { - string memory proof = vm.readLine("./circuits/proofs/p.proof"); + string memory proof = vm.readLine("./circuits/proofs/with_foundry.proof"); bytes memory proofBytes = vm.parseBytes(proof); starter.verifyEqual(proofBytes, correct); } function test_wrongProof() public { vm.expectRevert(); - string memory proof = vm.readLine("./circuits/proofs/p.proof"); + string memory proof = vm.readLine("./circuits/proofs/with_foundry.proof"); bytes memory proofBytes = vm.parseBytes(proof); starter.verifyEqual(proofBytes, wrong); } @@ -108,7 +108,7 @@ 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/d.proof")); + string memory _newProof = vm.readLine(string.concat("/tmp/", _testName, "/proofs/with_foundry.proof")); return vm.parseBytes(_newProof); } } From 7f2c2701cb00990279cf6afeda373a669c8e4e88 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Tue, 15 Aug 2023 14:47:13 -0400 Subject: [PATCH 09/10] Revert "fix with_foundry tests" This reverts commit 5a99ccaaf8d09e9e8a4947b6528a1eeb79c4d80f. --- with-foundry/contract/Starter.sol | 2 +- with-foundry/script/Starter.s.sol | 2 +- with-foundry/script/Verify.s.sol | 8 ++++---- with-foundry/script/prove.sh | 2 +- with-foundry/test/Starter.t.sol | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/with-foundry/contract/Starter.sol b/with-foundry/contract/Starter.sol index de49ac9..b4db518 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/contract/plonk_vk.sol"; contract Starter { UltraVerifier public verifier; diff --git a/with-foundry/script/Starter.s.sol b/with-foundry/script/Starter.s.sol index d29b9bb..e6ab452 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/contract/plonk_vk.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 3daf6b1..b9432db 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/contract/plonk_vk.sol"; import "../contract/Starter.sol"; contract VerifyScript is Script { @@ -10,7 +10,7 @@ contract VerifyScript is Script { function setUp() public {} - function run() public returns (bool) { + function run() public returns (bool){ uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); @@ -22,8 +22,8 @@ contract VerifyScript is Script { bytes32[] memory correct = new bytes32[](1); correct[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000003); - + bool equal = starter.verifyEqual(proofBytes, correct); return equal; } -} +} \ No newline at end of file diff --git a/with-foundry/script/prove.sh b/with-foundry/script/prove.sh index beffbb5..bce01a9 100755 --- a/with-foundry/script/prove.sh +++ b/with-foundry/script/prove.sh @@ -4,4 +4,4 @@ then echo "Usage: ./prove.sh [TESTNAME_STRING]" exit 1 fi -cd /tmp/$1 && nargo prove && echo "Proof Generated" +cd /tmp/$1 && nargo prove d && echo "Proof Generated" diff --git a/with-foundry/test/Starter.t.sol b/with-foundry/test/Starter.t.sol index b5e8c78..9fbc14a 100644 --- a/with-foundry/test/Starter.t.sol +++ b/with-foundry/test/Starter.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.17; import "forge-std/Test.sol"; import "../contract/Starter.sol"; -import "../circuits/contract/with_foundry/plonk_vk.sol"; +import "../circuits/contract/plonk_vk.sol"; contract StarterTest is Test { Starter public starter; @@ -21,14 +21,14 @@ contract StarterTest is Test { } function testVerifyProof() public { - string memory proof = vm.readLine("./circuits/proofs/with_foundry.proof"); + string memory proof = vm.readLine("./circuits/proofs/p.proof"); bytes memory proofBytes = vm.parseBytes(proof); starter.verifyEqual(proofBytes, correct); } function test_wrongProof() public { vm.expectRevert(); - string memory proof = vm.readLine("./circuits/proofs/with_foundry.proof"); + string memory proof = vm.readLine("./circuits/proofs/p.proof"); bytes memory proofBytes = vm.parseBytes(proof); starter.verifyEqual(proofBytes, wrong); } @@ -108,7 +108,7 @@ 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")); + string memory _newProof = vm.readLine(string.concat("/tmp/", _testName, "/proofs/d.proof")); return vm.parseBytes(_newProof); } } From 75ae2ec25258c474e1e9e124a0ec8056400d9ff1 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Tue, 15 Aug 2023 14:48:23 -0400 Subject: [PATCH 10/10] use 0.9.0 for CI --- .github/workflows/with_foundry.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/with_foundry.yaml b/.github/workflows/with_foundry.yaml index 1aa4244..1456ff9 100644 --- a/.github/workflows/with_foundry.yaml +++ b/.github/workflows/with_foundry.yaml @@ -19,7 +19,7 @@ jobs: - name: Install Nargo uses: noir-lang/noirup@v0.1.2 with: - toolchain: nightly + toolchain: 0.9.0 - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 @@ -31,7 +31,7 @@ jobs: - name: Generate proof run: | - nargo prove + nargo prove p working-directory: with-foundry/circuits - name: Test with Foundry