From 34141718e1b750f7cc2b52348056227a1ea34746 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 18 Apr 2023 12:31:35 +0000 Subject: [PATCH 01/15] initial setup --- .vscode/settings.json | 3 +- cpp/src/CMakeLists.txt | 1 + .../solidity_helpers/CMakeLists.txt | 17 + .../circuits/add_2_circuit.hpp | 32 + .../circuits/blake_circuit.hpp | 35 + .../circuits/recursive_circuit.hpp | 143 + .../barretenberg/solidity_helpers/key_gen.cpp | 100 + .../solidity_helpers/proof_gen.cpp | 93 + .../utils/instance_sol_gen.hpp | 30 + .../solidity_helpers/utils/utils.hpp | 23 + .../stdlib/hash/sha256/CMakeLists.txt | 2 +- .../stdlib/primitives/CMakeLists.txt | 2 +- sol/bootstrap.sh | 26 + sol/scripts/init.sh | 10 + sol/scripts/install_foundry.sh | 21 + sol/scripts/run_fuzzer.sh | 12 + sol/src/ultra/BaseUltraVerifier.sol | 2532 +++++++++++++++++ sol/src/ultra/instance/Add2UltraVerifier.sol | 16 + .../ultra/keys/Add2UltraVerificationKey.sol | 72 + 19 files changed, 3167 insertions(+), 3 deletions(-) create mode 100644 cpp/src/barretenberg/solidity_helpers/CMakeLists.txt create mode 100644 cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp create mode 100644 cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp create mode 100644 cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp create mode 100644 cpp/src/barretenberg/solidity_helpers/key_gen.cpp create mode 100644 cpp/src/barretenberg/solidity_helpers/proof_gen.cpp create mode 100644 cpp/src/barretenberg/solidity_helpers/utils/instance_sol_gen.hpp create mode 100644 cpp/src/barretenberg/solidity_helpers/utils/utils.hpp create mode 100644 sol/bootstrap.sh create mode 100755 sol/scripts/init.sh create mode 100755 sol/scripts/install_foundry.sh create mode 100755 sol/scripts/run_fuzzer.sh create mode 100644 sol/src/ultra/BaseUltraVerifier.sol create mode 100644 sol/src/ultra/instance/Add2UltraVerifier.sol create mode 100644 sol/src/ultra/keys/Add2UltraVerificationKey.sol diff --git a/.vscode/settings.json b/.vscode/settings.json index 489043bab0..f80de5b549 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -127,5 +127,6 @@ "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "cmake.sourceDirectory": "${workspaceFolder}/cpp" + "cmake.sourceDirectory": "${workspaceFolder}/cpp", + "C_Cpp.errorSquiggles": "disabled" } \ No newline at end of file diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index a90789f9c6..350392c187 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -52,6 +52,7 @@ add_subdirectory(barretenberg/plonk) add_subdirectory(barretenberg/stdlib) add_subdirectory(barretenberg/join_split_example) add_subdirectory(barretenberg/dsl) +add_subdirectory(barretenberg/solidity_helpers) if(BENCHMARKS) add_subdirectory(barretenberg/benchmark) diff --git a/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt b/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt new file mode 100644 index 0000000000..085b5297e5 --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt @@ -0,0 +1,17 @@ +barretenberg_module(stdlib_solidity_helpers plonk proof_system transcript crypto_pedersen_commitment polynomials crypto_sha256 ecc crypto_blake3s stdlib_primitives stdlib_pedersen_commitment stdlib_blake3s stdlib_blake2s) + +add_executable(solidity_key_gen key_gen.cpp) + +add_executable(solidity_proof_gen proof_gen.cpp) + +target_link_libraries( + solidity_key_gen + stdlib_solidity_helpers + env +) + +target_link_libraries( + solidity_proof_gen + stdlib_solidity_helpers + env +) diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp new file mode 100644 index 0000000000..1de3ab3c59 --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp @@ -0,0 +1,32 @@ +#include "barretenberg/stdlib/primitives/field/field.hpp" +#include "barretenberg/stdlib/primitives/witness/witness.hpp" +#include "barretenberg/stdlib/primitives/uint/uint.hpp" +#include "barretenberg/stdlib/primitives/bool/bool.hpp" + +// #include +// #include +// #include +// #include + +// using numeric::uint256_t; + +template class Add2Circuit { + public: + typedef stdlib::field_t field_ct; + typedef stdlib::witness_t witness_ct; + typedef stdlib::public_witness_t public_witness_ct; + + // Three public inputs + static Composer generate(std::string srs_path, uint256_t inputs[]) + { + + Composer composer(srs_path); + + field_ct a(public_witness_ct(&composer, inputs[0])); + field_ct b(public_witness_ct(&composer, inputs[1])); + field_ct c(public_witness_ct(&composer, inputs[2])); + c.assert_equal(a + b); + + return composer; + } +}; \ No newline at end of file diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp new file mode 100644 index 0000000000..a41a3c98a4 --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp @@ -0,0 +1,35 @@ +#include "barretenberg/stdlib/primitives/field/field.hpp" +#include "barretenberg/stdlib/primitives/witness/witness.hpp" +#include "barretenberg/stdlib/hash/blake2s/blake2s.hpp" + +//#include +//#include +//#include + +using namespace proof_system::plonk; +using namespace proof_system::plonk::stdlib; + +using numeric::uint256_t; + +template class BlakeCircuit { + public: + typedef stdlib::field_t field_ct; + typedef stdlib::public_witness_t public_witness_ct; + typedef stdlib::byte_array byte_array_ct; + + static constexpr size_t NUM_PUBLIC_INPUTS = 4; + + static Composer generate(std::string srs_path, uint256_t public_inputs[]) + { + Composer composer(srs_path); + + byte_array_ct input_buffer(&composer); + for (size_t i = 0; i < NUM_PUBLIC_INPUTS; ++i) { + input_buffer.write(byte_array_ct(field_ct(public_witness_ct(&composer, public_inputs[i])))); + } + + stdlib::blake2s(input_buffer); + + return composer; + } +}; \ No newline at end of file diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp new file mode 100644 index 0000000000..2e1add9315 --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp @@ -0,0 +1,143 @@ +#include "barretenberg/transcript/transcript.hpp" +#include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" +#include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib/recursion/verifier/verifier.hpp" +#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp" +#include "barretenberg/ecc/curves/bn254/fq12.hpp" +#include "barretenberg/ecc/curves/bn254/pairing.hpp" + +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +using namespace proof_system::plonk; + +using numeric::uint256_t; + +template class RecursiveCircuit { + using InnerComposer = UltraComposer; + + typedef stdlib::field_t field_ct; + typedef stdlib::bn254 inner_curve; + typedef stdlib::bn254 outer_curve; + typedef stdlib::recursion::verification_key verification_key_pt; + typedef stdlib::recursion::recursive_ultra_verifier_settings recursive_settings; + typedef stdlib::recursion::recursive_ultra_to_standard_verifier_settings + ultra_to_standard_recursive_settings; + typedef inner_curve::fr_ct fr_ct; + typedef inner_curve::public_witness_ct public_witness_ct; + typedef inner_curve::witness_ct witness_ct; + + struct circuit_outputs { + stdlib::recursion::aggregation_state aggregation_state; + std::shared_ptr verification_key; + }; + + static void create_inner_circuit_no_tables(InnerComposer& composer, uint256_t inputs[]) + { + field_ct a(witness_ct(&composer, inputs[0])); + field_ct b(public_witness_ct(&composer, inputs[1])); + field_ct c(public_witness_ct(&composer, inputs[2])); + + // @note For some reason, if we don't have this line, the circuit fails to verify. + // auto c_sq = c * c; + + c.assert_equal(a + b); + }; + + static circuit_outputs create_outer_circuit(InnerComposer& inner_composer, OuterComposer& outer_composer) + { + // These constexpr definitions are to allow for the following: + // An Ultra Pedersen hash evaluates to a different value from the Turbo/Standard versions of the Pedersen hash. + // Therefore, the fiat-shamir challenges generated by the prover and verifier _could_ accidentally be different + // if an ultra proof is generated using ultra-pedersen challenges, but is being verified within a non-ultra + // circuit which uses non-ultra-pedersen challenges. We need the prover and verifier hashes to be the same. The + // solution is to select the relevant prover and verifier types (whose settings use the same hash for + // fiat-shamir), depending on the Inner-Outer combo. It's a bit clunky, but the alternative is to have a + // template argument for the hashtype, and that would pervade the entire UltraComposer, which would be + // horrendous. + constexpr bool is_ultra_to_ultra = std::is_same::value; + typedef + typename std::conditional::type ProverOfInnerCircuit; + typedef typename std::conditional::type + VerifierOfInnerProof; + typedef + typename std::conditional::type + RecursiveSettings; + + ProverOfInnerCircuit prover; + if constexpr (is_ultra_to_ultra) { + prover = inner_composer.create_prover(); + } else { + prover = inner_composer.create_ultra_to_standard_prover(); + } + + const auto verification_key_native = inner_composer.compute_verification_key(); + + // Convert the verification key's elements into _circuit_ types, using the OUTER composer. + std::shared_ptr verification_key = + verification_key_pt::from_witness(&outer_composer, verification_key_native); + + proof recursive_proof = prover.construct_proof(); + + { + // Native check is mainly for comparison vs circuit version of the verifier. + VerifierOfInnerProof native_verifier; + + if constexpr (is_ultra_to_ultra) { + native_verifier = inner_composer.create_verifier(); + } else { + native_verifier = inner_composer.create_ultra_to_standard_verifier(); + } + auto native_result = native_verifier.verify_proof(recursive_proof); + if (native_result == false) { + throw std::runtime_error("Native verification failed"); + } + } + + transcript::Manifest recursive_manifest = InnerComposer::create_manifest(prover.key->num_public_inputs); + + // Verifying the ultra (inner) proof with CIRCUIT TYPES (i.e. within a standard or ultra plonk arithmetic + // circuit) + stdlib::recursion::aggregation_state output = + stdlib::recursion::verify_proof( + &outer_composer, verification_key, recursive_manifest, recursive_proof); + + return { output, verification_key }; + }; + + public: + static OuterComposer generate(std::string srs_path, uint256_t inputs[]) + { + InnerComposer inner_composer = InnerComposer(srs_path); + OuterComposer outer_composer = OuterComposer(srs_path); + + create_inner_circuit_no_tables(inner_composer, inputs); + auto circuit_output = create_outer_circuit(inner_composer, outer_composer); + + g1::affine_element P[2]; + P[0].x = barretenberg::fq(circuit_output.aggregation_state.P0.x.get_value().lo); + P[0].y = barretenberg::fq(circuit_output.aggregation_state.P0.y.get_value().lo); + P[1].x = barretenberg::fq(circuit_output.aggregation_state.P1.x.get_value().lo); + P[1].y = barretenberg::fq(circuit_output.aggregation_state.P1.y.get_value().lo); + + barretenberg::fq12 inner_proof_result = barretenberg::pairing::reduced_ate_pairing_batch_precomputed( + P, circuit_output.verification_key->reference_string->get_precomputed_g2_lines(), 2); + + if (inner_proof_result != barretenberg::fq12::one()) { + throw std::runtime_error("inner proof result != 1"); + } + + circuit_output.aggregation_state.add_proof_outputs_as_public_inputs(); + + if (outer_composer.failed()) { + throw std::runtime_error("outer composer failed"); + } + + return outer_composer; + } +}; \ No newline at end of file diff --git a/cpp/src/barretenberg/solidity_helpers/key_gen.cpp b/cpp/src/barretenberg/solidity_helpers/key_gen.cpp new file mode 100644 index 0000000000..c384bdcb6f --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/key_gen.cpp @@ -0,0 +1,100 @@ +#include + +#include "barretenberg/plonk/composer/standard_composer.hpp" +#include "barretenberg/plonk/composer/ultra_composer.hpp" +#include "barretenberg/plonk/proof_system/verification_key/sol_gen.hpp" + +#include "circuits/blake_circuit.hpp" +#include "circuits/add_2_circuit.hpp" +#include "circuits/recursive_circuit.hpp" + +#include "utils/utils.hpp" +#include "utils/instance_sol_gen.hpp" + +template +void generate_keys(std::string output_path, std::string srs_path, std::string flavour_prefix, std::string circuit_name) +{ + uint256_t public_inputs[4] = { 0, 0, 0, 0 }; + Composer composer = Circuit::generate(srs_path, public_inputs); + + (void)output_path; + (void)flavour_prefix; + (void)circuit_name; + + std::shared_ptr vkey = composer.compute_verification_key(); + + // Make verification key file upper case + circuit_name.at(0) = static_cast(std::toupper(static_cast(circuit_name.at(0)))); + flavour_prefix.at(0) = static_cast(std::toupper(static_cast(flavour_prefix.at(0)))); + + std::string vk_class_name = circuit_name + flavour_prefix + "VerificationKey"; + std::string base_class_name = "Base" + flavour_prefix + "Verifier"; + std::string instance_class_name = circuit_name + flavour_prefix + "Verifier"; + + { + auto vk_filename = output_path + "/keys/" + vk_class_name + ".sol"; + std::ofstream os(vk_filename); + proof_system::output_vk_sol(os, vkey, vk_class_name); + info("VK contract written to: ", vk_filename); + } + + { + auto instance_filename = output_path + "/instance/" + instance_class_name + ".sol"; + std::ofstream os(instance_filename); + output_instance(os, vk_class_name, base_class_name, instance_class_name); + info("Verifier instance written to: ", instance_filename); + } +} + +/* + * @brief Main entry point for the verification key generator + * + * 1. project_root_path: path to the solidity project root + * 2. srs_path: path to the srs db + */ +int main(int argc, char** argv) +{ + std::vector args(argv, argv + argc); + // if (args.size() < 3) + // { + // info( + // "usage: ", args[0], "[path to project root] [srs path]"); + // return 1; + // } + + if (args.size() < 5) { + info("usage: ", args[0], "[plonk flavour] [circuit flavour] [output path] [srs path]"); + return 1; + } + + const std::string plonk_flavour = args[1]; + const std::string circuit_flavour = args[2]; + const std::string output_path = args[3]; + const std::string srs_path = args[4]; + + // const std::string standard_path = project_root_path + "/src/standard"; + // const std::string ultra_path = project_root_path + "/src/ultra"; + + // @todo - Add support for unrolled standard verifier. Needs a new solidity verifier contract. + + if (plonk_flavour != "ultra") { + info("Only ultra plonk flavour is supported at the moment"); + return 1; + } else { + info("Generating ultra plonk keys"); + + if (circuit_flavour == "blake") { + generate_keys>( + output_path, srs_path, plonk_flavour, circuit_flavour); + } else if (circuit_flavour == "add2") { + generate_keys>( + output_path, srs_path, plonk_flavour, circuit_flavour); + } else if (circuit_flavour == "recursive") { + generate_keys>( + output_path, srs_path, plonk_flavour, circuit_flavour); + } else { + info("Only blake, add2 and recursive circuits are supported at the moment"); + return 1; + } + } +} \ No newline at end of file diff --git a/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp b/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp new file mode 100644 index 0000000000..44337c7b62 --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp @@ -0,0 +1,93 @@ +#include +#include +#include + +#include "barretenberg/plonk/composer/standard_composer.hpp" +#include "barretenberg/plonk/composer/ultra_composer.hpp" + +#include "circuits/blake_circuit.hpp" +#include "circuits/add_2_circuit.hpp" +#include "circuits/recursive_circuit.hpp" +#include "utils/utils.hpp" + +using namespace numeric; +using numeric::uint256_t; + +template void generate_proof(std::string srs_path, uint256_t inputs[]) +{ + Composer composer = Circuit::generate(srs_path, inputs); + + auto prover = composer.create_prover(); + auto proof = prover.construct_proof(); + { + auto verifier = composer.create_verifier(); + + if (!verifier.verify_proof(proof)) { + throw std::runtime_error("Verification failed"); + } + + std::string proof_bytes = bytes_to_hex_string(proof.proof_data); + std::cout << proof_bytes; + } +} + +std::string pad_left(std::string input, size_t length) +{ + return std::string(length - std::min(length, input.length()), '0') + input; +} + +/** + * @brief Main entry point for the proof generator. + * Expected inputs: + * 1. plonk_flavour: ultra + * 2. circuit_flavour: blake, add2, recursive + * 3. public_inputs: comma separated list of public inputs + * 4. project_root_path: path to the solidity project root + * 5. srs_path: path to the srs db + */ +int main(int argc, char** argv) +{ + std::vector args(argv, argv + argc); + + if (args.size() < 5) { + info("usage: ", args[0], "[plonk flavour] [circuit flavour] [srs path] [public inputs]"); + return 1; + } + + const std::string plonk_flavour = args[1]; + const std::string circuit_flavour = args[2]; + const std::string srs_path = args[3]; + const std::string string_input = args[4]; + + // @todo dynamically allocate this + uint256_t inputs[] = { 0, 0, 0, 0, 0 }; + + // Ran into issues with the old way of splitting strings. Used this to get around edge cases + size_t count = 0; + std::stringstream s_stream(string_input); // create string stream from the string + while (s_stream.good()) { + std::string sub; + getline(s_stream, sub, ','); // get first string delimited by comma + if (sub.substr(0, 2) == "0x") { + sub = sub.substr(2); + } + std::string padded = pad_left(sub, 64); + inputs[count++] = uint256_t(padded); + } + + if (plonk_flavour != "ultra") { + info("Only ultra plonk flavour is supported at the moment"); + return 1; + } else { + if (circuit_flavour == "blake") { + generate_proof>(srs_path, inputs); + } else if (circuit_flavour == "add2") { + generate_proof>(srs_path, inputs); + } else if (circuit_flavour == "recursive") { + generate_proof>(srs_path, inputs); + } else { + info("Invalid circuit flavour: " + circuit_flavour); + return 1; + } + } +} \ No newline at end of file diff --git a/cpp/src/barretenberg/solidity_helpers/utils/instance_sol_gen.hpp b/cpp/src/barretenberg/solidity_helpers/utils/instance_sol_gen.hpp new file mode 100644 index 0000000000..0bbcdb126e --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/utils/instance_sol_gen.hpp @@ -0,0 +1,30 @@ +/** + * Write a solidity file containing the instance importing vk params to the given stream. + **/ +inline void output_instance(std::ostream& os, + std::string const& vk_class_name, + std::string const& base_class_name, + std::string const& class_name) +{ + + std::string vk_filename = "../keys/" + vk_class_name + ".sol"; + std::string base_filename = "../" + base_class_name + ".sol"; + + // clang-format off + os << + "// SPDX-License-Identifier: Apache-2.0\n" + "// Copyright 2023 Aztec\n" + "pragma solidity >=0.8.4;\n\n" + "import {" << vk_class_name << " as VK} from \"" << vk_filename << "\";\n" + "import {" << base_class_name << " as BASE} from \"" << base_filename << "\";\n\n" + "contract " << class_name << " is BASE {\n" + " function getVerificationKeyHash() public pure override(BASE) returns (bytes32) {\n" + " return VK.verificationKeyHash();\n" + " }\n\n" + " function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BASE) {\n" + " VK.loadVerificationKey(vk, _omegaInverseLoc);\n" + " }\n" + "}\n"; + + os << std::flush; +} \ No newline at end of file diff --git a/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp b/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp new file mode 100644 index 0000000000..4e7046c809 --- /dev/null +++ b/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp @@ -0,0 +1,23 @@ +#include +#include + +// TODO Remove +// const std::string DEFAULT_PROJECT_ROOT_PATH = "../.."; +// const std::string DEFAULT_SRS_PATH = "../../barretenberg/cpp/srs_db/ignition"; + +std::string bytes_to_hex_string(const std::vector& input) +{ + static const char characters[] = "0123456789ABCDEF"; + + // Zeroes out the buffer unnecessarily, can't be avoided for std::string. + std::string ret(input.size() * 2, 0); + + // Hack... Against the rules but avoids copying the whole buffer. + auto buf = const_cast(ret.data()); + + for (const auto& oneInputByte : input) { + *buf++ = characters[oneInputByte >> 4]; + *buf++ = characters[oneInputByte & 0x0F]; + } + return ret; +} diff --git a/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt b/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt index e049536e74..00ee8f37e3 100644 --- a/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt +++ b/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_sha256 stdlib_primitives crypto_sha256) \ No newline at end of file +barretenberg_module(stdlib_sha256 stdlib_primitives crypto_sha256 crypto_blake3s) \ No newline at end of file diff --git a/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt b/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt index d3ec5d6738..6df807ad67 100644 --- a/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt +++ b/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_primitives plonk honk) \ No newline at end of file +barretenberg_module(stdlib_primitives plonk honk proof_system) \ No newline at end of file diff --git a/sol/bootstrap.sh b/sol/bootstrap.sh new file mode 100644 index 0000000000..70c6b1d18b --- /dev/null +++ b/sol/bootstrap.sh @@ -0,0 +1,26 @@ + +echo "Installing foundry..." +rm -rf broadcast cache out +. ./scripts/install_foundry.sh +forge install --no-commit +# Ensure libraries are at the correct version +git submodule update --init --recursive ./lib + +echo "Installing barretenberg..." +git submodule init +git submodule update + +echo "Downloading srs..." +cd ../cpp/srs_db +./download_ignition.sh 3 +#./download_ignition_lagrange.sh 12 +cd ../../sol + +echo "Building c++ binaries..." +./scripts/init.sh + +echo "Formatting code..." +forge fmt +forge build + +echo "Targets built, you are good to go!" \ No newline at end of file diff --git a/sol/scripts/init.sh b/sol/scripts/init.sh new file mode 100755 index 0000000000..3baf2367af --- /dev/null +++ b/sol/scripts/init.sh @@ -0,0 +1,10 @@ +#!/bin/bash + + +PLONK_FLAVOUR="ultra" +SRS_PATH="../cpp/srs_db/ignition" +OUTPUT_PATH="./src/ultra/" + +../cpp/build/bin/solidity_key_gen $PLONK_FLAVOUR add2 $OUTPUT_PATH $SRS_PATH +../cpp/build/bin/solidity_key_gen $PLONK_FLAVOUR blake $OUTPUT_PATH $SRS_PATH +../cpp/build/bin/solidity_key_gen $PLONK_FLAVOUR recursive $OUTPUT_PATH $SRS_PATH \ No newline at end of file diff --git a/sol/scripts/install_foundry.sh b/sol/scripts/install_foundry.sh new file mode 100755 index 0000000000..3842f6a431 --- /dev/null +++ b/sol/scripts/install_foundry.sh @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu + +export FOUNDRY_DIR="$PWD/.foundry" +FOUNDRY_BIN_DIR="$FOUNDRY_DIR/bin" +BIN_URL="https://raw.githubusercontent.com/foundry-rs/foundry/master/foundryup/foundryup" +BIN_PATH="$FOUNDRY_BIN_DIR/foundryup" +FOUNDRY_MAN_DIR="$FOUNDRY_DIR/share/man/man1" + +# Clean +rm -rf $FOUNDRY_DIR + +# Install foundryup. +mkdir -p $FOUNDRY_BIN_DIR +mkdir -p $FOUNDRY_MAN_DIR +curl -# -L $BIN_URL -o $BIN_PATH +chmod +x $BIN_PATH +export PATH=$FOUNDRY_BIN_DIR:$PATH + +# Use version. +foundryup \ No newline at end of file diff --git a/sol/scripts/run_fuzzer.sh b/sol/scripts/run_fuzzer.sh new file mode 100755 index 0000000000..e6e235a85e --- /dev/null +++ b/sol/scripts/run_fuzzer.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +PLONK_FLAVOUR=${1:-"ultra"} +CIRCUIT_FLAVOUR=${2:-"blake"} +INPUTS=${3:-"1,2,3,4"} + +INPUTS="$( sed 's/\\n//g' <<<"$INPUTS" )" + +SRS_PATH="../cpp/srs_db/ignition" + +# @note This needs to be updated to point to the generator +../cpp/build/bin/solidity_proof_gen $PLONK_FLAVOUR $CIRCUIT_FLAVOUR $SRS_PATH $INPUTS \ No newline at end of file diff --git a/sol/src/ultra/BaseUltraVerifier.sol b/sol/src/ultra/BaseUltraVerifier.sol new file mode 100644 index 0000000000..46f04c7f6b --- /dev/null +++ b/sol/src/ultra/BaseUltraVerifier.sol @@ -0,0 +1,2532 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +/** + * @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! + } + } + } +} \ No newline at end of file diff --git a/sol/src/ultra/instance/Add2UltraVerifier.sol b/sol/src/ultra/instance/Add2UltraVerifier.sol new file mode 100644 index 0000000000..44894f12f1 --- /dev/null +++ b/sol/src/ultra/instance/Add2UltraVerifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec +pragma solidity >=0.8.4; + +import {Add2UltraVerificationKey as VK} from "../keys/Add2UltraVerificationKey.sol"; +import {BaseUltraVerifier as BASE} from "../BaseUltraVerifier.sol"; + +contract Add2UltraVerifier is BASE { + function getVerificationKeyHash() public pure override(BASE) returns (bytes32) { + return VK.verificationKeyHash(); + } + + function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BASE) { + VK.loadVerificationKey(vk, _omegaInverseLoc); + } +} diff --git a/sol/src/ultra/keys/Add2UltraVerificationKey.sol b/sol/src/ultra/keys/Add2UltraVerificationKey.sol new file mode 100644 index 0000000000..51927724a4 --- /dev/null +++ b/sol/src/ultra/keys/Add2UltraVerificationKey.sol @@ -0,0 +1,72 @@ +// Verification Key Hash: a0e940165bfc708013d5b4f7940f3b07f3bcf3c0f57ee21d8b4bdb78630817a3 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +library Add2UltraVerificationKey { + function verificationKeyHash() internal pure returns(bytes32) { + return 0xa0e940165bfc708013d5b4f7940f3b07f3bcf3c0f57ee21d8b4bdb78630817a3; + } + + function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { + assembly { + mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000010) // vk.circuit_size + mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000003) // vk.num_inputs + mstore(add(_vk, 0x40), 0x21082ca216cbbf4e1c6e4f4594dd508c996dfbe1174efb98b11509c6e306460b) // vk.work_root + mstore(add(_vk, 0x60), 0x2d5e098bb31e86271ccb415b196942d755b0a9c3f21dd9882fa3d63ab1000001) // vk.domain_inverse + mstore(add(_vk, 0x80), 0x0fe8527a8494f827e4b332060e5569bdfe47aadc475cb1f03b4d222b0804e463) // vk.Q1.x + mstore(add(_vk, 0xa0), 0x2d051f6d8a9eec7ae2622b4b259fb91d942a8892632cffcdad4c03e2c9081593) // vk.Q1.y + mstore(add(_vk, 0xc0), 0x21be04985f898ef5e2a80f32fbaa16cd3eb8c451c243db46144b97113c8e556a) // vk.Q2.x + mstore(add(_vk, 0xe0), 0x2913bcdde62d6d2143aa6a0fed511ca527994df2cba6a780baa29dddac161de9) // vk.Q2.y + mstore(add(_vk, 0x100), 0x15bf0818d578953a624a127aa04d4b0aa1b09d3fe69b9a29e2546a41e9b08049) // vk.Q3.x + mstore(add(_vk, 0x120), 0x0148f0d2abf2ca1fe6cc20fdef0a8d4a88eb9602eaf48f0c1c02445c27cb9592) // vk.Q3.y + mstore(add(_vk, 0x140), 0x02d6fd9e84dbe74b7531e1801405a1c292117b1a17fefe9de0bfd9edf1a84bf9) // vk.Q4.x + mstore(add(_vk, 0x160), 0x293c6ab3c06a0669af13393a82c60a459a3b2a0b768da45ac7af7f2aec40fc42) // vk.Q4.y + mstore(add(_vk, 0x180), 0x2950076760523510abcfe90fa550b964e84b338f73af5222cdbbaefdacd4484e) // vk.Q_M.x + mstore(add(_vk, 0x1a0), 0x2e4e3e272c7b78ad894559812d7766e05615a8f7050a43d7ed1367adf30a9319) // vk.Q_M.y + mstore(add(_vk, 0x1c0), 0x1798c37010a4285e1774c1ad35779886380ee5ceee0ba183927e2a2103301a68) // vk.Q_C.x + mstore(add(_vk, 0x1e0), 0x2935f9e4d47a8e39aa0107f31a84584b47d903cfeb9690f6d850dc8ea7d2f4ea) // vk.Q_C.y + mstore(add(_vk, 0x200), 0x205aff7186f2cedc99e9cadb7930ef25f296991e5a7b574a33d6249f0a5db1f9) // vk.Q_ARITHMETIC.x + mstore(add(_vk, 0x220), 0x0beadc757bee3a2be1f6425385547099fc1eeeb1fed5a8552b07e997251d7c45) // 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), 0x01d8b8ff3b1674e57a7d30ce1d9e07c686174c643eb20d38e604eec7095248a9) // vk.SIGMA1.x + mstore(add(_vk, 0x320), 0x261015d69327a58810e6eb1052ed694914b7a89034e1334c50b9e70a161489b7) // vk.SIGMA1.y + mstore(add(_vk, 0x340), 0x1987df111730a8a6a650423757dbf048f3f43860a7d24a5e2e8bd67b6931ca67) // vk.SIGMA2.x + mstore(add(_vk, 0x360), 0x1fe074ff24b35d7830bec2a3fad7e53038ffb5e2a3f718a23660d68daffc2953) // vk.SIGMA2.y + mstore(add(_vk, 0x380), 0x191d6881b9369e50141da3f2009a2f2dfc9adba276e874eb9f7f3183a0ea8f89) // vk.SIGMA3.x + mstore(add(_vk, 0x3a0), 0x2cbfbdd75526be7e9f2830cb1fd99457227f90fb024902635e342344cb6b2926) // vk.SIGMA3.y + mstore(add(_vk, 0x3c0), 0x2e7fe658b8f1f34dc561568e4ef6c74bb36330404967952b1e15390c1e2443cf) // vk.SIGMA4.x + mstore(add(_vk, 0x3e0), 0x293a5337eedc88329f10aa45a11e4adbb77f74717345987d70ed726e3e4556f1) // 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), 0x0baaf073a203ba4ba0093c827bb5b3f7a55611765f111ecf80c456f631e99f29) // vk.ID1.x + mstore(add(_vk, 0x560), 0x27cd34cafd5735ec970278202765e0f1e9da3494b30b948ebce3414d078cef9e) // vk.ID1.y + mstore(add(_vk, 0x580), 0x0868357b28039385c5a5058b6d358ebb29f26f9890d6cc6401f4921d5884edca) // vk.ID2.x + mstore(add(_vk, 0x5a0), 0x1060afe929554ca473103f5e68193c36fb6e229dde8edf7ec858b12d7e8be485) // vk.ID2.y + mstore(add(_vk, 0x5c0), 0x0b1c02619282755533457230b19b4a15226e07e207744c0857074dcab883af4a) // vk.ID3.x + mstore(add(_vk, 0x5e0), 0x0d928deafed363659688ed4ccdef521f2a0277e4807e6e1cbabca21dde5eb5e1) // 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 + } + } +} From 319956b419ec491b70b763c18ff0a46c4af0c53e Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 18 Apr 2023 14:44:40 +0000 Subject: [PATCH 02/15] feat: add test setup --- .gitmodules | 9 + .../circuits/recursive_circuit.hpp | 5 +- .../barretenberg/solidity_helpers/key_gen.cpp | 2 +- .../solidity_helpers/proof_gen.cpp | 10 +- sol/.gitignore | 15 ++ sol/README.md | 71 ++++++++ sol/bootstrap.sh | 0 sol/figures/verifier.png | Bin 0 -> 29769 bytes sol/foundry.toml | 12 ++ sol/lib/forge-std | 1 + sol/lib/openzeppelin-contracts | 1 + sol/lib/solidity-stringutils | 1 + sol/remappings.txt | 2 + sol/src/interfaces/IVerifier.sol | 7 + sol/src/ultra/BaseUltraVerifier.sol | 2 +- sol/src/ultra/instance/Add2UltraVerifier.sol | 2 +- sol/src/ultra/instance/BlakeUltraVerifier.sol | 16 ++ .../ultra/instance/RecursiveUltraVerifier.sol | 16 ++ .../ultra/keys/Add2UltraVerificationKey.sol | 10 +- .../ultra/keys/BlakeUltraVerificationKey.sol | 72 ++++++++ .../keys/RecursiveUltraVerificationKey.sol | 72 ++++++++ sol/test/base/DifferentialFuzzer.sol | 101 +++++++++++ sol/test/base/TestBase.sol | 162 ++++++++++++++++++ sol/test/ultra/Add2.t.sol | 40 +++++ sol/test/ultra/Blake.t.sol | 42 +++++ sol/test/ultra/Recursive.t.sol | 40 +++++ sol/test/ultra/TestBaseUltra.sol | 23 +++ 27 files changed, 719 insertions(+), 15 deletions(-) create mode 100644 sol/.gitignore create mode 100644 sol/README.md mode change 100644 => 100755 sol/bootstrap.sh create mode 100644 sol/figures/verifier.png create mode 100644 sol/foundry.toml create mode 160000 sol/lib/forge-std create mode 160000 sol/lib/openzeppelin-contracts create mode 160000 sol/lib/solidity-stringutils create mode 100644 sol/remappings.txt create mode 100644 sol/src/interfaces/IVerifier.sol create mode 100644 sol/src/ultra/instance/BlakeUltraVerifier.sol create mode 100644 sol/src/ultra/instance/RecursiveUltraVerifier.sol create mode 100644 sol/src/ultra/keys/BlakeUltraVerificationKey.sol create mode 100644 sol/src/ultra/keys/RecursiveUltraVerificationKey.sol create mode 100644 sol/test/base/DifferentialFuzzer.sol create mode 100644 sol/test/base/TestBase.sol create mode 100644 sol/test/ultra/Add2.t.sol create mode 100644 sol/test/ultra/Blake.t.sol create mode 100644 sol/test/ultra/Recursive.t.sol create mode 100644 sol/test/ultra/TestBaseUltra.sol diff --git a/.gitmodules b/.gitmodules index 29296995e2..d07f11dee8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,12 @@ [submodule "foundation"] path = foundation url = git@github.com:AztecProtocol/foundation.git +[submodule "sol/lib/forge-std"] + path = sol/lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "sol/lib/solidity-stringutils"] + path = sol/lib/solidity-stringutils + url = https://github.com/Arachnid/solidity-stringutils +[submodule "sol/lib/openzeppelin-contracts"] + path = sol/lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp index 2e1add9315..64f17220c7 100644 --- a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp +++ b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp @@ -39,14 +39,15 @@ template class RecursiveCircuit { static void create_inner_circuit_no_tables(InnerComposer& composer, uint256_t inputs[]) { - field_ct a(witness_ct(&composer, inputs[0])); + field_ct a(public_witness_ct(&composer, inputs[0])); field_ct b(public_witness_ct(&composer, inputs[1])); field_ct c(public_witness_ct(&composer, inputs[2])); // @note For some reason, if we don't have this line, the circuit fails to verify. - // auto c_sq = c * c; + auto c_sq = c * c; c.assert_equal(a + b); + c_sq.assert_equal(c * c); }; static circuit_outputs create_outer_circuit(InnerComposer& inner_composer, OuterComposer& outer_composer) diff --git a/cpp/src/barretenberg/solidity_helpers/key_gen.cpp b/cpp/src/barretenberg/solidity_helpers/key_gen.cpp index c384bdcb6f..cd34f70e45 100644 --- a/cpp/src/barretenberg/solidity_helpers/key_gen.cpp +++ b/cpp/src/barretenberg/solidity_helpers/key_gen.cpp @@ -81,7 +81,7 @@ int main(int argc, char** argv) info("Only ultra plonk flavour is supported at the moment"); return 1; } else { - info("Generating ultra plonk keys"); + info("Generating ultra plonk keys for ", circuit_flavour, " circuit"); if (circuit_flavour == "blake") { generate_keys>( diff --git a/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp b/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp index 44337c7b62..1448597c32 100644 --- a/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp +++ b/cpp/src/barretenberg/solidity_helpers/proof_gen.cpp @@ -17,10 +17,11 @@ template void generate_proof(std::string s { Composer composer = Circuit::generate(srs_path, inputs); - auto prover = composer.create_prover(); + // @todo this only works for ultra! Why is ultra part of function name on ultra composer? + auto prover = composer.create_ultra_with_keccak_prover(); auto proof = prover.construct_proof(); { - auto verifier = composer.create_verifier(); + auto verifier = composer.create_ultra_with_keccak_verifier(); if (!verifier.verify_proof(proof)) { throw std::runtime_error("Verification failed"); @@ -62,12 +63,11 @@ int main(int argc, char** argv) // @todo dynamically allocate this uint256_t inputs[] = { 0, 0, 0, 0, 0 }; - // Ran into issues with the old way of splitting strings. Used this to get around edge cases size_t count = 0; - std::stringstream s_stream(string_input); // create string stream from the string + std::stringstream s_stream(string_input); while (s_stream.good()) { std::string sub; - getline(s_stream, sub, ','); // get first string delimited by comma + getline(s_stream, sub, ','); if (sub.substr(0, 2) == "0x") { sub = sub.substr(2); } diff --git a/sol/.gitignore b/sol/.gitignore new file mode 100644 index 0000000000..434dd3d2ff --- /dev/null +++ b/sol/.gitignore @@ -0,0 +1,15 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Dotenv file +.env +.vscode/settings.json +.foundry + +build/ \ No newline at end of file diff --git a/sol/README.md b/sol/README.md new file mode 100644 index 0000000000..1e94a935c6 --- /dev/null +++ b/sol/README.md @@ -0,0 +1,71 @@ +# Solidity Verifier contracts and tests + +**Note:** ONLY Ultra verifier as rolled versions were removed. [aztec-verifier-contracts](https://github.com/AztecProtocol/aztec-verifier-contracts) contains old code with rolled standard verifier and tests. + + +This folder contains verifier contracts and testing harnesses that are used by [Noir, our Zero-Knowledge Programming Language](https://github.com/noir-lang/noir). + +The implementations maintain the same interface, regardless of the verifier flavour (Standard, Turbo, Ultra), this should enable upstream implementations to be "plug-and-play". + +The verifier will follow an overall architecture below, consisting of 3 contracts/libraries. Namely, the verifier algorithm (stable across circuits), the verification key (circuit dependent) and then the "verifier instance", a base that reads from the verification key and uses the key's values in the verification algorithm. The main advantage of this design is that we can generate verification key's per circuit and plug them into a general verification algorithm. + +![Verifier architecture](./figures/verifier.png) + +The verification key is currently generated via [Barretenberg](https://github.com/AztecProtocol/barretenberg/blob/master/cpp/src/aztec/proof_system/verification_key/sol_gen.hpp), Aztec's backend for generating proofs. + +## Current implementations + +- UltraPlonK (see `src/ultra`) + +## Generating Verification Keys and Proofs + +Run `bootstrap.sh` to clone git submodules, download SRS and generate verification keys, relies on barretenberg already being compiled (run `./bootstrap` in `cpp`). The bootstrap will also install foundry to `./.foundry` so you can use `./.foundry/bin/forge` if you don't already have foundry installed. + +# Tests + +Test are performed with a `TestBase` harness, it provides helpers for reading files and printing proofs. The tests also require proofs and verification keys, those are build as part of the `bootstrap.sh`. + +## How To Run the Tests? + +To run all tests, run the following scripts at the root of the repo: + +```bash +forge test --no-match-contract TestBase # add -(v, vv, vvv, vvvv) for verbosity of logs, no logs emitted as default +``` + +To run test for a specific Contract test, + +```bash +forge test --match-contract # e.g., StandardTest +``` + +To run a specific test + +```bash +forge test --match-test # e.g., testValidProof +``` + +Example to run only `testValidProof` for the Standard verifier with logs: + +```bash +forge test --match-contract StandardTest --match-test testValidProof -vvvv +``` + +## Debugging in assembly + +Debugging from inside the assembly can be pretty inconvenient. The quickest way to get going is to add a custom error: +```solidity +bytes4 internal constant ERR_S = 0xf7b44074; +error ERR(bytes32,bytes32,bytes32); +``` +Where `ERR_S` is the selector (first 4 bytes of keccak256(function signature)). + +To revert the contract, and print values, you can then do as +```solidity +mstore(0x00, ERR_S) // put the selector in memory +mstore(0x04, val_1) // add first value after selector +mstore(0x24, val_2) // add second value after first +mstore(0x44, val_3) // add third value after second +revert(0x00, 0x64) // revert with a message containing 0x64 bytes defined above +``` +When running a test, you will then see the three values `val_1, val_2, val_3` in the console. \ No newline at end of file diff --git a/sol/bootstrap.sh b/sol/bootstrap.sh old mode 100644 new mode 100755 diff --git a/sol/figures/verifier.png b/sol/figures/verifier.png new file mode 100644 index 0000000000000000000000000000000000000000..b099f9c8af75588d4ac3bc91cf1e1bb2ff1466cd GIT binary patch literal 29769 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.8.4; + +interface IVerifier { + function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); +} diff --git a/sol/src/ultra/BaseUltraVerifier.sol b/sol/src/ultra/BaseUltraVerifier.sol index 46f04c7f6b..1d2842c35e 100644 --- a/sol/src/ultra/BaseUltraVerifier.sol +++ b/sol/src/ultra/BaseUltraVerifier.sol @@ -2529,4 +2529,4 @@ abstract contract BaseUltraVerifier { } } } -} \ No newline at end of file +} diff --git a/sol/src/ultra/instance/Add2UltraVerifier.sol b/sol/src/ultra/instance/Add2UltraVerifier.sol index 44894f12f1..1bbaed7216 100644 --- a/sol/src/ultra/instance/Add2UltraVerifier.sol +++ b/sol/src/ultra/instance/Add2UltraVerifier.sol @@ -11,6 +11,6 @@ contract Add2UltraVerifier is BASE { } function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BASE) { - VK.loadVerificationKey(vk, _omegaInverseLoc); + VK.loadVerificationKey(vk, _omegaInverseLoc); } } diff --git a/sol/src/ultra/instance/BlakeUltraVerifier.sol b/sol/src/ultra/instance/BlakeUltraVerifier.sol new file mode 100644 index 0000000000..5442c999e1 --- /dev/null +++ b/sol/src/ultra/instance/BlakeUltraVerifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec +pragma solidity >=0.8.4; + +import {BlakeUltraVerificationKey as VK} from "../keys/BlakeUltraVerificationKey.sol"; +import {BaseUltraVerifier as BASE} from "../BaseUltraVerifier.sol"; + +contract BlakeUltraVerifier is BASE { + function getVerificationKeyHash() public pure override(BASE) returns (bytes32) { + return VK.verificationKeyHash(); + } + + function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BASE) { + VK.loadVerificationKey(vk, _omegaInverseLoc); + } +} diff --git a/sol/src/ultra/instance/RecursiveUltraVerifier.sol b/sol/src/ultra/instance/RecursiveUltraVerifier.sol new file mode 100644 index 0000000000..f2147aada6 --- /dev/null +++ b/sol/src/ultra/instance/RecursiveUltraVerifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec +pragma solidity >=0.8.4; + +import {RecursiveUltraVerificationKey as VK} from "../keys/RecursiveUltraVerificationKey.sol"; +import {BaseUltraVerifier as BASE} from "../BaseUltraVerifier.sol"; + +contract RecursiveUltraVerifier is BASE { + function getVerificationKeyHash() public pure override(BASE) returns (bytes32) { + return VK.verificationKeyHash(); + } + + function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BASE) { + VK.loadVerificationKey(vk, _omegaInverseLoc); + } +} diff --git a/sol/src/ultra/keys/Add2UltraVerificationKey.sol b/sol/src/ultra/keys/Add2UltraVerificationKey.sol index 51927724a4..67c3b6080a 100644 --- a/sol/src/ultra/keys/Add2UltraVerificationKey.sol +++ b/sol/src/ultra/keys/Add2UltraVerificationKey.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.4; library Add2UltraVerificationKey { - function verificationKeyHash() internal pure returns(bytes32) { + function verificationKeyHash() internal pure returns (bytes32) { return 0xa0e940165bfc708013d5b4f7940f3b07f3bcf3c0f57ee21d8b4bdb78630817a3; } @@ -62,10 +62,10 @@ library Add2UltraVerificationKey { 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(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 } } diff --git a/sol/src/ultra/keys/BlakeUltraVerificationKey.sol b/sol/src/ultra/keys/BlakeUltraVerificationKey.sol new file mode 100644 index 0000000000..0b8676e4da --- /dev/null +++ b/sol/src/ultra/keys/BlakeUltraVerificationKey.sol @@ -0,0 +1,72 @@ +// Verification Key Hash: ab0e7eca8953a659e04b83b3e1eb0525036ab76b5c6c53b090c8e3e568df3912 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +library BlakeUltraVerificationKey { + function verificationKeyHash() internal pure returns (bytes32) { + return 0xab0e7eca8953a659e04b83b3e1eb0525036ab76b5c6c53b090c8e3e568df3912; + } + + function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { + assembly { + mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000008000) // vk.circuit_size + mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) // vk.num_inputs + mstore(add(_vk, 0x40), 0x2d1ba66f5941dc91017171fa69ec2bd0022a2a2d4115a009a93458fd4e26ecfb) // vk.work_root + mstore(add(_vk, 0x60), 0x3063edaa444bddc677fcd515f614555a777997e0a9287d1e62bf6dd004d82001) // vk.domain_inverse + mstore(add(_vk, 0x80), 0x1a80f3623f0778b08837c863a65a1947e56828b26496c5737e25041052f7009c) // vk.Q1.x + mstore(add(_vk, 0xa0), 0x2a3cacc92240779ca4f320c576190d0d6ec1266368357178a9a8260cfa235455) // vk.Q1.y + mstore(add(_vk, 0xc0), 0x2acda97834aca4418d41ed03d801e2dd48a1d0b5c41d76ad369a8f7af50e0661) // vk.Q2.x + mstore(add(_vk, 0xe0), 0x1b69f6a121b1cb789d87cbb3236233b7a4a480ee9bdde5b7bd47e62a227dc5fc) // vk.Q2.y + mstore(add(_vk, 0x100), 0x0ac1dea6a1af1f8971d1341ab89d8a04f441306474df59985c648f96d1de246c) // vk.Q3.x + mstore(add(_vk, 0x120), 0x0d41764f9161b19571da0200f8efa730ac7c2025e09a2decd3e4889261792e8b) // vk.Q3.y + mstore(add(_vk, 0x140), 0x26c4dcb136c91c0acb772bba73db577c1f0f3c09cf4dd7cf4a2bcecf4aa3057a) // vk.Q4.x + mstore(add(_vk, 0x160), 0x0a5072484a9fce7eef8d097a377375142da6f88bb9616d5ca1f2aad4bb092129) // vk.Q4.y + mstore(add(_vk, 0x180), 0x2c294f4909e331bfdaf0b65ac1b7197251217d346f0b990471359d419a632662) // vk.Q_M.x + mstore(add(_vk, 0x1a0), 0x0b3d987ce70e2cff4a2fd93156efd896e0f4f9f671ccb1ab8c3493217b3d9b07) // vk.Q_M.y + mstore(add(_vk, 0x1c0), 0x1dfbace7f5f42d72d8df9c6c40a118a8c05d340796095cdb30d5ae76807ff4c3) // vk.Q_C.x + mstore(add(_vk, 0x1e0), 0x1a8d4a2ec9837b684fa5b688e36f48288c1450591c7e807bbb86ec125d7b3dd4) // vk.Q_C.y + mstore(add(_vk, 0x200), 0x0a51756abf4c062b5f4d76b29e1dbba021b670d13442aee1fef9e3018eb4aca4) // vk.Q_ARITHMETIC.x + mstore(add(_vk, 0x220), 0x0ad4318714e1493aae41463ebd941fd2d7fb5357c55ae9eb6491c7c3ccb8399d) // vk.Q_ARITHMETIC.y + mstore(add(_vk, 0x240), 0x0d7d8284681025c0926d0bfda9a6887098f151a49b27160e76c0cbe5e081fcb8) // vk.QSORT.x + mstore(add(_vk, 0x260), 0x083b2abe0a5c29769ba8f427e7440a3dcb1ffcd86cb1b106f0aa27b6903655ba) // vk.QSORT.y + mstore(add(_vk, 0x280), 0x21959276775cd4749236c8bf773a9b2403cecb45fbf70e6439f73d75442e8850) // vk.Q_ELLIPTIC.x + mstore(add(_vk, 0x2a0), 0x017714509f01d1a9ee7ebaf4d50745e33a14150b4fe9850a27e44de56d88cb14) // vk.Q_ELLIPTIC.y + mstore(add(_vk, 0x2c0), 0x2e76c4474fcb457db84fb273ccc10a4647a1a37444369f2f275bb74540f5e2d0) // vk.Q_AUX.x + mstore(add(_vk, 0x2e0), 0x209035caddd02a78acd0ed617a85d782533bd142c6cad8e3338f3142b919c3a4) // vk.Q_AUX.y + mstore(add(_vk, 0x300), 0x12922936896c92f4773be96aa6eced49c9e6973d091baca38bcd2ce7c2432b13) // vk.SIGMA1.x + mstore(add(_vk, 0x320), 0x0195e866ae7531344bc2cec037b002d99caace033bdbdf98b4db64b1e23be236) // vk.SIGMA1.y + mstore(add(_vk, 0x340), 0x136128a1e6bc7bc733fcb9343fe23760d8d8a08d4ba4cdfc8970429696720a85) // vk.SIGMA2.x + mstore(add(_vk, 0x360), 0x222d19d2afae1cc8c5b1b802be90b5d4d648f5e89f4b32df381fb92135497a2c) // vk.SIGMA2.y + mstore(add(_vk, 0x380), 0x0dea033b8db2e2948559604ffac72f411931477ca58240ce0a3007c9a82d1b0a) // vk.SIGMA3.x + mstore(add(_vk, 0x3a0), 0x1fd05a799d3dfaba1bfed3145b27e4768be0bc0893b24962de96fdbce7cdc319) // vk.SIGMA3.y + mstore(add(_vk, 0x3c0), 0x07f75bc93d92e6dccd6ba833a23aa5d1ba7c36cd2e2d6c2e6406c62480e19119) // vk.SIGMA4.x + mstore(add(_vk, 0x3e0), 0x253f74ab6ef1778beba646f245c7dcd5e60cdaebcc37d2c5db22caf03ee7091f) // vk.SIGMA4.y + mstore(add(_vk, 0x400), 0x06c5d3c2a64587cf9dc278c6892854fc8f1aba4183115224cb2eda4c1aab64b8) // vk.TABLE1.x + mstore(add(_vk, 0x420), 0x132622df9222e04fa9c4cf2895212a49556038d4fdc6d0d7a15b1067bb446efa) // vk.TABLE1.y + mstore(add(_vk, 0x440), 0x2dbc1ac72b2f0c530b3bdbef307395e6059f82ce9f3beea34ff6c3a04ca112bc) // vk.TABLE2.x + mstore(add(_vk, 0x460), 0x23e9676a2c36926b3e10b1102f06aa3a9828d1422ae9e6ea77203025cd18ada0) // vk.TABLE2.y + mstore(add(_vk, 0x480), 0x298b6eb4baf5c75d4542a2089226886cc3ef984af332cae76356af6da70820fe) // vk.TABLE3.x + mstore(add(_vk, 0x4a0), 0x1bb16a4d3b60d47e572e02fac8bf861df5ba5f96942054e0896c7d4d602dc5c7) // vk.TABLE3.y + mstore(add(_vk, 0x4c0), 0x1f5976fc145f0524228ca90c221a21228ff9be92d487b56890a39c3bc0d22bf2) // vk.TABLE4.x + mstore(add(_vk, 0x4e0), 0x0f43d83a0d9eb36476e05c8d1280df98ec46ce93ae238597a687a4937ebec6cc) // vk.TABLE4.y + mstore(add(_vk, 0x500), 0x0b140556df3e8e29980eeae95a724d3c06c830707ce655b6bee64acc9be9e9c2) // vk.TABLE_TYPE.x + mstore(add(_vk, 0x520), 0x04de5162de4a6bea5e1e3b1386d87d41adef6c98203f749c98d2c2113ba12e9b) // vk.TABLE_TYPE.y + mstore(add(_vk, 0x540), 0x2e9d323290bebf84302163b43af960fde161663907a5e344ab62e3d0db9dc2a4) // vk.ID1.x + mstore(add(_vk, 0x560), 0x282cbb41af3a18746f880f35caf350a0e653cc9ff266380f9dad6c8145fc8532) // vk.ID1.y + mstore(add(_vk, 0x580), 0x29c73bc4fb55d00bb6b91bff171aaa98e3ab1d64829603b29a5364e510f692d7) // vk.ID2.x + mstore(add(_vk, 0x5a0), 0x1011dea47912a0daae13bf8f0e4b6df1f706252a27b69d34724cd05a3bbb5542) // vk.ID2.y + mstore(add(_vk, 0x5c0), 0x040261783eb93ad94557cb1c9c798d8468953eb65b00b3e0059fc7af5555ac5f) // vk.ID3.x + mstore(add(_vk, 0x5e0), 0x0e05422e3bc394ae55128d83ed0087f1d18810c951f4d03b2f0eff6d5b2e74a2) // vk.ID3.y + mstore(add(_vk, 0x600), 0x1b21ff32cadfbe3b43171ee3d0b14d1eed1c29e3719320d3e61f0e71c6aaf6d8) // vk.ID4.x + mstore(add(_vk, 0x620), 0x04f57e846a88c4a0254841cf7b6226e878e7a4ea49c34c3732870f1d8c4f6c18) // 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, 0x05d33766e4590b3722701b6f2fa43d0dc3f028424d384e68c92a742fb2dbc0b4) // vk.work_root_inverse + } + } +} diff --git a/sol/src/ultra/keys/RecursiveUltraVerificationKey.sol b/sol/src/ultra/keys/RecursiveUltraVerificationKey.sol new file mode 100644 index 0000000000..4b118cdef6 --- /dev/null +++ b/sol/src/ultra/keys/RecursiveUltraVerificationKey.sol @@ -0,0 +1,72 @@ +// Verification Key Hash: 507de35addf16b79526d713259492d5d1764fdb6ce55ff4ccb03c147b72f381a +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +library RecursiveUltraVerificationKey { + function verificationKeyHash() internal pure returns (bytes32) { + return 0x507de35addf16b79526d713259492d5d1764fdb6ce55ff4ccb03c147b72f381a; + } + + function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { + assembly { + mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000080000) // vk.circuit_size + mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000010) // vk.num_inputs + mstore(add(_vk, 0x40), 0x2260e724844bca5251829353968e4915305258418357473a5c1d597f613f6cbd) // vk.work_root + mstore(add(_vk, 0x60), 0x3064486657634403844b0eac78ca882cfd284341fcb0615a15cfcd17b14d8201) // vk.domain_inverse + mstore(add(_vk, 0x80), 0x18fe72968b540c1dad6c7648fcb3407edfc489d8dcf3fdce314c1f0e72684c43) // vk.Q1.x + mstore(add(_vk, 0xa0), 0x16f49263ee016852edfed2e84bf44c22b31064b9034b62059329b2af2f349c37) // vk.Q1.y + mstore(add(_vk, 0xc0), 0x1c382676d0f8e5691def3a60d533850f573c36aa200ab364c091acc4a7eb094f) // vk.Q2.x + mstore(add(_vk, 0xe0), 0x17c05ca7ea679681a3cf772fabcf2c1a988e39910f1ba8de3d1f68ffb0effda1) // vk.Q2.y + mstore(add(_vk, 0x100), 0x257d75dead2d8cbb2f63b3592a762a2c2dbe0195a533736fd01982370e768676) // vk.Q3.x + mstore(add(_vk, 0x120), 0x258b6d74446f5e532bce6e1a62372a82986eac9801c13a8553f373c30398a47c) // vk.Q3.y + mstore(add(_vk, 0x140), 0x290ff6a808f6abe7508a8c884ea0fc2f819e23a5b6d7c2dd1105da2a3f0637e0) // vk.Q4.x + mstore(add(_vk, 0x160), 0x2e6c3c419be44ed56b61069a06e980360f58830ad52b38bb69de92c456ebf0ca) // vk.Q4.y + mstore(add(_vk, 0x180), 0x282e6e14bbedfc7ef013feb4877ce9098389abfd3ad8899c957be4fdb20d0454) // vk.Q_M.x + mstore(add(_vk, 0x1a0), 0x2483d06975c3965d3f2d205ddeff196b90ca5883878bffc0bd190a357fee947e) // vk.Q_M.y + mstore(add(_vk, 0x1c0), 0x09af8fed71838d47b0052d8e3fdda11f55c62a6f2cb9aab24edd90b5e9640e9c) // vk.Q_C.x + mstore(add(_vk, 0x1e0), 0x2bdf7549fa146188dd750d032d9dec911c5799ca99f72405c4ac49f3f9e3a51a) // vk.Q_C.y + mstore(add(_vk, 0x200), 0x1479a535c87c413301d82c5ae1598b46c03117a57b878416d1143bb48f1df8bf) // vk.Q_ARITHMETIC.x + mstore(add(_vk, 0x220), 0x03203e3c02cc68282d93507d0ad9d56304d5a4b2908233bcb6f8682f8b264532) // vk.Q_ARITHMETIC.y + mstore(add(_vk, 0x240), 0x0cccd1de3f4ef2a2bfffbb7a91f8be2c49e9dc9b565ba4312015a88558f40d20) // vk.QSORT.x + mstore(add(_vk, 0x260), 0x092c5bd4edb996d6c1189a2682f6e93ede4b9aff7f07823605c894f833316718) // vk.QSORT.y + mstore(add(_vk, 0x280), 0x20089848d81ee4e8d7700679e7b5ed017916e2ee28bf76c0e0f4862274637bb8) // vk.Q_ELLIPTIC.x + mstore(add(_vk, 0x2a0), 0x0faae100924d24a70708e49a08ba2ba9df261088bf04e7b4c3f811cc0d8995fe) // vk.Q_ELLIPTIC.y + mstore(add(_vk, 0x2c0), 0x2de71f46452329536fe14dfff808692c405b9ef1ae47c451be8383ded868af5c) // vk.Q_AUX.x + mstore(add(_vk, 0x2e0), 0x0a520e2f877f19cc69aad2396bf741e6864a9f0b657887e80165b794f7612e71) // vk.Q_AUX.y + mstore(add(_vk, 0x300), 0x2779b1b7b8433eeee7333a1372feb4587da74e2c93cc54917e201748ed847204) // vk.SIGMA1.x + mstore(add(_vk, 0x320), 0x2198823f66ad59612f6cb77aff9437388abdbcc4d8f6eac792d8bca7d1b341d9) // vk.SIGMA1.y + mstore(add(_vk, 0x340), 0x1f6732b9d128931b2e32b2cae73b029720cca3cef23fee25363d520ed0ba3f92) // vk.SIGMA2.x + mstore(add(_vk, 0x360), 0x15fb336844e68b08361c10b83e7d6ea0f011958774e58e5f7c43e6606e989ecc) // vk.SIGMA2.y + mstore(add(_vk, 0x380), 0x0984b1b6c723afb4713656abf30b06e2ad04c054dd3acf016a6db1ee7111ca11) // vk.SIGMA3.x + mstore(add(_vk, 0x3a0), 0x03421d01f19c6b91e477648819f57d888b3b23b67599266293bddf91a2636ff1) // vk.SIGMA3.y + mstore(add(_vk, 0x3c0), 0x2f77cda90d366b151b17c5667f10526ab0fe144aecb307e00ede6039365bcfa0) // vk.SIGMA4.x + mstore(add(_vk, 0x3e0), 0x0d1e8f758babcbbf134dfe341c262ee25d0254cba8f5487ad5bddd190f27a9e8) // vk.SIGMA4.y + mstore(add(_vk, 0x400), 0x2f61a890b9f1dff4ef5c8b0eafe9b71c7a23dc4c8a6791d9c01418310f4a7b2e) // vk.TABLE1.x + mstore(add(_vk, 0x420), 0x07c8a51d1881fcdfe1cb7dcefc48a44047c7f5386797d5f8553ce2e12e8daba0) // vk.TABLE1.y + mstore(add(_vk, 0x440), 0x1adf56913dea23b7b14c952933b0b40fc476dc2697a758ec9df73802b0596c2f) // vk.TABLE2.x + mstore(add(_vk, 0x460), 0x212a1759e19285a35a70a245cca6477f89b6f156e4425cf52cfccb4594f59152) // vk.TABLE2.y + mstore(add(_vk, 0x480), 0x1527f8c19085ac209ebddbccae4dd0ca58b078e56fd20d651ce3a3194697b191) // vk.TABLE3.x + mstore(add(_vk, 0x4a0), 0x02247dca9c3cb09318aa6100a2a7c628281c69bc41cfda34aa72c263b69344b4) // vk.TABLE3.y + mstore(add(_vk, 0x4c0), 0x12eea56d2ada3befa5db215ea5ebbd37b5ce95fcd1cf7adb94d5a1784876b4f7) // vk.TABLE4.x + mstore(add(_vk, 0x4e0), 0x190df1146fbdd5cc79e8817ebcd6311e35cf5cc38795cee26371a707d685e05a) // vk.TABLE4.y + mstore(add(_vk, 0x500), 0x019b3a1970f9f77b13538cd8071ea3ee7c556fd98009e2a04be044ead0a94623) // vk.TABLE_TYPE.x + mstore(add(_vk, 0x520), 0x159cbdae3e194fe45524a171befdcb98b55c8d495fc463c98ac690eee947119f) // vk.TABLE_TYPE.y + mstore(add(_vk, 0x540), 0x16b2f7fa29f578aae3d4c0b8220101570adfcc9e8aa8a148267208540de189f1) // vk.ID1.x + mstore(add(_vk, 0x560), 0x2344a211fbbacc281de980197e4f12155d90d55a67f4ad08398bac665f813953) // vk.ID1.y + mstore(add(_vk, 0x580), 0x1af709df675db1688b95927324e71c5e551436ba7cb32478570a9cfaebf90614) // vk.ID2.x + mstore(add(_vk, 0x5a0), 0x2b83e76f61aa5cd70218c38e693ae0a99e9a2f4a192af5c77dbd27fa605fdae4) // vk.ID2.y + mstore(add(_vk, 0x5c0), 0x038c89635a8b6ec9766d5f98d13c16f8c312088f830610de72c00edf8c3b7800) // vk.ID3.x + mstore(add(_vk, 0x5e0), 0x1863d9217ba6c6764fa02298efe25fabfbe454a27431b970a6afff5d1986fadb) // vk.ID3.y + mstore(add(_vk, 0x600), 0x259a5dd47d44d6240407c26718201a122fb4b6b38d838f6e24d1c75515016761) // vk.ID4.x + mstore(add(_vk, 0x620), 0x14db344b735ffe084107e5cea07b00e4c41a82f0073f76e0536cd7118d78866f) // vk.ID4.y + mstore(add(_vk, 0x640), 0x01) // 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, 0x06e402c0a314fb67a15cf806664ae1b722dbc0efe66e6c81d98f9924ca535321) // vk.work_root_inverse + } + } +} diff --git a/sol/test/base/DifferentialFuzzer.sol b/sol/test/base/DifferentialFuzzer.sol new file mode 100644 index 0000000000..3f6ee18e1d --- /dev/null +++ b/sol/test/base/DifferentialFuzzer.sol @@ -0,0 +1,101 @@ +import {Vm} from "forge-std/Vm.sol"; +import {strings} from "stringutils/strings.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {TestBase} from "./TestBase.sol"; +import "forge-std/console.sol"; + +contract DifferentialFuzzer is TestBase { + using strings for *; + using Strings for uint256; + + enum PlonkFlavour { + Invalid, + Standard, + Turbo, + Ultra + } + enum CircuitFlavour { + Invalid, + Blake, + Add2, + Recursive + } + + constructor() {} + + /// @notice the fuzzing flavour + PlonkFlavour public plonkFlavour; + + /// @notice the circuit flavour + CircuitFlavour public circuitFlavour; + + /// @notice the proofs public inputs + uint256[] public inputs; + + function with_plonk_flavour(PlonkFlavour _flavour) public returns (DifferentialFuzzer) { + plonkFlavour = _flavour; + return this; + } + + function with_circuit_flavour(CircuitFlavour _flavour) public returns (DifferentialFuzzer) { + circuitFlavour = _flavour; + return this; + } + + function with_inputs(uint256[] memory _inputs) public returns (DifferentialFuzzer) { + inputs = _inputs; + return this; + } + + function get_plonk_flavour() internal view returns (string memory) { + if (plonkFlavour == PlonkFlavour.Standard) { + return "standard"; + } else if (plonkFlavour == PlonkFlavour.Turbo) { + return "turbo"; + } else if (plonkFlavour == PlonkFlavour.Ultra) { + return "ultra"; + } else { + revert("Invalid flavour"); + } + } + + function get_circuit_flavour() internal view returns (string memory) { + if (circuitFlavour == CircuitFlavour.Blake) { + return "blake"; + } else if (circuitFlavour == CircuitFlavour.Add2) { + return "add2"; + } else if (circuitFlavour == CircuitFlavour.Recursive) { + return "recursive"; + } else { + revert("Invalid circuit flavour"); + } + } + + // Encode inputs as a comma seperated string for the ffi call + function get_inputs() internal view returns (string memory input_params) { + input_params = ""; + if (inputs.length > 0) { + input_params = inputs[0].toHexString(); + for (uint256 i = 1; i < inputs.length; i++) { + input_params = string.concat(input_params, ",", inputs[i].toHexString()); + } + } + } + + function generate_proof() public returns (bytes memory proof) { + // Craft an ffi call to the prover binary + string memory prover_path = "./scripts/run_fuzzer.sh"; + string memory plonk_flavour = get_plonk_flavour(); + string memory circuit_flavour = get_circuit_flavour(); + string memory input_params = get_inputs(); + + // Execute the c++ prover binary + string[] memory ffi_cmds = new string[](4); + ffi_cmds[0] = prover_path; + ffi_cmds[1] = plonk_flavour; + ffi_cmds[2] = circuit_flavour; + ffi_cmds[3] = input_params; + + proof = vm.ffi(ffi_cmds); + } +} diff --git a/sol/test/base/TestBase.sol b/sol/test/base/TestBase.sol new file mode 100644 index 0000000000..78a239b569 --- /dev/null +++ b/sol/test/base/TestBase.sol @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec. +pragma solidity >=0.8.4; + +import {Test} from "forge-std/Test.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; + +contract TestBase is Test { + using Strings for uint256; + + function readProofData(string memory path) internal view returns (bytes memory) { + // format [4 byte length][data] + // Reads the raw bytes + bytes memory rawBytes = vm.readFileBinary(path); + + // Extract the [data], contains inputs and proof + bytes memory proofData = new bytes(rawBytes.length - 4); // + assembly { + let length := shr(224, mload(add(rawBytes, 0x20))) + + let wLoc := add(proofData, 0x20) + let rLoc := add(rawBytes, 0x24) + let end := add(rLoc, length) + + for {} lt(rLoc, end) { + wLoc := add(wLoc, 0x20) + rLoc := add(rLoc, 0x20) + } { mstore(wLoc, mload(rLoc)) } + } + return proofData; + } + + function splitProof(bytes memory _proofData, uint256 _numberOfPublicInputs) + internal + view + returns (bytes32[] memory publicInputs, bytes memory proof) + { + publicInputs = new bytes32[](_numberOfPublicInputs); + for (uint256 i = 0; i < _numberOfPublicInputs; i++) { + // The proofs spit out by barretenberg have the public inputs at the beginning + publicInputs[i] = readWordByIndex(_proofData, i); + } + + proof = new bytes(_proofData.length - (_numberOfPublicInputs * 0x20)); + uint256 len = proof.length; + assembly { + pop( + staticcall( + gas(), 0x4, add(_proofData, add(0x20, mul(0x20, _numberOfPublicInputs))), len, add(proof, 0x20), len + ) + ) + } + } + + function printBytes(bytes memory _data, uint256 _offset) internal { + uint256 length = _data.length - _offset; + for (uint256 i = 0; i < length / 0x20; i++) { + bytes32 val; + assembly { + val := mload(add(_offset, add(_data, mul(0x20, add(1, i))))) + } + emit log_named_bytes32(toHexString(bytes32(i * 0x20)), val); + } + } + + function printList(bytes32[] memory _data, uint256 _offset) internal { + for (uint256 i = _offset; i < _data.length; i++) { + emit log_named_bytes32(i.toString(), _data[i]); + } + } + + function printList(uint256[] memory _data, uint256 _offset) internal { + for (uint256 i = _offset; i < _data.length; i++) { + emit log_named_bytes32(i.toString(), bytes32(_data[i])); + } + } + + function readWordByIndex(bytes memory _data, uint256 index) internal pure returns (bytes32 result) { + assembly { + result := mload(add(_data, add(0x20, mul(0x20, index)))) + } + } + + /** + * Convert a bytes32 into an ASCII encoded hex string + * @param input bytes32 variable + * @return result hex-encoded string + */ + function toHexString(bytes32 input) public pure returns (string memory result) { + if (uint256(input) == 0x00) { + assembly { + result := mload(0x40) + mstore(result, 0x40) + mstore(add(result, 0x20), 0x3030303030303030303030303030303030303030303030303030303030303030) + mstore(add(result, 0x40), 0x3030303030303030303030303030303030303030303030303030303030303030) + mstore(0x40, add(result, 0x60)) + } + return result; + } + assembly { + result := mload(0x40) + let table := add(result, 0x60) + + // Store lookup table that maps an integer from 0 to 99 into a 2-byte ASCII equivalent + // Store lookup table that maps an integer from 0 to ff into a 2-byte ASCII equivalent + mstore(add(table, 0x1e), 0x3030303130323033303430353036303730383039306130623063306430653066) + mstore(add(table, 0x3e), 0x3130313131323133313431353136313731383139316131623163316431653166) + mstore(add(table, 0x5e), 0x3230323132323233323432353236323732383239326132623263326432653266) + mstore(add(table, 0x7e), 0x3330333133323333333433353336333733383339336133623363336433653366) + mstore(add(table, 0x9e), 0x3430343134323433343434353436343734383439346134623463346434653466) + mstore(add(table, 0xbe), 0x3530353135323533353435353536353735383539356135623563356435653566) + mstore(add(table, 0xde), 0x3630363136323633363436353636363736383639366136623663366436653666) + mstore(add(table, 0xfe), 0x3730373137323733373437353736373737383739376137623763376437653766) + mstore(add(table, 0x11e), 0x3830383138323833383438353836383738383839386138623863386438653866) + mstore(add(table, 0x13e), 0x3930393139323933393439353936393739383939396139623963396439653966) + mstore(add(table, 0x15e), 0x6130613161326133613461356136613761386139616161626163616461656166) + mstore(add(table, 0x17e), 0x6230623162326233623462356236623762386239626162626263626462656266) + mstore(add(table, 0x19e), 0x6330633163326333633463356336633763386339636163626363636463656366) + mstore(add(table, 0x1be), 0x6430643164326433643464356436643764386439646164626463646464656466) + mstore(add(table, 0x1de), 0x6530653165326533653465356536653765386539656165626563656465656566) + mstore(add(table, 0x1fe), 0x6630663166326633663466356636663766386639666166626663666466656666) + /** + * Convert `input` into ASCII. + * + * Slice 2 base-10 digits off of the input, use to index the ASCII lookup table. + * + * We start from the least significant digits, write results into mem backwards, + * this prevents us from overwriting memory despite the fact that each mload + * only contains 2 byteso f useful data. + * + */ + + let base := input + function slice(v, tableptr) { + mstore(0x1e, mload(add(tableptr, shl(1, and(v, 0xff))))) + mstore(0x1c, mload(add(tableptr, shl(1, and(shr(8, v), 0xff))))) + mstore(0x1a, mload(add(tableptr, shl(1, and(shr(16, v), 0xff))))) + mstore(0x18, mload(add(tableptr, shl(1, and(shr(24, v), 0xff))))) + mstore(0x16, mload(add(tableptr, shl(1, and(shr(32, v), 0xff))))) + mstore(0x14, mload(add(tableptr, shl(1, and(shr(40, v), 0xff))))) + mstore(0x12, mload(add(tableptr, shl(1, and(shr(48, v), 0xff))))) + mstore(0x10, mload(add(tableptr, shl(1, and(shr(56, v), 0xff))))) + mstore(0x0e, mload(add(tableptr, shl(1, and(shr(64, v), 0xff))))) + mstore(0x0c, mload(add(tableptr, shl(1, and(shr(72, v), 0xff))))) + mstore(0x0a, mload(add(tableptr, shl(1, and(shr(80, v), 0xff))))) + mstore(0x08, mload(add(tableptr, shl(1, and(shr(88, v), 0xff))))) + mstore(0x06, mload(add(tableptr, shl(1, and(shr(96, v), 0xff))))) + mstore(0x04, mload(add(tableptr, shl(1, and(shr(104, v), 0xff))))) + mstore(0x02, mload(add(tableptr, shl(1, and(shr(112, v), 0xff))))) + mstore(0x00, mload(add(tableptr, shl(1, and(shr(120, v), 0xff))))) + } + + mstore(result, 0x40) + slice(base, table) + mstore(add(result, 0x40), mload(0x1e)) + base := shr(128, base) + slice(base, table) + mstore(add(result, 0x20), mload(0x1e)) + mstore(0x40, add(result, 0x60)) + } + } +} diff --git a/sol/test/ultra/Add2.t.sol b/sol/test/ultra/Add2.t.sol new file mode 100644 index 0000000000..33a3ef8389 --- /dev/null +++ b/sol/test/ultra/Add2.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +import {TestBaseUltra} from "./TestBaseUltra.sol"; +import {Add2UltraVerifier} from "../../src/ultra/instance/Add2UltraVerifier.sol"; +import {DifferentialFuzzer} from "../base/DifferentialFuzzer.sol"; +import {IVerifier} from "../../src/interfaces/IVerifier.sol"; + +contract Add2UltraTest is TestBaseUltra { + function setUp() public override(TestBaseUltra) { + super.setUp(); + + verifier = IVerifier(address(new Add2UltraVerifier())); + fuzzer = fuzzer.with_circuit_flavour(DifferentialFuzzer.CircuitFlavour.Add2); + + PUBLIC_INPUT_COUNT = 3; + + // Add default inputs to the fuzzer (we will override these in fuzz test) + uint256[] memory defaultInputs = new uint256[](3); + defaultInputs[0] = 5; + defaultInputs[1] = 10; + defaultInputs[2] = 15; + + fuzzer = fuzzer.with_inputs(defaultInputs); + } + + function testFuzzProof(uint16 input1, uint16 input2) public { + uint256[] memory inputs = new uint256[](3); + inputs[0] = uint256(input1); + inputs[1] = uint256(input2); + inputs[2] = inputs[0] + inputs[1]; + + bytes memory proofData = fuzzer.with_inputs(inputs).generate_proof(); + + (bytes32[] memory publicInputs, bytes memory proof) = splitProof(proofData, PUBLIC_INPUT_COUNT); + + assertTrue(verifier.verify(proof, publicInputs), "The proof is not valid"); + } +} diff --git a/sol/test/ultra/Blake.t.sol b/sol/test/ultra/Blake.t.sol new file mode 100644 index 0000000000..3403574616 --- /dev/null +++ b/sol/test/ultra/Blake.t.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +import {TestBaseUltra} from "./TestBaseUltra.sol"; +import {BlakeUltraVerifier} from "../../src/ultra/instance/BlakeUltraVerifier.sol"; +import {DifferentialFuzzer} from "../base/DifferentialFuzzer.sol"; +import {IVerifier} from "../../src/interfaces/IVerifier.sol"; + +contract BlakeUltraTest is TestBaseUltra { + function setUp() public override(TestBaseUltra) { + super.setUp(); + + verifier = IVerifier(address(new BlakeUltraVerifier())); + fuzzer = fuzzer.with_circuit_flavour(DifferentialFuzzer.CircuitFlavour.Blake); + + PUBLIC_INPUT_COUNT = 4; + + // Add default inputs to the fuzzer (we will override these in fuzz test) + uint256[] memory defaultInputs = new uint256[](4); + defaultInputs[0] = 1; + defaultInputs[1] = 2; + defaultInputs[2] = 3; + defaultInputs[3] = 4; + + fuzzer = fuzzer.with_inputs(defaultInputs); + } + + function testFuzzProof(uint256 input1, uint256 input2, uint256 input3, uint256 input4) public { + uint256[] memory inputs = new uint256[](4); + inputs[0] = input1; + inputs[1] = input2; + inputs[2] = input3; + inputs[3] = input4; + + bytes memory proofData = fuzzer.with_inputs(inputs).generate_proof(); + + (bytes32[] memory publicInputs, bytes memory proof) = splitProof(proofData, PUBLIC_INPUT_COUNT); + + assertTrue(verifier.verify(proof, publicInputs), "The proof is not valid"); + } +} diff --git a/sol/test/ultra/Recursive.t.sol b/sol/test/ultra/Recursive.t.sol new file mode 100644 index 0000000000..43dac05dd6 --- /dev/null +++ b/sol/test/ultra/Recursive.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.4; + +import {TestBaseUltra} from "./TestBaseUltra.sol"; +import {RecursiveUltraVerifier} from "../../src/ultra/instance/RecursiveUltraVerifier.sol"; +import {DifferentialFuzzer} from "../base/DifferentialFuzzer.sol"; +import {IVerifier} from "../../src/interfaces/IVerifier.sol"; + +contract RecursiveUltraTest is TestBaseUltra { + function setUp() public override(TestBaseUltra) { + super.setUp(); + + verifier = IVerifier(address(new RecursiveUltraVerifier())); + fuzzer = fuzzer.with_circuit_flavour(DifferentialFuzzer.CircuitFlavour.Recursive); + + PUBLIC_INPUT_COUNT = 16; + + // Add default inputs to the fuzzer (we will override these in fuzz test) + uint256[] memory defaultInputs = new uint256[](3); + defaultInputs[0] = 5; + defaultInputs[1] = 10; + defaultInputs[2] = 15; + + fuzzer = fuzzer.with_inputs(defaultInputs); + } + + function testFuzzProof(uint16 input1, uint16 input2) public { + uint256[] memory inputs = new uint256[](3); + inputs[0] = uint256(input1); + inputs[1] = uint256(input2); + inputs[2] = inputs[0] + inputs[1]; + + bytes memory proofData = fuzzer.with_inputs(inputs).generate_proof(); + + (bytes32[] memory publicInputs, bytes memory proof) = splitProof(proofData, PUBLIC_INPUT_COUNT); + + assertTrue(verifier.verify(proof, publicInputs), "The proof is not valid"); + } +} diff --git a/sol/test/ultra/TestBaseUltra.sol b/sol/test/ultra/TestBaseUltra.sol new file mode 100644 index 0000000000..51a621b03c --- /dev/null +++ b/sol/test/ultra/TestBaseUltra.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {TestBase} from "../base/TestBase.sol"; +import {DifferentialFuzzer} from "../base/DifferentialFuzzer.sol"; +import {BaseUltraVerifier} from "../../src/ultra/BaseUltraVerifier.sol"; +import {IVerifier} from "../../src/interfaces/IVerifier.sol"; + +contract TestBaseUltra is TestBase { + IVerifier public verifier; + DifferentialFuzzer public fuzzer; + uint256 public PUBLIC_INPUT_COUNT; + + function setUp() public virtual { + fuzzer = new DifferentialFuzzer().with_plonk_flavour(DifferentialFuzzer.PlonkFlavour.Ultra); + } + + function testValidProof() public { + bytes memory proofData = fuzzer.generate_proof(); + (bytes32[] memory publicInputs, bytes memory proof) = splitProof(proofData, PUBLIC_INPUT_COUNT); + assertTrue(verifier.verify(proof, publicInputs), "The proof is not valid"); + } +} From ac2bf12cc380860cccbb0a32aa6b2d90b724bec7 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 18 Apr 2023 16:35:09 +0000 Subject: [PATCH 03/15] fix: revert unneeded cmakelist changes + typos --- .vscode/settings.json | 3 +-- cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt | 2 +- cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt | 2 +- sol/scripts/init.sh | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f80de5b549..489043bab0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -127,6 +127,5 @@ "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "cmake.sourceDirectory": "${workspaceFolder}/cpp", - "C_Cpp.errorSquiggles": "disabled" + "cmake.sourceDirectory": "${workspaceFolder}/cpp" } \ No newline at end of file diff --git a/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt b/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt index 00ee8f37e3..e049536e74 100644 --- a/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt +++ b/cpp/src/barretenberg/stdlib/hash/sha256/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_sha256 stdlib_primitives crypto_sha256 crypto_blake3s) \ No newline at end of file +barretenberg_module(stdlib_sha256 stdlib_primitives crypto_sha256) \ No newline at end of file diff --git a/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt b/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt index 6df807ad67..d3ec5d6738 100644 --- a/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt +++ b/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_primitives plonk honk proof_system) \ No newline at end of file +barretenberg_module(stdlib_primitives plonk honk) \ No newline at end of file diff --git a/sol/scripts/init.sh b/sol/scripts/init.sh index 3baf2367af..fa00f288bd 100755 --- a/sol/scripts/init.sh +++ b/sol/scripts/init.sh @@ -3,7 +3,7 @@ PLONK_FLAVOUR="ultra" SRS_PATH="../cpp/srs_db/ignition" -OUTPUT_PATH="./src/ultra/" +OUTPUT_PATH="./src/ultra" ../cpp/build/bin/solidity_key_gen $PLONK_FLAVOUR add2 $OUTPUT_PATH $SRS_PATH ../cpp/build/bin/solidity_key_gen $PLONK_FLAVOUR blake $OUTPUT_PATH $SRS_PATH From 65e5b60dcc691b1da08f6315156fe0ab7d70820b Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 18 Apr 2023 21:21:23 +0000 Subject: [PATCH 04/15] fix: solidity helper binaries in docker --- cpp/dockerfiles/Dockerfile.x86_64-linux-clang | 1 + sol/.dockerignore | 5 ++++ sol/Dockerfile | 25 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 sol/.dockerignore create mode 100644 sol/Dockerfile diff --git a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang index 6e0b707b52..7f6058ee77 100644 --- a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang +++ b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang @@ -20,3 +20,4 @@ RUN cmake --preset default && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add openmp COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/barretenberg/cpp/build/bin/solidity_* /usr/src/barretenberg/cpp/build/bin/ \ No newline at end of file diff --git a/sol/.dockerignore b/sol/.dockerignore new file mode 100644 index 0000000000..d5fb189d60 --- /dev/null +++ b/sol/.dockerignore @@ -0,0 +1,5 @@ +broadcast +cache +out +Dockerfile +lib \ No newline at end of file diff --git a/sol/Dockerfile b/sol/Dockerfile new file mode 100644 index 0000000000..62f5e20845 --- /dev/null +++ b/sol/Dockerfile @@ -0,0 +1,25 @@ +FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang + +FROM ubuntu:focal as builder +RUN apt-get update && apt install -y git curl + +COPY --from=0 /usr/src/barretenberg/cpp/build/bin /usr/src/barretenberg/cpp/build/bin +COPY --from=0 /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db +WORKDIR /usr/src/barretenberg/sol +RUN git init +COPY . . + +RUN ls /usr/src/barretenberg/cpp/build/bin + +RUN ./scripts/install_foundry.sh +ENV PATH="/usr/src/barretenberg/sol/.foundry/bin:${PATH}" + +RUN forge install --no-commit \ + https://github.com/foundry-rs/forge-std \ + https://github.com/openzeppelin/openzeppelin-contracts + +RUN cd ../cpp/srs_db && ./download_ignition.sh 3 && cd ../../sol + +RUN ./scripts/init.sh + +RUN forge test --no-match-contract TestBase \ No newline at end of file From 7dec98aba2322e071d89ea9f87bad2216c2bec10 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 18 Apr 2023 21:48:21 +0000 Subject: [PATCH 05/15] chore: Use `-assert` variant instead of plain --- .circleci/build_local | 1 + .circleci/config.yml | 12 ++++++++++++ cpp/dockerfiles/Dockerfile.x86_64-linux-clang | 3 +-- cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert | 3 ++- sol/Dockerfile | 2 +- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.circleci/build_local b/.circleci/build_local index 84e7224123..7d488e6d66 100755 --- a/.circleci/build_local +++ b/.circleci/build_local @@ -14,6 +14,7 @@ PUSH_LABEL=$3 PROJECTS=( cpp:barretenberg-cpp:./dockerfiles/Dockerfile.x86_64-linux-clang:barretenberg-x86_64-linux-clang + cpp:barretenberg-cpp:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:barretenberg-x86_64-linux-clang-assert cpp:barretenberg-cpp:./dockerfiles/Dockerfile.wasm-linux-clang:barretenberg-wasm-linux-clang # js:barretenberg-js ) diff --git a/.circleci/config.yml b/.circleci/config.yml index c4618ddcca..f2b86a5052 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -136,6 +136,17 @@ jobs: name: "Build" command: cond_spot_run_build barretenberg-x86_64-linux-clang-assert 64 + solidity-verifier-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: build sol + barretenberg-tests: docker: - image: aztecprotocol/alpine-build-image @@ -247,6 +258,7 @@ workflows: - x86_64-linux-clang - x86_64-linux-clang-assert - wasm-linux-clang + - solidity-verifier-tests: *bb_test - honk-tests: *bb_test - barretenberg-tests: *bb_test - stdlib-primitives-tests: *bb_test diff --git a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang index 7f6058ee77..f05aa87a94 100644 --- a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang +++ b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang @@ -19,5 +19,4 @@ RUN cmake --preset default && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add openmp -COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/barretenberg/cpp/build/bin/solidity_* /usr/src/barretenberg/cpp/build/bin/ \ No newline at end of file +COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db \ No newline at end of file diff --git a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert index d03fa89cdf..398408eb74 100644 --- a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert +++ b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -20,4 +20,5 @@ RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON && cmake --b FROM alpine:3.17 RUN apk update && apk add curl openmp COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/barretenberg/cpp/build/bin/*_tests /usr/src/barretenberg/cpp/build/bin/ \ No newline at end of file +COPY --from=builder /usr/src/barretenberg/cpp/build/bin/*_tests /usr/src/barretenberg/cpp/build/bin/ +COPY --from=builder /usr/src/barretenberg/cpp/build/bin/solidity* /usr/src/barretenberg/cpp/build/bin/ \ No newline at end of file diff --git a/sol/Dockerfile b/sol/Dockerfile index 62f5e20845..1520476e2b 100644 --- a/sol/Dockerfile +++ b/sol/Dockerfile @@ -1,4 +1,4 @@ -FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang +FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang-assert FROM ubuntu:focal as builder RUN apt-get update && apt install -y git curl From 8085a92f27ff2a4b0c79b6dc491eccfac52acb60 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 18 Apr 2023 21:50:22 +0000 Subject: [PATCH 06/15] chore: config.yml missing whitespace --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f2b86a5052..e53ccca880 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -144,8 +144,8 @@ jobs: - *checkout - *setup_env - run: - name: "Test" - command: build sol + name: "Test" + command: build sol barretenberg-tests: docker: From b69ad8b08bd7369282cef461ce2467e47766d174 Mon Sep 17 00:00:00 2001 From: cheethas Date: Tue, 18 Apr 2023 23:59:16 +0000 Subject: [PATCH 07/15] fix: alpine base dockerfile --- sol/Dockerfile | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sol/Dockerfile b/sol/Dockerfile index 62f5e20845..6542fc2754 100644 --- a/sol/Dockerfile +++ b/sol/Dockerfile @@ -1,7 +1,7 @@ -FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang +FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang-assert -FROM ubuntu:focal as builder -RUN apt-get update && apt install -y git curl +FROM alpine:3.17 as builder +RUN apk update && apk add git curl bash build-base openmp-dev COPY --from=0 /usr/src/barretenberg/cpp/build/bin /usr/src/barretenberg/cpp/build/bin COPY --from=0 /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db @@ -9,10 +9,8 @@ WORKDIR /usr/src/barretenberg/sol RUN git init COPY . . -RUN ls /usr/src/barretenberg/cpp/build/bin - -RUN ./scripts/install_foundry.sh -ENV PATH="/usr/src/barretenberg/sol/.foundry/bin:${PATH}" +# Copy forge binary directly from foundry +COPY --from=ghcr.io/foundry-rs/foundry:latest /usr/local/bin/forge /usr/local/bin/forge RUN forge install --no-commit \ https://github.com/foundry-rs/forge-std \ From e2f34f8cb4c9ee2ff5d3e62ff1a44b0428021ff0 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 19 Apr 2023 07:40:15 +0000 Subject: [PATCH 08/15] chore: add sol to build_manifest --- build_manifest.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build_manifest.json b/build_manifest.json index a44071b71e..fcedadbae5 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -28,5 +28,11 @@ "dockerfile": "js/Dockerfile", "rebuildPatterns": ["^js/"], "dependencies": ["barretenberg-wasm-linux-clang"] + }, + "sol": { + "buildDir": "sol", + "dockerfile": "sol/Dockerfile", + "rebuildPatterns": ["^sol/"], + "dependencies": ["barretenberg-x86_64-linux-clang-assert"] } } From 05d943cd6c2b7c4cf08bb8ace92333aeb0fedc80 Mon Sep 17 00:00:00 2001 From: cheethas Date: Wed, 19 Apr 2023 08:38:06 +0000 Subject: [PATCH 09/15] Dockerfile: add string utils --- sol/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sol/Dockerfile b/sol/Dockerfile index 6542fc2754..3e0bfb33b3 100644 --- a/sol/Dockerfile +++ b/sol/Dockerfile @@ -1,7 +1,7 @@ FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang-assert FROM alpine:3.17 as builder -RUN apk update && apk add git curl bash build-base openmp-dev +RUN apk update && apk add git curl build-base openmp-dev COPY --from=0 /usr/src/barretenberg/cpp/build/bin /usr/src/barretenberg/cpp/build/bin COPY --from=0 /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db @@ -14,7 +14,8 @@ COPY --from=ghcr.io/foundry-rs/foundry:latest /usr/local/bin/forge /usr/local/bi RUN forge install --no-commit \ https://github.com/foundry-rs/forge-std \ - https://github.com/openzeppelin/openzeppelin-contracts + https://github.com/openzeppelin/openzeppelin-contracts \ + https://github.com/Arachnid/solidity-stringutils RUN cd ../cpp/srs_db && ./download_ignition.sh 3 && cd ../../sol From 54f7ebbd5609a6a8fc8ea123d907beb653a752bc Mon Sep 17 00:00:00 2001 From: cheethas Date: Wed, 19 Apr 2023 09:07:00 +0000 Subject: [PATCH 10/15] fix: use different base, add bash --- sol/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sol/Dockerfile b/sol/Dockerfile index 3e0bfb33b3..91491ebc68 100644 --- a/sol/Dockerfile +++ b/sol/Dockerfile @@ -1,7 +1,7 @@ FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang-assert -FROM alpine:3.17 as builder -RUN apk update && apk add git curl build-base openmp-dev +FROM docker.io/frolvlad/alpine-glibc:alpine-3.16_glibc-2.34 as builder +RUN apk update && apk add git curl build-base openmp-dev bash COPY --from=0 /usr/src/barretenberg/cpp/build/bin /usr/src/barretenberg/cpp/build/bin COPY --from=0 /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db From ca5f638df7a462a6b102d6a7e86a94759a95d335 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 19 Apr 2023 10:03:48 +0000 Subject: [PATCH 11/15] chore: remove stale misc --- .../solidity_helpers/circuits/add_2_circuit.hpp | 7 ------- .../solidity_helpers/circuits/blake_circuit.hpp | 4 ---- .../solidity_helpers/circuits/recursive_circuit.hpp | 8 -------- cpp/src/barretenberg/solidity_helpers/key_gen.cpp | 13 ------------- .../barretenberg/solidity_helpers/utils/utils.hpp | 4 ---- 5 files changed, 36 deletions(-) diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp index 1de3ab3c59..99f443faf4 100644 --- a/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp +++ b/cpp/src/barretenberg/solidity_helpers/circuits/add_2_circuit.hpp @@ -3,13 +3,6 @@ #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/stdlib/primitives/bool/bool.hpp" -// #include -// #include -// #include -// #include - -// using numeric::uint256_t; - template class Add2Circuit { public: typedef stdlib::field_t field_ct; diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp index a41a3c98a4..1b19bd8b3b 100644 --- a/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp +++ b/cpp/src/barretenberg/solidity_helpers/circuits/blake_circuit.hpp @@ -2,10 +2,6 @@ #include "barretenberg/stdlib/primitives/witness/witness.hpp" #include "barretenberg/stdlib/hash/blake2s/blake2s.hpp" -//#include -//#include -//#include - using namespace proof_system::plonk; using namespace proof_system::plonk::stdlib; diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp index 64f17220c7..077427af51 100644 --- a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp +++ b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp @@ -6,14 +6,6 @@ #include "barretenberg/ecc/curves/bn254/fq12.hpp" #include "barretenberg/ecc/curves/bn254/pairing.hpp" -//#include -//#include -//#include -//#include -//#include -//#include -//#include - using namespace proof_system::plonk; using numeric::uint256_t; diff --git a/cpp/src/barretenberg/solidity_helpers/key_gen.cpp b/cpp/src/barretenberg/solidity_helpers/key_gen.cpp index cd34f70e45..86913a0d92 100644 --- a/cpp/src/barretenberg/solidity_helpers/key_gen.cpp +++ b/cpp/src/barretenberg/solidity_helpers/key_gen.cpp @@ -17,10 +17,6 @@ void generate_keys(std::string output_path, std::string srs_path, std::string fl uint256_t public_inputs[4] = { 0, 0, 0, 0 }; Composer composer = Circuit::generate(srs_path, public_inputs); - (void)output_path; - (void)flavour_prefix; - (void)circuit_name; - std::shared_ptr vkey = composer.compute_verification_key(); // Make verification key file upper case @@ -55,12 +51,6 @@ void generate_keys(std::string output_path, std::string srs_path, std::string fl int main(int argc, char** argv) { std::vector args(argv, argv + argc); - // if (args.size() < 3) - // { - // info( - // "usage: ", args[0], "[path to project root] [srs path]"); - // return 1; - // } if (args.size() < 5) { info("usage: ", args[0], "[plonk flavour] [circuit flavour] [output path] [srs path]"); @@ -72,9 +62,6 @@ int main(int argc, char** argv) const std::string output_path = args[3]; const std::string srs_path = args[4]; - // const std::string standard_path = project_root_path + "/src/standard"; - // const std::string ultra_path = project_root_path + "/src/ultra"; - // @todo - Add support for unrolled standard verifier. Needs a new solidity verifier contract. if (plonk_flavour != "ultra") { diff --git a/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp b/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp index 4e7046c809..0567e73739 100644 --- a/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp +++ b/cpp/src/barretenberg/solidity_helpers/utils/utils.hpp @@ -1,10 +1,6 @@ #include #include -// TODO Remove -// const std::string DEFAULT_PROJECT_ROOT_PATH = "../.."; -// const std::string DEFAULT_SRS_PATH = "../../barretenberg/cpp/srs_db/ignition"; - std::string bytes_to_hex_string(const std::vector& input) { static const char characters[] = "0123456789ABCDEF"; From f2728e7e12e6306c9322a0289690dbc93c71b25f Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 19 Apr 2023 10:49:17 +0000 Subject: [PATCH 12/15] circle-ci fiddling --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e53ccca880..3fd2b6e319 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -144,8 +144,8 @@ jobs: - *checkout - *setup_env - run: - name: "Test" - command: build sol + name: "Build and test" + command: cond_spot_run_build sol 64 barretenberg-tests: docker: From 437864469307e0fb2d590f3d947eea9ec0fcde6d Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 19 Apr 2023 10:52:30 +0000 Subject: [PATCH 13/15] more circle fiddling --- build_manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_manifest.json b/build_manifest.json index fcedadbae5..9d94b0fb32 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -31,7 +31,7 @@ }, "sol": { "buildDir": "sol", - "dockerfile": "sol/Dockerfile", + "dockerfile": "Dockerfile", "rebuildPatterns": ["^sol/"], "dependencies": ["barretenberg-x86_64-linux-clang-assert"] } From a03c023f7f0f72aa3e23877f4e000fb6d66eb891 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 19 Apr 2023 10:55:54 +0000 Subject: [PATCH 14/15] fiddle --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3fd2b6e319..5f53df2aa3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -145,7 +145,7 @@ jobs: - *setup_env - run: name: "Build and test" - command: cond_spot_run_build sol 64 + command: build sol barretenberg-tests: docker: From 62a9ded7deac5ee1722a74f056c745b1ae05ebcf Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:00:40 +0100 Subject: [PATCH 15/15] Circle-ci fiddling for verifiers (#365) * build_manifest update * fiddling * fiddling * skip ensure_repo * skipping more stuff * fiddling * get docker version * force change in key_gen * fiddle * docker version in cond_spot * fiddle * update path * fiddle * build in init * fiddle * fiddle * fiddle * fiddle * alpine * package naming * add apt-repository * add apt rep key * lld-15 * fiddle with docker * chore: cleanups * chore: remove log --- .circleci/build_local | 1 - .circleci/config.yml | 12 ---------- .dockerignore | 8 +++++++ .github/workflows/solidity_verifier_test.yml | 23 +++++++++++++++++++ build_manifest.json | 6 ----- .../Dockerfile.x86_64-linux-clang-assert | 3 +-- sol/.dockerignore | 5 ---- sol/Dockerfile | 21 +++++++++++++++-- sol/README.md | 11 ++++++++- sol/bootstrap.sh | 6 +++++ sol/foundry.toml | 2 +- 11 files changed, 68 insertions(+), 30 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/solidity_verifier_test.yml delete mode 100644 sol/.dockerignore diff --git a/.circleci/build_local b/.circleci/build_local index 7d488e6d66..84e7224123 100755 --- a/.circleci/build_local +++ b/.circleci/build_local @@ -14,7 +14,6 @@ PUSH_LABEL=$3 PROJECTS=( cpp:barretenberg-cpp:./dockerfiles/Dockerfile.x86_64-linux-clang:barretenberg-x86_64-linux-clang - cpp:barretenberg-cpp:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:barretenberg-x86_64-linux-clang-assert cpp:barretenberg-cpp:./dockerfiles/Dockerfile.wasm-linux-clang:barretenberg-wasm-linux-clang # js:barretenberg-js ) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f53df2aa3..c4618ddcca 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -136,17 +136,6 @@ jobs: name: "Build" command: cond_spot_run_build barretenberg-x86_64-linux-clang-assert 64 - solidity-verifier-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build and test" - command: build sol - barretenberg-tests: docker: - image: aztecprotocol/alpine-build-image @@ -258,7 +247,6 @@ workflows: - x86_64-linux-clang - x86_64-linux-clang-assert - wasm-linux-clang - - solidity-verifier-tests: *bb_test - honk-tests: *bb_test - barretenberg-tests: *bb_test - stdlib-primitives-tests: *bb_test diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..b38d06b335 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +sol/broadcast +sol/cache +sol/out +sol/Dockerfile +sol/lib +cpp/build +cpp/srs_db/ignition +.gitmodules \ No newline at end of file diff --git a/.github/workflows/solidity_verifier_test.yml b/.github/workflows/solidity_verifier_test.yml new file mode 100644 index 0000000000..8203b494ba --- /dev/null +++ b/.github/workflows/solidity_verifier_test.yml @@ -0,0 +1,23 @@ +name: solidity-verifier-test + +on: + - workflow_dispatch + - push + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Solidity Verifier Tests + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Build docker image + run: docker build . -f sol/Dockerfile \ No newline at end of file diff --git a/build_manifest.json b/build_manifest.json index 9d94b0fb32..a44071b71e 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -28,11 +28,5 @@ "dockerfile": "js/Dockerfile", "rebuildPatterns": ["^js/"], "dependencies": ["barretenberg-wasm-linux-clang"] - }, - "sol": { - "buildDir": "sol", - "dockerfile": "Dockerfile", - "rebuildPatterns": ["^sol/"], - "dependencies": ["barretenberg-x86_64-linux-clang-assert"] } } diff --git a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert index 398408eb74..d03fa89cdf 100644 --- a/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert +++ b/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -20,5 +20,4 @@ RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON && cmake --b FROM alpine:3.17 RUN apk update && apk add curl openmp COPY --from=builder /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/barretenberg/cpp/build/bin/*_tests /usr/src/barretenberg/cpp/build/bin/ -COPY --from=builder /usr/src/barretenberg/cpp/build/bin/solidity* /usr/src/barretenberg/cpp/build/bin/ \ No newline at end of file +COPY --from=builder /usr/src/barretenberg/cpp/build/bin/*_tests /usr/src/barretenberg/cpp/build/bin/ \ No newline at end of file diff --git a/sol/.dockerignore b/sol/.dockerignore deleted file mode 100644 index d5fb189d60..0000000000 --- a/sol/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -broadcast -cache -out -Dockerfile -lib \ No newline at end of file diff --git a/sol/Dockerfile b/sol/Dockerfile index 91491ebc68..8284044d0e 100644 --- a/sol/Dockerfile +++ b/sol/Dockerfile @@ -1,4 +1,21 @@ -FROM 278380418400.dkr.ecr.us-east-2.amazonaws.com/barretenberg-x86_64-linux-clang-assert +FROM alpine:3.17 +RUN apk update \ + && apk upgrade \ + && apk add --no-cache \ + build-base \ + clang15 \ + openmp-dev \ + cmake \ + ninja \ + git \ + curl \ + perl + +WORKDIR /usr/src/barretenberg/cpp + +COPY ./cpp . +# Build everything to ensure everything builds. All tests will be run from the result of this build. +RUN cmake --preset default && cmake --build --preset default --target solidity_key_gen solidity_proof_gen FROM docker.io/frolvlad/alpine-glibc:alpine-3.16_glibc-2.34 as builder RUN apk update && apk add git curl build-base openmp-dev bash @@ -7,7 +24,7 @@ COPY --from=0 /usr/src/barretenberg/cpp/build/bin /usr/src/barretenberg/cpp/buil COPY --from=0 /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db WORKDIR /usr/src/barretenberg/sol RUN git init -COPY . . +COPY ./sol . # Copy forge binary directly from foundry COPY --from=ghcr.io/foundry-rs/foundry:latest /usr/local/bin/forge /usr/local/bin/forge diff --git a/sol/README.md b/sol/README.md index 1e94a935c6..d0ae9ffa1b 100644 --- a/sol/README.md +++ b/sol/README.md @@ -25,6 +25,8 @@ Run `bootstrap.sh` to clone git submodules, download SRS and generate verificati Test are performed with a `TestBase` harness, it provides helpers for reading files and printing proofs. The tests also require proofs and verification keys, those are build as part of the `bootstrap.sh`. +Note that foundry is set to just run 1 fuzz run, this is mainly to limit the duty for CI, and then it can be hammered more heavily when needed. + ## How To Run the Tests? To run all tests, run the following scripts at the root of the repo: @@ -68,4 +70,11 @@ mstore(0x24, val_2) // add second value after first mstore(0x44, val_3) // add third value after second revert(0x00, 0x64) // revert with a message containing 0x64 bytes defined above ``` -When running a test, you will then see the three values `val_1, val_2, val_3` in the console. \ No newline at end of file +When running a test, you will then see the three values `val_1, val_2, val_3` in the console. + +# Docker +To run the docker image, which will build keygen and proofgen and then run tests, run the following from root: +```bash +# From root +docker build . -f sol/Dockerfile +``` diff --git a/sol/bootstrap.sh b/sol/bootstrap.sh index 70c6b1d18b..fa9a85bbf0 100755 --- a/sol/bootstrap.sh +++ b/sol/bootstrap.sh @@ -17,6 +17,12 @@ cd ../cpp/srs_db cd ../../sol echo "Building c++ binaries..." +cd ../cpp +cmake --preset clang15 +cmake --build --preset clang15 --target solidity_key_gen solidity_proof_gen +cd ../sol + +echo "Generating keys..." ./scripts/init.sh echo "Formatting code..." diff --git a/sol/foundry.toml b/sol/foundry.toml index 4b00788aac..15f71ad424 100644 --- a/sol/foundry.toml +++ b/sol/foundry.toml @@ -5,7 +5,7 @@ libs = ['lib'] ffi = true [fuzz] -runs = 5 +runs = 1 solc = "0.8.18"