diff --git a/.github/workflows/solidity_verifier_test.yml b/.github/workflows/solidity_verifier_test.yml deleted file mode 100644 index 8203b494ba..0000000000 --- a/.github/workflows/solidity_verifier_test.yml +++ /dev/null @@ -1,23 +0,0 @@ -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/.vscode/settings.json b/.vscode/settings.json index 61ccd9f458..0134c08493 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -110,7 +110,8 @@ "solidity.compileUsingRemoteVersion": "v0.6.10+commit.00c0fcaf", "search.exclude": { "**/.yarn": true, - "**/.pnp.*": true + "**/.pnp.*": true, + "**/msgpack-c/**": true }, "typescript.tsdk": "ts/.yarn/sdks/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, diff --git a/cpp/CMakePresets.json b/cpp/CMakePresets.json index 8534af50bf..a7a79fe950 100644 --- a/cpp/CMakePresets.json +++ b/cpp/CMakePresets.json @@ -140,6 +140,7 @@ "displayName": "Build for pthread enabled WASM", "description": "Build for pthread enabled WASM", "inherits": "wasm", + "binaryDir": "build-wasm-threads", "environment": { "WASI_SDK_PREFIX": "${sourceDir}/src/wasi-sdk-20.0+threads", "CMAKE_BUILD_TYPE": "Release" diff --git a/cpp/bootstrap.sh b/cpp/bootstrap.sh index e6d854c5a7..277744c161 100755 --- a/cpp/bootstrap.sh +++ b/cpp/bootstrap.sh @@ -66,5 +66,9 @@ cmake --build --preset $PRESET ${@/#/--target } ./scripts/install-wasi-sdk.sh # Build WASM. +cmake --preset wasm +cmake --build --preset wasm + +# Build WASM with new threading. cmake --preset wasm-threads cmake --build --preset wasm-threads diff --git a/cpp/scripts/build_libacvm_backend.sh b/cpp/scripts/build_libacvm_backend.sh new file mode 100755 index 0000000000..ed42572df2 --- /dev/null +++ b/cpp/scripts/build_libacvm_backend.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -eu + +BB_TARGETS=( + libenv.a + libcommon.a + libcrypto_blake2s.a + libcrypto_pedersen_hash.a + libcrypto_pedersen_commitment.a + libcrypto_keccak.a + libcrypto_schnorr.a + libcrypto_generators.a + libnumeric.a +) + +CMD="cmake --preset wasm && cmake --build --preset wasm" +for target in "${BB_TARGETS[@]}"; do CMD="$CMD --target $target"; done +eval $CMD + +cd ./build-wasm/lib + +LIBS=( + $PWD/libenv.a + $PWD/libcommon.a + $PWD/libcrypto_blake2s.a + $PWD/libcrypto_pedersen_hash.a + $PWD/libcrypto_pedersen_commitment.a + $PWD/libcrypto_keccak.a + $PWD/libcrypto_schnorr.a + $PWD/libcrypto_generators.a + $PWD/libnumeric.a + $PWD/../../src/wasi-sdk-20.0/share/wasi-sysroot/lib/wasm32-wasi/libc++.a + $PWD/../../src/wasi-sdk-20.0/share/wasi-sysroot/lib/wasm32-wasi/libc++abi.a +) + +rm -rf scratch +mkdir -p scratch +cd scratch + +for LIB_FILE_PATH in "${LIBS[@]}"; do + LIB=$(basename $LIB_FILE_PATH) + echo Extracting lib: $LIB + mkdir $LIB + cd $LIB + ar x $LIB_FILE_PATH + cd .. +done + +rm -f ../libacvm_backend.a +#../../../src/wasi-sdk-12.0/bin/ar rcs ../libxyz.a libcrypto_blake2s.a/* libc++.a/* libc++abi.a/* libcrypto_pedersen_commitment.a/* +find . -type f -print0 | xargs -0 ../../../src/wasi-sdk-20.0/bin/ar rcs ../libacvm_backend.a diff --git a/cpp/scripts/install-wasi-sdk.sh b/cpp/scripts/install-wasi-sdk.sh index 9ea9b43196..3a8eecf243 100755 --- a/cpp/scripts/install-wasi-sdk.sh +++ b/cpp/scripts/install-wasi-sdk.sh @@ -27,6 +27,5 @@ else # Replace wasi-sysroot in wasi-sdk-20.0+threads with our custom build. # It contains libc++ and a patch by yamt to improve thread join stability. # Can remove once future releases are more stable. - # UPDATE: Commenting out as we switched to "parallel_for_mutex_pool" as this we actually not very stable. - # curl -s -L https://wasi-sdk.s3.eu-west-2.amazonaws.com/yamt-wasi-sysroot-20.0.threads.tgz | tar zxfv - + curl -s -L https://wasi-sdk.s3.eu-west-2.amazonaws.com/yamt-wasi-sysroot-20.0.threads.tgz | tar zxfv - fi diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 6522078499..9d1bf92925 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -28,9 +28,12 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") endif() # We enable -O1 level optimsations, even when compiling debug wasm, otherwise we get "local count too large" at runtime. +# We prioritise reducing size of final artefacts in release with -Oz. if(WASM) set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g") set(CMAKE_C_FLAGS_DEBUG "-O1 -g") + set(CMAKE_CXX_FLAGS_RELEASE "-Oz -DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "-Oz -DNDEBUG") add_link_options(-Wl,--export-memory,--import-memory,--stack-first,-z,stack-size=1048576,--max-memory=4294967296) endif() @@ -70,6 +73,10 @@ endif() include(GNUInstallDirs) +# For this library we include everything but the env and wasi modules, as it is the responsibility of the +# consumer of this library to define how and in what environment its artefact will run. +# libbarretenberg + libwasi = a wasi "reactor" that implements it's own env (e.g. logstr), e.g. barretenberg.wasm. +# libbarretenberg + env = a wasi "command" that expects a full wasi runtime (e.g. wasmtime), e.g. test binaries. message(STATUS "Compiling all-in-one barretenberg archive") add_library( barretenberg @@ -108,24 +115,73 @@ add_library( $ ) -if(WASM) - add_executable( - barretenberg.wasm - $ - ) - - target_link_libraries(barretenberg.wasm barretenberg) +# Small library to provide necessary primitives for rust crate. +add_library( + acvm_backend + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ +) +if(WASM) # With binaryen installed, it seems its wasm backend optimiser gets invoked automatically. # Due to either a bug in the optimiser, or non-standards compliant c++ in crypto/aes, tests start failing with # -O3 level optimisations. We force down to -O2 for current workaround. # TODO: Time has passed, check if this is still needed. + # UPDATE: Uninstall binaryen and any need downstream. set(CMAKE_CXX_FLAGS_RELEASE "-O2") + # When building this wasm "executable", we include the wasi module but exclude the env module. + # That's because we expect this wasm to be run as a wasi "reactor" and for the host environment + # to implement the functions in env. + add_executable( + barretenberg.wasm + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + target_link_options( barretenberg.wasm PRIVATE - -nostartfiles -Wl,--whole-archive,--no-entry,--export-dynamic,--allow-undefined + -nostartfiles -Wl,--no-entry,--export-dynamic,--allow-undefined ) if(INSTALL_BARRETENBERG) diff --git a/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp b/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp index 40f2b15284..da6877b963 100644 --- a/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp +++ b/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp @@ -2,7 +2,7 @@ #include "barretenberg/common/assert.hpp" #include #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" // #include @@ -41,7 +41,7 @@ constexpr size_t NUM_POINTS = 1 << 16; std::vector scalars; static barretenberg::evaluation_domain small_domain; static barretenberg::evaluation_domain large_domain; -auto reference_string = std::make_shared(NUM_POINTS, "../srs_db/ignition"); +auto reference_string = std::make_shared(NUM_POINTS, "../srs_db/ignition"); const auto init = []() { small_domain = barretenberg::evaluation_domain(NUM_POINTS); diff --git a/cpp/src/barretenberg/common/c_bind.cpp b/cpp/src/barretenberg/common/c_bind.cpp index 11de5a72a8..0d99414262 100644 --- a/cpp/src/barretenberg/common/c_bind.cpp +++ b/cpp/src/barretenberg/common/c_bind.cpp @@ -1,7 +1,9 @@ +#ifndef NO_MULTITHREADING #include "./c_bind.hpp" #include "./mem.hpp" #include "./timer.hpp" #include "./serialize.hpp" +#include "./slab_allocator.hpp" #include #include @@ -31,8 +33,6 @@ void thread_test_abort_entry_point(void*) std::abort(); } -extern "C" { - WASM_EXPORT void test_threads(uint32_t const* thread_num, uint32_t const* iterations, uint32_t* out) { info("test starting..."); @@ -66,4 +66,9 @@ WASM_EXPORT void test_abort() info("test_abort aborting"); std::abort(); } + +WASM_EXPORT void common_init_slab_allocator(uint32_t const* circuit_size) +{ + barretenberg::init_slab_allocator(ntohl(*circuit_size)); } +#endif \ No newline at end of file diff --git a/cpp/src/barretenberg/common/c_bind.hpp b/cpp/src/barretenberg/common/c_bind.hpp index 350bd3f331..8cc7a9df1d 100644 --- a/cpp/src/barretenberg/common/c_bind.hpp +++ b/cpp/src/barretenberg/common/c_bind.hpp @@ -2,11 +2,10 @@ #include "./wasm_export.hpp" #include "./serialize.hpp" -extern "C" { - WASM_EXPORT void test_threads(uint32_t const* threads, uint32_t const* iterations, uint32_t* out); WASM_EXPORT void test_thread_abort(); WASM_EXPORT void test_abort(); -} + +WASM_EXPORT void common_init_slab_allocator(uint32_t const* circuit_size); diff --git a/cpp/src/barretenberg/common/fuzzer.hpp b/cpp/src/barretenberg/common/fuzzer.hpp index adf0aa5d1b..202b733884 100644 --- a/cpp/src/barretenberg/common/fuzzer.hpp +++ b/cpp/src/barretenberg/common/fuzzer.hpp @@ -84,80 +84,83 @@ class FastRandom { * * @tparam T */ -template -concept SimpleRng = requires(T a) { - { - a.next() - } -> std::convertible_to; - }; +template concept SimpleRng = requires(T a) +{ + { + a.next() + } + ->std::convertible_to; +}; /** * @brief Concept for forcing ArgumentSizes to be size_t * * @tparam T */ -template -concept InstructionArgumentSizes = requires { - { - std::make_tuple(T::CONSTANT, - T::WITNESS, - T::CONSTANT_WITNESS, - T::ADD, - T::SUBTRACT, - T::MULTIPLY, - T::DIVIDE, - T::ADD_TWO, - T::MADD, - T::MULT_MADD, - T::MSUB_DIV, - T::SQR, - T::SQR_ADD, - T::SUBTRACT_WITH_CONSTRAINT, - T::DIVIDE_WITH_CONSTRAINTS, - T::SLICE, - T::ASSERT_ZERO, - T::ASSERT_NOT_ZERO) - } -> std::same_as>; - }; +template concept InstructionArgumentSizes = requires +{ + { + std::make_tuple(T::CONSTANT, + T::WITNESS, + T::CONSTANT_WITNESS, + T::ADD, + T::SUBTRACT, + T::MULTIPLY, + T::DIVIDE, + T::ADD_TWO, + T::MADD, + T::MULT_MADD, + T::MSUB_DIV, + T::SQR, + T::SQR_ADD, + T::SUBTRACT_WITH_CONSTRAINT, + T::DIVIDE_WITH_CONSTRAINTS, + T::SLICE, + T::ASSERT_ZERO, + T::ASSERT_NOT_ZERO) + } + ->std::same_as>; +}; /** * @brief Concept for Havoc Configurations * * @tparam T */ -template -concept HavocConfigConstraint = - requires { - { - std::make_tuple(T::GEN_MUTATION_COUNT_LOG, T::GEN_STRUCTURAL_MUTATION_PROBABILITY) - } -> std::same_as>; - T::GEN_MUTATION_COUNT_LOG <= 7; - }; +template concept HavocConfigConstraint = requires +{ + { + std::make_tuple(T::GEN_MUTATION_COUNT_LOG, T::GEN_STRUCTURAL_MUTATION_PROBABILITY) + } + ->std::same_as>; + T::GEN_MUTATION_COUNT_LOG <= 7; +}; /** * @brief Concept specifying the class used by the fuzzer * * @tparam T */ -template -concept ArithmeticFuzzHelperConstraint = requires { - typename T::ArgSizes; - typename T::Instruction; - typename T::ExecutionState; - typename T::ExecutionHandler; - InstructionArgumentSizes; - // HavocConfigConstraint; - }; +template concept ArithmeticFuzzHelperConstraint = requires +{ + typename T::ArgSizes; + typename T::Instruction; + typename T::ExecutionState; + typename T::ExecutionHandler; + InstructionArgumentSizes; + // HavocConfigConstraint; +}; /** * @brief Fuzzer uses only composers with check_circuit function * * @tparam T */ -template -concept CheckableComposer = requires(T a) { - { - a.check_circuit() - } -> std::same_as; - }; +template concept CheckableComposer = requires(T a) +{ + { + a.check_circuit() + } + ->std::same_as; +}; /** * @brief The fuzzer can use a postprocessing function that is specific to the type being fuzzed @@ -167,11 +170,13 @@ concept CheckableComposer = requires(T a) { * @tparam Context The class containing the full context */ template -concept PostProcessingEnabled = requires(Composer composer, Context context) { - { - T::postProcess(&composer, context) - } -> std::same_as; - }; +concept PostProcessingEnabled = requires(Composer composer, Context context) +{ + { + T::postProcess(&composer, context) + } + ->std::same_as; +}; /** * @brief This concept is used when we want to limit the number of executions of certain instructions (for example, @@ -179,19 +184,17 @@ concept PostProcessingEnabled = requires(Composer composer, Context context) { * * @tparam T */ -template -concept InstructionWeightsEnabled = requires { - typename T::InstructionWeights; - T::InstructionWeights::_LIMIT; - }; +template concept InstructionWeightsEnabled = requires +{ + typename T::InstructionWeights; + T::InstructionWeights::_LIMIT; +}; /** * @brief A templated class containing most of the fuzzing logic for a generic Arithmetic class * * @tparam T */ -template - requires ArithmeticFuzzHelperConstraint -class ArithmeticFuzzHelper { +template requires ArithmeticFuzzHelperConstraint class ArithmeticFuzzHelper { private: /** * @brief Mutator swapping two instructions together @@ -494,8 +497,8 @@ class ArithmeticFuzzHelper { * @param instructions */ template - inline static void executeInstructions(std::vector& instructions) - requires CheckableComposer + inline static void executeInstructions( + std::vector& instructions) requires CheckableComposer { typename T::ExecutionState state; Composer composer = Composer(); diff --git a/cpp/src/barretenberg/common/mem.cpp b/cpp/src/barretenberg/common/mem.cpp index 7b953a2d8d..58b59226d0 100644 --- a/cpp/src/barretenberg/common/mem.cpp +++ b/cpp/src/barretenberg/common/mem.cpp @@ -1,15 +1,16 @@ #include "./mem.hpp" #include "./wasm_export.hpp" +#include "./slab_allocator.hpp" extern "C" { WASM_EXPORT void* bbmalloc(size_t size) { - return aligned_alloc(64, size); + return barretenberg::get_mem_slab_raw(size); } WASM_EXPORT void bbfree(void* ptr) { - aligned_free(ptr); + barretenberg::free_mem_slab_raw(ptr); } } \ No newline at end of file diff --git a/cpp/src/barretenberg/common/serialize.hpp b/cpp/src/barretenberg/common/serialize.hpp index 861a4a8ccd..77f21c952d 100644 --- a/cpp/src/barretenberg/common/serialize.hpp +++ b/cpp/src/barretenberg/common/serialize.hpp @@ -276,7 +276,7 @@ template inline void write(B& buf, std::array } // Generic read of vector of types from supported buffer types. -template inline void read(B& it, std::vector& value) +template inline void read(B& it, std::vector& value) { DEBUG_CANARY_READ(it, value); uint32_t size; @@ -406,7 +406,7 @@ template uint8_t* to_heap_buffer(T const& value) std::vector buf; write(buf, value); auto* ptr = (uint8_t*)aligned_alloc(64, buf.size()); - write(ptr, buf); + std::copy(buf.begin(), buf.end(), ptr); return ptr; } @@ -442,7 +442,11 @@ using in_buf64 = uint8_t const*; using out_buf64 = uint8_t*; using in_buf128 = uint8_t const*; using out_buf128 = uint8_t*; + +// Variable length string buffers. Prefixed with length. using in_str_buf = uint8_t const*; -using out_str_buf = uint8_t*; +using out_str_buf = uint8_t**; + +// Use these to pass a raw memory pointer. using in_ptr = void* const*; using out_ptr = void**; \ No newline at end of file diff --git a/cpp/src/barretenberg/common/slab_allocator.cpp b/cpp/src/barretenberg/common/slab_allocator.cpp index 7c2f166a08..96be5d7426 100644 --- a/cpp/src/barretenberg/common/slab_allocator.cpp +++ b/cpp/src/barretenberg/common/slab_allocator.cpp @@ -3,6 +3,9 @@ #include #include #include +#include + +#define LOGGING 0 /** * If we can guarantee that all slabs will be released before the allocator is destroyed, we wouldn't need this. @@ -14,10 +17,23 @@ namespace { bool allocator_destroyed = false; +// Slabs that are being manually managed by the user. +std::unordered_map> manual_slabs; + +template inline void dbg_info(Args... args) +{ +#if LOGGING == 1 + info(args...); +#else + // Suppress warning. + (void)(sizeof...(args)); +#endif +} + /** - * Allows preallocating memory slabs sized to serve the fact that these slabs of memory follow certain sizing patterns - * and numbers based on prover system type and circuit size. Without the slab allocator, memory fragmentation prevents - * proof construction when approaching memory space limits (4GB in WASM). + * Allows preallocating memory slabs sized to serve the fact that these slabs of memory follow certain sizing + * patterns and numbers based on prover system type and circuit size. Without the slab allocator, memory + * fragmentation prevents proof construction when approaching memory space limits (4GB in WASM). * * If no circuit_size_hint is given to the constructor, it behaves as a standard memory allocator. */ @@ -36,7 +52,7 @@ class SlabAllocator { std::shared_ptr get(size_t size); - // size_t get_total_size(); + size_t get_total_size(); private: void release(void* ptr, size_t size); @@ -68,7 +84,7 @@ void SlabAllocator::init(size_t circuit_size_hint) } memory_store.clear(); - // info("slab allocator initing for size: ", circuit_size_hint); + dbg_info("slab allocator initing for size: ", circuit_size_hint); if (circuit_size_hint == 0ULL) { return; @@ -78,6 +94,7 @@ void SlabAllocator::init(size_t circuit_size_hint) // Think max I saw was 65 extra related to pippenger runtime state. Likely related to the machine having 64 cores. // Strange things may happen here if double to 128 cores, might request 129 extra? size_t overalloc = 128; + size_t tiny_size = 4 * (circuit_size_hint + overalloc); size_t small_size = 32 * (circuit_size_hint + overalloc); size_t large_size = small_size * 4; @@ -88,7 +105,10 @@ void SlabAllocator::init(size_t circuit_size_hint) // on repeated prover runs as the memory becomes fragmented. Maybe best to just recreate the WASM // for each proof for now, if not too expensive. std::map prealloc_num; - prealloc_num[small_size] = 4 + // Monomial wires. + prealloc_num[tiny_size] = 4 + // Composer base wire vectors. + 1; // Miscellaneous. + prealloc_num[small_size] = 11 + // Composer base selector vectors. + 4 + // Monomial wires. 4 + // Lagrange wires. 15 + // Monomial constraint selectors. 15 + // Lagrange constraint selectors. @@ -98,7 +118,7 @@ void SlabAllocator::init(size_t circuit_size_hint) 5 + // Lagrange sorted poly. 2 + // Perm poly. 4 + // Quotient poly. - 7; // Miscellaneous. + 8; // Miscellaneous. prealloc_num[small_size * 2] = 1; // Miscellaneous. prealloc_num[large_size] = 4 + // Coset-fft wires. 15 + // Coset-fft constraint selectors. @@ -112,7 +132,7 @@ void SlabAllocator::init(size_t circuit_size_hint) for (size_t i = 0; i < e.second; ++i) { auto size = e.first; memory_store[size].push_back(aligned_alloc(32, size)); - // info("Allocated memory slab of size: ", size, " total: ", get_total_size()); + dbg_info("Allocated memory slab of size: ", size, " total: ", get_total_size()); } } } @@ -135,7 +155,7 @@ std::shared_ptr SlabAllocator::get(size_t req_size) memory_store.erase(it); } - // info("Reusing memory slab of size: ", size, " for requested ", req_size, " total: ", get_total_size()); + dbg_info("Reusing memory slab of size: ", size, " for requested ", req_size, " total: ", get_total_size()); return std::shared_ptr(ptr, [this, size](void* p) { if (allocator_destroyed) { @@ -147,20 +167,20 @@ std::shared_ptr SlabAllocator::get(size_t req_size) } if (req_size % 32 == 0) { - // info("Allocating unmanaged memory slab of size: ", req_size); + dbg_info("Allocating unmanaged memory slab of size: ", req_size); return std::shared_ptr(aligned_alloc(32, req_size), aligned_free); } else { - // info("Allocating unaligned unmanaged memory slab of size: ", req_size); + dbg_info("Allocating unaligned unmanaged memory slab of size: ", req_size); return std::shared_ptr(malloc(req_size), free); } } -// size_t SlabAllocator::get_total_size() -// { -// return std::accumulate(memory_store.begin(), memory_store.end(), size_t{ 0 }, [](size_t acc, const auto& kv) { -// return acc + kv.first * kv.second.size(); -// }); -// } +size_t SlabAllocator::get_total_size() +{ + return std::accumulate(memory_store.begin(), memory_store.end(), size_t{ 0 }, [](size_t acc, const auto& kv) { + return acc + kv.first * kv.second.size(); + }); +} void SlabAllocator::release(void* ptr, size_t size) { @@ -168,16 +188,16 @@ void SlabAllocator::release(void* ptr, size_t size) std::unique_lock lock(memory_store_mutex); #endif memory_store[size].push_back(ptr); - // info("Pooled poly memory of size: ", size, " total: ", get_total_size()); + dbg_info("Pooled poly memory of size: ", size, " total: ", get_total_size()); } SlabAllocator allocator; } // namespace namespace barretenberg { -void init_slab_allocator(size_t circuit_size) +void init_slab_allocator(size_t circuit_subgroup_size) { - allocator.init(circuit_size); + allocator.init(circuit_subgroup_size); } // auto init = ([]() { @@ -189,4 +209,20 @@ std::shared_ptr get_mem_slab(size_t size) { return allocator.get(size); } + +void* get_mem_slab_raw(size_t size) +{ + auto slab = get_mem_slab(size); + manual_slabs[slab.get()] = slab; + return slab.get(); +} + +void free_mem_slab_raw(void* p) +{ + if (allocator_destroyed) { + aligned_free(p); + return; + } + manual_slabs.erase(p); +} } // namespace barretenberg diff --git a/cpp/src/barretenberg/common/slab_allocator.hpp b/cpp/src/barretenberg/common/slab_allocator.hpp index d4ffef3bf9..be5ef6ea1b 100644 --- a/cpp/src/barretenberg/common/slab_allocator.hpp +++ b/cpp/src/barretenberg/common/slab_allocator.hpp @@ -3,6 +3,8 @@ #include #include #include +#include "./log.hpp" +#include "./assert.hpp" #ifndef NO_MULTITHREADING #include #endif @@ -23,11 +25,47 @@ namespace barretenberg { * TODO: De-globalise. Init the allocator and pass around. Use a PolynomialFactory (PolynomialStore?). * TODO: Consider removing, but once due-dilligence has been done that we no longer have memory limitations. */ -void init_slab_allocator(size_t circuit_size); +void init_slab_allocator(size_t circuit_subgroup_size); /** * Returns a slab from the preallocated pool of slabs, or fallback to a new heap allocation (32 byte aligned). + * Ref counted result so no need to manually free. */ std::shared_ptr get_mem_slab(size_t size); +/** + * Sometimes you want a raw pointer to a slab so you can manage when it's released manually (e.g. c_binds, containers). + * This still gets a slab with a shared_ptr, but holds the shared_ptr internally until free_mem_slab_raw is called. + */ +void* get_mem_slab_raw(size_t size); + +void free_mem_slab_raw(void*); + +/** + * Allocator for containers such as std::vector. Makes them leverage the underlying slab allocator where possible. + */ +template class ContainerSlabAllocator { + public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using size_type = std::size_t; + + template struct rebind { + using other = ContainerSlabAllocator; + }; + + pointer allocate(size_type n) + { + // info("ContainerSlabAllocator allocating: ", n * sizeof(T)); + return reinterpret_cast(get_mem_slab_raw(n * sizeof(T))); + } + + void deallocate(pointer p, size_type /*unused*/) { free_mem_slab_raw(p); } + + friend bool operator==(const ContainerSlabAllocator&, const ContainerSlabAllocator&) { return true; } + + friend bool operator!=(const ContainerSlabAllocator&, const ContainerSlabAllocator&) { return false; } +}; + } // namespace barretenberg \ No newline at end of file diff --git a/cpp/src/barretenberg/common/streams.hpp b/cpp/src/barretenberg/common/streams.hpp index af8c9e2403..c3dd64aa7c 100644 --- a/cpp/src/barretenberg/common/streams.hpp +++ b/cpp/src/barretenberg/common/streams.hpp @@ -19,8 +19,8 @@ inline std::ostream& operator<<(std::ostream& os, std::vector const& ar return os; } -template ::value, bool> = true> -inline std::ostream& operator<<(std::ostream& os, std::vector const& arr) +template ::value, bool> = true, typename A> +inline std::ostream& operator<<(std::ostream& os, std::vector const& arr) { os << "["; for (auto element : arr) { @@ -30,8 +30,8 @@ inline std::ostream& operator<<(std::ostream& os, std::vector const& arr) return os; } -template ::value, bool> = true> -inline std::ostream& operator<<(std::ostream& os, std::vector const& arr) +template ::value, bool> = true, typename A> +inline std::ostream& operator<<(std::ostream& os, std::vector const& arr) { os << "[\n"; for (auto element : arr) { diff --git a/cpp/src/barretenberg/common/wasm_export.hpp b/cpp/src/barretenberg/common/wasm_export.hpp index f5ae500838..7bbe9feb61 100644 --- a/cpp/src/barretenberg/common/wasm_export.hpp +++ b/cpp/src/barretenberg/common/wasm_export.hpp @@ -1,7 +1,8 @@ #ifdef __clang__ -#define WASM_EXPORT __attribute__((visibility("default"))) __attribute__((annotate("wasm_export"))) -#define ASYNC_WASM_EXPORT __attribute__((visibility("default"))) __attribute__((annotate("async_wasm_export"))) +#define WASM_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((annotate("wasm_export"))) +#define ASYNC_WASM_EXPORT \ + extern "C" __attribute__((visibility("default"))) __attribute__((annotate("async_wasm_export"))) #else -#define WASM_EXPORT __attribute__((visibility("default"))) -#define ASYNC_WASM_EXPORT __attribute__((visibility("default"))) +#define WASM_EXPORT extern "C" __attribute__((visibility("default"))) +#define ASYNC_WASM_EXPORT extern "C" __attribute__((visibility("default"))) #endif \ No newline at end of file diff --git a/cpp/src/barretenberg/crypto/hmac/hmac.hpp b/cpp/src/barretenberg/crypto/hmac/hmac.hpp index e78ef5206c..e1f83905e5 100644 --- a/cpp/src/barretenberg/crypto/hmac/hmac.hpp +++ b/cpp/src/barretenberg/crypto/hmac/hmac.hpp @@ -93,8 +93,8 @@ std::array hmac(const MessageContainer& message, con * @return Fr output field element as uint512_t( H(10...0 || HMAC(k,m)) || H(00...0 || HMAC(k,m)) ) % r */ template -Fr get_unbiased_field_from_hmac(const MessageContainer& message, const KeyContainer& key) - requires(Hash::OUTPUT_SIZE == 32) +Fr get_unbiased_field_from_hmac(const MessageContainer& message, + const KeyContainer& key) requires(Hash::OUTPUT_SIZE == 32) { // Strong assumption that works for now with our suite of Hashers static_assert(Hash::BLOCK_SIZE > Hash::OUTPUT_SIZE); diff --git a/cpp/src/barretenberg/crypto/pedersen_commitment/pedersen_lookup.test.cpp b/cpp/src/barretenberg/crypto/pedersen_commitment/pedersen_lookup.test.cpp index a06f5cea58..fa38853d74 100644 --- a/cpp/src/barretenberg/crypto/pedersen_commitment/pedersen_lookup.test.cpp +++ b/cpp/src/barretenberg/crypto/pedersen_commitment/pedersen_lookup.test.cpp @@ -59,6 +59,13 @@ auto compute_expected(const grumpkin::fq exponent, size_t generator_offset) return (accumulators[0] + accumulators[1]); } +TEST(pedersen_lookup, zero_one) +{ + auto r = + crypto::pedersen_commitment::lookup::compress_native({ barretenberg::fr::zero(), barretenberg::fr::one() }); + EXPECT_EQ(format(r), "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af"); +} + TEST(pedersen_lookup, endomorphism_test) { typedef grumpkin::fq fq; diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 8f2c4d17f5..63d6c6791a 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -3,7 +3,7 @@ namespace acir_format { -void read_witness(Composer& composer, std::vector witness) +void read_witness(Composer& composer, WitnessVector const& witness) { composer.variables[0] = 0; for (size_t i = 0; i < witness.size(); ++i) { @@ -11,7 +11,7 @@ void read_witness(Composer& composer, std::vector witness) } } -void create_circuit(Composer& composer, const acir_format& constraint_system) +void create_circuit(Composer& composer, acir_format const& constraint_system) { if (constraint_system.public_inputs.size() > constraint_system.varnum) { info("create_circuit: too many public inputs!"); @@ -73,6 +73,9 @@ void create_circuit(Composer& composer, const acir_format& constraint_system) for (const auto& constraint : constraint_system.keccak_constraints) { create_keccak_constraints(composer, constraint); } + for (const auto& constraint : constraint_system.keccak_var_constraints) { + create_keccak_var_constraints(composer, constraint); + } // Add pedersen constraints for (const auto& constraint : constraint_system.pedersen_constraints) { @@ -93,16 +96,32 @@ void create_circuit(Composer& composer, const acir_format& constraint_system) for (const auto& constraint : constraint_system.block_constraints) { create_block_constraints(composer, constraint); } + + // Add recursion constraints + for (size_t i = 0; i < constraint_system.recursion_constraints.size(); ++i) { + auto& constraint = constraint_system.recursion_constraints[i]; + create_recursion_constraints(composer, constraint); + + // make sure the verification key records the public input indices of the final recursion output + // (N.B. up to the ACIR description to make sure that the final output aggregation object wires are public + // inputs!) + if (i == constraint_system.recursion_constraints.size() - 1) { + std::vector proof_output_witness_indices(constraint.output_aggregation_object.begin(), + constraint.output_aggregation_object.end()); + composer.set_recursive_proof(proof_output_witness_indices); + } + } } Composer create_circuit(const acir_format& constraint_system, - std::unique_ptr&& crs_factory) + std::shared_ptr const& crs_factory, + size_t size_hint) { if (constraint_system.public_inputs.size() > constraint_system.varnum) { info("create_circuit: too many public inputs!"); } - Composer composer(std::move(crs_factory)); + Composer composer(crs_factory, size_hint); for (size_t i = 1; i < constraint_system.varnum; ++i) { // If the index is in the public inputs vector, then we add it as a public input @@ -116,6 +135,7 @@ Composer create_circuit(const acir_format& constraint_system, composer.add_variable(0); } } + // Add arithmetic gates for (const auto& constraint : constraint_system.constraints) { composer.create_poly_gate(constraint); @@ -161,6 +181,9 @@ Composer create_circuit(const acir_format& constraint_system, for (const auto& constraint : constraint_system.keccak_constraints) { create_keccak_constraints(composer, constraint); } + for (const auto& constraint : constraint_system.keccak_var_constraints) { + create_keccak_var_constraints(composer, constraint); + } // Add pedersen constraints for (const auto& constraint : constraint_system.pedersen_constraints) { @@ -182,18 +205,33 @@ Composer create_circuit(const acir_format& constraint_system, create_block_constraints(composer, constraint); } + // Add recursion constraints + for (size_t i = 0; i < constraint_system.recursion_constraints.size(); ++i) { + auto& constraint = constraint_system.recursion_constraints[i]; + create_recursion_constraints(composer, constraint); + + // make sure the verification key records the public input indices of the final recursion output + // (N.B. up to the ACIR description to make sure that the final output aggregation object wires are public + // inputs!) + if (i == constraint_system.recursion_constraints.size() - 1) { + std::vector proof_output_witness_indices(constraint.output_aggregation_object.begin(), + constraint.output_aggregation_object.end()); + composer.set_recursive_proof(proof_output_witness_indices); + } + } + return composer; } -Composer create_circuit_with_witness(const acir_format& constraint_system, - std::vector witness, - std::unique_ptr&& crs_factory) +Composer create_circuit_with_witness(acir_format const& constraint_system, + WitnessVector const& witness, + std::shared_ptr const& crs_factory) { if (constraint_system.public_inputs.size() > constraint_system.varnum) { info("create_circuit_with_witness: too many public inputs!"); } - Composer composer(std::move(crs_factory)); + Composer composer(crs_factory); for (size_t i = 1; i < constraint_system.varnum; ++i) { // If the index is in the public inputs vector, then we add it as a public input @@ -255,6 +293,9 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, for (const auto& constraint : constraint_system.keccak_constraints) { create_keccak_constraints(composer, constraint); } + for (const auto& constraint : constraint_system.keccak_var_constraints) { + create_keccak_var_constraints(composer, constraint); + } // Add pedersen constraints for (const auto& constraint : constraint_system.pedersen_constraints) { @@ -276,9 +317,24 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, create_block_constraints(composer, constraint); } + // Add recursion constraints + for (size_t i = 0; i < constraint_system.recursion_constraints.size(); ++i) { + auto& constraint = constraint_system.recursion_constraints[i]; + create_recursion_constraints(composer, constraint, true); + + // make sure the verification key records the public input indices of the final recursion output + // (N.B. up to the ACIR description to make sure that the final output aggregation object wires are public + // inputs!) + if (i == constraint_system.recursion_constraints.size() - 1) { + std::vector proof_output_witness_indices(constraint.output_aggregation_object.begin(), + constraint.output_aggregation_object.end()); + composer.set_recursive_proof(proof_output_witness_indices); + } + } + return composer; } -Composer create_circuit_with_witness(const acir_format& constraint_system, std::vector witness) +Composer create_circuit_with_witness(const acir_format& constraint_system, WitnessVector const& witness) { if (constraint_system.public_inputs.size() > constraint_system.varnum) { info("create_circuit_with_witness: too many public inputs!"); @@ -346,6 +402,9 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, std:: for (const auto& constraint : constraint_system.keccak_constraints) { create_keccak_constraints(composer, constraint); } + for (const auto& constraint : constraint_system.keccak_var_constraints) { + create_keccak_var_constraints(composer, constraint); + } // Add pedersen constraints for (const auto& constraint : constraint_system.pedersen_constraints) { @@ -367,9 +426,24 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, std:: create_block_constraints(composer, constraint); } + // Add recursion constraints + for (size_t i = 0; i < constraint_system.recursion_constraints.size(); ++i) { + auto& constraint = constraint_system.recursion_constraints[i]; + create_recursion_constraints(composer, constraint, true); + + // make sure the verification key records the public input indices of the final recursion output + // (N.B. up to the ACIR description to make sure that the final output aggregation object wires are public + // inputs!) + if (i == constraint_system.recursion_constraints.size() - 1) { + std::vector proof_output_witness_indices(constraint.output_aggregation_object.begin(), + constraint.output_aggregation_object.end()); + composer.set_recursive_proof(proof_output_witness_indices); + } + } + return composer; } -void create_circuit_with_witness(Composer& composer, const acir_format& constraint_system, std::vector witness) +void create_circuit_with_witness(Composer& composer, acir_format const& constraint_system, WitnessVector const& witness) { if (constraint_system.public_inputs.size() > constraint_system.varnum) { info("create_circuit_with_witness: too many public inputs!"); @@ -435,6 +509,9 @@ void create_circuit_with_witness(Composer& composer, const acir_format& constrai for (const auto& constraint : constraint_system.keccak_constraints) { create_keccak_constraints(composer, constraint); } + for (const auto& constraint : constraint_system.keccak_var_constraints) { + create_keccak_var_constraints(composer, constraint); + } // Add pedersen constraints for (const auto& constraint : constraint_system.pedersen_constraints) { @@ -455,6 +532,21 @@ void create_circuit_with_witness(Composer& composer, const acir_format& constrai for (const auto& constraint : constraint_system.block_constraints) { create_block_constraints(composer, constraint); } + + // Add recursion constraints + for (size_t i = 0; i < constraint_system.recursion_constraints.size(); ++i) { + auto& constraint = constraint_system.recursion_constraints[i]; + create_recursion_constraints(composer, constraint, true); + + // make sure the verification key records the public input indices of the final recursion output + // (N.B. up to the ACIR description to make sure that the final output aggregation object wires are public + // inputs!) + if (i == constraint_system.recursion_constraints.size() - 1) { + std::vector proof_output_witness_indices(constraint.output_aggregation_object.begin(), + constraint.output_aggregation_object.end()); + composer.set_recursive_proof(proof_output_witness_indices); + } + } } } // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index cf14558c31..6dc5e8dd1b 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/common/slab_allocator.hpp" #include "logic_constraint.hpp" #include "range_constraint.hpp" #include "sha256_constraint.hpp" @@ -8,6 +9,7 @@ #include "schnorr_verify.hpp" #include "ecdsa_secp256k1.hpp" #include "compute_merkle_root_constraint.hpp" +#include "recursion_constraint.hpp" #include "block_constraint.hpp" #include "pedersen.hpp" #include "hash_to_field.hpp" @@ -29,31 +31,39 @@ struct acir_format { std::vector sha256_constraints; std::vector blake2s_constraints; std::vector keccak_constraints; + std::vector keccak_var_constraints; std::vector hash_to_field_constraints; std::vector pedersen_constraints; std::vector compute_merkle_root_constraints; std::vector block_constraints; + std::vector recursion_constraints; // A standard plonk arithmetic constraint, as defined in the poly_triple struct, consists of selector values // for q_M,q_L,q_R,q_O,q_C and indices of three variables taking the role of left, right and output wire - std::vector constraints; + // This could be a large vector so use slab allocator, we don't expect the blackbox implementations to be so large. + std::vector> constraints; friend bool operator==(acir_format const& lhs, acir_format const& rhs) = default; }; -void read_witness(Composer& composer, std::vector witness); +using WitnessVector = std::vector>; + +void read_witness(Composer& composer, std::vector const& witness); void create_circuit(Composer& composer, const acir_format& constraint_system); Composer create_circuit(const acir_format& constraint_system, - std::unique_ptr&& crs_factory); + std::shared_ptr const& crs_factory, + size_t size_hint = 0); Composer create_circuit_with_witness(const acir_format& constraint_system, - std::vector witness, - std::unique_ptr&& crs_factory); + WitnessVector const& witness, + std::shared_ptr const& crs_factory); -Composer create_circuit_with_witness(const acir_format& constraint_system, std::vector witness); +Composer create_circuit_with_witness(const acir_format& constraint_system, WitnessVector const& witness); -void create_circuit_with_witness(Composer& composer, const acir_format& constraint_system, std::vector witness); +void create_circuit_with_witness(Composer& composer, + const acir_format& constraint_system, + WitnessVector const& witness); // Serialisation template inline void read(B& buf, acir_format& data) @@ -69,9 +79,11 @@ template inline void read(B& buf, acir_format& data) read(buf, data.ecdsa_constraints); read(buf, data.blake2s_constraints); read(buf, data.keccak_constraints); + read(buf, data.keccak_var_constraints); read(buf, data.pedersen_constraints); read(buf, data.hash_to_field_constraints); read(buf, data.fixed_base_scalar_mul_constraints); + read(buf, data.recursion_constraints); read(buf, data.constraints); read(buf, data.block_constraints); } @@ -89,9 +101,11 @@ template inline void write(B& buf, acir_format const& data) write(buf, data.ecdsa_constraints); write(buf, data.blake2s_constraints); write(buf, data.keccak_constraints); + write(buf, data.keccak_var_constraints); write(buf, data.pedersen_constraints); write(buf, data.hash_to_field_constraints); write(buf, data.fixed_base_scalar_mul_constraints); + write(buf, data.recursion_constraints); write(buf, data.constraints); write(buf, data.block_constraints); } diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index b9fed48eb9..96c067805a 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -5,6 +5,51 @@ #include "barretenberg/common/streams.hpp" #include "barretenberg/serialize/test_helper.hpp" #include "ecdsa_secp256k1.hpp" + +TEST(acir_format, test_a_single_constraint_no_pub_inputs) +{ + + poly_triple constraint{ + .a = 1, + .b = 2, + .c = 3, + .q_m = 0, + .q_l = 1, + .q_r = 1, + .q_o = -1, + .q_c = 0, + }; + + acir_format::acir_format constraint_system{ + .varnum = 4, + .public_inputs = {}, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_constraints = {}, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .compute_merkle_root_constraints = {}, + .block_constraints = {}, + .recursion_constraints = {}, + .constraints = { constraint }, + }; + + auto composer = acir_format::create_circuit_with_witness(constraint_system, { 0, 0, 1 }); + + auto prover = composer.create_ultra_with_keccak_prover(); + auto proof = prover.construct_proof(); + + auto verifier = composer.create_ultra_with_keccak_verifier(); + + EXPECT_EQ(verifier.verify_proof(proof), false); +} + TEST(acir_format, msgpack_logic_constraint) { auto [actual, expected] = msgpack_roundtrip(acir_format::LogicConstraint{}); @@ -80,7 +125,6 @@ TEST(acir_format, test_logic_gate_from_noir_circuit) // EXPR [ (1, _4, _5) (-1, _6) 0 ] // EXPR [ (1, _4, _6) (-1, _4) 0 ] // EXPR [ (-1, _6) 1 ] - std::cout << "made struct" << std::endl; acir_format::acir_format constraint_system{ .varnum = 7, @@ -93,10 +137,12 @@ TEST(acir_format, test_logic_gate_from_noir_circuit) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = {}, + .recursion_constraints = {}, .constraints = { expr_a, expr_b, expr_c, expr_d }, }; @@ -111,8 +157,6 @@ TEST(acir_format, test_logic_gate_from_noir_circuit) 1, }); - std::cout << "made composer" << std::endl; - auto prover = composer.create_ultra_with_keccak_prover(); auto proof = prover.construct_proof(); @@ -159,10 +203,12 @@ TEST(acir_format, test_schnorr_verify_pass) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = {}, + .recursion_constraints = {}, .constraints = { poly_triple{ .a = schnorr_constraint.result, .b = schnorr_constraint.result, @@ -230,10 +276,12 @@ TEST(acir_format, test_schnorr_verify_small_range) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = {}, + .recursion_constraints = {}, .constraints = { poly_triple{ .a = schnorr_constraint.result, .b = schnorr_constraint.result, diff --git a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 66ab73e84a..de75643564 100644 --- a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -6,7 +6,7 @@ #include #include -size_t generate_block_constraint(acir_format::BlockConstraint& constraint, std::vector& witness_values) +size_t generate_block_constraint(acir_format::BlockConstraint& constraint, acir_format::WitnessVector& witness_values) { size_t witness_len = 1; witness_values.emplace_back(1); @@ -100,7 +100,7 @@ size_t generate_block_constraint(acir_format::BlockConstraint& constraint, std:: TEST(up_ram, TestBlockConstraint) { acir_format::BlockConstraint block; - std::vector witness_values; + acir_format::WitnessVector witness_values; size_t num_variables = generate_block_constraint(block, witness_values); acir_format::acir_format constraint_system{ .varnum = static_cast(num_variables), @@ -113,10 +113,12 @@ TEST(up_ram, TestBlockConstraint) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = { block }, + .recursion_constraints = {}, .constraints = {}, }; diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index fb8b3711b0..d82de5a870 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -10,7 +10,7 @@ using curve = proof_system::plonk::stdlib::secp256k1; size_t generate_ecdsa_constraint(acir_format::EcdsaSecp256k1Constraint& ecdsa_constraint, - std::vector& witness_values) + acir_format::WitnessVector& witness_values) { std::string message_string = "Instructions unclear, ask again later."; @@ -81,7 +81,7 @@ size_t generate_ecdsa_constraint(acir_format::EcdsaSecp256k1Constraint& ecdsa_co TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) { acir_format::EcdsaSecp256k1Constraint ecdsa_constraint; - std::vector witness_values; + acir_format::WitnessVector witness_values; size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); acir_format::acir_format constraint_system{ .varnum = static_cast(num_variables), @@ -94,10 +94,12 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = {}, + .recursion_constraints = {}, .constraints = {}, }; @@ -117,7 +119,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) TEST(ECDSASecp256k1, TestECDSACompilesForVerifier) { acir_format::EcdsaSecp256k1Constraint ecdsa_constraint; - std::vector witness_values; + acir_format::WitnessVector witness_values; size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); acir_format::acir_format constraint_system{ .varnum = static_cast(num_variables), @@ -130,20 +132,22 @@ TEST(ECDSASecp256k1, TestECDSACompilesForVerifier) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = {}, + .recursion_constraints = {}, .constraints = {}, }; - auto crs_factory = std::make_unique(); + auto crs_factory = std::make_unique(); auto composer = create_circuit(constraint_system, std::move(crs_factory)); } TEST(ECDSASecp256k1, TestECDSAConstraintFail) { acir_format::EcdsaSecp256k1Constraint ecdsa_constraint; - std::vector witness_values; + acir_format::WitnessVector witness_values; size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); // set result value to be false @@ -163,10 +167,12 @@ TEST(ECDSASecp256k1, TestECDSAConstraintFail) .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, + .keccak_var_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, .block_constraints = {}, + .recursion_constraints = {}, .constraints = {}, }; diff --git a/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp b/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp index f89e530c10..b573e57153 100644 --- a/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp @@ -35,4 +35,37 @@ void create_keccak_constraints(Composer& composer, const KeccakConstraint& const } } +void create_keccak_var_constraints(Composer& composer, const KeccakVarConstraint& constraint) +{ + + // Create byte array struct + byte_array_ct arr(&composer); + + // Get the witness assignment for each witness index + // Write the witness assignment to the byte_array + for (const auto& witness_index_num_bits : constraint.inputs) { + auto witness_index = witness_index_num_bits.witness; + auto num_bits = witness_index_num_bits.num_bits; + + // XXX: The implementation requires us to truncate the element to the nearest byte and not bit + auto num_bytes = round_to_nearest_byte(num_bits); + + field_ct element = field_ct::from_witness_index(&composer, witness_index); + byte_array_ct element_bytes(element, num_bytes); + + arr.write(element_bytes); + } + + uint32_ct length = field_ct::from_witness_index(&composer, constraint.var_message_size); + + byte_array_ct output_bytes = proof_system::plonk::stdlib::keccak::hash(arr, length); + + // Convert byte array to vector of field_t + auto bytes = output_bytes.bytes(); + + for (size_t i = 0; i < bytes.size(); ++i) { + composer.assert_equal(bytes[i].normalize().witness_index, constraint.result[i]); + } +} + } // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp b/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp index 15322b6562..95fabe00d5 100644 --- a/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp @@ -19,7 +19,16 @@ struct KeccakConstraint { friend bool operator==(KeccakConstraint const& lhs, KeccakConstraint const& rhs) = default; }; +struct KeccakVarConstraint { + std::vector inputs; + uint32_t var_message_size; + std::vector result; + + friend bool operator==(KeccakVarConstraint const& lhs, KeccakVarConstraint const& rhs) = default; +}; + void create_keccak_constraints(Composer& composer, const KeccakConstraint& constraint); +void create_keccak_var_constraints(Composer& composer, const KeccakVarConstraint& constraint); template inline void read(B& buf, HashInput& constraint) { @@ -49,4 +58,20 @@ template inline void write(B& buf, KeccakConstraint const& constrai write(buf, constraint.result); } +template inline void read(B& buf, KeccakVarConstraint& constraint) +{ + using serialize::read; + read(buf, constraint.inputs); + read(buf, constraint.result); + read(buf, constraint.var_message_size); +} + +template inline void write(B& buf, KeccakVarConstraint const& constraint) +{ + using serialize::write; + write(buf, constraint.inputs); + write(buf, constraint.result); + write(buf, constraint.var_message_size); +} + } // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp new file mode 100644 index 0000000000..f5064788cb --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -0,0 +1,352 @@ +#include "recursion_constraint.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/recursion/verifier/verifier.hpp" +#include "barretenberg/transcript/transcript_wrappers.hpp" + +namespace acir_format { + +using namespace proof_system::plonk; + +// `NUM_LIMB_BITS_IN_FIELD_SIMULATION` is the limb size when simulating a non-native field using the bigfield class +// A aggregation object is two acir_format::g1_ct types where each coordinate in a point is a non-native field. +// Each field is represented as four limbs. We split those limbs in half when serializing to/from buffer. +static constexpr uint64_t TWO_LIMBS_BITS_IN_FIELD_SIMULATION = NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2; +static constexpr uint64_t FOUR_LIMBS_BITS_IN_FIELD_SIMULATION = NUM_LIMB_BITS_IN_FIELD_SIMULATION * 4; + +void generate_dummy_proof() {} +/** + * @brief Add constraints required to recursively verify an UltraPlonk proof + * + * @param composer + * @param input + * @tparam has_valid_witness_assignment. Do we have witnesses or are we just generating keys? + * @tparam inner_proof_contains_recursive_proof. Do we expect the inner proof to also have performed recursive + * verification? We need to know this at circuit-compile time. + * + * @note We currently only support RecursionConstraint where inner_proof_contains_recursive_proof = false. + * We would either need a separate ACIR opcode where inner_proof_contains_recursive_proof = true, + * or we need non-witness data to be provided as metadata in the ACIR opcode + */ +void create_recursion_constraints(Composer& composer, + const RecursionConstraint& input, + bool has_valid_witness_assignments) +{ + const auto& nested_aggregation_indices = input.nested_aggregation_object; + bool nested_aggregation_indices_all_zero = true; + for (const auto& idx : nested_aggregation_indices) { + nested_aggregation_indices_all_zero &= (idx == 0); + } + const bool inner_proof_contains_recursive_proof = !nested_aggregation_indices_all_zero; + + // If we do not have a witness, we must ensure that our dummy witness will not trigger + // on-curve errors and inverting-zero errors + { + // get a fake key/proof that satisfies on-curve + inversion-zero checks + const std::vector dummy_key = export_dummy_key_in_recursion_format(PolynomialManifest(Composer::type), + inner_proof_contains_recursive_proof); + const auto manifest = Composer::create_unrolled_manifest(input.public_inputs.size()); + const std::vector dummy_proof = + export_dummy_transcript_in_recursion_format(manifest, inner_proof_contains_recursive_proof); + for (size_t i = 0; i < input.proof.size(); ++i) { + const auto proof_field_idx = input.proof[i]; + // if we do NOT have a witness assignment (i.e. are just building the proving/verification keys), + // we add our dummy proof values as Composer variables. + // if we DO have a valid witness assignment, we use the real witness assignment + barretenberg::fr dummy_field = + has_valid_witness_assignments ? composer.get_variable(proof_field_idx) : dummy_proof[i]; + // Create a copy constraint between our dummy field and the witness index provided by RecursionConstraint. + // This will make the RecursionConstraint idx equal to `dummy_field`. + // In the case of a valid witness assignment, this does nothing (as dummy_field = real value) + // In the case of no valid witness assignment, this makes sure that the RecursionConstraint witness indices + // will not trigger basic errors (check inputs are on-curve, check we are not inverting 0) + composer.assert_equal(composer.add_variable(dummy_field), proof_field_idx); + } + for (size_t i = 0; i < input.key.size(); ++i) { + const auto key_field_idx = input.key[i]; + barretenberg::fr dummy_field = + has_valid_witness_assignments ? composer.get_variable(key_field_idx) : dummy_key[i]; + composer.assert_equal(composer.add_variable(dummy_field), key_field_idx); + } + } + + // Construct an in-circuit representation of the verification key. + // For now, the v-key is a circuit constant and is fixed for the circuit. + // (We may need a separate recursion opcode for this to vary, or add more config witnesses to this opcode) + const auto& aggregation_input = input.input_aggregation_object; + aggregation_state_ct previous_aggregation; + + // If we have previously recursively verified proofs, `is_aggregation_object_nonzero = true` + // For now this is a complile-time constant i.e. whether this is true/false is fixed for the circuit! + bool inner_aggregation_indices_all_zero = true; + for (const auto& idx : aggregation_input) { + inner_aggregation_indices_all_zero &= (idx == 0); + } + + if (!inner_aggregation_indices_all_zero) { + std::array aggregation_elements; + for (size_t i = 0; i < 4; ++i) { + aggregation_elements[i] = + bn254::fq_ct(field_ct::from_witness_index(&composer, aggregation_input[4 * i]), + field_ct::from_witness_index(&composer, aggregation_input[4 * i + 1]), + field_ct::from_witness_index(&composer, aggregation_input[4 * i + 2]), + field_ct::from_witness_index(&composer, aggregation_input[4 * i + 3])); + aggregation_elements[i].assert_is_in_field(); + } + // If we have a previous aggregation object, assign it to `previous_aggregation` so that it is included + // in stdlib::recursion::verify_proof + previous_aggregation.P0 = bn254::g1_ct(aggregation_elements[0], aggregation_elements[1]); + previous_aggregation.P1 = bn254::g1_ct(aggregation_elements[2], aggregation_elements[3]); + previous_aggregation.has_data = true; + } else { + previous_aggregation.has_data = false; + } + + transcript::Manifest manifest = Composer::create_unrolled_manifest(input.public_inputs.size()); + + std::vector key_fields; + key_fields.reserve(input.key.size()); + for (const auto& idx : input.key) { + auto field = field_ct::from_witness_index(&composer, idx); + key_fields.emplace_back(field); + } + + std::vector proof_fields; + proof_fields.reserve(input.proof.size()); + for (const auto& idx : input.proof) { + auto field = field_ct::from_witness_index(&composer, idx); + proof_fields.emplace_back(field); + } + + // recursively verify the proof + std::shared_ptr vkey = verification_key_ct::from_field_elements( + &composer, key_fields, inner_proof_contains_recursive_proof, nested_aggregation_indices); + vkey->program_width = noir_recursive_settings::program_width; + Transcript_ct transcript(&composer, manifest, proof_fields, input.public_inputs.size()); + aggregation_state_ct result = proof_system::plonk::stdlib::recursion::verify_proof_( + &composer, vkey, transcript, previous_aggregation); + + // Assign correct witness value to the verification key hash + vkey->compress().assert_equal(field_ct::from_witness_index(&composer, input.key_hash)); + + ASSERT(result.public_inputs.size() == input.public_inputs.size()); + + // Assign the `public_input` field to the public input of the inner proof + for (size_t i = 0; i < input.public_inputs.size(); ++i) { + result.public_inputs[i].assert_equal(field_ct::from_witness_index(&composer, input.public_inputs[i])); + } + + // Assign the recursive proof outputs to `output_aggregation_object` + for (size_t i = 0; i < result.proof_witness_indices.size(); ++i) { + const auto lhs = field_ct::from_witness_index(&composer, result.proof_witness_indices[i]); + const auto rhs = field_ct::from_witness_index(&composer, input.output_aggregation_object[i]); + lhs.assert_equal(rhs); + } +} + +/** + * @brief When recursively verifying proofs, we represent the verification key using field elements. + * This method exports the key formatted in the manner our recursive verifier expects. + * NOTE: only used by the dsl at the moment. Might be cleaner to make this a dsl function? + * + * @return std::vector + */ +std::vector export_key_in_recursion_format(std::shared_ptr const& vkey) +{ + std::vector output; + output.emplace_back(vkey->domain.root); + output.emplace_back(vkey->domain.domain); + output.emplace_back(vkey->domain.generator); + output.emplace_back(vkey->circuit_size); + output.emplace_back(vkey->num_public_inputs); + output.emplace_back(vkey->contains_recursive_proof); + for (size_t i = 0; i < RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + if (vkey->recursive_proof_public_input_indices.size() > i) { + output.emplace_back(vkey->recursive_proof_public_input_indices[i]); + } else { + output.emplace_back(0); + ASSERT(vkey->contains_recursive_proof == false); + } + } + for (const auto& descriptor : vkey->polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + const auto element = vkey->commitments.at(std::string(descriptor.commitment_label)); + auto g1_as_fields = export_g1_affine_element_as_fields(element); + output.emplace_back(g1_as_fields.x_lo); + output.emplace_back(g1_as_fields.x_hi); + output.emplace_back(g1_as_fields.y_lo); + output.emplace_back(g1_as_fields.y_hi); + } + } + + verification_key_data vkey_data{ + .composer_type = vkey->composer_type, + .circuit_size = static_cast(vkey->circuit_size), + .num_public_inputs = static_cast(vkey->num_public_inputs), + .commitments = vkey->commitments, + .contains_recursive_proof = vkey->contains_recursive_proof, + .recursive_proof_public_input_indices = vkey->recursive_proof_public_input_indices, + }; + output.emplace_back(vkey_data.compress_native(0)); // key_hash + return output; +} + +/** + * @brief When recursively verifying proofs, we represent the verification key using field elements. + * This method exports the key formatted in the manner our recursive verifier expects. + * A dummy key is used when building a circuit without a valid witness assignment. + * We want the transcript to contain valid G1 points to prevent on-curve errors being thrown. + * We want a non-zero circuit size as this element will be inverted by the circuit + * and we do not want an "inverting 0" error thrown + * + * @return std::vector + */ +std::vector export_dummy_key_in_recursion_format(const PolynomialManifest& polynomial_manifest, + const bool contains_recursive_proof) +{ + std::vector output; + output.emplace_back(1); // domain.domain (will be inverted) + output.emplace_back(1); // domain.root (will be inverted) + output.emplace_back(1); // domain.generator (will be inverted) + + output.emplace_back(1); // circuit size + output.emplace_back(1); // num public inputs + + output.emplace_back(contains_recursive_proof); // contains_recursive_proof + for (size_t i = 0; i < RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + output.emplace_back(0); // recursive_proof_public_input_indices + } + + for (const auto& descriptor : polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + // the std::biggroup class creates unsatisfiable constraints when identical points are added/subtracted. + // (when verifying zk proofs this is acceptable as we make sure verification key points are not identical. + // And prover points should contain randomness for an honest Prover). + // This check can also trigger a runtime error due to causing 0 to be inverted. + // When creating dummy verification key points we must be mindful of the above and make sure that each + // transcript point is unique. + auto scalar = barretenberg::fr::random_element(); + const auto element = barretenberg::g1::affine_element(barretenberg::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(element); + output.emplace_back(g1_as_fields.x_lo); + output.emplace_back(g1_as_fields.x_hi); + output.emplace_back(g1_as_fields.y_lo); + output.emplace_back(g1_as_fields.y_hi); + } + } + + output.emplace_back(0); // key_hash + + return output; +} + +/** + * @brief Returns transcript represented as a vector of barretenberg::fr. + * Used to represent recursive proofs (i.e. proof represented as circuit-native field elements) + * + * @return std::vector + */ +std::vector export_transcript_in_recursion_format(const transcript::StandardTranscript& transcript) +{ + std::vector fields; + const auto num_rounds = transcript.get_manifest().get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (const auto& manifest_element : transcript.get_manifest().get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + fields.emplace_back(transcript.get_field_element(manifest_element.name)); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + const auto group_element = transcript.get_group_element(manifest_element.name); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } else { + ASSERT(manifest_element.name == "public_inputs"); + const auto public_inputs_vector = transcript.get_field_element_vector(manifest_element.name); + for (const auto& ele : public_inputs_vector) { + fields.emplace_back(ele); + } + } + } + } + } + return fields; +} + +/** + * @brief Get a dummy fake proof for recursion. All elliptic curve group elements are still valid points to prevent + * errors being thrown. + * + * @param manifest + * @return std::vector + */ +std::vector export_dummy_transcript_in_recursion_format(const transcript::Manifest& manifest, + const bool contains_recursive_proof) +{ + std::vector fields; + const auto num_rounds = manifest.get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (const auto& manifest_element : manifest.get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + // auto scalar = barretenberg::fr::random_element(); + fields.emplace_back(0); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + // the std::biggroup class creates unsatisfiable constraints when identical points are + // added/subtracted. + // (when verifying zk proofs this is acceptable as we make sure verification key points are not + // identical. And prover points should contain randomness for an honest Prover). This check can + // also trigger a runtime error due to causing 0 to be inverted. When creating dummy proof + // points we must be mindful of the above and make sure that each point is unique. + auto scalar = barretenberg::fr::random_element(); + const auto group_element = barretenberg::g1::affine_element(barretenberg::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } else { + ASSERT(manifest_element.name == "public_inputs"); + const size_t num_public_inputs = manifest_element.num_bytes / 32; + // If we have a recursive proofs the public inputs must describe an aggregation object that + // is composed of two valid G1 points on the curve. Without this conditional we will get a + // runtime error that we are attempting to invert 0. + if (contains_recursive_proof) { + ASSERT(num_public_inputs == RecursionConstraint::AGGREGATION_OBJECT_SIZE); + for (size_t k = 0; k < RecursionConstraint::NUM_AGGREGATION_ELEMENTS; ++k) { + auto scalar = barretenberg::fr::random_element(); + const auto group_element = barretenberg::g1::affine_element(barretenberg::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } + } else { + for (size_t j = 0; j < num_public_inputs; ++j) { + // auto scalar = barretenberg::fr::random_element(); + fields.emplace_back(0); + } + } + } + } + } + } + return fields; +} + +G1AsFields export_g1_affine_element_as_fields(const barretenberg::g1::affine_element& group_element) +{ + const uint256_t x = group_element.x; + const uint256_t y = group_element.y; + const barretenberg::fr x_lo = x.slice(0, TWO_LIMBS_BITS_IN_FIELD_SIMULATION); + const barretenberg::fr x_hi = x.slice(TWO_LIMBS_BITS_IN_FIELD_SIMULATION, FOUR_LIMBS_BITS_IN_FIELD_SIMULATION); + const barretenberg::fr y_lo = y.slice(0, TWO_LIMBS_BITS_IN_FIELD_SIMULATION); + const barretenberg::fr y_hi = y.slice(TWO_LIMBS_BITS_IN_FIELD_SIMULATION, FOUR_LIMBS_BITS_IN_FIELD_SIMULATION); + + return G1AsFields{ x_lo, x_hi, y_lo, y_hi }; +} + +} // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp new file mode 100644 index 0000000000..f99dc21230 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp @@ -0,0 +1,110 @@ +#pragma once +#include +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" + +namespace acir_format { + +using namespace proof_system::plonk; + +/** + * @brief RecursionConstraint struct contains information required to recursively verify a proof! + * + * @details The recursive verifier algorithm produces an 'aggregation object' representing 2 G1 points, expressed as 16 + * witness values. The smart contract Verifier must be aware of this aggregation object in order to complete the full + * recursive verification. If the circuit verifies more than 1 proof, the recursion algorithm will update a pre-existing + * aggregation object (`input_aggregation_object`). + * + * @details We currently require that the inner circuit being verified only has a single public input. If more are + * required, the outer circuit can hash them down to 1 input. + * + * @param verification_key_data The inner circuit vkey. Is converted into circuit witness values (internal to the + * backend) + * @param proof The plonk proof. Is converted into circuit witness values (internal to the backend) + * @param is_aggregation_object_nonzero A flag to tell us whether the circuit has already recursively verified proofs + * (and therefore an aggregation object is present) + * @param public_input The index of the single public input + * @param input_aggregation_object Witness indices of pre-existing aggregation object (if it exists) + * @param output_aggregation_object Witness indices of the aggregation object produced by recursive verification + * @param nested_aggregation_object Public input indices of an aggregation object inside the proof. + * + * @note If input_aggregation_object witness indices are all zero, we interpret this to mean that the inner proof does + * NOT contain a previously recursively verified proof + * @note nested_aggregation_object is used for cases where the proof being verified contains an aggregation object in + * its public inputs! If this is the case, we record the public input locations in `nested_aggregation_object`. If the + * inner proof is of a circuit that does not have a nested aggregation object, these values are all zero. + * + * To outline the interaction between the input_aggergation_object and the nested_aggregation_object take the following + * example: If we have a circuit that verifies 2 proofs A and B, the recursion constraint for B will have an + * input_aggregation_object that points to the aggregation output produced by verifying A. If circuit B also verifies a + * proof, in the above example the recursion constraint for verifying B will have a nested object that describes the + * aggregation object in B’s public inputs as well as an input aggregation object that points to the object produced by + * the previous recursion constraint in the circuit (the one that verifies A) + * + */ +struct RecursionConstraint { + // An aggregation state is represented by two G1 affine elements. Each G1 point has + // two field element coordinates (x, y). Thus, four field elements + static constexpr size_t NUM_AGGREGATION_ELEMENTS = 4; + // Four limbs are used when simulating a non-native field using the bigfield class + static constexpr size_t AGGREGATION_OBJECT_SIZE = + NUM_AGGREGATION_ELEMENTS * NUM_QUOTIENT_PARTS; // 16 field elements + std::vector key; + std::vector proof; + std::vector public_inputs; + uint32_t key_hash; + std::array input_aggregation_object; + std::array output_aggregation_object; + std::array nested_aggregation_object; + + friend bool operator==(RecursionConstraint const& lhs, RecursionConstraint const& rhs) = default; +}; + +void create_recursion_constraints(Composer& composer, + const RecursionConstraint& input, + bool has_valid_witness_assignments = false); + +std::vector export_key_in_recursion_format(std::shared_ptr const& vkey); +std::vector export_dummy_key_in_recursion_format(const PolynomialManifest& polynomial_manifest, + bool contains_recursive_proof = 0); + +std::vector export_transcript_in_recursion_format(const transcript::StandardTranscript& transcript); +std::vector export_dummy_transcript_in_recursion_format(const transcript::Manifest& manifest, + const bool contains_recursive_proof); + +// In order to interact with a recursive aggregation state inside of a circuit, we need to represent its internal G1 +// elements as field elements. This happens in multiple locations when creating a recursion constraint. The struct and +// method below export a g1 affine element as fields to use as part of the recursive circuit. +struct G1AsFields { + barretenberg::fr x_lo; + barretenberg::fr x_hi; + barretenberg::fr y_lo; + barretenberg::fr y_hi; +}; +G1AsFields export_g1_affine_element_as_fields(const barretenberg::g1::affine_element& group_element); + +template inline void read(B& buf, RecursionConstraint& constraint) +{ + using serialize::read; + read(buf, constraint.key); + read(buf, constraint.proof); + read(buf, constraint.public_inputs); + read(buf, constraint.key_hash); + read(buf, constraint.input_aggregation_object); + read(buf, constraint.output_aggregation_object); + read(buf, constraint.nested_aggregation_object); +} + +template inline void write(B& buf, RecursionConstraint const& constraint) +{ + using serialize::write; + write(buf, constraint.key); + write(buf, constraint.proof); + write(buf, constraint.public_inputs); + write(buf, constraint.key_hash); + write(buf, constraint.input_aggregation_object); + write(buf, constraint.output_aggregation_object); + write(buf, constraint.nested_aggregation_object); +} + +} // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp new file mode 100644 index 0000000000..0117b4f0a5 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -0,0 +1,303 @@ +#include "acir_format.hpp" +#include "recursion_constraint.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" + +#include +#include + +using namespace proof_system::plonk; + +acir_format::Composer create_inner_circuit() +{ + /** + * constraints produced by Noir program: + * fn main(x : u32, y : pub u32) { + * let z = x ^ y; + * + * constrain z != 10; + * } + **/ + acir_format::RangeConstraint range_a{ + .witness = 1, + .num_bits = 32, + }; + acir_format::RangeConstraint range_b{ + .witness = 2, + .num_bits = 32, + }; + + acir_format::LogicConstraint logic_constraint{ + .a = 1, + .b = 2, + .result = 3, + .num_bits = 32, + .is_xor_gate = 1, + }; + poly_triple expr_a{ + .a = 3, + .b = 4, + .c = 0, + .q_m = 0, + .q_l = 1, + .q_r = -1, + .q_o = 0, + .q_c = -10, + }; + poly_triple expr_b{ + .a = 4, + .b = 5, + .c = 6, + .q_m = 1, + .q_l = 0, + .q_r = 0, + .q_o = -1, + .q_c = 0, + }; + poly_triple expr_c{ + .a = 4, + .b = 6, + .c = 4, + .q_m = 1, + .q_l = 0, + .q_r = 0, + .q_o = -1, + .q_c = 0, + + }; + poly_triple expr_d{ + .a = 6, + .b = 0, + .c = 0, + .q_m = 0, + .q_l = -1, + .q_r = 0, + .q_o = 0, + .q_c = 1, + }; + + acir_format::acir_format constraint_system{ + .varnum = 7, + .public_inputs = { 2, 3 }, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = { logic_constraint }, + .range_constraints = { range_a, range_b }, + .schnorr_constraints = {}, + .ecdsa_constraints = {}, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .compute_merkle_root_constraints = {}, + .block_constraints = {}, + .recursion_constraints = {}, + .constraints = { expr_a, expr_b, expr_c, expr_d }, + }; + + uint256_t inverse_of_five = fr(5).invert(); + auto composer = acir_format::create_circuit_with_witness(constraint_system, + { + 5, + 10, + 15, + 5, + inverse_of_five, + 1, + }); + + return composer; +} + +/** + * @brief Create a circuit that recursively verifies one or more inner circuits + * + * @param inner_composers + * @return acir_format::Composer + */ +acir_format::Composer create_outer_circuit(std::vector& inner_composers) +{ + std::vector recursion_constraints; + + // witness count starts at 1 (Composer reserves 1st witness to be the zero-valued zero_idx) + size_t witness_offset = 1; + std::array output_aggregation_object; + std::vector> witness; + + for (size_t i = 0; i < inner_composers.size(); ++i) { + const bool has_input_aggregation_object = i > 0; + + auto& inner_composer = inner_composers[i]; + auto inner_prover = inner_composer.create_prover(); + auto inner_proof = inner_prover.construct_proof(); + auto inner_verifier = inner_composer.create_verifier(); + + const bool has_nested_proof = inner_verifier.key->contains_recursive_proof; + const size_t num_inner_public_inputs = inner_composer.get_num_public_inputs(); + + transcript::StandardTranscript transcript(inner_proof.proof_data, + acir_format::Composer::create_manifest(num_inner_public_inputs), + transcript::HashType::PlookupPedersenBlake3s, + 16); + + const std::vector proof_witnesses = + acir_format::export_transcript_in_recursion_format(transcript); + const std::vector key_witnesses = + acir_format::export_key_in_recursion_format(inner_verifier.key); + + const uint32_t key_hash_start_idx = static_cast(witness_offset); + const uint32_t public_input_start_idx = key_hash_start_idx + 1; + const uint32_t output_aggregation_object_start_idx = + static_cast(public_input_start_idx + num_inner_public_inputs + (has_nested_proof ? 16 : 0)); + const uint32_t proof_indices_start_idx = output_aggregation_object_start_idx + 16; + const uint32_t key_indices_start_idx = static_cast(proof_indices_start_idx + proof_witnesses.size()); + + std::vector proof_indices; + std::vector key_indices; + std::vector inner_public_inputs; + std::array input_aggregation_object = {}; + std::array nested_aggregation_object = {}; + if (has_input_aggregation_object) { + input_aggregation_object = output_aggregation_object; + } + for (size_t i = 0; i < 16; ++i) { + output_aggregation_object[i] = (static_cast(i + output_aggregation_object_start_idx)); + } + if (has_nested_proof) { + for (size_t i = 0; i < 16; ++i) { + nested_aggregation_object[i] = inner_composer.recursive_proof_public_input_indices[i]; + } + } + for (size_t i = 0; i < proof_witnesses.size(); ++i) { + proof_indices.emplace_back(static_cast(i + proof_indices_start_idx)); + } + const size_t key_size = key_witnesses.size(); + for (size_t i = 0; i < key_size; ++i) { + key_indices.emplace_back(static_cast(i + key_indices_start_idx)); + } + for (size_t i = 0; i < num_inner_public_inputs; ++i) { + inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); + } + + acir_format::RecursionConstraint recursion_constraint{ + .key = key_indices, + .proof = proof_indices, + .public_inputs = inner_public_inputs, + .key_hash = key_hash_start_idx, + .input_aggregation_object = input_aggregation_object, + .output_aggregation_object = output_aggregation_object, + .nested_aggregation_object = nested_aggregation_object, + }; + recursion_constraints.push_back(recursion_constraint); + for (size_t i = 0; i < proof_indices_start_idx - witness_offset; ++i) { + witness.emplace_back(0); + } + for (const auto& wit : proof_witnesses) { + witness.emplace_back(wit); + } + for (const auto& wit : key_witnesses) { + witness.emplace_back(wit); + } + witness_offset = key_indices_start_idx + key_witnesses.size(); + } + + std::vector public_inputs(output_aggregation_object.begin(), output_aggregation_object.end()); + + acir_format::acir_format constraint_system{ + .varnum = static_cast(witness.size() + 1), + .public_inputs = public_inputs, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_constraints = {}, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .compute_merkle_root_constraints = {}, + .block_constraints = {}, + .recursion_constraints = recursion_constraints, + .constraints = {}, + }; + + auto composer = acir_format::create_circuit_with_witness(constraint_system, witness); + + return composer; +} + +TEST(RecursionConstraint, TestBasicDoubleRecursionConstraints) +{ + std::vector layer_1_composers; + layer_1_composers.push_back(create_inner_circuit()); + + layer_1_composers.push_back(create_inner_circuit()); + + auto layer_2_composer = create_outer_circuit(layer_1_composers); + + std::cout << "composer gates = " << layer_2_composer.get_num_gates() << std::endl; + auto prover = layer_2_composer.create_ultra_with_keccak_prover(); + std::cout << "prover gates = " << prover.circuit_size << std::endl; + auto proof = prover.construct_proof(); + auto verifier = layer_2_composer.create_ultra_with_keccak_verifier(); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST(RecursionConstraint, TestFullRecursionConstraints) +{ + /** + * We want to test the following: + * 1. circuit that verifies a proof of another circuit + * 2. the above, but the inner circuit contains a recursive proof output that we have to aggregate + * 3. the above, but the outer circuit verifies 2 proofs, the aggregation outputs from the 2 proofs (+ the recursive + * proof output from 2) are aggregated together + * + * A = basic circuit + * B = circuit that verifies proof of A + * C = circuit that verifies proof of B and a proof of A + * + * Layer 1 = proof of A + * Layer 2 = verifies proof of A and proof of B + * Layer 3 = verifies proof of C + * + * Attempt at a visual graphic + * =========================== + * + * C + * ^ + * | + * | - B + * ^ ^ + * | | + * | -A + * | + * - A + * + * =========================== + * + * Final aggregation object contains aggregated proofs for 2 instances of A and 1 instance of B + */ + std::vector layer_1_composers; + layer_1_composers.push_back(create_inner_circuit()); + std::cout << "created first inner circuit\n"; + std::vector layer_2_composers; + + layer_2_composers.push_back(create_inner_circuit()); + std::cout << "created second inner circuit\n"; + + layer_2_composers.push_back(create_outer_circuit(layer_1_composers)); + std::cout << "created first outer circuit\n"; + + auto layer_3_composer = create_outer_circuit(layer_2_composers); + std::cout << "created second outer circuit\n"; + + std::cout << "composer gates = " << layer_3_composer.get_num_gates() << std::endl; + auto prover = layer_3_composer.create_ultra_with_keccak_prover(); + std::cout << "prover gates = " << prover.circuit_size << std::endl; + auto proof = prover.construct_proof(); + auto verifier = layer_3_composer.create_ultra_with_keccak_verifier(); + EXPECT_EQ(verifier.verify_proof(proof), true); +} diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp new file mode 100644 index 0000000000..0dc392c284 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -0,0 +1,143 @@ +#include "acir_composer.hpp" +#include "barretenberg/common/serialize.hpp" +#include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" +#include "barretenberg/dsl/acir_format/acir_format.hpp" +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" +#include "barretenberg/plonk/proof_system/verification_key/sol_gen.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" + +namespace acir_proofs { + +AcirComposer::AcirComposer() + : composer_(0, 0, 0) +{} + +void AcirComposer::create_circuit(acir_format::acir_format& constraint_system) +{ + composer_ = acir_format::create_circuit(constraint_system, nullptr); + + // We are done with the constraint system at this point, and we need the memory slab back. + constraint_system.constraints.clear(); + constraint_system.constraints.shrink_to_fit(); + + exact_circuit_size_ = composer_.get_num_gates(); + total_circuit_size_ = composer_.get_total_circuit_size(); + circuit_subgroup_size_ = composer_.get_circuit_subgroup_size(total_circuit_size_); +} + +void AcirComposer::init_proving_key(std::shared_ptr const& crs_factory, + acir_format::acir_format& constraint_system, + size_t size_hint) +{ + composer_ = acir_format::create_circuit(constraint_system, crs_factory, size_hint); + + // We are done with the constraint system at this point, and we need the memory slab back. + constraint_system.constraints.clear(); + constraint_system.constraints.shrink_to_fit(); + + exact_circuit_size_ = composer_.get_num_gates(); + total_circuit_size_ = composer_.get_total_circuit_size(); + circuit_subgroup_size_ = composer_.get_circuit_subgroup_size(total_circuit_size_); + + proving_key_ = composer_.compute_proving_key(); +} + +std::vector AcirComposer::create_proof( + std::shared_ptr const& crs_factory, + acir_format::acir_format& constraint_system, + acir_format::WitnessVector& witness, + bool is_recursive) +{ + composer_ = acir_format::Composer(proving_key_, verification_key_, circuit_subgroup_size_); + // You can't produce the verification key unless you manually set the crs. Which seems like a bug. + composer_.crs_factory_ = crs_factory; + + create_circuit_with_witness(composer_, constraint_system, witness); + + // We are done with the constraint system at this point, and we need the memory slab back. + constraint_system.constraints.clear(); + constraint_system.constraints.shrink_to_fit(); + witness.clear(); + witness.shrink_to_fit(); + + std::vector proof; + if (is_recursive) { + auto prover = composer_.create_prover(); + proof = prover.construct_proof().proof_data; + } else { + auto prover = composer_.create_ultra_with_keccak_prover(); + proof = prover.construct_proof().proof_data; + } + return proof; +} + +std::shared_ptr AcirComposer::init_verification_key() +{ + return verification_key_ = composer_.compute_verification_key(); +} + +void AcirComposer::load_verification_key(std::shared_ptr const& crs_factory, + proof_system::plonk::verification_key_data&& data) +{ + verification_key_ = + std::make_shared(std::move(data), crs_factory->get_verifier_crs()); + composer_ = acir_format::Composer(proving_key_, verification_key_, circuit_subgroup_size_); +} + +bool AcirComposer::verify_proof(std::vector const& proof, bool is_recursive) +{ + // Hack. Shouldn't need to do this. 2144 is size with no public inputs. + composer_.public_inputs.resize((proof.size() - 2144) / 32); + + if (is_recursive) { + auto verifier = composer_.create_verifier(); + return verifier.verify_proof({ proof }); + } else { + auto verifier = composer_.create_ultra_with_keccak_verifier(); + return verifier.verify_proof({ proof }); + } +} + +std::string AcirComposer::get_solidity_verifier() +{ + std::ostringstream stream; + output_vk_sol(stream, verification_key_, "UltraVerificationKey"); + return stream.str(); +} + +/** + * @brief Takes in a proof buffer and converts into a vector of field elements. + * The Recursion opcode requires the proof serialized as a vector of witnesses. + * Use this method to get the witness values! + * + * @param proof + * @param num_inner_public_inputs - number of public inputs on the proof being serialized + */ +std::vector AcirComposer::serialize_proof_into_fields(std::vector const& proof, + size_t num_inner_public_inputs) +{ + transcript::StandardTranscript transcript(proof, + acir_format::Composer::create_manifest(num_inner_public_inputs), + transcript::HashType::PlookupPedersenBlake3s, + 16); + + std::vector output = acir_format::export_transcript_in_recursion_format(transcript); + return output; +} + +/** + * @brief Takes in a verification key buffer and converts into a vector of field elements. + * The Recursion opcode requires the vk serialized as a vector of witnesses. + * Use this method to get the witness values! + * The composer should already have a verification key initialized. + */ +std::vector AcirComposer::serialize_verification_key_into_fields() +{ + std::vector output = acir_format::export_key_in_recursion_format(verification_key_); + return output; +} + +} // namespace acir_proofs diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp new file mode 100644 index 0000000000..c6de53c205 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +namespace acir_proofs { + +class AcirComposer { + public: + AcirComposer(); + + void create_circuit(acir_format::acir_format& constraint_system); + + void init_proving_key(std::shared_ptr const& crs_factory, + acir_format::acir_format& constraint_system, + size_t size_hint = 0); + + std::vector create_proof(std::shared_ptr const& crs_factory, + acir_format::acir_format& constraint_system, + acir_format::WitnessVector& witness, + bool is_recursive); + + void load_verification_key(std::shared_ptr const& crs_factory, + proof_system::plonk::verification_key_data&& data); + + std::shared_ptr init_verification_key(); + + bool verify_proof(std::vector const& proof, bool is_recursive); + + std::string get_solidity_verifier(); + size_t get_exact_circuit_size() { return exact_circuit_size_; }; + size_t get_total_circuit_size() { return total_circuit_size_; }; + + std::vector serialize_proof_into_fields(std::vector const& proof, + size_t num_inner_public_inputs); + + std::vector serialize_verification_key_into_fields(); + + private: + acir_format::Composer composer_; + size_t exact_circuit_size_; + size_t total_circuit_size_; + size_t circuit_subgroup_size_; + std::shared_ptr proving_key_; + std::shared_ptr verification_key_; +}; + +} // namespace acir_proofs diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_proofs.cpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_proofs.cpp deleted file mode 100644 index 2010c592fb..0000000000 --- a/cpp/src/barretenberg/dsl/acir_proofs/acir_proofs.cpp +++ /dev/null @@ -1,157 +0,0 @@ - -#include "acir_proofs.hpp" -#include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" -#include "barretenberg/dsl/acir_format/acir_format.hpp" -#include "barretenberg/dsl/types.hpp" -#include "barretenberg/srs/reference_string/pippenger_reference_string.hpp" -#include "barretenberg/plonk/proof_system/verification_key/sol_gen.hpp" - -namespace acir_proofs { - -size_t get_solidity_verifier(uint8_t const* g2x, uint8_t const* vk_buf, uint8_t** output_buf) -{ - auto crs = std::make_shared(g2x); - proof_system::plonk::verification_key_data vk_data; - read(vk_buf, vk_data); - auto verification_key = std::make_shared(std::move(vk_data), crs); - - std::ostringstream stream; - // TODO(blaine): Should we just use "VerificationKey" generically? - output_vk_sol(stream, verification_key, "UltraVerificationKey"); - - auto content_str = stream.str(); - auto raw_buf = (uint8_t*)malloc(content_str.size()); - memcpy(raw_buf, (void*)content_str.data(), content_str.size()); - *output_buf = raw_buf; - - return content_str.size(); -} - -uint32_t get_exact_circuit_size(uint8_t const* constraint_system_buf) -{ - auto constraint_system = from_buffer(constraint_system_buf); - auto crs_factory = std::make_unique(); - auto composer = create_circuit(constraint_system, std::move(crs_factory)); - - auto num_gates = composer.get_num_gates(); - return static_cast(num_gates); -} - -uint32_t get_total_circuit_size(uint8_t const* constraint_system_buf) -{ - auto constraint_system = from_buffer(constraint_system_buf); - auto crs_factory = std::make_unique(); - auto composer = create_circuit(constraint_system, std::move(crs_factory)); - - return static_cast(composer.get_total_circuit_size()); -} - -size_t init_proving_key(uint8_t const* constraint_system_buf, uint8_t const** pk_buf) -{ - auto constraint_system = from_buffer(constraint_system_buf); - - // We know that we don't actually need any CRS to create a proving key, so just feed in a nothing. - // Hacky, but, right now it needs *something*. - auto crs_factory = std::make_unique(); - auto composer = create_circuit(constraint_system, std::move(crs_factory)); - auto proving_key = composer.compute_proving_key(); - - auto buffer = to_buffer(*proving_key); - auto raw_buf = (uint8_t*)malloc(buffer.size()); - memcpy(raw_buf, (void*)buffer.data(), buffer.size()); - *pk_buf = raw_buf; - - return buffer.size(); -} - -size_t init_verification_key(void* pippenger, uint8_t const* g2x, uint8_t const* pk_buf, uint8_t const** vk_buf) -{ - std::shared_ptr crs; - plonk::proving_key_data pk_data; - read(pk_buf, pk_data); - auto proving_key = std::make_shared(std::move(pk_data), crs); - - auto crs_factory = std::make_unique( - reinterpret_cast(pippenger), g2x); - proving_key->reference_string = crs_factory->get_prover_crs(proving_key->circuit_size); - - acir_format::Composer composer(proving_key, nullptr); - auto verification_key = - acir_format::Composer::compute_verification_key_base(proving_key, crs_factory->get_verifier_crs()); - - // The composer_type has not yet been set. We need to set the composer_type for when we later read in and - // construct the verification key so that we have the correct polynomial manifest - verification_key->composer_type = proof_system::ComposerType::PLOOKUP; - - auto buffer = to_buffer(*verification_key); - auto raw_buf = (uint8_t*)malloc(buffer.size()); - memcpy(raw_buf, (void*)buffer.data(), buffer.size()); - *vk_buf = raw_buf; - - return buffer.size(); -} - -size_t new_proof(void* pippenger, - uint8_t const* g2x, - uint8_t const* pk_buf, - uint8_t const* constraint_system_buf, - uint8_t const* witness_buf, - uint8_t** proof_data_buf) -{ - auto constraint_system = from_buffer(constraint_system_buf); - - std::shared_ptr crs; - plonk::proving_key_data pk_data; - read(pk_buf, pk_data); - auto proving_key = std::make_shared(std::move(pk_data), crs); - - auto witness = from_buffer>(witness_buf); - - auto crs_factory = std::make_unique( - reinterpret_cast(pippenger), g2x); - proving_key->reference_string = crs_factory->get_prover_crs(proving_key->circuit_size); - - acir_format::Composer composer(proving_key, nullptr); - - create_circuit_with_witness(composer, constraint_system, witness); - - auto prover = composer.create_ultra_with_keccak_prover(); - - auto heapProver = new acir_format::Prover(std::move(prover)); - auto& proof_data = heapProver->construct_proof().proof_data; - *proof_data_buf = proof_data.data(); - - return proof_data.size(); -} - -bool verify_proof( - uint8_t const* g2x, uint8_t const* vk_buf, uint8_t const* constraint_system_buf, uint8_t* proof, uint32_t length) -{ - bool verified = false; - -#ifndef __wasm__ - try { -#endif - auto constraint_system = from_buffer(constraint_system_buf); - auto crs = std::make_shared(g2x); - plonk::verification_key_data vk_data; - read(vk_buf, vk_data); - auto verification_key = std::make_shared(std::move(vk_data), crs); - - acir_format::Composer composer(nullptr, verification_key); - create_circuit(composer, constraint_system); - plonk::proof pp = { std::vector(proof, proof + length) }; - - auto verifier = composer.create_ultra_with_keccak_verifier(); - - verified = verifier.verify_proof(pp); -#ifndef __wasm__ - } catch (const std::exception& e) { - verified = false; - info(e.what()); - } -#endif - return verified; -} - -} // namespace acir_proofs diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_proofs.hpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_proofs.hpp deleted file mode 100644 index 4bd126aae9..0000000000 --- a/cpp/src/barretenberg/dsl/acir_proofs/acir_proofs.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -namespace acir_proofs { - -size_t get_solidity_verifier(uint8_t const* g2x, uint8_t const* vk_buf, uint8_t** output_buf); -uint32_t get_exact_circuit_size(uint8_t const* constraint_system_buf); -uint32_t get_total_circuit_size(uint8_t const* constraint_system_buf); -size_t init_proving_key(uint8_t const* constraint_system_buf, uint8_t const** pk_buf); -size_t init_verification_key(void* pippenger, uint8_t const* g2x, uint8_t const* pk_buf, uint8_t const** vk_buf); -size_t new_proof(void* pippenger, - uint8_t const* g2x, - uint8_t const* pk_buf, - uint8_t const* constraint_system_buf, - uint8_t const* witness_buf, - uint8_t** proof_data_buf); -bool verify_proof( - uint8_t const* g2x, uint8_t const* vk_buf, uint8_t const* constraint_system_buf, uint8_t* proof, uint32_t length); - -} // namespace acir_proofs diff --git a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index 4051aada3a..8cce085b72 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -1,53 +1,132 @@ #include "c_bind.hpp" -#include "acir_proofs.hpp" +#include "acir_composer.hpp" #include +#include +#include "barretenberg/common/net.hpp" +#include "barretenberg/common/mem.hpp" +#include "barretenberg/common/serialize.hpp" +#include "barretenberg/common/slab_allocator.hpp" +#include "barretenberg/dsl/acir_format/acir_format.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/srs/global_crs.hpp" -#define WASM_EXPORT __attribute__((visibility("default"))) +WASM_EXPORT void acir_get_circuit_sizes(uint8_t const* constraint_system_buf, + uint32_t* exact, + uint32_t* total, + uint32_t* subgroup) +{ + auto constraint_system = from_buffer(constraint_system_buf); + free_mem_slab_raw((void*)constraint_system_buf); + auto composer = acir_format::create_circuit(constraint_system, nullptr, 1 << 19); + *exact = htonl((uint32_t)composer.get_num_gates()); + *total = htonl((uint32_t)composer.get_total_circuit_size()); + *subgroup = htonl((uint32_t)composer.get_circuit_subgroup_size(composer.get_total_circuit_size())); +} -extern "C" { +WASM_EXPORT void acir_new_acir_composer(out_ptr out) +{ + *out = new acir_proofs::AcirComposer(); +} -WASM_EXPORT size_t acir_proofs_get_solidity_verifier(uint8_t const* g2x, uint8_t const* vk_buf, uint8_t** output_buf) +WASM_EXPORT void acir_delete_acir_composer(in_ptr acir_composer_ptr) { - return acir_proofs::get_solidity_verifier(g2x, vk_buf, output_buf); + delete reinterpret_cast(*acir_composer_ptr); } -// Get the exact circuit size for the constraint system. -WASM_EXPORT uint32_t acir_proofs_get_exact_circuit_size(uint8_t const* constraint_system_buf) +WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, + uint8_t const* constraint_system_buf, + uint32_t const* size_hint) { - return acir_proofs::get_exact_circuit_size(constraint_system_buf); + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto constraint_system = from_buffer(constraint_system_buf); + + // The binder would normally free the the constraint_system_buf, but we need the memory now. + free_mem_slab_raw((void*)constraint_system_buf); + + acir_composer->init_proving_key(barretenberg::srs::get_crs_factory(), constraint_system, ntohl(*size_hint)); } -WASM_EXPORT uint32_t acir_proofs_get_total_circuit_size(uint8_t const* constraint_system_buf) +WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, + uint8_t const* constraint_system_buf, + uint8_t const* witness_buf, + bool const* is_recursive, + uint8_t** out) { - return acir_proofs::get_total_circuit_size(constraint_system_buf); + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto constraint_system = from_buffer(constraint_system_buf); + auto witness = from_buffer>>(witness_buf); + + // The binder would normally free the the constraint_system_buf, but we need the memory now. + free_mem_slab_raw((void*)constraint_system_buf); + free_mem_slab_raw((void*)witness_buf); + + auto proof_data = + acir_composer->create_proof(barretenberg::srs::get_crs_factory(), constraint_system, witness, *is_recursive); + *out = to_heap_buffer(proof_data); } -WASM_EXPORT size_t acir_proofs_init_proving_key(uint8_t const* constraint_system_buf, uint8_t const** pk_buf) +WASM_EXPORT void acir_load_verification_key(in_ptr acir_composer_ptr, uint8_t const* vk_buf) { - return acir_proofs::init_proving_key(constraint_system_buf, pk_buf); + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto vk_data = from_buffer(vk_buf); + acir_composer->load_verification_key(barretenberg::srs::get_crs_factory(), std::move(vk_data)); } -WASM_EXPORT size_t acir_proofs_init_verification_key(void* pippenger, - uint8_t const* g2x, - uint8_t const* pk_buf, - uint8_t const** vk_buf) +WASM_EXPORT void acir_init_verification_key(in_ptr acir_composer_ptr) { - return acir_proofs::init_verification_key(pippenger, g2x, pk_buf, vk_buf); + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + acir_composer->init_verification_key(); } -WASM_EXPORT size_t acir_proofs_new_proof(void* pippenger, - uint8_t const* g2x, - uint8_t const* pk_buf, - uint8_t const* constraint_system_buf, - uint8_t const* witness_buf, - uint8_t** proof_data_buf) +WASM_EXPORT void acir_get_verification_key(in_ptr acir_composer_ptr, uint8_t** out) { - return acir_proofs::new_proof(pippenger, g2x, pk_buf, constraint_system_buf, witness_buf, proof_data_buf); + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto vk = acir_composer->init_verification_key(); + // to_buffer gives a vector. + // to_heap_buffer serializes that into the heap (i.e. length prefixes). + // if you just did: to_heap_buffer(*vk) you get the un-prefixed buffer. no good. + *out = to_heap_buffer(to_buffer(*vk)); } -WASM_EXPORT bool acir_proofs_verify_proof( - uint8_t const* g2x, uint8_t const* vk_buf, uint8_t const* constraint_system_buf, uint8_t* proof, uint32_t length) +WASM_EXPORT void acir_verify_proof(in_ptr acir_composer_ptr, + uint8_t const* proof_buf, + bool const* is_recursive, + bool* result) { - return acir_proofs::verify_proof(g2x, vk_buf, constraint_system_buf, proof, length); + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto proof = from_buffer>(proof_buf); + *result = acir_composer->verify_proof(proof, *is_recursive); } + +WASM_EXPORT void acir_get_solidity_verifier(in_ptr acir_composer_ptr, out_str_buf out) +{ + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto str = acir_composer->get_solidity_verifier(); + *out = to_heap_buffer(str); +} + +WASM_EXPORT void acir_serialize_proof_into_fields(in_ptr acir_composer_ptr, + uint8_t const* proof_buf, + uint32_t const* num_inner_public_inputs, + fr::vec_out_buf out) +{ + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto proof = from_buffer>(proof_buf); + auto proof_as_fields = acir_composer->serialize_proof_into_fields(proof, ntohl(*num_inner_public_inputs)); + + *out = to_heap_buffer(proof_as_fields); +} + +WASM_EXPORT void acir_serialize_verification_key_into_fields(in_ptr acir_composer_ptr, + fr::vec_out_buf out_vkey, + fr::out_buf out_key_hash) +{ + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + + auto vkey_as_fields = acir_composer->serialize_verification_key_into_fields(); + auto vk_hash = vkey_as_fields.back(); + vkey_as_fields.pop_back(); + + *out_vkey = to_heap_buffer(vkey_as_fields); + write(out_key_hash, vk_hash); } diff --git a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp index a628c928cb..9fbd0be14a 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp @@ -1,25 +1,57 @@ #include #include +#include +#include +#include -#define WASM_EXPORT __attribute__((visibility("default"))) - -extern "C" { - -WASM_EXPORT size_t acir_proofs_get_solidity_verifier(uint8_t const* g2x, uint8_t const* vk_buf, uint8_t** output_buf); -WASM_EXPORT uint32_t acir_proofs_get_exact_circuit_size(uint8_t const* constraint_system_buf); -WASM_EXPORT uint32_t acir_proofs_get_total_circuit_size(uint8_t const* constraint_system_buf); -// Construct composer using prover and verifier key buffers -WASM_EXPORT size_t acir_proofs_init_proving_key(uint8_t const* constraint_system_buf, uint8_t const** pk_buf); -WASM_EXPORT size_t acir_proofs_init_verification_key(void* pippenger, - uint8_t const* g2x, - uint8_t const* pk_buf, - uint8_t const** vk_buf); -WASM_EXPORT size_t acir_proofs_new_proof(void* pippenger, - uint8_t const* g2x, - uint8_t const* pk_buf, - uint8_t const* constraint_system_buf, - uint8_t const* witness_buf, - uint8_t** proof_data_buf); -WASM_EXPORT bool acir_proofs_verify_proof( - uint8_t const* g2x, uint8_t const* vk_buf, uint8_t const* constraint_system_buf, uint8_t* proof, uint32_t length); -} +using namespace barretenberg; + +WASM_EXPORT void acir_get_circuit_sizes(uint8_t const* constraint_system_buf, + uint32_t* exact, + uint32_t* total, + uint32_t* subgroup); + +WASM_EXPORT void acir_new_acir_composer(out_ptr out); + +WASM_EXPORT void acir_delete_acir_composer(in_ptr acir_composer_ptr); + +WASM_EXPORT void acir_create_circuit(in_ptr acir_composer_ptr, + uint8_t const* constraint_system_buf, + uint32_t const* size_hint); + +WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, + uint8_t const* constraint_system_buf, + uint32_t const* size_hint); + +/** + * It would have been nice to just hold onto the constraint_system in the acir_composer, but we can't waste the + * memory. Being able to reuse the underlying Composer would help as well. But, given the situation, we just have + * to pass it in everytime. + */ +WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, + uint8_t const* constraint_system_buf, + uint8_t const* witness_buf, + bool const* is_recursive, + uint8_t** out); + +WASM_EXPORT void acir_load_verification_key(in_ptr acir_composer_ptr, uint8_t const* vk_buf); + +WASM_EXPORT void acir_init_verification_key(in_ptr acir_composer_ptr); + +WASM_EXPORT void acir_get_verification_key(in_ptr acir_composer_ptr, uint8_t** out); + +WASM_EXPORT void acir_verify_proof(in_ptr acir_composer_ptr, + uint8_t const* proof_buf, + bool const* is_recursive, + bool* result); + +WASM_EXPORT void acir_get_solidity_verifier(in_ptr acir_composer_ptr, out_str_buf out); + +WASM_EXPORT void acir_serialize_proof_into_fields(in_ptr acir_composer_ptr, + uint8_t const* proof_buf, + uint32_t const* num_inner_public_inputs, + fr::vec_out_buf out); + +WASM_EXPORT void acir_serialize_verification_key_into_fields(in_ptr acir_composer_ptr, + fr::vec_out_buf out_vkey, + fr::out_buf out_key_hash); \ No newline at end of file diff --git a/cpp/src/barretenberg/dsl/types.hpp b/cpp/src/barretenberg/dsl/types.hpp index e5277faf2d..f9823984bf 100644 --- a/cpp/src/barretenberg/dsl/types.hpp +++ b/cpp/src/barretenberg/dsl/types.hpp @@ -20,6 +20,10 @@ #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/memory/rom_table.hpp" #include "barretenberg/stdlib/primitives/memory/ram_table.hpp" +#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp" +#include "barretenberg/stdlib/recursion/verification_key/verification_key.hpp" +#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" + namespace acir_format { using Composer = plonk::UltraComposer; @@ -34,6 +38,8 @@ using Verifier = std::conditional_t< plonk::UltraWithKeccakVerifier, std::conditional_t, plonk::TurboVerifier, plonk::Verifier>>; +using RecursiveProver = plonk::UltraProver; + using witness_ct = proof_system::plonk::stdlib::witness_t; using public_witness_ct = proof_system::plonk::stdlib::public_witness_t; using bool_ct = proof_system::plonk::stdlib::bool_t; @@ -58,8 +64,13 @@ using hash_path_ct = proof_system::plonk::stdlib::merkle_tree::hash_path; -// Ultra-composer specific typesv +// Ultra-composer specific types using rom_table_ct = proof_system::plonk::stdlib::rom_table; using ram_table_ct = proof_system::plonk::stdlib::ram_table; +using verification_key_ct = proof_system::plonk::stdlib::recursion::verification_key; +using aggregation_state_ct = proof_system::plonk::stdlib::recursion::aggregation_state; +using noir_recursive_settings = proof_system::plonk::stdlib::recursion::recursive_ultra_verifier_settings; +using Transcript_ct = proof_system::plonk::stdlib::recursion::Transcript; + } // namespace acir_format diff --git a/cpp/src/barretenberg/ecc/c_bind.cpp b/cpp/src/barretenberg/ecc/c_bind.cpp index e559eccc13..109b8ff0eb 100644 --- a/cpp/src/barretenberg/ecc/c_bind.cpp +++ b/cpp/src/barretenberg/ecc/c_bind.cpp @@ -14,6 +14,12 @@ WASM_EXPORT void ecc_new_pippenger(uint8_t const* points, uint32_t const* num_po *out = new scalar_multiplication::Pippenger(points_vec.data(), num_points); } +WASM_EXPORT void ecc_new_pippenger_mem_prealloced(in_ptr points, uint32_t const* num_points_buf, out_ptr out) +{ + auto num_points = ntohl(*num_points_buf); + *out = new scalar_multiplication::Pippenger((g1::affine_element*)*points, num_points); +} + WASM_EXPORT void ecc_delete_pippenger(in_ptr pippenger) { delete (scalar_multiplication::Pippenger*)(*pippenger); diff --git a/cpp/src/barretenberg/ecc/c_bind.hpp b/cpp/src/barretenberg/ecc/c_bind.hpp index f2761b890b..c7e8f8fa5b 100644 --- a/cpp/src/barretenberg/ecc/c_bind.hpp +++ b/cpp/src/barretenberg/ecc/c_bind.hpp @@ -7,7 +7,9 @@ extern "C" { using namespace barretenberg; using affine_element = g1::affine_element; -WASM_EXPORT void ecc_new_pippenger(uint8_t const* points, uint32_t const* num_points, out_ptr out); +WASM_EXPORT void ecc_new_pippenger(uint8_t const* points, uint32_t const* num_points_buf, out_ptr out); + +WASM_EXPORT void ecc_new_pippenger_mem_prealloced(in_ptr points, uint32_t const* num_points, out_ptr out); WASM_EXPORT void ecc_delete_pippenger(in_ptr pippenger); diff --git a/cpp/src/barretenberg/ecc/fields/field2.hpp b/cpp/src/barretenberg/ecc/fields/field2.hpp index 630b25c1b4..32be96eab9 100644 --- a/cpp/src/barretenberg/ecc/fields/field2.hpp +++ b/cpp/src/barretenberg/ecc/fields/field2.hpp @@ -126,6 +126,22 @@ template struct alignas(32) field2 { } }; +// template void read(B& it, field2& value) +// { +// using serialize::read; +// field2 result; +// read(it, result.c0); +// read(it, result.c1); +// value = result.to_montgomery_form(); +// } +// template void write(B& buf, field2 const& value) +// { +// using serialize::write; +// const auto input = value.from_montgomery_form(); +// write(buf, input.c0); +// write(buf, input.c1); +// } + } // namespace barretenberg #include "field2_impl.hpp" diff --git a/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp b/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp index 0f59db209c..2664f12345 100644 --- a/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp +++ b/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp @@ -87,12 +87,12 @@ template field field::asm_mul_with_coarse_reduction(const field& : "%r"(&a), "%r"(&b), "r"(&r), - [modulus_0] "m"(modulus_0), - [modulus_1] "m"(modulus_1), - [modulus_2] "m"(modulus_2), - [modulus_3] "m"(modulus_3), - [r_inv] "m"(r_inv), - [zero_reference] "m"(zero_ref) + [ modulus_0 ] "m"(modulus_0), + [ modulus_1 ] "m"(modulus_1), + [ modulus_2 ] "m"(modulus_2), + [ modulus_3 ] "m"(modulus_3), + [ r_inv ] "m"(r_inv), + [ zero_reference ] "m"(zero_ref) : "%rdx", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); return r; } @@ -119,12 +119,12 @@ template void field::asm_self_mul_with_coarse_reduction(const field : : "r"(&a), "r"(&b), - [modulus_0] "m"(modulus_0), - [modulus_1] "m"(modulus_1), - [modulus_2] "m"(modulus_2), - [modulus_3] "m"(modulus_3), - [r_inv] "m"(r_inv), - [zero_reference] "m"(zero_ref) + [ modulus_0 ] "m"(modulus_0), + [ modulus_1 ] "m"(modulus_1), + [ modulus_2 ] "m"(modulus_2), + [ modulus_3 ] "m"(modulus_3), + [ r_inv ] "m"(r_inv), + [ zero_reference ] "m"(zero_ref) : "%rdx", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); } @@ -157,12 +157,12 @@ template field field::asm_sqr_with_coarse_reduction(const field& : "%r"(&a), "%r"(&a), "r"(&r), - [modulus_0] "m"(modulus_0), - [modulus_1] "m"(modulus_1), - [modulus_2] "m"(modulus_2), - [modulus_3] "m"(modulus_3), - [r_inv] "m"(r_inv), - [zero_reference] "m"(zero_ref) + [ modulus_0 ] "m"(modulus_0), + [ modulus_1 ] "m"(modulus_1), + [ modulus_2 ] "m"(modulus_2), + [ modulus_3 ] "m"(modulus_3), + [ r_inv ] "m"(r_inv), + [ zero_reference ] "m"(zero_ref) : "%rdx", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); #else @@ -181,12 +181,12 @@ template field field::asm_sqr_with_coarse_reduction(const field& : : "r"(&a), "r"(&r), - [zero_reference] "m"(zero_ref), - [modulus_0] "m"(modulus_0), - [modulus_1] "m"(modulus_1), - [modulus_2] "m"(modulus_2), - [modulus_3] "m"(modulus_3), - [r_inv] "m"(r_inv) + [ zero_reference ] "m"(zero_ref), + [ modulus_0 ] "m"(modulus_0), + [ modulus_1 ] "m"(modulus_1), + [ modulus_2 ] "m"(modulus_2), + [ modulus_3 ] "m"(modulus_3), + [ r_inv ] "m"(r_inv) : "%rcx", "%rdx", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); #endif return r; @@ -219,12 +219,12 @@ template void field::asm_self_sqr_with_coarse_reduction(const field : : "r"(&a), "r"(&a), - [modulus_0] "m"(modulus_0), - [modulus_1] "m"(modulus_1), - [modulus_2] "m"(modulus_2), - [modulus_3] "m"(modulus_3), - [r_inv] "m"(r_inv), - [zero_reference] "m"(zero_ref) + [ modulus_0 ] "m"(modulus_0), + [ modulus_1 ] "m"(modulus_1), + [ modulus_2 ] "m"(modulus_2), + [ modulus_3 ] "m"(modulus_3), + [ r_inv ] "m"(r_inv), + [ zero_reference ] "m"(zero_ref) : "%rdx", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); #else @@ -241,12 +241,12 @@ template void field::asm_self_sqr_with_coarse_reduction(const field STORE_FIELD_ELEMENT("%0", "%%r12", "%%r13", "%%r14", "%%r15") : : "r"(&a), - [zero_reference] "m"(zero_ref), - [modulus_0] "m"(modulus_0), - [modulus_1] "m"(modulus_1), - [modulus_2] "m"(modulus_2), - [modulus_3] "m"(modulus_3), - [r_inv] "m"(r_inv) + [ zero_reference ] "m"(zero_ref), + [ modulus_0 ] "m"(modulus_0), + [ modulus_1 ] "m"(modulus_1), + [ modulus_2 ] "m"(modulus_2), + [ modulus_3 ] "m"(modulus_3), + [ r_inv ] "m"(r_inv) : "%rcx", "%rdx", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); #endif } @@ -270,10 +270,10 @@ template field field::asm_add_with_coarse_reduction(const field& : "%r"(&a), "%r"(&b), "r"(&r), - [twice_not_modulus_0] "m"(twice_not_modulus_0), - [twice_not_modulus_1] "m"(twice_not_modulus_1), - [twice_not_modulus_2] "m"(twice_not_modulus_2), - [twice_not_modulus_3] "m"(twice_not_modulus_3) + [ twice_not_modulus_0 ] "m"(twice_not_modulus_0), + [ twice_not_modulus_1 ] "m"(twice_not_modulus_1), + [ twice_not_modulus_2 ] "m"(twice_not_modulus_2), + [ twice_not_modulus_3 ] "m"(twice_not_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); return r; } @@ -294,10 +294,10 @@ template void field::asm_self_add_with_coarse_reduction(const field : : "r"(&a), "r"(&b), - [twice_not_modulus_0] "m"(twice_not_modulus_0), - [twice_not_modulus_1] "m"(twice_not_modulus_1), - [twice_not_modulus_2] "m"(twice_not_modulus_2), - [twice_not_modulus_3] "m"(twice_not_modulus_3) + [ twice_not_modulus_0 ] "m"(twice_not_modulus_0), + [ twice_not_modulus_1 ] "m"(twice_not_modulus_1), + [ twice_not_modulus_2 ] "m"(twice_not_modulus_2), + [ twice_not_modulus_3 ] "m"(twice_not_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); } @@ -318,10 +318,10 @@ template field field::asm_sub_with_coarse_reduction(const field& : "r"(&a), "r"(&b), "r"(&r), - [twice_modulus_0] "m"(twice_modulus_0), - [twice_modulus_1] "m"(twice_modulus_1), - [twice_modulus_2] "m"(twice_modulus_2), - [twice_modulus_3] "m"(twice_modulus_3) + [ twice_modulus_0 ] "m"(twice_modulus_0), + [ twice_modulus_1 ] "m"(twice_modulus_1), + [ twice_modulus_2 ] "m"(twice_modulus_2), + [ twice_modulus_3 ] "m"(twice_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); return r; } @@ -340,10 +340,10 @@ template void field::asm_self_sub_with_coarse_reduction(const field : : "r"(&a), "r"(&b), - [twice_modulus_0] "m"(twice_modulus_0), - [twice_modulus_1] "m"(twice_modulus_1), - [twice_modulus_2] "m"(twice_modulus_2), - [twice_modulus_3] "m"(twice_modulus_3) + [ twice_modulus_0 ] "m"(twice_modulus_0), + [ twice_modulus_1 ] "m"(twice_modulus_1), + [ twice_modulus_2 ] "m"(twice_modulus_2), + [ twice_modulus_3 ] "m"(twice_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); } @@ -372,10 +372,10 @@ template void field::asm_conditional_negate(field& r, const uint64_ : : "r"(predicate), "r"(&r), - [twice_modulus_0] "i"(twice_modulus_0), - [twice_modulus_1] "i"(twice_modulus_1), - [twice_modulus_2] "i"(twice_modulus_2), - [twice_modulus_3] "i"(twice_modulus_3) + [ twice_modulus_0 ] "i"(twice_modulus_0), + [ twice_modulus_1 ] "i"(twice_modulus_1), + [ twice_modulus_2 ] "i"(twice_modulus_2), + [ twice_modulus_3 ] "i"(twice_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); } @@ -394,10 +394,10 @@ template field field::asm_reduce_once(const field& a) noexcept : : "r"(&a), "r"(&r), - [not_modulus_0] "m"(not_modulus_0), - [not_modulus_1] "m"(not_modulus_1), - [not_modulus_2] "m"(not_modulus_2), - [not_modulus_3] "m"(not_modulus_3) + [ not_modulus_0 ] "m"(not_modulus_0), + [ not_modulus_1 ] "m"(not_modulus_1), + [ not_modulus_2 ] "m"(not_modulus_2), + [ not_modulus_3 ] "m"(not_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); return r; } @@ -414,10 +414,10 @@ template void field::asm_self_reduce_once(const field& a) noexcept STORE_FIELD_ELEMENT("%0", "%%r12", "%%r13", "%%r14", "%%r15") : : "r"(&a), - [not_modulus_0] "m"(not_modulus_0), - [not_modulus_1] "m"(not_modulus_1), - [not_modulus_2] "m"(not_modulus_2), - [not_modulus_3] "m"(not_modulus_3) + [ not_modulus_0 ] "m"(not_modulus_0), + [ not_modulus_1 ] "m"(not_modulus_1), + [ not_modulus_2 ] "m"(not_modulus_2), + [ not_modulus_3 ] "m"(not_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"); } } // namespace barretenberg diff --git a/cpp/src/barretenberg/ecc/groups/group_impl_asm.tcc b/cpp/src/barretenberg/ecc/groups/group_impl_asm.tcc index 17d714b487..73a6374b95 100644 --- a/cpp/src/barretenberg/ecc/groups/group_impl_asm.tcc +++ b/cpp/src/barretenberg/ecc/groups/group_impl_asm.tcc @@ -98,10 +98,10 @@ inline void group::conditional_ne : "r"(src), "r"(dest), "r"(predicate), - [modulus_0] "i"(twice_modulus_0), - [modulus_1] "i"(twice_modulus_1), - [modulus_2] "i"(twice_modulus_2), - [modulus_3] "i"(twice_modulus_3) + [ modulus_0 ] "i"(twice_modulus_0), + [ modulus_1 ] "i"(twice_modulus_1), + [ modulus_2 ] "i"(twice_modulus_2), + [ modulus_3 ] "i"(twice_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%ymm0", "memory", "cc"); #else __asm__ __volatile__("xorq %%r8, %%r8 \n\t" @@ -138,10 +138,10 @@ inline void group::conditional_ne : "r"(src), "r"(dest), "r"(predicate), - [modulus_0] "i"(twice_modulus_0), - [modulus_1] "i"(twice_modulus_1), - [modulus_2] "i"(twice_modulus_2), - [modulus_3] "i"(twice_modulus_3) + [ modulus_0 ] "i"(twice_modulus_0), + [ modulus_1 ] "i"(twice_modulus_1), + [ modulus_2 ] "i"(twice_modulus_2), + [ modulus_3 ] "i"(twice_modulus_3) : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc"); #endif } else { diff --git a/cpp/src/barretenberg/examples/c_bind.cpp b/cpp/src/barretenberg/examples/c_bind.cpp index eae7bedaac..cdc25c6b77 100644 --- a/cpp/src/barretenberg/examples/c_bind.cpp +++ b/cpp/src/barretenberg/examples/c_bind.cpp @@ -1,22 +1,13 @@ #include "c_bind.hpp" #include "simple/simple.hpp" -#include "barretenberg/srs/reference_string/pippenger_reference_string.hpp" - -extern "C" { +#include "barretenberg/srs/global_crs.hpp" using namespace proof_system::plonk::stdlib::types; -WASM_EXPORT void examples_simple_create_and_verify_proof(in_ptr pippenger, uint8_t const* g2x_buf, bool* valid) +WASM_EXPORT void examples_simple_create_and_verify_proof(bool* valid) { - auto g2x = from_buffer>(g2x_buf); - auto crs_factory = std::make_shared( - (scalar_multiplication::Pippenger*)(*pippenger), g2x.data()); - - auto* composer_ptr = examples::simple::create_composer(crs_factory); - + auto* composer_ptr = examples::simple::create_composer(barretenberg::srs::get_crs_factory()); auto proof = examples::simple::create_proof(composer_ptr); - *valid = examples::simple::verify_proof(composer_ptr, proof); examples::simple::delete_composer(composer_ptr); } -} diff --git a/cpp/src/barretenberg/examples/c_bind.hpp b/cpp/src/barretenberg/examples/c_bind.hpp index bf682c0f8e..37c6c6768b 100644 --- a/cpp/src/barretenberg/examples/c_bind.hpp +++ b/cpp/src/barretenberg/examples/c_bind.hpp @@ -2,7 +2,4 @@ #include #include "barretenberg/common/wasm_export.hpp" -extern "C" { - -WASM_EXPORT void examples_simple_create_and_verify_proof(in_ptr pippenger, uint8_t const* g2x, bool* valid); -} +WASM_EXPORT void examples_simple_create_and_verify_proof(bool* valid); diff --git a/cpp/src/barretenberg/examples/simple/simple.cpp b/cpp/src/barretenberg/examples/simple/simple.cpp index f7d4dffa9f..dc7cb6b33a 100644 --- a/cpp/src/barretenberg/examples/simple/simple.cpp +++ b/cpp/src/barretenberg/examples/simple/simple.cpp @@ -19,7 +19,7 @@ void build_circuit(Composer& composer) } } -Composer* create_composer(std::shared_ptr const& crs_factory) +Composer* create_composer(std::shared_ptr const& crs_factory) { // WARNING: Size hint is essential to perform 512k circuits! auto composer = std::make_unique(crs_factory, CIRCUIT_SIZE); @@ -45,7 +45,6 @@ proof create_proof(Composer* composer) Timer timer; info("computing proof..."); auto prover = composer->create_ultra_with_keccak_prover(); - // auto prover = composer->create_prover(); auto proof = prover.construct_proof(); info("proof construction took ", timer.seconds(), "s"); return proof; @@ -56,7 +55,6 @@ bool verify_proof(Composer* composer, proof_system::plonk::proof const& proof) info("computing verification key..."); composer->compute_verification_key(); auto verifier = composer->create_ultra_with_keccak_verifier(); - // auto verifier = composer->create_verifier(); auto valid = verifier.verify_proof(proof); info("proof validity: ", valid); return valid; diff --git a/cpp/src/barretenberg/examples/simple/simple.hpp b/cpp/src/barretenberg/examples/simple/simple.hpp index c9af42a966..a3695899f8 100644 --- a/cpp/src/barretenberg/examples/simple/simple.hpp +++ b/cpp/src/barretenberg/examples/simple/simple.hpp @@ -7,7 +7,7 @@ namespace examples::simple { using namespace proof_system::plonk; using namespace stdlib::types; -Composer* create_composer(std::shared_ptr const& crs_factory); +Composer* create_composer(std::shared_ptr const& crs_factory); proof create_proof(Composer* composer); diff --git a/cpp/src/barretenberg/examples/simple/simple.test.cpp b/cpp/src/barretenberg/examples/simple/simple.test.cpp index 2f6f2f5ba3..95fb679b2e 100644 --- a/cpp/src/barretenberg/examples/simple/simple.test.cpp +++ b/cpp/src/barretenberg/examples/simple/simple.test.cpp @@ -1,5 +1,5 @@ #include "simple.hpp" -#include +#include #include #include @@ -8,7 +8,7 @@ namespace examples::simple { TEST(examples_simple, create_proof) { auto srs_path = std::filesystem::absolute("../srs_db/ignition"); - auto crs_factory = std::make_shared(srs_path); + auto crs_factory = std::make_shared(srs_path); auto* composer = create_composer(crs_factory); auto proof = create_proof(composer); bool valid = verify_proof(composer, proof); diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp index 1b8568779b..bbf96fadfb 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.cpp @@ -3,7 +3,7 @@ #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include #include @@ -44,7 +44,7 @@ std::shared_ptr StandardHonkComposerHelp std::shared_ptr StandardHonkComposerHelper::compute_verification_key_base( std::shared_ptr const& proving_key, - std::shared_ptr const& vrs) + std::shared_ptr const& vrs) { auto key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp index 031ebb8115..42fdf9fe29 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/standard_honk_composer_helper.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/honk/proof_system/prover.hpp" #include "barretenberg/honk/proof_system/verifier.hpp" #include "barretenberg/proof_system/circuit_constructors/standard_circuit_constructor.hpp" @@ -25,18 +25,18 @@ class StandardHonkComposerHelper { std::shared_ptr verification_key; // TODO(#218)(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs // at all - std::shared_ptr crs_factory_; + std::shared_ptr crs_factory_; bool computed_witness = false; // TODO(Luke): use make_shared StandardHonkComposerHelper() - : StandardHonkComposerHelper(std::shared_ptr( - new proof_system::FileReferenceStringFactory("../srs_db/ignition"))) + : StandardHonkComposerHelper(std::shared_ptr( + new barretenberg::srs::factories::FileCrsFactory("../srs_db/ignition"))) {} - StandardHonkComposerHelper(std::shared_ptr crs_factory) + StandardHonkComposerHelper(std::shared_ptr crs_factory) : crs_factory_(std::move(crs_factory)) {} - StandardHonkComposerHelper(std::unique_ptr&& crs_factory) + StandardHonkComposerHelper(std::unique_ptr&& crs_factory) : crs_factory_(std::move(crs_factory)) {} StandardHonkComposerHelper(std::shared_ptr p_key, std::shared_ptr v_key) @@ -63,7 +63,8 @@ class StandardHonkComposerHelper { // This needs to be static as it may be used only to compute the selector commitments. static std::shared_ptr compute_verification_key_base( - std::shared_ptr const& proving_key, std::shared_ptr const& vrs); + std::shared_ptr const& proving_key, + std::shared_ptr const& vrs); void compute_witness(const CircuitConstructor& circuit_constructor, const size_t minimum_circuit_size = 0); }; diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp index cf14fea6f0..0e607184f1 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp @@ -2,7 +2,7 @@ #include "barretenberg/proof_system/composer/composer_helper_lib.hpp" #include "barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/honk/proof_system/ultra_prover.hpp" #include "barretenberg/honk/proof_system/ultra_verifier.hpp" @@ -31,7 +31,7 @@ class UltraHonkComposerHelper { std::shared_ptr verification_key; // TODO(#218)(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs // at all - std::shared_ptr crs_factory_; + std::shared_ptr crs_factory_; std::vector recursive_proof_public_input_indices; bool contains_recursive_proof = false; @@ -43,7 +43,7 @@ class UltraHonkComposerHelper { // vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3. static constexpr size_t s_randomness = 3; - explicit UltraHonkComposerHelper(std::shared_ptr crs_factory) + explicit UltraHonkComposerHelper(std::shared_ptr crs_factory) : crs_factory_(std::move(crs_factory)) {} diff --git a/cpp/src/barretenberg/honk/composer/standard_honk_composer.hpp b/cpp/src/barretenberg/honk/composer/standard_honk_composer.hpp index ea60cb6a2a..2fe53791ee 100644 --- a/cpp/src/barretenberg/honk/composer/standard_honk_composer.hpp +++ b/cpp/src/barretenberg/honk/composer/standard_honk_composer.hpp @@ -2,7 +2,7 @@ #include "composer_helper/standard_honk_composer_helper.hpp" #include "barretenberg/proof_system/circuit_constructors/standard_circuit_constructor.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" @@ -46,18 +46,20 @@ class StandardHonkComposer { , variables(circuit_constructor.variables){}; StandardHonkComposer(std::string const& crs_path, const size_t size_hint = 0) - : StandardHonkComposer( - std::unique_ptr(new proof_system::FileReferenceStringFactory(crs_path)), - size_hint){}; + : StandardHonkComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), + size_hint){}; - StandardHonkComposer(std::shared_ptr const& crs_factory, const size_t size_hint = 0) + StandardHonkComposer(std::shared_ptr const& crs_factory, + const size_t size_hint = 0) : circuit_constructor(size_hint) , composer_helper(crs_factory) , num_gates(circuit_constructor.num_gates) , variables(circuit_constructor.variables) {} - StandardHonkComposer(std::unique_ptr&& crs_factory, const size_t size_hint = 0) + StandardHonkComposer(std::unique_ptr&& crs_factory, + const size_t size_hint = 0) : circuit_constructor(size_hint) , composer_helper(std::move(crs_factory)) , num_gates(circuit_constructor.num_gates) diff --git a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp index 78a8c930ad..a13e0df167 100644 --- a/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/standard_honk_composer.test.cpp @@ -1,13 +1,12 @@ #include "standard_honk_composer.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include #include #include #include "barretenberg/honk/proof_system/prover.hpp" #include "barretenberg/honk/sumcheck/sumcheck_round.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/polynomials/polynomial.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp index 1073ec7825..c85e57432c 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp @@ -28,10 +28,12 @@ class UltraHonkComposer { : UltraHonkComposer("../srs_db/ignition", 0){}; UltraHonkComposer(std::string const& crs_path, const size_t size_hint) - : UltraHonkComposer(std::unique_ptr(new FileReferenceStringFactory(crs_path)), + : UltraHonkComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), size_hint){}; - UltraHonkComposer(std::shared_ptr const& crs_factory, const size_t size_hint) + UltraHonkComposer(std::shared_ptr const& crs_factory, + const size_t size_hint) : circuit_constructor(size_hint) , composer_helper(crs_factory) , num_gates(circuit_constructor.num_gates){}; diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 09b3373e7f..2eb23f820a 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -1,14 +1,13 @@ #include "ultra_honk_composer.hpp" #include "barretenberg/common/log.hpp" #include "barretenberg/honk/proof_system/ultra_prover.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include #include #include "barretenberg/honk/proof_system/prover.hpp" #include "barretenberg/honk/sumcheck/sumcheck_round.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/utils/grand_product_delta.hpp" #include "barretenberg/proof_system/plookup_tables/types.hpp" @@ -649,7 +648,6 @@ TEST(UltraHonkComposer, non_native_field_multiplication) fq a = fq::random_element(); fq b = fq::random_element(); - uint256_t modulus = fq::modulus; uint1024_t a_big = uint512_t(uint256_t(a)); diff --git a/cpp/src/barretenberg/honk/flavor/flavor.test.cpp b/cpp/src/barretenberg/honk/flavor/flavor.test.cpp index 1211313af4..d3c44be8bc 100644 --- a/cpp/src/barretenberg/honk/flavor/flavor.test.cpp +++ b/cpp/src/barretenberg/honk/flavor/flavor.test.cpp @@ -1,6 +1,6 @@ #include "barretenberg/honk/flavor/standard.hpp" #include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include #include @@ -15,7 +15,7 @@ TEST(Flavor, StandardGetters) using ProvingKey = typename Flavor::ProvingKey; ProvingKey proving_key = []() { - auto crs_factory = ReferenceStringFactory(); + auto crs_factory = barretenberg::srs::factories::CrsFactory(); auto crs = crs_factory.get_prover_crs(4); return Flavor::ProvingKey(/*circuit_size=*/4, /*num_public_inputs=*/0, crs, ComposerType::STANDARD); }(); @@ -38,7 +38,7 @@ TEST(Flavor, StandardGetters) Flavor::VerificationKey verification_key; Flavor::ProverPolynomials prover_polynomials; Flavor::ExtendedEdges edges; - Flavor::PurportedEvaluations evals; + Flavor::ClaimedEvaluations evals; Flavor::CommitmentLabels commitment_labels; // Globals are also available through STL container sizes @@ -120,11 +120,11 @@ TEST(Flavor, AllEntitiesSpecialMemberFunctions) { using Flavor = proof_system::honk::flavor::Standard; using FF = Flavor::FF; - using FoldedPolynomials = Flavor::FoldedPolynomials; - using Polynomial = Polynomial; + using PartiallyEvaluatedMultivariates = Flavor::PartiallyEvaluatedMultivariates; + using Polynomial = barretenberg::Polynomial; - FoldedPolynomials polynomials_A; - std::vector random_poly{ 10 }; + PartiallyEvaluatedMultivariates polynomials_A; + auto random_poly = Polynomial(10); for (auto& coeff : random_poly) { coeff = FF::random_element(); } @@ -135,10 +135,10 @@ TEST(Flavor, AllEntitiesSpecialMemberFunctions) ASSERT_EQ(random_poly, polynomials_A.w_l); - FoldedPolynomials polynomials_B(polynomials_A); + PartiallyEvaluatedMultivariates polynomials_B(polynomials_A); ASSERT_EQ(random_poly, polynomials_B.w_l); - FoldedPolynomials polynomials_C(std::move(polynomials_B)); + PartiallyEvaluatedMultivariates polynomials_C(std::move(polynomials_B)); ASSERT_EQ(random_poly, polynomials_C.w_l); } diff --git a/cpp/src/barretenberg/honk/flavor/standard.hpp b/cpp/src/barretenberg/honk/flavor/standard.hpp index a88c1b6cfc..745cc2ec10 100644 --- a/cpp/src/barretenberg/honk/flavor/standard.hpp +++ b/cpp/src/barretenberg/honk/flavor/standard.hpp @@ -6,14 +6,17 @@ #include #include #include "barretenberg/honk/pcs/commitment_key.hpp" +#include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" #include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/circuit_constructors/standard_circuit_constructor.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" namespace proof_system::honk::flavor { @@ -48,6 +51,22 @@ class Standard { // The total number of witness entities not including shifts. static constexpr size_t NUM_WITNESS_ENTITIES = 4; + // define the tuple of Relations that comprise the Sumcheck relation + using Relations = std::tuple, sumcheck::PermutationRelation>; + + static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length(); + static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + + // Instantiate the BarycentricData needed to extend each Relation Univariate + static_assert(instantiate_barycentric_utils()); + + // define the containers for storing the contributions from each relation in Sumcheck + using RelationUnivariates = decltype(create_relation_univariates_container()); + using RelationValues = decltype(create_relation_values_container()); + + // define utilities to extend univarates from RELATION_LENGTH to MAX_RELATION_LENGTH for each Relation + // using BarycentricUtils = decltype(create_barycentric_utils()); + private: /** * @brief A base class labelling precomputed entities and (ordered) subsets of interest. @@ -190,10 +209,20 @@ class Standard { using ProverPolynomials = AllEntities; /** - * @brief A container for polynomials produced after the first round of sumcheck. - * @todo TODO(#394) Use polynomial classes for guaranteed memory alignment. + * @brief A container for storing the partially evaluated multivariates produced by sumcheck. */ - using FoldedPolynomials = AllEntities, PolynomialHandle>; + class PartiallyEvaluatedMultivariates : public AllEntities { + + public: + PartiallyEvaluatedMultivariates() = default; + PartiallyEvaluatedMultivariates(const size_t circuit_size) + { + // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2) + for (auto& poly : this->_data) { + poly = Polynomial(circuit_size / 2); + } + } + }; /** * @brief A container for univariates produced during the hot loop in sumcheck. @@ -207,11 +236,11 @@ class Standard { * @brief A container for the polynomials evaluations produced during sumcheck, which are purported to be the * evaluations of polynomials committed in earlier rounds. */ - class PurportedEvaluations : public AllEntities { + class ClaimedEvaluations : public AllEntities { public: using Base = AllEntities; using Base::Base; - PurportedEvaluations(std::array _data_in) { this->_data = _data_in; } + ClaimedEvaluations(std::array _data_in) { this->_data = _data_in; } }; /** diff --git a/cpp/src/barretenberg/honk/flavor/ultra.hpp b/cpp/src/barretenberg/honk/flavor/ultra.hpp index 1c9ac16326..5613a0fee7 100644 --- a/cpp/src/barretenberg/honk/flavor/ultra.hpp +++ b/cpp/src/barretenberg/honk/flavor/ultra.hpp @@ -6,6 +6,7 @@ #include #include #include "barretenberg/honk/pcs/commitment_key.hpp" +#include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" #include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/transcript/transcript.hpp" @@ -13,8 +14,14 @@ #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" namespace proof_system::honk::flavor { @@ -41,6 +48,24 @@ class Ultra { // The total number of witness entities not including shifts. static constexpr size_t NUM_WITNESS_ENTITIES = 11; + // define the tuple of Relations that comprise the Sumcheck relation + using Relations = std::tuple, + sumcheck::UltraPermutationRelation, + sumcheck::LookupRelation, + sumcheck::GenPermSortRelation, + sumcheck::EllipticRelation, + sumcheck::AuxiliaryRelation>; + + static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length(); + static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + + // Instantiate the BarycentricData needed to extend each Relation Univariate + static_assert(instantiate_barycentric_utils()); + + // define the container for storing the univariate contribution from each relation in Sumcheck + using RelationUnivariates = decltype(create_relation_univariates_container()); + using RelationValues = decltype(create_relation_values_container()); + private: template /** @@ -249,10 +274,20 @@ class Ultra { using ProverPolynomials = AllEntities; /** - * @brief A container for polynomials produced after the first round of sumcheck. - * @todo TODO(#394) Use polynomial classes for guaranteed memory alignment. + * @brief A container for storing the partially evaluated multivariates produced by sumcheck. */ - using FoldedPolynomials = AllEntities, PolynomialHandle>; + class PartiallyEvaluatedMultivariates : public AllEntities { + + public: + PartiallyEvaluatedMultivariates() = default; + PartiallyEvaluatedMultivariates(const size_t circuit_size) + { + // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2) + for (auto& poly : this->_data) { + poly = Polynomial(circuit_size / 2); + } + } + }; /** * @brief A container for univariates produced during the hot loop in sumcheck. @@ -266,11 +301,11 @@ class Ultra { * @brief A container for the polynomials evaluations produced during sumcheck, which are purported to be the * evaluations of polynomials committed in earlier rounds. */ - class PurportedEvaluations : public AllEntities { + class ClaimedEvaluations : public AllEntities { public: using Base = AllEntities; using Base::Base; - PurportedEvaluations(std::array _data_in) { this->_data = _data_in; } + ClaimedEvaluations(std::array _data_in) { this->_data = _data_in; } }; /** diff --git a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp index 5d4e32c80d..3db3cbf6e0 100644 --- a/cpp/src/barretenberg/honk/pcs/commitment_key.hpp +++ b/cpp/src/barretenberg/honk/pcs/commitment_key.hpp @@ -7,7 +7,7 @@ #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/ecc/curves/bn254/pairing.hpp" #include "barretenberg/numeric/bitop/pow.hpp" @@ -67,7 +67,7 @@ class CommitmentKey { private: barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; - proof_system::FileReferenceString srs; + barretenberg::srs::factories::FileProverCrs srs; }; class VerificationKey { @@ -109,7 +109,7 @@ class VerificationKey { } private: - proof_system::VerifierFileReferenceString verifier_srs; + barretenberg::srs::factories::FileVerifierCrs verifier_srs; }; struct Params { @@ -244,7 +244,7 @@ class CommitmentKey { }; barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; - proof_system::FileReferenceString srs; + barretenberg::srs::factories::FileProverCrs srs; }; class VerificationKey { @@ -269,7 +269,7 @@ class VerificationKey { {} barretenberg::scalar_multiplication::pippenger_runtime_state pippenger_runtime_state; - proof_system::FileReferenceString srs; + barretenberg::srs::factories::FileProverCrs srs; }; struct Params { diff --git a/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp b/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp index 991bc98386..dabfbf95aa 100644 --- a/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp +++ b/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp @@ -9,7 +9,7 @@ #include #include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "../oracle/oracle.hpp" diff --git a/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp b/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp index 24c89a3a06..d780f9f90d 100644 --- a/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp +++ b/cpp/src/barretenberg/honk/proof_system/composer_helper.lib.hpp @@ -18,7 +18,7 @@ namespace proof_system::honk { template std::shared_ptr compute_verification_key_common( std::shared_ptr const& proving_key, - std::shared_ptr const& vrs) + std::shared_ptr const& vrs) { auto verification_key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); diff --git a/cpp/src/barretenberg/honk/proof_system/prover.cpp b/cpp/src/barretenberg/honk/proof_system/prover.cpp index ca92ca8f27..6747fc0bee 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover.cpp @@ -3,9 +3,6 @@ #include "barretenberg/honk/sumcheck/sumcheck.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" -#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" #include "barretenberg/honk/flavor/standard.hpp" namespace proof_system::honk { @@ -130,11 +127,7 @@ template void StandardProver_::execute_grand_pro * */ template void StandardProver_::execute_relation_check_rounds() { - using Sumcheck = sumcheck::Sumcheck, - sumcheck::ArithmeticRelation, - sumcheck::GrandProductComputationRelation, - sumcheck::GrandProductInitializationRelation>; + using Sumcheck = sumcheck::Sumcheck>; auto sumcheck = Sumcheck(key->circuit_size, transcript); diff --git a/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp b/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp index 74295a3255..88c9199622 100644 --- a/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp +++ b/cpp/src/barretenberg/honk/proof_system/prover_library.test.cpp @@ -5,7 +5,7 @@ #include "prover_library.hpp" #include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include #include #include @@ -56,7 +56,8 @@ template class ProverLibraryTests : public testing::Test { // Define some mock inputs for proving key constructor static const size_t num_gates = 8; static const size_t num_public_inputs = 0; - auto reference_string = std::make_shared(num_gates + 1, "../srs_db/ignition"); + auto reference_string = + std::make_shared(num_gates + 1, "../srs_db/ignition"); // Instatiate a proving_key and make a pointer to it. This will be used to instantiate a Prover. auto proving_key = std::make_shared( @@ -169,7 +170,8 @@ template class ProverLibraryTests : public testing::Test { // Define some mock inputs for proving key constructor static const size_t circuit_size = 8; static const size_t num_public_inputs = 0; - auto reference_string = std::make_shared(circuit_size + 1, "../srs_db/ignition"); + auto reference_string = + std::make_shared(circuit_size + 1, "../srs_db/ignition"); // Instatiate a proving_key and make a pointer to it. This will be used to instantiate a Prover. using Flavor = honk::flavor::Ultra; @@ -305,7 +307,8 @@ template class ProverLibraryTests : public testing::Test { // Construct a proving_key static const size_t circuit_size = 8; static const size_t num_public_inputs = 0; - auto reference_string = std::make_shared(circuit_size + 1, "../srs_db/ignition"); + auto reference_string = + std::make_shared(circuit_size + 1, "../srs_db/ignition"); using Flavor = honk::flavor::Ultra; auto proving_key = std::make_shared( circuit_size, num_public_inputs, reference_string, ComposerType::STANDARD_HONK); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index ad6cb81d70..f0d7d26089 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -2,8 +2,6 @@ #include #include #include "barretenberg/honk/proof_system/prover_library.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/sumcheck/sumcheck.hpp" #include #include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" // will go away @@ -15,13 +13,6 @@ #include #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/transcript/transcript_wrappers.hpp" #include @@ -191,17 +182,7 @@ template void UltraProver_::execute_grand_product_c */ template void UltraProver_::execute_relation_check_rounds() { - using Sumcheck = sumcheck::Sumcheck, - sumcheck::UltraArithmeticRelation, - sumcheck::UltraArithmeticRelationSecondary, - sumcheck::UltraGrandProductComputationRelation, - sumcheck::UltraGrandProductInitializationRelation, - sumcheck::LookupGrandProductComputationRelation, - sumcheck::LookupGrandProductInitializationRelation, - sumcheck::GenPermSortRelation, - sumcheck::EllipticRelation, - sumcheck::AuxiliaryRelation>; + using Sumcheck = sumcheck::Sumcheck>; auto sumcheck = Sumcheck(key->circuit_size, transcript); diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index bcf665711c..5b42bbd150 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -6,7 +6,7 @@ #include "barretenberg/honk/pcs/kzg/kzg.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/flavor/ultra.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" namespace proof_system::honk { diff --git a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 194d44b6e9..628a969d26 100644 --- a/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -4,14 +4,6 @@ #include "barretenberg/honk/flavor/standard.hpp" #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -107,17 +99,7 @@ template bool UltraVerifier_::verify_proof(const plonk commitments.z_lookup = transcript.template receive_from_prover(commitment_labels.z_lookup); // Execute Sumcheck Verifier - auto sumcheck = Sumcheck, - honk::sumcheck::UltraArithmeticRelation, - honk::sumcheck::UltraArithmeticRelationSecondary, - honk::sumcheck::UltraGrandProductComputationRelation, - honk::sumcheck::UltraGrandProductInitializationRelation, - honk::sumcheck::LookupGrandProductComputationRelation, - honk::sumcheck::LookupGrandProductInitializationRelation, - honk::sumcheck::GenPermSortRelation, - honk::sumcheck::EllipticRelation, - honk::sumcheck::AuxiliaryRelation>(circuit_size, transcript); + auto sumcheck = Sumcheck>(circuit_size, transcript); std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); diff --git a/cpp/src/barretenberg/honk/proof_system/verifier.cpp b/cpp/src/barretenberg/honk/proof_system/verifier.cpp index 6238f6e2e1..3506f15aaa 100644 --- a/cpp/src/barretenberg/honk/proof_system/verifier.cpp +++ b/cpp/src/barretenberg/honk/proof_system/verifier.cpp @@ -4,9 +4,6 @@ #include "barretenberg/honk/flavor/standard.hpp" #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" -#include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" using namespace barretenberg; using namespace proof_system::honk::sumcheck; @@ -111,11 +108,7 @@ template bool StandardVerifier_::verify_proof(const pl commitments.z_perm = transcript.template receive_from_prover(commitment_labels.z_perm); // Execute Sumcheck Verifier - auto sumcheck = Sumcheck, - honk::sumcheck::ArithmeticRelation, - honk::sumcheck::GrandProductComputationRelation, - honk::sumcheck::GrandProductInitializationRelation>(circuit_size, transcript); + auto sumcheck = Sumcheck>(circuit_size, transcript); std::optional sumcheck_output = sumcheck.execute_verifier(relation_parameters); // If Sumcheck does not return an output, sumcheck verification has failed diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp index ae2d5f5d9b..f7e13ceabf 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp @@ -6,12 +6,10 @@ /* IMPROVEMENT(Cody): This could or should be improved in various ways. In no particular order: 1) Edge cases are not considered. One non-use case situation (I forget which) leads to a segfault. - 2) This could all be constexpr. - - 3) Precomputing for all possible size pairs is probably feasible and might be a better solution than instantiating + 2) Precomputing for all possible size pairs is probably feasible and might be a better solution than instantiating many instances separately. Then perhaps we could infer input type to `extend`. - 4) There should be more thorough testing of this class in isolation. + 3) There should be more thorough testing of this class in isolation. */ namespace proof_system::honk::sumcheck { @@ -23,54 +21,77 @@ namespace proof_system::honk::sumcheck { template class BarycentricData { public: static constexpr size_t big_domain_size = std::max(domain_size, num_evals); - // TODO(#224)(Cody): these should be static, also constexpr, but arrays are not constexpr - std::array big_domain; - std::array lagrange_denominators; - std::array precomputed_denominator_inverses; - std::array full_numerator_values; - constexpr BarycentricData() + /** + * Static constexpr methods for computing arrays of precomputable data used for barycentric extension and evaluation + */ + + // build big_domain, currently the set of x_i in {0, 1, ..., t-1} + static constexpr std::array construct_big_domain() { - // build big_domain, currently the set of x_i in {0, 1, ..., t-1} - for (size_t i = 0; i != big_domain_size; ++i) { - big_domain[i] = i; + std::array result; + for (size_t i = 0; i < big_domain_size; ++i) { + result[i] = static_cast(i); } + return result; + } - // build set of lagrange_denominators d_i = \prod_{j!=i} x_i - x_j + // build set of lagrange_denominators d_i = \prod_{j!=i} x_i - x_j + static constexpr std::array construct_lagrange_denominators(const auto& big_domain) + { + std::array result; for (size_t i = 0; i != domain_size; ++i) { - lagrange_denominators[i] = 1; + result[i] = 1; for (size_t j = 0; j != domain_size; ++j) { if (j != i) { - lagrange_denominators[i] *= big_domain[i] - big_domain[j]; + result[i] *= big_domain[i] - big_domain[j]; } } } + return result; + } - // for each x_k in the big domain, build set of domain size-many denominator inverses - // 1/(d_i*(x_k - x_j)). will multiply against each of these (rather than to divide by something) - // for each barycentric evaluation - for (size_t k = domain_size; k != num_evals; ++k) { - for (size_t j = 0; j != domain_size; ++j) { + // for each x_k in the big domain, build set of domain size-many denominator inverses + // 1/(d_i*(x_k - x_j)). will multiply against each of these (rather than to divide by something) + // for each barycentric evaluation + static constexpr std::array construct_denominator_inverses( + const auto& big_domain, const auto& lagrange_denominators) + { + std::array result{}; // default init to 0 since below does not init all elements + for (size_t k = domain_size; k < num_evals; ++k) { + for (size_t j = 0; j < domain_size; ++j) { Fr inv = lagrange_denominators[j]; inv *= (big_domain[k] - big_domain[j]); inv = Fr(1) / inv; // prob have self_inverse method; should be part of Field concept - precomputed_denominator_inverses[k * domain_size + j] = inv; + result[k * domain_size + j] = inv; } } + return result; + } - // get full numerator values - // full numerator is M(x) = \prod_{i} (x-x_i) - // these will be zero for i < domain_size, but that's ok because - // at such entries we will already have the evaluations of the polynomial + // get full numerator values + // full numerator is M(x) = \prod_{i} (x-x_i) + // these will be zero for i < domain_size, but that's ok because + // at such entries we will already have the evaluations of the polynomial + static constexpr std::array construct_full_numerator_values(const auto& big_domain) + { + std::array result; for (size_t i = 0; i != num_evals; ++i) { - full_numerator_values[i] = 1; + result[i] = 1; Fr v_i = i; for (size_t j = 0; j != domain_size; ++j) { - full_numerator_values[i] *= v_i - big_domain[j]; + result[i] *= v_i - big_domain[j]; } } + return result; } + static constexpr auto big_domain = construct_big_domain(); + static constexpr auto lagrange_denominators = construct_lagrange_denominators(big_domain); + static constexpr auto precomputed_denominator_inverses = + construct_denominator_inverses(big_domain, lagrange_denominators); + static constexpr auto full_numerator_values = construct_full_numerator_values(big_domain); + /** * @brief Given A univariate f represented by {f(0), ..., f(t-1)}, compute {f(t), ..., f(u-1)} * and return the Univariate represented by {f(0), ..., f(u-1)}. diff --git a/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp b/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp index 3e40df0113..f7417d5624 100644 --- a/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/polynomials/multivariates.test.cpp @@ -61,23 +61,23 @@ TYPED_TEST(MultivariatesTests, FoldTwoRoundsSpecial) auto full_polynomials = std::array, 1>({ f0 }); auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_0 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; round_challenge_0.self_to_montgomery_form(); FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + sumcheck.partially_evaluate(full_polynomials, multivariate_n, round_challenge_0); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], round_challenge_0); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], FF(0)); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], round_challenge_0); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][1], FF(0)); FF round_challenge_1 = 2; FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_val); } TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) @@ -98,21 +98,21 @@ TYPED_TEST(MultivariatesTests, FoldTwoRoundsGeneric) auto full_polynomials = std::array, 1>({ f0 }); auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_0 = FF::random_element(); FF expected_lo = v00 * (FF(1) - round_challenge_0) + v10 * round_challenge_0; FF expected_hi = v01 * (FF(1) - round_challenge_0) + v11 * round_challenge_0; - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + sumcheck.partially_evaluate(full_polynomials, multivariate_n, round_challenge_0); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][1], expected_hi); FF round_challenge_1 = FF::random_element(); FF expected_val = expected_lo * (FF(1) - round_challenge_1) + expected_hi * round_challenge_1; - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_val); } /* @@ -159,7 +159,7 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) auto full_polynomials = std::array, 1>({ f0 }); auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_0 = 1; FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; // 2 @@ -167,25 +167,25 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsSpecial) FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; // 6 FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; // 8 - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + sumcheck.partially_evaluate(full_polynomials, multivariate_n, round_challenge_0); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); - EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); - EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_q1); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][1], expected_q2); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][2], expected_q3); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][3], expected_q4); FF round_challenge_1 = 2; FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; // 6 FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; // 10 - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][1], expected_hi); FF round_challenge_2 = 3; FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; // 18 - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 2, round_challenge_2); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_val); } TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) @@ -210,7 +210,7 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) auto full_polynomials = std::array, 1>({ f0 }); auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); + auto sumcheck = Sumcheck(multivariate_n, transcript); FF round_challenge_0 = FF::random_element(); FF expected_q1 = v000 * (FF(1) - round_challenge_0) + v100 * round_challenge_0; @@ -218,25 +218,25 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGeneric) FF expected_q3 = v001 * (FF(1) - round_challenge_0) + v101 * round_challenge_0; FF expected_q4 = v011 * (FF(1) - round_challenge_0) + v111 * round_challenge_0; - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + sumcheck.partially_evaluate(full_polynomials, multivariate_n, round_challenge_0); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_q1); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_q2); - EXPECT_EQ(sumcheck.folded_polynomials[0][2], expected_q3); - EXPECT_EQ(sumcheck.folded_polynomials[0][3], expected_q4); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_q1); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][1], expected_q2); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][2], expected_q3); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][3], expected_q4); FF round_challenge_1 = FF::random_element(); FF expected_lo = expected_q1 * (FF(1) - round_challenge_1) + expected_q2 * round_challenge_1; FF expected_hi = expected_q3 * (FF(1) - round_challenge_1) + expected_q4 * round_challenge_1; - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_lo); - EXPECT_EQ(sumcheck.folded_polynomials[0][1], expected_hi); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 1, round_challenge_1); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_lo); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][1], expected_hi); FF round_challenge_2 = FF::random_element(); FF expected_val = expected_lo * (FF(1) - round_challenge_2) + expected_hi * round_challenge_2; - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); - EXPECT_EQ(sumcheck.folded_polynomials[0][0], expected_val); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 2, round_challenge_2); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[0][0], expected_val); } TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) @@ -272,7 +272,7 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) auto full_polynomials = std::array, 3>{ f0, f1, f2 }; auto transcript = Transcript::init_empty(); - auto sumcheck = Sumcheck(multivariate_n, transcript); + auto sumcheck = Sumcheck(multivariate_n, transcript); std::array expected_q1; std::array expected_q2; @@ -286,12 +286,12 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) expected_q4[i] = v011[i] * (FF(1) - round_challenge_0) + v111[i] * round_challenge_0; } - sumcheck.fold(full_polynomials, multivariate_n, round_challenge_0); + sumcheck.partially_evaluate(full_polynomials, multivariate_n, round_challenge_0); for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_q1[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_q2[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][2], expected_q3[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][3], expected_q4[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][0], expected_q1[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][1], expected_q2[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][2], expected_q3[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][3], expected_q4[i]); } FF round_challenge_1 = FF::random_element(); @@ -301,19 +301,19 @@ TYPED_TEST(MultivariatesTests, FoldThreeRoundsGenericMultiplePolys) expected_lo[i] = expected_q1[i] * (FF(1) - round_challenge_1) + expected_q2[i] * round_challenge_1; expected_hi[i] = expected_q3[i] * (FF(1) - round_challenge_1) + expected_q4[i] * round_challenge_1; } - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 1, round_challenge_1); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 1, round_challenge_1); for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_lo[i]); - EXPECT_EQ(sumcheck.folded_polynomials[i][1], expected_hi[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][0], expected_lo[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][1], expected_hi[i]); } FF round_challenge_2 = FF::random_element(); std::array expected_val; for (size_t i = 0; i < 3; i++) { expected_val[i] = expected_lo[i] * (FF(1) - round_challenge_2) + expected_hi[i] * round_challenge_2; } - sumcheck.fold(sumcheck.folded_polynomials, multivariate_n >> 2, round_challenge_2); + sumcheck.partially_evaluate(sumcheck.partially_evaluated_polynomials, multivariate_n >> 2, round_challenge_2); for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sumcheck.folded_polynomials[i][0], expected_val[i]); + EXPECT_EQ(sumcheck.partially_evaluated_polynomials[i][0], expected_val[i]); } } diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp index e7d095119c..1f0349fae5 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { @@ -12,6 +12,12 @@ template class ArithmeticRelation { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 4; + static constexpr size_t NUM_CONSTRAINTS = 1; + static constexpr std::array CONSTRAINT_LENGTH = { 4 }; + + using RelationUnivariates = std::tuple>; + using RelationValues = std::array; + /** * @brief Expression for the StandardArithmetic gate. * @details The relation is defined as C(extended_edges(X)...) = @@ -22,7 +28,7 @@ template class ArithmeticRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, const FF& scaling_factor) const @@ -44,10 +50,17 @@ template class ArithmeticRelation { tmp += q_o * w_o; tmp += q_c; tmp *= scaling_factor; - evals += tmp; + std::get<0>(evals) += tmp; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const { @@ -60,10 +73,10 @@ template class ArithmeticRelation { auto q_o = purported_evaluations.q_o; auto q_c = purported_evaluations.q_c; - full_honk_relation_value += w_l * (q_m * w_r + q_l); - full_honk_relation_value += q_r * w_r; - full_honk_relation_value += q_o * w_o; - full_honk_relation_value += q_c; + std::get<0>(full_honk_relation_value) += w_l * (q_m * w_r + q_l); + std::get<0>(full_honk_relation_value) += q_r * w_r; + std::get<0>(full_honk_relation_value) += q_o * w_o; + std::get<0>(full_honk_relation_value) += q_c; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp index c8b7f288a2..890e16326b 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp @@ -4,26 +4,61 @@ #include "../polynomials/univariate.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { template class AuxiliaryRelation { public: // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 6; // degree() = WORKTODO + static constexpr size_t RELATION_LENGTH = 6; + + static constexpr size_t NUM_CONSTRAINTS = 6; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 6, 6, 6, 6, 6 }; // Each has degree 5 + + using RelationUnivariates = std::tuple, + Univariate, + Univariate, + Univariate, + Univariate, + Univariate>; + using RelationValues = std::array; /** * @brief Expression for the generalized permutation sort gate. - * @details The relation is defined as C(extended_edges(X)...) = - * //WORKTODO + * @details The following explanation is reproduced from the Plonk analog 'plookup_auxiliary_widget': + * Adds contributions for identities associated with several custom gates: + * * RAM/ROM read-write consistency check + * * RAM timestamp difference consistency check + * * RAM/ROM index difference consistency check + * * Bigfield product evaluation (3 in total) + * * Bigfield limb accumulation (2 in total) + * + * Multiple selectors are used to 'switch' aux gates on/off according to the following pattern: + * + * | gate type | q_aux | q_1 | q_2 | q_3 | q_4 | q_m | q_c | q_arith | + * | ---------------------------- | ----- | --- | --- | --- | --- | --- | --- | ------ | + * | Bigfield Limb Accumulation 1 | 1 | 0 | 0 | 1 | 1 | 0 | --- | 0 | + * | Bigfield Limb Accumulation 2 | 1 | 0 | 0 | 1 | 0 | 1 | --- | 0 | + * | Bigfield Product 1 | 1 | 0 | 1 | 1 | 0 | 0 | --- | 0 | + * | Bigfield Product 2 | 1 | 0 | 1 | 0 | 1 | 0 | --- | 0 | + * | Bigfield Product 3 | 1 | 0 | 1 | 0 | 0 | 1 | --- | 0 | + * | RAM/ROM access gate | 1 | 1 | 0 | 0 | 0 | 1 | --- | 0 | + * | RAM timestamp check | 1 | 1 | 0 | 0 | 1 | 0 | --- | 0 | + * | ROM consistency check | 1 | 1 | 1 | 0 | 0 | 0 | --- | 0 | + * | RAM consistency check | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | + * + * N.B. The RAM consistency check identity is degree 3. To keep the overall quotient degree at <=5, only 2 selectors + * can be used to select it. + * + * N.B.2 The q_c selector is used to store circuit-specific values in the RAM/ROM access gate * * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` * @param extended_edges an std::array containing the fully extended Univariate edges. * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -32,7 +67,6 @@ template class AuxiliaryRelation { // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); auto w_1 = UnivariateView(extended_edges.w_l); auto w_2 = UnivariateView(extended_edges.w_r); @@ -177,11 +211,9 @@ template class AuxiliaryRelation { auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; - auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += memory_record_check; + std::get<1>(evals) += adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2) * (q_aux * scaling_factor); + std::get<2>(evals) += index_is_monotonically_increasing * (q_1 * q_2) * (q_aux * scaling_factor); + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); /** * RAM Consistency Check @@ -224,14 +256,11 @@ template class AuxiliaryRelation { auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; // Putting it all together... - auto RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += access_check; + std::get<3>(evals) += adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * + (q_arith) * (q_aux * scaling_factor); + std::get<4>(evals) += index_is_monotonically_increasing * (q_arith) * (q_aux * scaling_factor); + std::get<5>(evals) += next_gate_access_type_is_boolean * (q_arith) * (q_aux * scaling_factor); + auto RAM_consistency_check_identity = access_check * (q_arith); /** * RAM Timestamp Consistency Check @@ -251,25 +280,28 @@ template class AuxiliaryRelation { * The complete RAM/ROM memory identity * */ - auto 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); + auto memory_identity = ROM_consistency_check_identity; + memory_identity += RAM_timestamp_check_identity * (q_4 * q_1); + memory_identity += memory_record_check * (q_m * q_1); + memory_identity += RAM_consistency_check_identity; auto auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; - auxiliary_identity *= q_aux; - auxiliary_identity *= scaling_factor; - - evals += auxiliary_identity; + auxiliary_identity *= (q_aux * scaling_factor); + std::get<0>(evals) += auxiliary_identity; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters& relation_parameters) const { const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); auto w_1 = purported_evaluations.w_l; auto w_2 = purported_evaluations.w_r; @@ -417,11 +449,9 @@ template class AuxiliaryRelation { auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; - auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += memory_record_check; + std::get<1>(full_honk_relation_value) += adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2) * q_aux; + std::get<2>(full_honk_relation_value) += index_is_monotonically_increasing * (q_1 * q_2) * q_aux; + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); /** * RAM Consistency Check @@ -465,14 +495,11 @@ template class AuxiliaryRelation { auto next_gate_access_type_is_boolean = next_gate_access_type.sqr() - next_gate_access_type; // Putting it all together... - auto RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += access_check; + std::get<3>(full_honk_relation_value) += + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_arith)*q_aux; + std::get<4>(full_honk_relation_value) += index_is_monotonically_increasing * (q_arith)*q_aux; + std::get<5>(full_honk_relation_value) += next_gate_access_type_is_boolean * (q_arith)*q_aux; + auto RAM_consistency_check_identity = access_check * (q_arith); /** * RAM Timestamp Consistency Check @@ -492,17 +519,15 @@ template class AuxiliaryRelation { * The complete RAM/ROM memory identity * */ - auto 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); + auto memory_identity = ROM_consistency_check_identity; + memory_identity += RAM_timestamp_check_identity * q_1 * q_4; + memory_identity += memory_record_check * q_1 * q_m; + memory_identity += RAM_consistency_check_identity; // auto auxiliary_identity = limb_accumulator_identity; auto auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; auxiliary_identity *= q_aux; - - full_honk_relation_value += auxiliary_identity; + std::get<0>(full_honk_relation_value) += auxiliary_identity; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp index 9063a43297..f05cacbf5b 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/elliptic_relation.hpp @@ -3,14 +3,20 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { template class EllipticRelation { public: // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 + static constexpr size_t RELATION_LENGTH = 5; // degree(q_elliptic * q_beta * x^3) = 5 + + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 5 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; /** * @brief Expression for the Ultra Arithmetic gate. @@ -22,64 +28,83 @@ template class EllipticRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, - const FF& scaling_factor) const - { + const FF& scaling_factor) const { // OPTIMIZATION?: Karatsuba in general, at least for some degrees? // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both - - auto x_1 = UnivariateView(extended_edges.w_r); - auto y_1 = UnivariateView(extended_edges.w_o); - - auto x_2 = UnivariateView(extended_edges.w_l_shift); - auto y_2 = UnivariateView(extended_edges.w_4_shift); - auto x_3 = UnivariateView(extended_edges.w_r_shift); - auto y_3 = UnivariateView(extended_edges.w_o_shift); - - auto q_sign = UnivariateView(extended_edges.q_l); - auto q_beta = UnivariateView(extended_edges.q_o); - auto q_beta_sqr = UnivariateView(extended_edges.q_4); - auto q_elliptic = UnivariateView(extended_edges.q_elliptic); - - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - - auto beta_term = x_2 * x_1 * (x_3 + x_3 + x_1) * FF(-1); // -x_1 * x_2 * (2 * x_3 + x_1) - auto beta_sqr_term = x_2 * x_2; // x_2^2 - auto leftovers = beta_sqr_term; // x_2^2 - beta_sqr_term *= (x_3 - x_1); // x_2^2 * (x_3 - x_1) - auto sign_term = y_2 * y_1; // y_1 * y_2 - sign_term += sign_term; // 2 * y_1 * y_2 - beta_term *= q_beta; // -β * x_1 * x_2 * (2 * x_3 + x_1) - beta_sqr_term *= q_beta_sqr; // β^2 * x_2^2 * (x_3 - x_1) - sign_term *= q_sign; // 2 * y_1 * y_2 * sign - leftovers *= x_2; // x_2^3 - leftovers += x_1 * x_1 * (x_3 + x_1); // x_2^3 + x_1 * (x_3 + x_1) - leftovers -= (y_2 * y_2 + y_1 * y_1); // x_2^3 + x_1 * (x_3 + x_1) - y_2^2 - y_1^2 - - // Can be found in class description - auto x_identity = beta_term + beta_sqr_term + sign_term + leftovers; - x_identity *= fake_alpha_1; - - beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) - sign_term = y_2 * (x_1 - x_3) * q_sign * FF(-1); // - signt * y_2 * (x_1 - x_3) - // TODO: remove extra additions if we decide to stay with this implementation - leftovers = x_1 * (y_3 + y_1) * FF(-1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 - - auto y_identity = beta_term + sign_term + leftovers; - y_identity *= fake_alpha_2; - - auto tmp = x_identity + y_identity; - tmp *= q_elliptic; - - tmp *= scaling_factor; - - evals += tmp; + // TODO(luke): Formatter doesnt properly handle explicit scoping below so turning off. Whats up? + // clang-format off + // Contribution (1) + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto x_1 = UnivariateView(extended_edges.w_r); + auto y_1 = UnivariateView(extended_edges.w_o); + + auto x_2 = UnivariateView(extended_edges.w_l_shift); + auto y_2 = UnivariateView(extended_edges.w_4_shift); + auto x_3 = UnivariateView(extended_edges.w_r_shift); + + auto q_sign = UnivariateView(extended_edges.q_l); + auto q_beta = UnivariateView(extended_edges.q_o); + auto q_beta_sqr = UnivariateView(extended_edges.q_4); + auto q_elliptic = UnivariateView(extended_edges.q_elliptic); + + auto beta_term = x_2 * x_1 * (x_3 + x_3 + x_1) * FF(-1); // -x_1 * x_2 * (2 * x_3 + x_1) + auto beta_sqr_term = x_2 * x_2; // x_2^2 + auto leftovers = beta_sqr_term; // x_2^2 + beta_sqr_term *= (x_3 - x_1); // x_2^2 * (x_3 - x_1) + auto sign_term = y_2 * y_1; // y_1 * y_2 + sign_term += sign_term; // 2 * y_1 * y_2 + beta_term *= q_beta; // -β * x_1 * x_2 * (2 * x_3 + x_1) + beta_sqr_term *= q_beta_sqr; // β^2 * x_2^2 * (x_3 - x_1) + sign_term *= q_sign; // 2 * y_1 * y_2 * sign + leftovers *= x_2; // x_2^3 + leftovers += x_1 * x_1 * (x_3 + x_1); // x_2^3 + x_1 * (x_3 + x_1) + leftovers -= (y_2 * y_2 + y_1 * y_1); // x_2^3 + x_1 * (x_3 + x_1) - y_2^2 - y_1^2 + + // Can be found in class description + auto x_identity = beta_term + beta_sqr_term + sign_term + leftovers; + x_identity *= q_elliptic; + x_identity *= scaling_factor; + std::get<0>(evals) += x_identity; + } + // Contribution (2) + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto x_1 = UnivariateView(extended_edges.w_r); + auto y_1 = UnivariateView(extended_edges.w_o); + + auto x_2 = UnivariateView(extended_edges.w_l_shift); + auto y_2 = UnivariateView(extended_edges.w_4_shift); + auto x_3 = UnivariateView(extended_edges.w_r_shift); + auto y_3 = UnivariateView(extended_edges.w_o_shift); + + auto q_sign = UnivariateView(extended_edges.q_l); + auto q_beta = UnivariateView(extended_edges.q_o); + auto q_elliptic = UnivariateView(extended_edges.q_elliptic); + + auto beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) + auto sign_term = y_2 * (x_1 - x_3) * q_sign * FF(-1); // - signt * y_2 * (x_1 - x_3) + // TODO: remove extra additions if we decide to stay with this implementation + auto leftovers = x_1 * (y_3 + y_1) * FF(-1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 + + auto y_identity = beta_term + sign_term + leftovers; + y_identity *= q_elliptic; + y_identity *= scaling_factor; + std::get<1>(evals) += y_identity; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const { @@ -96,9 +121,7 @@ template class EllipticRelation { auto q_beta_sqr = purported_evaluations.q_4; auto q_elliptic = purported_evaluations.q_elliptic; - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - + // Contribution (1) auto beta_term = x_2 * x_1 * (x_3 + x_3 + x_1) * FF(-1); // -x_1 * x_2 * (2 * x_3 + x_1) auto beta_sqr_term = x_2 * x_2; // x_2^2 auto leftovers = beta_sqr_term; // x_2^2 @@ -114,20 +137,19 @@ template class EllipticRelation { // Can be found in class description auto x_identity = beta_term + beta_sqr_term + sign_term + leftovers; - x_identity *= fake_alpha_1; + x_identity *= q_elliptic; + std::get<0>(full_honk_relation_value) += x_identity; + // Contribution (2) beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) sign_term = y_2 * (x_1 - x_3) * q_sign * FF(-1); // - signt * y_2 * (x_1 - x_3) // TODO: remove extra additions if we decide to stay with this implementation leftovers = x_1 * (y_3 + y_1) * FF(-1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 auto y_identity = beta_term + sign_term + leftovers; - y_identity *= fake_alpha_2; - - auto tmp = x_identity + y_identity; - tmp *= q_elliptic; - - full_honk_relation_value += tmp; + y_identity *= q_elliptic; + std::get<1>(full_honk_relation_value) += y_identity; }; }; +// clang-format on } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp index 1eb10c0670..d4649acafa 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { @@ -12,6 +12,15 @@ template class GenPermSortRelation { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // degree(q_sort * D(D - 1)(D - 2)(D - 3)) = 5 + static constexpr size_t NUM_CONSTRAINTS = 4; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 6, 6, 6 }; + + using RelationUnivariates = std::tuple, + Univariate, + Univariate, + Univariate>; + using RelationValues = std::array; + /** * @brief Expression for the generalized permutation sort gate. * @details The relation is defined as C(extended_edges(X)...) = @@ -27,7 +36,7 @@ template class GenPermSortRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, const FF& scaling_factor) const @@ -46,53 +55,57 @@ template class GenPermSortRelation { static const FF minus_two = FF(-2); static const FF minus_three = FF(-3); - // TODO(#427): Eventually this would be based on real alpha but this is not a full solution - // since utilizing powers of alpha internal to a relation results in incorrect powers - // being used in the ultimate univariate batching. i.e we'd wind up reusing the same power - // of alpha in multiple relations. - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; - static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - // Compute wire differences auto delta_1 = w_2 - w_1; auto delta_2 = w_3 - w_2; auto delta_3 = w_4 - w_3; auto delta_4 = w_1_shift - w_4; + // Contribution (1) auto tmp_1 = delta_1; tmp_1 *= (delta_1 + minus_one); tmp_1 *= (delta_1 + minus_two); tmp_1 *= (delta_1 + minus_three); - tmp_1 *= fake_alpha_1; // 1 + tmp_1 *= q_sort; + tmp_1 *= scaling_factor; + std::get<0>(evals) += tmp_1; + // Contribution (2) auto tmp_2 = delta_2; tmp_2 *= (delta_2 + minus_one); tmp_2 *= (delta_2 + minus_two); tmp_2 *= (delta_2 + minus_three); - tmp_2 *= fake_alpha_2; // alpha + tmp_2 *= q_sort; + tmp_2 *= scaling_factor; + std::get<1>(evals) += tmp_2; + // Contribution (3) auto tmp_3 = delta_3; tmp_3 *= (delta_3 + minus_one); tmp_3 *= (delta_3 + minus_two); tmp_3 *= (delta_3 + minus_three); - tmp_3 *= fake_alpha_3; // alpha^2 + tmp_3 *= q_sort; + tmp_3 *= scaling_factor; + std::get<2>(evals) += tmp_3; + // Contribution (4) auto tmp_4 = delta_4; tmp_4 *= (delta_4 + minus_one); tmp_4 *= (delta_4 + minus_two); tmp_4 *= (delta_4 + minus_three); - tmp_4 *= fake_alpha_4; // alpha^3 - - auto tmp = tmp_1 + tmp_2 + tmp_3 + tmp_4; - tmp *= q_sort; - tmp *= scaling_factor; - - evals += tmp; + tmp_4 *= q_sort; + tmp_4 *= scaling_factor; + std::get<3>(evals) += tmp_4; }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, const auto& purported_evaluations, const RelationParameters&) const { @@ -107,15 +120,6 @@ template class GenPermSortRelation { static const FF minus_two = FF(-2); static const FF minus_three = FF(-3); - // TODO(#427): Eventually this would be based on real alpha but this is not a full solution - // since utilizing powers of alpha internal to a relation results in incorrect powers - // being used in the ultimate univariate batching. i.e we'd wind up reusing the same power - // of alpha in multiple relations. - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; - static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - // Compute wire differences auto delta_1 = w_2 - w_1; auto delta_2 = w_3 - w_2; @@ -126,30 +130,29 @@ template class GenPermSortRelation { tmp_1 *= (delta_1 + minus_one); tmp_1 *= (delta_1 + minus_two); tmp_1 *= (delta_1 + minus_three); - tmp_1 *= fake_alpha_1; // 1 + tmp_1 *= q_sort; + std::get<0>(full_honk_relation_value) += tmp_1; auto tmp_2 = delta_2; tmp_2 *= (delta_2 + minus_one); tmp_2 *= (delta_2 + minus_two); tmp_2 *= (delta_2 + minus_three); - tmp_2 *= fake_alpha_2; // alpha + tmp_2 *= q_sort; + std::get<1>(full_honk_relation_value) += tmp_2; auto tmp_3 = delta_3; tmp_3 *= (delta_3 + minus_one); tmp_3 *= (delta_3 + minus_two); tmp_3 *= (delta_3 + minus_three); - tmp_3 *= fake_alpha_3; // alpha^2 + tmp_3 *= q_sort; + std::get<2>(full_honk_relation_value) += tmp_3; auto tmp_4 = delta_4; tmp_4 *= (delta_4 + minus_one); tmp_4 *= (delta_4 + minus_two); tmp_4 *= (delta_4 + minus_three); - tmp_4 *= fake_alpha_4; // alpha^3 - - auto tmp = tmp_1 + tmp_2 + tmp_3 + tmp_4; - tmp *= q_sort; - - full_honk_relation_value += tmp; + tmp_4 *= q_sort; + std::get<3>(full_honk_relation_value) += tmp_4; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp deleted file mode 100644 index 0fd8fbd606..0000000000 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include "relation.hpp" -#include "../polynomials/univariate.hpp" - -namespace proof_system::honk::sumcheck { - -template class GrandProductInitializationRelation { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 3; - - /** - * @brief Add contribution of the permutation relation for a given edge - * - * @details There are 2 relations associated with enforcing the wire copy relations - * This file handles the relation Z_perm_shift(n_last) = 0 via the relation: - * - * C(X) = L_LAST(X) * Z_perm_shift(X) - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters&, - const FF& scaling_factor) const - { - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - evals += (lagrange_last * z_perm_shift) * scaling_factor; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - auto& purported_evaluations, - const RelationParameters&) const - { - auto z_perm_shift = purported_evaluations.z_perm_shift; - auto lagrange_last = purported_evaluations.lagrange_last; - - full_honk_relation_value += lagrange_last * z_perm_shift; - }; -}; - -// TODO(luke): The only difference between the Ultra relation and the Standard version is the enum -// used to refer into the edge polynomials. Seems desireable to not duplicate the code here but -// leaving this as is until Codys Flavor work is settled. -template class UltraGrandProductInitializationRelation { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 3; - - /** - * @brief Add contribution of the permutation relation for a given edge - * - * @details There are 2 relations associated with enforcing the wire copy relations - * This file handles the relation Z_perm_shift(n_last) = 0 via the relation: - * - * C(X) = L_LAST(X) * Z_perm_shift(X) - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters&, - const FF& scaling_factor) const - { - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - evals += (lagrange_last * z_perm_shift) * scaling_factor; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - auto& purported_evaluations, - const RelationParameters&) const - { - auto z_perm_shift = purported_evaluations.z_perm_shift; - auto lagrange_last = purported_evaluations.lagrange_last; - - full_honk_relation_value += lagrange_last * z_perm_shift; - }; -}; -} // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp similarity index 50% rename from cpp/src/barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp rename to cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp index 32830a8dc3..b08a2bdedd 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/lookup_relation.hpp @@ -1,5 +1,5 @@ #pragma once -#include "relation.hpp" +#include "relation_parameters.hpp" #include "../polynomials/univariate.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -7,11 +7,17 @@ namespace proof_system::honk::sumcheck { -template class LookupGrandProductComputationRelation { +template class LookupRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // deg(z_lookup * column_selector * wire * q_lookup * table) = 5 + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 3 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Compute contribution of the lookup grand prod relation for a given edge (internal function) * @@ -30,7 +36,7 @@ template class LookupGrandProductComputationRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - inline void add_edge_contribution(Univariate& evals, + inline void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -45,60 +51,78 @@ template class LookupGrandProductComputationRelation { const auto eta_sqr = eta * eta; const auto eta_cube = eta_sqr * eta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - - auto w_1_shift = UnivariateView(extended_edges.w_l_shift); - auto w_2_shift = UnivariateView(extended_edges.w_r_shift); - auto w_3_shift = UnivariateView(extended_edges.w_o_shift); - - auto table_1 = UnivariateView(extended_edges.table_1); - auto table_2 = UnivariateView(extended_edges.table_2); - auto table_3 = UnivariateView(extended_edges.table_3); - auto table_4 = UnivariateView(extended_edges.table_4); - - auto table_1_shift = UnivariateView(extended_edges.table_1_shift); - auto table_2_shift = UnivariateView(extended_edges.table_2_shift); - auto table_3_shift = UnivariateView(extended_edges.table_3_shift); - auto table_4_shift = UnivariateView(extended_edges.table_4_shift); - - auto s_accum = UnivariateView(extended_edges.sorted_accum); - auto s_accum_shift = UnivariateView(extended_edges.sorted_accum_shift); - - auto z_lookup = UnivariateView(extended_edges.z_lookup); - auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); - - auto table_index = UnivariateView(extended_edges.q_o); - auto column_1_step_size = UnivariateView(extended_edges.q_r); - auto column_2_step_size = UnivariateView(extended_edges.q_m); - auto column_3_step_size = UnivariateView(extended_edges.q_c); - auto q_lookup = UnivariateView(extended_edges.q_lookup); - - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - // (w_1 + q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η²(w_3 + q_c*w_3_shift) + η³q_index. - auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + - (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; - - // t_1 + ηt_2 + η²t_3 + η³t_4 - auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; - // t_1_shift + ηt_2_shift + η²t_3_shift + η³t_4_shift - auto table_accum_shift = - table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; - // Contribution (1) - auto tmp = (q_lookup * wire_accum + gamma); - tmp *= (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta); - tmp *= one_plus_beta; - tmp *= (z_lookup + lagrange_first); - tmp -= (z_lookup_shift + lagrange_last * grand_product_delta) * - (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); - evals += tmp * scaling_factor; + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + + auto w_1_shift = UnivariateView(extended_edges.w_l_shift); + auto w_2_shift = UnivariateView(extended_edges.w_r_shift); + auto w_3_shift = UnivariateView(extended_edges.w_o_shift); + + auto table_1 = UnivariateView(extended_edges.table_1); + auto table_2 = UnivariateView(extended_edges.table_2); + auto table_3 = UnivariateView(extended_edges.table_3); + auto table_4 = UnivariateView(extended_edges.table_4); + + auto table_1_shift = UnivariateView(extended_edges.table_1_shift); + auto table_2_shift = UnivariateView(extended_edges.table_2_shift); + auto table_3_shift = UnivariateView(extended_edges.table_3_shift); + auto table_4_shift = UnivariateView(extended_edges.table_4_shift); + + auto s_accum = UnivariateView(extended_edges.sorted_accum); + auto s_accum_shift = UnivariateView(extended_edges.sorted_accum_shift); + + auto z_lookup = UnivariateView(extended_edges.z_lookup); + auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); + + auto table_index = UnivariateView(extended_edges.q_o); + auto column_1_step_size = UnivariateView(extended_edges.q_r); + auto column_2_step_size = UnivariateView(extended_edges.q_m); + auto column_3_step_size = UnivariateView(extended_edges.q_c); + auto q_lookup = UnivariateView(extended_edges.q_lookup); + + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // (w_1 + q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η²(w_3 + q_c*w_3_shift) + η³q_index. + auto wire_accum = (w_1 + column_1_step_size * w_1_shift) + (w_2 + column_2_step_size * w_2_shift) * eta + + (w_3 + column_3_step_size * w_3_shift) * eta_sqr + table_index * eta_cube; + + // t_1 + ηt_2 + η²t_3 + η³t_4 + auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; + // t_1_shift + ηt_2_shift + η²t_3_shift + η³t_4_shift + auto table_accum_shift = + table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; + + auto tmp = (q_lookup * wire_accum + gamma); + tmp *= (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta); + tmp *= one_plus_beta; + tmp *= (z_lookup + lagrange_first); + tmp -= (z_lookup_shift + lagrange_last * grand_product_delta) * + (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); + std::get<0>(evals) += tmp * scaling_factor; + } + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // Contribution (2) + std::get<1>(evals) += (lagrange_last * z_lookup_shift) * scaling_factor; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const { @@ -162,45 +186,10 @@ template class LookupGrandProductComputationRelation { tmp *= (z_lookup + lagrange_first); tmp -= (z_lookup_shift + lagrange_last * grand_product_delta) * (s_accum + beta * s_accum_shift + gamma_by_one_plus_beta); - full_honk_relation_value += tmp; - }; -}; - -template class LookupGrandProductInitializationRelation { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 3; // deg(lagrange_last * z_lookup_shift) = 2 - - /** - * @brief Compute contribution of the lookup grand prod relation for a given edge (internal function) - * - * @details This the relation confirms correct initialization of the lookup grand - * product polynomial Z_lookup with Z_lookup[circuit_size] = 0. - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - inline void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters& /*unused*/, - const FF& scaling_factor) const - { - auto z_lookup_shift = UnivariateView(extended_edges.z_lookup_shift); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - - evals += (lagrange_last * z_lookup_shift) * scaling_factor; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - auto& purported_evaluations, - const RelationParameters& /*unused*/) const - { - auto z_lookup_shift = purported_evaluations.z_lookup_shift; - auto lagrange_last = purported_evaluations.lagrange_last; + std::get<0>(full_honk_relation_value) += tmp; - full_honk_relation_value += lagrange_last * z_lookup_shift; + // Contribution (2) + std::get<1>(full_honk_relation_value) += lagrange_last * z_lookup_shift; }; }; } // namespace proof_system::honk::sumcheck \ No newline at end of file diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp similarity index 50% rename from cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp rename to cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp index ff2bc0ea8f..f613f0c3b6 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/permutation_relation.hpp @@ -1,15 +1,21 @@ #pragma once -#include "relation.hpp" +#include "relation_parameters.hpp" #include "../polynomials/univariate.hpp" // TODO(luke): change name of this file to permutation_grand_product_relation(s).hpp and move 'init' relation into it. namespace proof_system::honk::sumcheck { -template class GrandProductComputationRelation { +template class PermutationRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 5; + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 5, 3 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Compute contribution of the permutation relation for a given edge (internal function) * @@ -28,7 +34,7 @@ template class GrandProductComputationRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - inline void add_edge_contribution(Univariate& evals, + inline void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -37,29 +43,48 @@ template class GrandProductComputationRelation { const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - auto sigma_1 = UnivariateView(extended_edges.sigma_1); - auto sigma_2 = UnivariateView(extended_edges.sigma_2); - auto sigma_3 = UnivariateView(extended_edges.sigma_3); - auto id_1 = UnivariateView(extended_edges.id_1); - auto id_2 = UnivariateView(extended_edges.id_2); - auto id_3 = UnivariateView(extended_edges.id_3); - auto z_perm = UnivariateView(extended_edges.z_perm); - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + auto sigma_1 = UnivariateView(extended_edges.sigma_1); + auto sigma_2 = UnivariateView(extended_edges.sigma_2); + auto sigma_3 = UnivariateView(extended_edges.sigma_3); + auto id_1 = UnivariateView(extended_edges.id_1); + auto id_2 = UnivariateView(extended_edges.id_2); + auto id_3 = UnivariateView(extended_edges.id_3); + auto z_perm = UnivariateView(extended_edges.z_perm); + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - // Contribution (1) - evals += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma)) - - ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma))) * - scaling_factor; + // Contribution (1) + std::get<0>(evals) += + (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma)) - + ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma))) * + scaling_factor; + } + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + // Contribution (2) + std::get<1>(evals) += (lagrange_last * z_perm_shift) * scaling_factor; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const { @@ -82,21 +107,30 @@ template class GrandProductComputationRelation { auto lagrange_last = purported_evaluations.lagrange_last; // Contribution (1) - full_honk_relation_value += + std::get<0>(full_honk_relation_value) += ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * (w_3 + beta * id_3 + gamma) - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma)); + + // Contribution (2) + std::get<1>(full_honk_relation_value) += lagrange_last * z_perm_shift; }; }; // TODO(luke): With Cody's Flavor work it should be easier to create a simple templated relation // for handling arbitrary width. For now I'm duplicating the width 3 logic for width 4. -template class UltraGrandProductComputationRelation { +template class UltraPermutationRelation { public: // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; + static constexpr size_t NUM_CONSTRAINTS = 2; + static constexpr std::array CONSTRAINT_LENGTH = { 6, 3 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Compute contribution of the permutation relation for a given edge (internal function) * @@ -108,7 +142,7 @@ template class UltraGrandProductComputationRelation { * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - inline void add_edge_contribution(Univariate& evals, + inline void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters& relation_parameters, const FF& scaling_factor) const @@ -117,32 +151,51 @@ template class UltraGrandProductComputationRelation { const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - auto w_1 = UnivariateView(extended_edges.w_l); - auto w_2 = UnivariateView(extended_edges.w_r); - auto w_3 = UnivariateView(extended_edges.w_o); - auto w_4 = UnivariateView(extended_edges.w_4); - auto sigma_1 = UnivariateView(extended_edges.sigma_1); - auto sigma_2 = UnivariateView(extended_edges.sigma_2); - auto sigma_3 = UnivariateView(extended_edges.sigma_3); - auto sigma_4 = UnivariateView(extended_edges.sigma_4); - auto id_1 = UnivariateView(extended_edges.id_1); - auto id_2 = UnivariateView(extended_edges.id_2); - auto id_3 = UnivariateView(extended_edges.id_3); - auto id_4 = UnivariateView(extended_edges.id_4); - auto z_perm = UnivariateView(extended_edges.z_perm); - auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); - auto lagrange_first = UnivariateView(extended_edges.lagrange_first); - auto lagrange_last = UnivariateView(extended_edges.lagrange_last); - // Contribution (1) - evals += (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma)) - - ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * (w_4 + sigma_4 * beta + gamma))) * - scaling_factor; + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_1 = UnivariateView(extended_edges.w_l); + auto w_2 = UnivariateView(extended_edges.w_r); + auto w_3 = UnivariateView(extended_edges.w_o); + auto w_4 = UnivariateView(extended_edges.w_4); + auto sigma_1 = UnivariateView(extended_edges.sigma_1); + auto sigma_2 = UnivariateView(extended_edges.sigma_2); + auto sigma_3 = UnivariateView(extended_edges.sigma_3); + auto sigma_4 = UnivariateView(extended_edges.sigma_4); + auto id_1 = UnivariateView(extended_edges.id_1); + auto id_2 = UnivariateView(extended_edges.id_2); + auto id_3 = UnivariateView(extended_edges.id_3); + auto id_4 = UnivariateView(extended_edges.id_4); + auto z_perm = UnivariateView(extended_edges.z_perm); + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_first = UnivariateView(extended_edges.lagrange_first); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + std::get<0>(evals) += + (((z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma)) - + ((z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * + (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * (w_4 + sigma_4 * beta + gamma))) * + scaling_factor; + } + // Contribution (2) + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto z_perm_shift = UnivariateView(extended_edges.z_perm_shift); + auto lagrange_last = UnivariateView(extended_edges.lagrange_last); + + std::get<1>(evals) += (lagrange_last * z_perm_shift) * scaling_factor; + } }; - void add_full_relation_value_contribution(FF& full_honk_relation_value, + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, auto& purported_evaluations, const RelationParameters& relation_parameters) const { @@ -168,11 +221,14 @@ template class UltraGrandProductComputationRelation { auto lagrange_last = purported_evaluations.lagrange_last; // Contribution (1) - full_honk_relation_value += + std::get<0>(full_honk_relation_value) += ((z_perm + lagrange_first) * (w_1 + beta * id_1 + gamma) * (w_2 + beta * id_2 + gamma) * (w_3 + beta * id_3 + gamma) * (w_4 + beta * id_4 + gamma) - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + beta * sigma_1 + gamma) * (w_2 + beta * sigma_2 + gamma) * (w_3 + beta * sigma_3 + gamma) * (w_4 + beta * sigma_4 + gamma)); + + // Contribution (2) + std::get<1>(full_honk_relation_value) += lagrange_last * z_perm_shift; }; }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp index be3cce9708..f794b16603 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_consistency.test.cpp @@ -1,11 +1,9 @@ -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" #include "barretenberg/honk/flavor/standard.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" #include "arithmetic_relation.hpp" -#include "grand_product_initialization_relation.hpp" -#include "grand_product_computation_relation.hpp" +#include "permutation_relation.hpp" #include "../polynomials/univariate.hpp" #include "../polynomials/barycentric_data.hpp" @@ -16,14 +14,14 @@ #include using namespace proof_system::honk::sumcheck; /** - * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, - * GrandProductInitializationRelation) provide correct contributions by manually computing their - * contributions with deterministic and random inputs. The relations are supposed to work with - * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have - * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, - * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation - points), - * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. + * The purpose of this test suite is to show that the identity arithmetic implemented in the Relations is equivalent to + * a simpler unoptimized version implemented in the tests themselves. This is useful 1) as documentation since the + * simple implementations here should make the underlying arithmetic easier to see, and 2) as a check that optimizations + * introduced into the Relations have not changed the result. + * + * For this purpose, we simply feed (the same) random inputs into each of the two implementations and confirm that + * the outputs match. This does not confirm the correctness of the identity arithmetic (the identities will not be + * satisfied in general by random inputs) only that the two implementations are equivalent. */ static const size_t INPUT_UNIVARIATE_LENGTH = 2; @@ -33,14 +31,14 @@ class StandardRelationConsistency : public testing::Test { public: using Flavor = honk::flavor::Standard; using FF = typename Flavor::FF; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; // TODO(#390): Move MAX_RELATION_LENGTH into Flavor and simplify this. template using ExtendedEdges = typename Flavor::template ExtendedEdges; - // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the test - // can decide to which degree the polynomials must be extended. Possible accept an existing list of "edges" and - // extend them to the degree. + // TODO(#225)(Adrian): Accept FULL_RELATION_LENGTH as a template parameter for this function only, so that the + // test can decide to which degree the polynomials must be extended. Possible accept an existing list of + // "edges" and extend them to the degree. template static void compute_mock_extended_edges( ExtendedEdges& extended_edges, @@ -82,7 +80,7 @@ class StandardRelationConsistency : public testing::Test { * @return std::array such that result[j] = univariates[j].value_at(i) */ template - static PurportedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t i) + static ClaimedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t i) { ASSERT(i < univariate_length); std::array result; @@ -107,34 +105,76 @@ class StandardRelationConsistency : public testing::Test { * @param relation_parameters */ template - static void validate_evaluations(const Univariate& expected_evals, + static void validate_evaluations(const auto& expected_full_length_univariates, /* array of Univariates*/ const auto relation, const ExtendedEdges& extended_edges, const RelationParameters& relation_parameters) { + // First check that the verifier's computation on individual evaluations is correct. + // Note: since add_full_relation_value_contribution computes the identities at a single evaluation of the + // multivariates, we need only pass in one evaluation point from the extended edges. Which one we choose is + // arbitrary so we choose the 0th. - // Compute the expression index-by-index - Univariate expected_evals_index{ 0 }; - for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { - // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. - PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); - // Evaluate the relation - relation.add_full_relation_value_contribution( - expected_evals_index.value_at(i), evals_i, relation_parameters); + // Extract the RelationValues type for the given relation + using RelationValues = typename decltype(relation)::RelationValues; + RelationValues relation_evals; + RelationValues expected_relation_evals; + + ASSERT_EQ(expected_relation_evals.size(), expected_full_length_univariates.size()); + // Initialize expected_evals to 0th coefficient of expected full length univariates + for (size_t idx = 0; idx < relation_evals.size(); ++idx) { + relation_evals[idx] = FF(0); // initialize to 0 + expected_relation_evals[idx] = expected_full_length_univariates[idx].value_at(0); } - EXPECT_EQ(expected_evals, expected_evals_index); - // Compute the expression using the class, that converts the extended edges to UnivariateView - auto expected_evals_view = Univariate(0); - // The scaling factor is essentially 1 since we are working with degree 1 univariates - relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); + // Extract 0th evaluation from extended edges + ClaimedEvaluations edge_evaluations = transposed_univariate_array_at(extended_edges, 0); - // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` - Univariate expected_evals_restricted{ - UnivariateView(expected_evals) - }; - EXPECT_EQ(expected_evals_restricted, expected_evals_view); + // Evaluate the relation using the verifier functionality + relation.add_full_relation_value_contribution(relation_evals, edge_evaluations, relation_parameters); + + EXPECT_EQ(relation_evals, expected_relation_evals); + + // Next, check that the prover's computation on Univariates is correct + + using RelationUnivariates = typename decltype(relation)::RelationUnivariates; + RelationUnivariates relation_univariates; + zero_univariates<>(relation_univariates); + + constexpr std::size_t num_univariates = std::tuple_size::value; + + // Compute the relatiion univariates via the sumcheck prover functionality, then extend + // them to full length for easy comparison with the expected result. + relation.add_edge_contribution(relation_univariates, extended_edges, relation_parameters, 1); + + auto full_length_univariates = std::array, num_univariates>(); + extend_tuple_of_arrays(relation_univariates, full_length_univariates); + + EXPECT_EQ(full_length_univariates, expected_full_length_univariates); }; + + template static void zero_univariates(std::tuple& tuple) + { + auto& element = std::get(tuple); + std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0)); + + if constexpr (idx + 1 < sizeof...(Ts)) { + zero_univariates(tuple); + } + } + + template + static void extend_tuple_of_arrays(std::tuple& tuple, auto& result_univariates) + { + auto& element = std::get(tuple); + using Element = std::remove_reference_t; + BarycentricData barycentric_utils; + result_univariates[idx] = barycentric_utils.extend(element); + + if constexpr (idx + 1 < sizeof...(Ts)) { + extend_tuple_of_arrays(tuple, result_univariates); + } + } }; TEST_F(StandardRelationConsistency, ArithmeticRelation) @@ -174,17 +214,19 @@ TEST_F(StandardRelationConsistency, ArithmeticRelation) const auto& q_o = extended_edges.q_o; const auto& q_c = extended_edges.q_c; - // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. - // Ensure that expression changes are detected. - // expected_evals, length 4, extends to { { 5, 22, 57, 116, 205} } for input polynomial {1, 2} - auto expected_evals = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + // Compute expected full length Univariates using straight forward expressions. + // Note: expect { { 5, 22, 57, 116, 205} } for input polynomial {1, 2} + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + + expected_full_length_univariates[0] = (q_m * w_r * w_l) + (q_r * w_r) + (q_l * w_l) + (q_o * w_o) + (q_c); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); }; -TEST_F(StandardRelationConsistency, GrandProductComputationRelation) +TEST_F(StandardRelationConsistency, PermutationRelation) { using Flavor = honk::flavor::Standard; using FF = typename Flavor::FF; @@ -210,16 +252,11 @@ TEST_F(StandardRelationConsistency, GrandProductComputationRelation) } compute_mock_extended_edges(extended_edges, input_polynomials); }; - auto relation = GrandProductComputationRelation(); + auto relation = PermutationRelation(); const auto& beta = relation_parameters.beta; const auto& gamma = relation_parameters.gamma; const auto& public_input_delta = relation_parameters.public_input_delta; - // TODO(#225)(luke): Write a test that illustrates the following? - // Note: the below z_perm_shift = X^2 will fail because it results in a relation of degree 2*1*1*1 = 5 which - // cannot be represented by 5 points. Therefore when we do the calculation then barycentrically extend, we are - // effectively exprapolating a 4th degree polynomial instead of the correct 5th degree poly - // auto z_perm_shift = Univariate({ 1, 4, 9, 16, 25 }); // X^2 // Manually compute the expected edge contribution const auto& w_1 = extended_edges.w_l; @@ -236,55 +273,19 @@ TEST_F(StandardRelationConsistency, GrandProductComputationRelation) const auto& lagrange_first = extended_edges.lagrange_first; const auto& lagrange_last = extended_edges.lagrange_last; - // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. - // Ensure that expression changes are detected. - // expected_evals in the below step { { 27, 250, 1029, 2916, 6655 } } - { { 27, 125, 343, 729, 1331 } } - auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * - (w_3 + id_3 * beta + gamma) - - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * - (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma); + // Compute expected full length Univariates using straight forward expressions + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); - }; - run_test(/* is_random_input=*/true); - run_test(/* is_random_input=*/false); -}; + expected_full_length_univariates[0] = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * + (w_2 + id_2 * beta + gamma) * (w_3 + id_3 * beta + gamma) - + (z_perm_shift + lagrange_last * public_input_delta) * + (w_1 + sigma_1 * beta + gamma) * (w_2 + sigma_2 * beta + gamma) * + (w_3 + sigma_3 * beta + gamma); -TEST_F(StandardRelationConsistency, GrandProductInitializationRelation) -{ - using Flavor = honk::flavor::Standard; - using FF = typename Flavor::FF; - static constexpr size_t FULL_RELATION_LENGTH = 5; - using ExtendedEdges = typename Flavor::template ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - const auto relation_parameters = compute_mock_relation_parameters(); - auto run_test = [&relation_parameters](bool is_random_input) { - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - if (!is_random_input) { - // evaluation form, i.e. input_univariate(0) = 1, input_univariate(1) = 2,.. The polynomial is x+1. - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ 1, 2 }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - } else { - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = - Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - }; - auto relation = GrandProductInitializationRelation(); - const auto& z_perm_shift = extended_edges.z_perm_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - // We first compute the evaluations using UnivariateViews, with the provided hard-coded formula. - // Ensure that expression changes are detected. - // expected_evals, lenght 3 (coeff form = x^2 + x), extends to { { 0, 2, 6, 12, 20 } } - auto expected_evals = z_perm_shift * lagrange_last; + expected_full_length_univariates[1] = z_perm_shift * lagrange_last; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; run_test(/* is_random_input=*/true); run_test(/* is_random_input=*/false); diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp index d9b1bc3a3e..01d3624083 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/relation_correctness.test.cpp @@ -3,13 +3,11 @@ #include "barretenberg/honk/composer/ultra_honk_composer.hpp" #include "barretenberg/honk/composer/standard_honk_composer.hpp" #include "barretenberg/honk/proof_system/prover_library.hpp" -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/honk/sumcheck/relations/arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_initialization_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/grand_product_computation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" @@ -27,6 +25,40 @@ void ensure_non_zero(auto& polynomial) ASSERT_TRUE(has_non_zero_coefficient); } +/** + * @brief Check that a given relation is satified for a set of polynomials + * + * @tparam relation_idx Index into a tuple of provided relations + * @tparam Flavor + */ +template void check_relation(auto relation, auto circuit_size, auto polynomials, auto params) +{ + using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; + for (size_t i = 0; i < circuit_size; i++) { + + // Extract an array containing all the polynomial evaluations at a given row i + ClaimedEvaluations evaluations_at_index_i; + size_t poly_idx = 0; + for (auto& poly : polynomials) { + evaluations_at_index_i[poly_idx] = poly[i]; + ++poly_idx; + } + + // Define the appropriate RelationValues type for this relation and initialize to zero + using RelationValues = typename decltype(relation)::RelationValues; + RelationValues result; + for (auto& element : result) { + element = 0; + } + + // Evaluate each constraint in the relation and check that each is satisfied + relation.add_full_relation_value_contribution(result, evaluations_at_index_i, params); + for (auto& element : result) { + ASSERT_EQ(element, 0); + } + } +} + /** * @brief Test the correctness of the Standard Honk relations * @@ -42,7 +74,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) using Flavor = honk::flavor::Standard; using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + // using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; // Create a composer and a dummy circuit with a few gates auto composer = StandardHonkComposer(); @@ -61,6 +93,7 @@ TEST(RelationCorrectness, StandardRelationCorrectness) } // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); + auto circuit_size = prover.key->circuit_size; // Generate beta and gamma fr beta = fr::random_element(); @@ -107,34 +140,11 @@ TEST(RelationCorrectness, StandardRelationCorrectness) prover_polynomials.lagrange_last = prover.key->lagrange_last; // Construct the round for applying sumcheck relations and results for storing computed results - auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), - honk::sumcheck::GrandProductComputationRelation(), - honk::sumcheck::GrandProductInitializationRelation()); - - fr result = 0; - for (size_t i = 0; i < prover.key->circuit_size; i++) { - // Compute an array containing all the evaluations at a given row i - - PurportedEvaluations evaluations_at_index_i; - size_t poly_idx = 0; - for (auto& polynomial : prover_polynomials) { - evaluations_at_index_i[poly_idx] = polynomial[i]; - ++poly_idx; - } + auto relations = std::tuple(honk::sumcheck::ArithmeticRelation(), honk::sumcheck::PermutationRelation()); - // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the - // i-th row/vertex of the hypercube. - // We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at the first index at which the result is not - // 0, since result = 0 + C(transposed), which we expect will equal 0. - std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - } + // Check that each relation is satisfied across each row of the prover polynomials + check_relation(std::get<0>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<1>(relations), circuit_size, prover_polynomials, params); } /** @@ -154,7 +164,7 @@ TEST(RelationCorrectness, UltraRelationCorrectness) using Flavor = honk::flavor::Ultra; using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + // using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented // by each relation are non-trivially exercised. @@ -275,6 +285,7 @@ TEST(RelationCorrectness, UltraRelationCorrectness) // Create a prover (it will compute proving key and witness) auto prover = composer.create_prover(); + auto circuit_size = prover.key->circuit_size; // Generate eta, beta and gamma fr eta = fr::random_element(); @@ -308,10 +319,6 @@ TEST(RelationCorrectness, UltraRelationCorrectness) // Compute lookup grand product polynomial prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); - // Create an array of spans to the underlying polynomials to more easily - // get the transposition. - // Ex: polynomial_spans[3][i] returns the i-th coefficient of the third polynomial - // in the list below ProverPolynomials prover_polynomials; prover_polynomials.w_l = prover.key->w_l; @@ -367,56 +374,19 @@ TEST(RelationCorrectness, UltraRelationCorrectness) // Construct the round for applying sumcheck relations and results for storing computed results auto relations = std::tuple(honk::sumcheck::UltraArithmeticRelation(), - honk::sumcheck::UltraArithmeticRelationSecondary(), - honk::sumcheck::UltraGrandProductInitializationRelation(), - honk::sumcheck::UltraGrandProductComputationRelation(), - honk::sumcheck::LookupGrandProductComputationRelation(), - honk::sumcheck::LookupGrandProductInitializationRelation(), + honk::sumcheck::UltraPermutationRelation(), + honk::sumcheck::LookupRelation(), honk::sumcheck::GenPermSortRelation(), honk::sumcheck::EllipticRelation(), honk::sumcheck::AuxiliaryRelation()); - fr result = 0; - for (size_t i = 0; i < prover.key->circuit_size; i++) { - // Compute an array containing all the evaluations at a given row i - PurportedEvaluations evaluations_at_index_i; - size_t poly_idx = 0; - for (auto& polynomial : prover_polynomials) { - evaluations_at_index_i[poly_idx] = polynomial[i]; - ++poly_idx; - } - - // For each relation, call the `accumulate_relation_evaluation` over all witness/selector values at the - // i-th row/vertex of the hypercube. We use ASSERT_EQ instead of EXPECT_EQ so that the tests stops at - // the first index at which the result is not 0, since result = 0 + C(transposed), which we expect will - // equal 0. - std::get<0>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<1>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<2>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<3>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<4>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<5>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<6>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<7>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - - std::get<8>(relations).add_full_relation_value_contribution(result, evaluations_at_index_i, params); - ASSERT_EQ(result, 0); - } + // Check that each relation is satisfied across each row of the prover polynomials + check_relation(std::get<0>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<1>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<2>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<3>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<4>(relations), circuit_size, prover_polynomials, params); + check_relation(std::get<5>(relations), circuit_size, prover_polynomials, params); } } // namespace test_honk_relations diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/relation_parameters.hpp similarity index 100% rename from cpp/src/barretenberg/honk/sumcheck/relations/relation.hpp rename to cpp/src/barretenberg/honk/sumcheck/relations/relation_parameters.hpp diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp index dd5aa02b85..1ea1de263e 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp @@ -3,7 +3,7 @@ #include #include "../polynomials/univariate.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" namespace proof_system::honk::sumcheck { @@ -12,55 +12,127 @@ template class UltraArithmeticRelation { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 6; // degree(q_arith^2 * q_m * w_r * w_l) = 5 + static constexpr size_t NUM_CONSTRAINTS = 2; + // TODO(luke): The degree of the identities varies based on q_arith. Can we do something to improve efficiency here? + static constexpr std::array CONSTRAINT_LENGTH = { 6, 5 }; + + using RelationUnivariates = std::tuple, Univariate>; + using RelationValues = std::array; + /** * @brief Expression for the Ultra Arithmetic gate. - * @details The relation is defined as C(extended_edges(X)...) = + * @details This relation encapsulates several idenitities, toggled by the value of q_arith in [0, 1, 2, 3, ...]. + * The following description is reproduced from the Plonk analog 'plookup_arithmetic_widget': + * The whole formula is: + * + * 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 + * + * 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 + * + * 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. + * + * The The relation is + * defined as C(extended_edges(X)...) = q_arith * [ -1/2(q_arith - 3)(q_m * w_r * w_l) + (q_l * w_l) + (q_r * w_r) + + * (q_o * w_o) + (q_4 * w_4) + q_c + (q_arith - 1)w_4_shift ] + * * q_arith * - * [ -1/2(q_arith - 3)(q_m * w_r * w_l) + - * (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c + - * (q_arith - 1)w_4_shift ] + * (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m) * * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` * @param extended_edges an std::array containing the fully extended Univariate edges. * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ - void add_edge_contribution(Univariate& evals, + void add_edge_contribution(RelationUnivariates& evals, const auto& extended_edges, const RelationParameters&, - const FF& scaling_factor) const - { + const FF& scaling_factor) const { // OPTIMIZATION?: Karatsuba in general, at least for some degrees? // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both + // clang-format off + // Contribution 1 + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[0]; + auto w_l = UnivariateView(extended_edges.w_l); + auto w_r = UnivariateView(extended_edges.w_r); + auto w_o = UnivariateView(extended_edges.w_o); + auto w_4 = UnivariateView(extended_edges.w_4); + auto w_4_shift = UnivariateView(extended_edges.w_4_shift); + auto q_m = UnivariateView(extended_edges.q_m); + auto q_l = UnivariateView(extended_edges.q_l); + auto q_r = UnivariateView(extended_edges.q_r); + auto q_o = UnivariateView(extended_edges.q_o); + auto q_4 = UnivariateView(extended_edges.q_4); + auto q_c = UnivariateView(extended_edges.q_c); + auto q_arith = UnivariateView(extended_edges.q_arith); - auto w_l = UnivariateView(extended_edges.w_l); - auto w_r = UnivariateView(extended_edges.w_r); - auto w_o = UnivariateView(extended_edges.w_o); - auto w_4 = UnivariateView(extended_edges.w_4); - auto w_4_shift = UnivariateView(extended_edges.w_4_shift); - auto q_m = UnivariateView(extended_edges.q_m); - auto q_l = UnivariateView(extended_edges.q_l); - auto q_r = UnivariateView(extended_edges.q_r); - auto q_o = UnivariateView(extended_edges.q_o); - auto q_4 = UnivariateView(extended_edges.q_4); - auto q_c = UnivariateView(extended_edges.q_c); - auto q_arith = UnivariateView(extended_edges.q_arith); + static const FF neg_half = FF(-2).invert(); - static const FF neg_half = FF(-2).invert(); + auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; + tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; + tmp += (q_arith - 1) * w_4_shift; + tmp *= q_arith; + tmp *= scaling_factor; + std::get<0>(evals) += tmp; + } + // Contribution 2 + { + static constexpr size_t LENGTH = CONSTRAINT_LENGTH[1]; + auto w_l = UnivariateView(extended_edges.w_l); + auto w_4 = UnivariateView(extended_edges.w_4); + auto w_l_shift = UnivariateView(extended_edges.w_l_shift); + auto q_m = UnivariateView(extended_edges.q_m); + auto q_arith = UnivariateView(extended_edges.q_arith); - auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; - tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; - tmp += (q_arith - 1) * w_4_shift; - tmp *= q_arith; - tmp *= scaling_factor; - evals += tmp; - }; + auto tmp = w_l + w_4 - w_l_shift + q_m; + tmp *= (q_arith - 2); + tmp *= (q_arith - 1); + tmp *= q_arith; + tmp *= scaling_factor; + std::get<1>(evals) += tmp; + } + }; // namespace proof_system::honk::sumcheck - void add_full_relation_value_contribution(FF& full_honk_relation_value, - const auto& purported_evaluations, - const RelationParameters&) const + /** + * @brief Add the result of each identity in this relation evaluated at the multivariate evaluations produced by the + * Sumcheck Prover. + * + * @param full_honk_relation_value + * @param purported_evaluations + */ + void add_full_relation_value_contribution(RelationValues& full_honk_relation_value, + const auto& purported_evaluations, + const RelationParameters&) const { auto w_l = purported_evaluations.w_l; + auto w_l_shift = purported_evaluations.w_l_shift; auto w_r = purported_evaluations.w_r; auto w_o = purported_evaluations.w_o; auto w_4 = purported_evaluations.w_4; @@ -75,11 +147,20 @@ template class UltraArithmeticRelation { static const FF neg_half = FF(-2).invert(); + // Contribution 1 auto tmp = (q_arith - 3) * (q_m * w_r * w_l) * neg_half; tmp += (q_l * w_l) + (q_r * w_r) + (q_o * w_o) + (q_4 * w_4) + q_c; tmp += (q_arith - 1) * w_4_shift; tmp *= q_arith; - full_honk_relation_value += tmp; + std::get<0>(full_honk_relation_value) += tmp; + + // Contribution 2 + tmp = w_l + w_4 - w_l_shift + q_m; + tmp *= (q_arith - 2); + tmp *= (q_arith - 1); + tmp *= q_arith; + std::get<1>(full_honk_relation_value) += tmp; }; }; +// clang-format on } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp deleted file mode 100644 index 84bb0ce60c..0000000000 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include -#include - -#include "../polynomials/univariate.hpp" -#include "relation.hpp" - -// TODO(luke): Move this into ultra_arithmetic_relation.hpp. -namespace proof_system::honk::sumcheck { - -template class UltraArithmeticRelationSecondary { - public: - // 1 + polynomial degree of this relation - static constexpr size_t RELATION_LENGTH = 5; // degree(q_arith^3 * w_l) = 4 - - /** - * @brief Expression for the Ultra Arithmetic gate. - * @details The relation is defined as C(extended_edges(X)...) = - * q_arith * - * (q_arith - 2) * (q_arith - 1) * (w_l + w_4 - w_l_shift + q_m) - * - * @param evals transformed to `evals + C(extended_edges(X)...)*scaling_factor` - * @param extended_edges an std::array containing the fully extended Univariate edges. - * @param parameters contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ - void add_edge_contribution(Univariate& evals, - const auto& extended_edges, - const RelationParameters&, - const FF& scaling_factor) const - { - // OPTIMIZATION?: Karatsuba in general, at least for some degrees? - // See https://hackmd.io/xGLuj6biSsCjzQnYN-pEiA?both - - auto w_l = UnivariateView(extended_edges.w_l); - auto w_4 = UnivariateView(extended_edges.w_4); - auto w_l_shift = UnivariateView(extended_edges.w_l_shift); - auto q_m = UnivariateView(extended_edges.q_m); - auto q_arith = UnivariateView(extended_edges.q_arith); - - auto tmp = w_l + w_4 - w_l_shift + q_m; - tmp *= (q_arith - 2); - tmp *= (q_arith - 1); - tmp *= q_arith; - tmp *= scaling_factor; - evals += tmp; - }; - - void add_full_relation_value_contribution(FF& full_honk_relation_value, - const auto& purported_evaluations, - const RelationParameters&) const - { - auto w_l = purported_evaluations.w_l; - auto w_4 = purported_evaluations.w_4; - auto w_l_shift = purported_evaluations.w_l_shift; - auto q_m = purported_evaluations.q_m; - auto q_arith = purported_evaluations.q_arith; - - auto tmp = w_l + w_4 - w_l_shift + q_m; - tmp *= (q_arith - 2); - tmp *= (q_arith - 1); - tmp *= q_arith; - full_honk_relation_value += tmp; - }; -}; -} // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp index e363dd8725..1be27d4bda 100644 --- a/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/relations/ultra_relation_consistency.test.cpp @@ -1,14 +1,13 @@ #include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation_secondary.hpp" -#include "barretenberg/honk/sumcheck/relations/lookup_grand_product_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" #include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" #include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" #include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" #include "barretenberg/honk/flavor/ultra.hpp" -#include "relation.hpp" +#include "relation_parameters.hpp" #include "arithmetic_relation.hpp" -#include "grand_product_initialization_relation.hpp" -#include "grand_product_computation_relation.hpp" +#include "permutation_relation.hpp" #include "../polynomials/univariate.hpp" #include "../polynomials/barycentric_data.hpp" @@ -17,16 +16,18 @@ #include #include +// TODO(luke): This testing infrastructure was duplicated between here and relation_consistency.test.cpp with the +// orignal Flavor PR. Find a way to recombine these test suites or at least share this functionality. using namespace proof_system::honk::sumcheck; /** - * We want to test if all three relations (namely, ArithmeticRelation, GrandProductComputationRelation, - * GrandProductInitializationRelation) provide correct contributions by manually computing their - * contributions with deterministic and random inputs. The relations are supposed to work with - * univariates (edges) of degree one (length 2) and spit out polynomials of corresponding degrees. We have - * MAX_RELATION_LENGTH = 5, meaning the output of a relation can atmost be a degree 5 polynomial. Hence, - * we use a method compute_mock_extended_edges() which starts with degree one input polynomial (two evaluation - points), - * extends them (using barycentric formula) to six evaluation points, and stores them to an array of polynomials. + * The purpose of this test suite is to show that the identity arithmetic implemented in the Relations is equivalent to + * a simpler unoptimized version implemented in the tests themselves. This is useful 1) as documentation since the + * simple implementations here should make the underlying arithmetic easier to see, and 2) as a check that optimizations + * introduced into the Relations have not changed the result. + * + * For this purpose, we simply feed (the same) random inputs into each of the two implementations and confirm that + * the outputs match. This does not confirm the correctness of the identity arithmetic (the identities will not be + * satisfied in general by random inputs) only that the two implementations are equivalent. */ static const size_t INPUT_UNIVARIATE_LENGTH = 2; @@ -36,7 +37,7 @@ class UltraRelationConsistency : public testing::Test { public: using Flavor = honk::flavor::Ultra; using FF = typename Flavor::FF; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; // TODO(#390): Move MAX_RELATION_LENGTH into Flavor and simplify this. template using ExtendedEdges = typename Flavor::template ExtendedEdges; @@ -63,9 +64,11 @@ class UltraRelationConsistency : public testing::Test { */ RelationParameters compute_mock_relation_parameters() { - return { .beta = FF::random_element(), + return { .eta = FF::random_element(), + .beta = FF::random_element(), .gamma = FF::random_element(), - .public_input_delta = FF::random_element() }; + .public_input_delta = FF::random_element(), + .lookup_grand_product_delta = FF::random_element() }; } /** @@ -83,7 +86,7 @@ class UltraRelationConsistency : public testing::Test { * @return std::array such that result[j] = univariates[j].value_at(i) */ template - static PurportedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t i) + static ClaimedEvaluations transposed_univariate_array_at(ExtendedEdges univariates, size_t i) { ASSERT(i < univariate_length); std::array result; @@ -108,34 +111,76 @@ class UltraRelationConsistency : public testing::Test { * @param relation_parameters */ template - static void validate_evaluations(const Univariate& expected_evals, + static void validate_evaluations(const auto& expected_full_length_univariates, /* array of Univariates*/ const auto relation, const ExtendedEdges& extended_edges, const RelationParameters& relation_parameters) { - - // Compute the expression index-by-index - Univariate expected_evals_index{ 0 }; - for (size_t i = 0; i < FULL_RELATION_LENGTH; ++i) { - // Get an array of the same size as `extended_edges` with only the i-th element of each extended edge. - PurportedEvaluations evals_i = transposed_univariate_array_at(extended_edges, i); - // Evaluate the relation - relation.add_full_relation_value_contribution( - expected_evals_index.value_at(i), evals_i, relation_parameters); + // First check that the verifier's computation on individual evaluations is correct. + // Note: since add_full_relation_value_contribution computes the identities at a single evaluation of the + // multivariates, we need only pass in one evaluation point from the extended edges. Which one we choose is + // arbitrary so we choose the 0th. + + // Extract the RelationValues type for the given relation + using RelationValues = typename decltype(relation)::RelationValues; + RelationValues relation_evals; + RelationValues expected_relation_evals; + + ASSERT_EQ(expected_relation_evals.size(), expected_full_length_univariates.size()); + // Initialize expected_evals to 0th coefficient of expected full length univariates + for (size_t idx = 0; idx < relation_evals.size(); ++idx) { + relation_evals[idx] = FF(0); // initialize to 0 + expected_relation_evals[idx] = expected_full_length_univariates[idx].value_at(0); } - EXPECT_EQ(expected_evals, expected_evals_index); - - // Compute the expression using the class, that converts the extended edges to UnivariateView - auto expected_evals_view = Univariate(0); - // The scaling factor is essentially 1 since we are working with degree 1 univariates - relation.add_edge_contribution(expected_evals_view, extended_edges, relation_parameters, 1); - - // Tiny hack to reduce `expected_evals` to be of size `relation.RELATION_LENGTH` - Univariate expected_evals_restricted{ - UnivariateView(expected_evals) - }; - EXPECT_EQ(expected_evals_restricted, expected_evals_view); + + // Extract 0th evaluation from extended edges + ClaimedEvaluations edge_evaluations = transposed_univariate_array_at(extended_edges, 0); + + // Evaluate the relation using the verifier functionality + relation.add_full_relation_value_contribution(relation_evals, edge_evaluations, relation_parameters); + + EXPECT_EQ(relation_evals, expected_relation_evals); + + // Next, check that the prover's computation on Univariates is correct + + using RelationUnivariates = typename decltype(relation)::RelationUnivariates; + RelationUnivariates relation_univariates; + zero_univariates<>(relation_univariates); + + constexpr std::size_t num_univariates = std::tuple_size::value; + + // Compute the relatiion univariates via the sumcheck prover functionality, then extend + // them to full length for easy comparison with the expected result. + relation.add_edge_contribution(relation_univariates, extended_edges, relation_parameters, 1); + + auto full_length_univariates = std::array, num_univariates>(); + extend_tuple_of_arrays(relation_univariates, full_length_univariates); + + EXPECT_EQ(full_length_univariates, expected_full_length_univariates); }; + + template static void zero_univariates(std::tuple& tuple) + { + auto& element = std::get(tuple); + std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0)); + + if constexpr (idx + 1 < sizeof...(Ts)) { + zero_univariates(tuple); + } + } + + template + static void extend_tuple_of_arrays(std::tuple& tuple, auto& result_univariates) + { + auto& element = std::get(tuple); + using Element = std::remove_reference_t; + BarycentricData barycentric_utils; + result_univariates[idx] = barycentric_utils.extend(element); + + if constexpr (idx + 1 < sizeof...(Ts)) { + extend_tuple_of_arrays(tuple, result_univariates); + } + } }; TEST_F(UltraRelationConsistency, UltraArithmeticRelation) @@ -160,6 +205,7 @@ TEST_F(UltraRelationConsistency, UltraArithmeticRelation) // Extract the extended edges for manual computation of relation contribution const auto& w_1 = extended_edges.w_l; + const auto& w_1_shift = extended_edges.w_l_shift; const auto& w_2 = extended_edges.w_r; const auto& w_3 = extended_edges.w_o; const auto& w_4 = extended_edges.w_4; @@ -174,78 +220,25 @@ TEST_F(UltraRelationConsistency, UltraArithmeticRelation) static const FF neg_half = FF(-2).invert(); - auto expected_evals = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; - expected_evals += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; - expected_evals += (q_arith - 1) * w_4_shift; - expected_evals *= q_arith; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, UltraArithmeticRelationSecondary) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::template ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - const auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = UltraArithmeticRelationSecondary(); + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); - // Extract the extended edges for manual computation of relation contribution - const auto& w_1 = extended_edges.w_l; - const auto& w_4 = extended_edges.w_4; - const auto& w_l_shift = extended_edges.w_l_shift; - const auto& q_m = extended_edges.q_m; - const auto& q_arith = extended_edges.q_arith; + // Contribution 1 + auto contribution_1 = (q_arith - 3) * (q_m * w_2 * w_1) * neg_half; + contribution_1 += (q_l * w_1) + (q_r * w_2) + (q_o * w_3) + (q_4 * w_4) + q_c; + contribution_1 += (q_arith - 1) * w_4_shift; + contribution_1 *= q_arith; + expected_full_length_univariates[0] = contribution_1; - auto expected_evals = (w_1 + w_4 - w_l_shift + q_m); - expected_evals *= (q_arith - 2) * (q_arith - 1) * q_arith; + // Contribution 2 + auto contribution_2 = (w_1 + w_4 - w_1_shift + q_m); + contribution_2 *= (q_arith - 2) * (q_arith - 1) * q_arith; + expected_full_length_univariates[1] = contribution_2; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; -TEST_F(UltraRelationConsistency, UltraGrandProductInitializationRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = UltraGrandProductInitializationRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& z_perm_shift = extended_edges.z_perm_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = z_perm_shift * lagrange_last; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; - -TEST_F(UltraRelationConsistency, UltraGrandProductComputationRelation) +TEST_F(UltraRelationConsistency, UltraPermutationRelation) { using Flavor = honk::flavor::Ultra; using FF = typename Flavor::FF; @@ -263,7 +256,7 @@ TEST_F(UltraRelationConsistency, UltraGrandProductComputationRelation) } compute_mock_extended_edges(extended_edges, input_polynomials); - auto relation = UltraGrandProductComputationRelation(); + auto relation = UltraPermutationRelation(); const auto& beta = relation_parameters.beta; const auto& gamma = relation_parameters.gamma; @@ -287,17 +280,27 @@ TEST_F(UltraRelationConsistency, UltraGrandProductComputationRelation) const auto& lagrange_first = extended_edges.lagrange_first; const auto& lagrange_last = extended_edges.lagrange_last; + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * + + // Contribution 1 + auto contribution_1 = (z_perm + lagrange_first) * (w_1 + id_1 * beta + gamma) * (w_2 + id_2 * beta + gamma) * (w_3 + id_3 * beta + gamma) * (w_4 + id_4 * beta + gamma) - (z_perm_shift + lagrange_last * public_input_delta) * (w_1 + sigma_1 * beta + gamma) * (w_2 + sigma_2 * beta + gamma) * (w_3 + sigma_3 * beta + gamma) * (w_4 + sigma_4 * beta + gamma); + expected_full_length_univariates[0] = contribution_1; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + // Contribution 2 + auto contribution_2 = z_perm_shift * lagrange_last; + expected_full_length_univariates[1] = contribution_2; + + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; -TEST_F(UltraRelationConsistency, LookupGrandProductComputationRelation) +TEST_F(UltraRelationConsistency, LookupRelation) { using Flavor = honk::flavor::Ultra; using FF = typename Flavor::FF; @@ -315,7 +318,7 @@ TEST_F(UltraRelationConsistency, LookupGrandProductComputationRelation) } compute_mock_extended_edges(extended_edges, input_polynomials); - auto relation = LookupGrandProductComputationRelation(); + auto relation = LookupRelation(); const auto eta = relation_parameters.eta; const auto beta = relation_parameters.beta; @@ -366,43 +369,23 @@ TEST_F(UltraRelationConsistency, LookupGrandProductComputationRelation) auto table_accum = table_1 + table_2 * eta + table_3 * eta_sqr + table_4 * eta_cube; auto table_accum_shift = table_1_shift + table_2_shift * eta + table_3_shift * eta_sqr + table_4_shift * eta_cube; + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * + + // Contribution 1 + auto contribution_1 = (z_lookup + lagrange_first) * (q_lookup * wire_accum + gamma) * (table_accum + table_accum_shift * beta + gamma_by_one_plus_beta) * one_plus_beta; - expected_evals -= (z_lookup_shift + lagrange_last * grand_product_delta) * + contribution_1 -= (z_lookup_shift + lagrange_last * grand_product_delta) * (s_accum + s_accum_shift * beta + gamma_by_one_plus_beta); + expected_full_length_univariates[0] = contribution_1; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); -}; + // Contribution 2 + auto contribution_2 = z_lookup_shift * lagrange_last; + expected_full_length_univariates[1] = contribution_2; -TEST_F(UltraRelationConsistency, LookupGrandProductInitializationRelation) -{ - using Flavor = honk::flavor::Ultra; - using FF = typename Flavor::FF; - using Flavor = honk::flavor::Ultra; - static constexpr size_t FULL_RELATION_LENGTH = 6; - using ExtendedEdges = typename Flavor::ExtendedEdges; - static const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - auto relation_parameters = compute_mock_relation_parameters(); - ExtendedEdges extended_edges; - std::array, NUM_POLYNOMIALS> input_polynomials; - - // input_univariates are random polynomials of degree one - for (size_t i = 0; i < NUM_POLYNOMIALS; ++i) { - input_polynomials[i] = Univariate({ FF::random_element(), FF::random_element() }); - } - compute_mock_extended_edges(extended_edges, input_polynomials); - - auto relation = LookupGrandProductInitializationRelation(); - - // Extract the extended edges for manual computation of relation contribution - const auto& z_lookup_shift = extended_edges.z_lookup_shift; - const auto& lagrange_last = extended_edges.lagrange_last; - - // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = z_lookup_shift * lagrange_last; - - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; TEST_F(UltraRelationConsistency, GenPermSortRelation) @@ -436,25 +419,27 @@ TEST_F(UltraRelationConsistency, GenPermSortRelation) const auto& w_1_shift = extended_edges.w_l_shift; const auto& q_sort = extended_edges.q_sort; - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; - static const FF fake_alpha_3 = fake_alpha_2 * fake_alpha_1; - static const FF fake_alpha_4 = fake_alpha_3 * fake_alpha_1; - // Compute wire differences auto delta_1 = w_2 - w_1; auto delta_2 = w_3 - w_2; auto delta_3 = w_4 - w_3; auto delta_4 = w_1_shift - w_4; + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + // Compute the expected result using a simple to read version of the relation expression - auto expected_evals = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3) * fake_alpha_1; - expected_evals += delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3) * fake_alpha_2; - expected_evals += delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3) * fake_alpha_3; - expected_evals += delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3) * fake_alpha_4; - expected_evals *= q_sort; + auto contribution_1 = delta_1 * (delta_1 - 1) * (delta_1 - 2) * (delta_1 - 3); + auto contribution_2 = delta_2 * (delta_2 - 1) * (delta_2 - 2) * (delta_2 - 3); + auto contribution_3 = delta_3 * (delta_3 - 1) * (delta_3 - 2) * (delta_3 - 3); + auto contribution_4 = delta_4 * (delta_4 - 1) * (delta_4 - 2) * (delta_4 - 3); + + expected_full_length_univariates[0] = contribution_1 * q_sort; + expected_full_length_univariates[1] = contribution_2 * q_sort; + expected_full_length_univariates[2] = contribution_3 * q_sort; + expected_full_length_univariates[3] = contribution_4 * q_sort; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; TEST_F(UltraRelationConsistency, EllipticRelation) @@ -491,23 +476,26 @@ TEST_F(UltraRelationConsistency, EllipticRelation) const auto& q_beta_sqr = extended_edges.q_4; const auto& q_elliptic = extended_edges.q_elliptic; - static const FF fake_alpha_1 = FF(1); - static const FF fake_alpha_2 = fake_alpha_1 * fake_alpha_1; + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); // Compute x/y coordinate identities + + // Contribution 1 auto x_identity = q_sign * (y_1 * y_2 * 2); x_identity += q_beta * (x_1 * x_2 * x_3 * 2 + x_1 * x_1 * x_2) * FF(-1); x_identity += q_beta_sqr * (x_2 * x_2 * x_3 - x_1 * x_2 * x_2); x_identity += (x_1 * x_1 * x_3 - y_2 * y_2 - y_1 * y_1 + x_2 * x_2 * x_2 + x_1 * x_1 * x_1); + // Contribution 2 auto y_identity = q_sign * (y_2 * x_3 - y_2 * x_1); y_identity += q_beta * (x_2 * y_3 + y_1 * x_2); y_identity += (x_1 * y_1 - x_1 * y_3 - y_1 * x_3 - x_1 * y_1); - auto expected_evals = x_identity * fake_alpha_1 + y_identity * fake_alpha_2; - expected_evals *= q_elliptic; + expected_full_length_univariates[0] = x_identity * q_elliptic; + expected_full_length_univariates[1] = y_identity * q_elliptic; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; TEST_F(UltraRelationConsistency, AuxiliaryRelation) @@ -531,7 +519,6 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) auto relation = AuxiliaryRelation(); const auto& eta = relation_parameters.eta; - const auto fake_alpha = FF(1); // Extract the extended edges for manual computation of relation contribution const auto& w_1 = extended_edges.w_l; @@ -552,6 +539,9 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) const auto& q_arith = extended_edges.q_arith; const auto& q_aux = extended_edges.q_aux; + constexpr std::size_t NUM_CONSTRAINTS = decltype(relation)::NUM_CONSTRAINTS; + auto expected_full_length_univariates = std::array, NUM_CONSTRAINTS>(); + constexpr FF LIMB_SIZE(uint256_t(1) << 68); constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14); constexpr FF SUBLIMB_SHIFT_2(SUBLIMB_SHIFT * SUBLIMB_SHIFT); @@ -572,32 +562,28 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) non_native_field_gate_2 *= LIMB_SIZE; non_native_field_gate_2 -= w_4_shift; non_native_field_gate_2 += limb_subproduct; - non_native_field_gate_2 *= q_4; limb_subproduct *= LIMB_SIZE; limb_subproduct += (w_1_shift * w_2_shift); auto non_native_field_gate_1 = limb_subproduct; non_native_field_gate_1 -= (w_3 + w_4); - non_native_field_gate_1 *= q_3; auto non_native_field_gate_3 = limb_subproduct; non_native_field_gate_3 += w_4; non_native_field_gate_3 -= (w_3_shift + w_4_shift); - non_native_field_gate_3 *= q_m; - auto non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3; - non_native_field_identity *= q_2; + auto non_native_field_identity = q_2 * q_3 * non_native_field_gate_1; + non_native_field_identity += q_2 * q_4 * non_native_field_gate_2; + non_native_field_identity += q_2 * q_m * non_native_field_gate_3; auto limb_accumulator_1 = w_1 + w_2 * SUBLIMB_SHIFT + w_3 * SUBLIMB_SHIFT_2 + w_1_shift * SUBLIMB_SHIFT_3 + w_2_shift * SUBLIMB_SHIFT_4 - w_4; - limb_accumulator_1 *= q_4; auto limb_accumulator_2 = w_3 + w_4 * SUBLIMB_SHIFT + w_1_shift * SUBLIMB_SHIFT_2 + w_2_shift * SUBLIMB_SHIFT_3 + w_3_shift * SUBLIMB_SHIFT_4 - w_4_shift; - limb_accumulator_2 *= q_m; - auto limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; - limb_accumulator_identity *= q_3; + auto limb_accumulator_identity = q_3 * q_4 * limb_accumulator_1; + limb_accumulator_identity += q_3 * q_m * limb_accumulator_2; /** * MEMORY @@ -627,11 +613,9 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) // auto adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; auto adjacent_values_match_if_adjacent_indices_match = (index_delta * FF(-1) + FF(1)) * record_delta; - auto ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= fake_alpha; - ROM_consistency_check_identity += memory_record_check; + expected_full_length_univariates[1] = adjacent_values_match_if_adjacent_indices_match * (q_1 * q_2); + expected_full_length_univariates[2] = index_is_monotonically_increasing * (q_1 * q_2); + auto ROM_consistency_check_identity = memory_record_check * (q_1 * q_2); /** * RAM Consistency Check @@ -659,34 +643,42 @@ TEST_F(UltraRelationConsistency, AuxiliaryRelation) auto next_gate_access_type_is_boolean = next_gate_access_type * next_gate_access_type - next_gate_access_type; // Putting it all together... - auto RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= fake_alpha; - RAM_consistency_check_identity += access_check; + expected_full_length_univariates[3] = + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_arith); + expected_full_length_univariates[4] = index_is_monotonically_increasing * (q_arith); + expected_full_length_univariates[5] = next_gate_access_type_is_boolean * (q_arith); + auto RAM_consistency_check_identity = access_check * (q_arith); + + /** + * RAM/ROM access check gate + */ + memory_record_check *= (q_1 * q_m); /** * RAM Timestamp Consistency Check */ auto timestamp_delta = w_2_shift - w_2; auto RAM_timestamp_check_identity = (index_delta * FF(-1) + FF(1)) * timestamp_delta - w_3; + RAM_timestamp_check_identity *= (q_1 * q_4); /** * The complete RAM/ROM memory identity */ - auto 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); + auto memory_identity = ROM_consistency_check_identity; + memory_identity += RAM_timestamp_check_identity; + memory_identity += memory_record_check; + memory_identity += RAM_consistency_check_identity; + + expected_full_length_univariates[0] = memory_identity + non_native_field_identity + limb_accumulator_identity; - auto expected_evals = memory_identity + non_native_field_identity + limb_accumulator_identity; - expected_evals *= q_aux; + expected_full_length_univariates[0] *= q_aux; + expected_full_length_univariates[1] *= q_aux; + expected_full_length_univariates[2] *= q_aux; + expected_full_length_univariates[3] *= q_aux; + expected_full_length_univariates[4] *= q_aux; + expected_full_length_univariates[5] *= q_aux; - validate_evaluations(expected_evals, relation, extended_edges, relation_parameters); + validate_evaluations(expected_full_length_univariates, relation, extended_edges, relation_parameters); }; } // namespace proof_system::honk_relation_tests diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp index 8968ee1260..399b943870 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp @@ -1,7 +1,7 @@ #pragma once #include "barretenberg/common/serialize.hpp" #include -#include "barretenberg/honk/sumcheck/relations/relation.hpp" +#include "barretenberg/honk/sumcheck/relations/relation_parameters.hpp" #include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/grand_product_delta.hpp" #include "barretenberg/common/throw_or_abort.hpp" @@ -18,29 +18,31 @@ namespace proof_system::honk::sumcheck { -template class... Relations> class Sumcheck { +template class Sumcheck { public: using FF = typename Flavor::FF; - using FoldedPolynomials = typename Flavor::FoldedPolynomials; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + using PartiallyEvaluatedMultivariates = typename Flavor::PartiallyEvaluatedMultivariates; + using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; - static constexpr size_t MAX_RELATION_LENGTH = std::max({ Relations::RELATION_LENGTH... }); + static constexpr size_t MAX_RELATION_LENGTH = Flavor::MAX_RELATION_LENGTH; static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; Transcript& transcript; const size_t multivariate_n; const size_t multivariate_d; - SumcheckRound round; + SumcheckRound round; /** * - * @brief (folded_polynomials) Suppose the Honk polynomials (multilinear in d variables) are called P_1, ..., P_N. + * @brief (partially_evaluated_polynomials) Suppose the Honk polynomials (multilinear in d variables) are called P_1, + ..., P_N. * At initialization, * we think of these as lying in a two-dimensional array, where each column records the value of one P_i on H^d. - * After the first round, the array will be updated ('folded'), so that the first n/2 rows will represent the + * After the first round, the array will be updated (partially evaluated), so that the first n/2 rows will represent + the * evaluations P_i(u0, X1, ..., X_{d-1}) as a low-degree extension on H^{d-1}. In reality, we elude copying all - * of the polynomial-defining data by only populating folded_multivariates after the first round. I.e.: + * of the polynomial-defining data by only populating partially_evaluated_polynomials after the first round. I.e.: We imagine all of the defining polynomial data in a matrix like this: | P_1 | P_2 | P_3 | P_4 | ... | P_N | N = number of multivariatesk @@ -54,7 +56,7 @@ template class... Relations \-| * | * | * | * | ... | * | vertex n-1 m = n/2 * - Each group consists of N edges |, and our construction of univariates and folding + Each group consists of N edges |, and our construction of univariates and partial evaluation * operations naturally operate on these groups of edges @@ -62,30 +64,26 @@ template class... Relations * NOTE: With ~40 columns, prob only want to allocate 256 EdgeGroup's at once to keep stack under 1MB? * TODO(#224)(Cody): might want to just do C-style multidimensional array? for guaranteed adjacency? */ - FoldedPolynomials folded_polynomials; + PartiallyEvaluatedMultivariates partially_evaluated_polynomials; // prover instantiates sumcheck with circuit size and a prover transcript Sumcheck(size_t multivariate_n, ProverTranscript& transcript) : transcript(transcript) , multivariate_n(multivariate_n) , multivariate_d(numeric::get_msb(multivariate_n)) - , round(multivariate_n, std::tuple(Relations()...)) - { - for (auto& polynomial : folded_polynomials) { - polynomial.resize(multivariate_n >> 1); - } - }; + , round(multivariate_n) + , partially_evaluated_polynomials(multivariate_n){}; // verifier instantiates sumcheck with circuit size and a verifier transcript explicit Sumcheck(size_t multivariate_n, VerifierTranscript& transcript) : transcript(transcript) , multivariate_n(multivariate_n) , multivariate_d(numeric::get_msb(multivariate_n)) - , round(std::tuple(Relations()...)){}; + , round(){}; /** - * @brief Compute univariate restriction place in transcript, generate challenge, fold,... repeat until final round, - * then compute multivariate evaluations and place in transcript. + * @brief Compute univariate restriction place in transcript, generate challenge, partially evaluate,... repeat + * until final round, then compute multivariate evaluations and place in transcript. * * @details */ @@ -100,32 +98,34 @@ template class... Relations multivariate_challenge.reserve(multivariate_d); // First round - // This populates folded_polynomials. + // This populates partially_evaluated_polynomials. auto round_univariate = round.compute_univariate(full_polynomials, relation_parameters, pow_univariate, alpha); transcript.send_to_verifier("Sumcheck:univariate_0", round_univariate); FF round_challenge = transcript.get_challenge("Sumcheck:u_0"); multivariate_challenge.emplace_back(round_challenge); - fold(full_polynomials, multivariate_n, round_challenge); + partially_evaluate(full_polynomials, multivariate_n, round_challenge); pow_univariate.partially_evaluate(round_challenge); - round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe fold should do this and release memory? + round.round_size = + round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and release memory? // All but final round - // We operate on folded_polynomials in place. + // We operate on partially_evaluated_polynomials in place. for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { // Write the round univariate to the transcript - round_univariate = round.compute_univariate(folded_polynomials, relation_parameters, pow_univariate, alpha); + round_univariate = + round.compute_univariate(partially_evaluated_polynomials, relation_parameters, pow_univariate, alpha); transcript.send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); FF round_challenge = transcript.get_challenge("Sumcheck:u_" + std::to_string(round_idx)); multivariate_challenge.emplace_back(round_challenge); - fold(folded_polynomials, round.round_size, round_challenge); + partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); pow_univariate.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; } - // Final round: Extract multivariate evaluations from folded_polynomials and add to transcript - PurportedEvaluations multivariate_evaluations; + // Final round: Extract multivariate evaluations from partially_evaluated_polynomials and add to transcript + ClaimedEvaluations multivariate_evaluations; size_t evaluation_idx = 0; - for (auto& polynomial : folded_polynomials) { // TODO(#391) zip + for (auto& polynomial : partially_evaluated_polynomials) { // TODO(#391) zip multivariate_evaluations[evaluation_idx] = polynomial[0]; ++evaluation_idx; } @@ -178,7 +178,7 @@ template class... Relations } // Final round - PurportedEvaluations purported_evaluations = + ClaimedEvaluations purported_evaluations = transcript.template receive_from_prover>("Sumcheck:evaluations"); FF full_honk_relation_purported_value = round.compute_full_honk_relation_purported_value( @@ -191,14 +191,12 @@ template class... Relations return SumcheckOutput{ multivariate_challenge, purported_evaluations }; }; - // TODO(#224)(Cody): Rename. fold is not descriptive, and it's already in use in the Gemini context. - // Probably just call it partial_evaluation? /** * @brief Evaluate at the round challenge and prepare class for next round. * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, * i.e., what happens in just one column of our two-dimensional array): * - * groups vertex terms collected vertex terms groups after folding + * groups vertex terms collected vertex terms groups after partial evaluation * g0 -- v0 (1-X0)(1-X1)(1-X2) --- (v0(1-X0) + v1 X0) (1-X1)(1-X2) ---- (v0(1-u0) + v1 u0) (1-X1)(1-X2) * \- v1 X0 (1-X1)(1-X2) --/ --- (v2(1-u0) + v3 u0) X1 (1-X2) * g1 -- v2 (1-X0) X1 (1-X2) --- (v2(1-X0) + v3 X0) X1 (1-X2)-/ -- (v4(1-u0) + v5 u0) (1-X1) X2 @@ -210,12 +208,12 @@ template class... Relations * * @param challenge */ - void fold(auto& polynomials, size_t round_size, FF round_challenge) + void partially_evaluate(auto& polynomials, size_t round_size, FF round_challenge) { - // after the first round, operate in place on folded_polynomials + // after the first round, operate in place on partially_evaluated_polynomials for (size_t j = 0; j < polynomials.size(); ++j) { for (size_t i = 0; i < round_size; i += 2) { - folded_polynomials[j][i >> 1] = + partially_evaluated_polynomials[j][i >> 1] = polynomials[j][i] + round_challenge * (polynomials[j][i + 1] - polynomials[j][i]); } } diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp index 356ad662b9..c7dee556ca 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp @@ -3,8 +3,7 @@ #include "barretenberg/honk/flavor/standard.hpp" #include "barretenberg/transcript/transcript_wrappers.hpp" #include "relations/arithmetic_relation.hpp" -#include "relations/grand_product_computation_relation.hpp" -#include "relations/grand_product_initialization_relation.hpp" +#include "relations/permutation_relation.hpp" #include "barretenberg/transcript/manifest.hpp" #include #include @@ -12,6 +11,13 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include #include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/honk/composer/standard_honk_composer.hpp" +#include "barretenberg/honk/composer/ultra_honk_composer.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" #include #include @@ -138,11 +144,7 @@ TEST(Sumcheck, PolynomialNormalization) auto transcript = ProverTranscript::init_empty(); - auto sumcheck = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, transcript); + auto sumcheck = Sumcheck>(multivariate_n, transcript); auto [multivariate_challenge, evaluations] = sumcheck.execute_prover(full_polynomials, {}); @@ -178,7 +180,7 @@ TEST(Sumcheck, PolynomialNormalization) l_2 * full_polynomials[i][2] + l_3 * full_polynomials[i][3] + l_4 * full_polynomials[i][4] + l_5 * full_polynomials[i][5] + l_6 * full_polynomials[i][6] + l_7 * full_polynomials[i][7]; - EXPECT_EQ(hand_computed_value, sumcheck.folded_polynomials[i][0]); + EXPECT_EQ(hand_computed_value, sumcheck.partially_evaluated_polynomials[i][0]); } } @@ -238,11 +240,7 @@ TEST(Sumcheck, Prover) auto transcript = ProverTranscript::init_empty(); - auto sumcheck = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, transcript); + auto sumcheck = Sumcheck>(multivariate_n, transcript); auto [multivariate_challenge, evaluations] = sumcheck.execute_prover(full_polynomials, {}); FF u_0 = multivariate_challenge[0]; @@ -319,21 +317,13 @@ TEST(Sumcheck, ProverAndVerifier) auto prover_transcript = ProverTranscript::init_empty(); - auto sumcheck_prover = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, prover_transcript); + auto sumcheck_prover = Sumcheck>(multivariate_n, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(full_polynomials, relation_parameters); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - auto sumcheck_verifier = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, verifier_transcript); + auto sumcheck_verifier = Sumcheck>(multivariate_n, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); @@ -401,21 +391,13 @@ TEST(Sumcheck, ProverAndVerifierLonger) auto prover_transcript = ProverTranscript::init_empty(); - auto sumcheck_prover = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, prover_transcript); + auto sumcheck_prover = Sumcheck>(multivariate_n, prover_transcript); auto prover_output = sumcheck_prover.execute_prover(full_polynomials, relation_parameters); auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); - auto sumcheck_verifier = Sumcheck, - ArithmeticRelation, - GrandProductComputationRelation, - GrandProductInitializationRelation>(multivariate_n, verifier_transcript); + auto sumcheck_verifier = Sumcheck>(multivariate_n, verifier_transcript); std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); @@ -426,4 +408,304 @@ TEST(Sumcheck, ProverAndVerifierLonger) run_test(/* expect_verified=*/false); } +/** + * @brief Test the Standard Sumcheck Prover and Verifier for a real circuit + * + */ +TEST(Sumcheck, RealCircuitStandard) +{ + using Flavor = honk::flavor::Standard; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and a dummy circuit with a few gates + auto composer = StandardHonkComposer(); + fr a = fr::one(); + // Using the public variable to check that public_input_delta is computed and added to the relation correctly + uint32_t a_idx = composer.add_public_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); + composer.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); + } + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate beta and gamma + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters relation_parameters{ + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + }; + + // Compute grand product polynomial + polynomial z_permutation = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.z_perm = z_permutation; + prover_polynomials.z_perm_shift = z_permutation.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + auto prover_transcript = ProverTranscript::init_empty(); + + auto sumcheck_prover = Sumcheck>(prover.key->circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto sumcheck_verifier = Sumcheck>(prover.key->circuit_size, verifier_transcript); + + std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + ASSERT_TRUE(verifier_output.has_value()); +} + +/** + * @brief Test the Ultra Sumcheck Prover and Verifier for a real circuit + * + */ +TEST(Sumcheck, RealCircuitUltra) +{ + using Flavor = honk::flavor::Ultra; + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + + // Create a composer and a dummy circuit with a few gates + auto composer = UltraHonkComposer(); + fr a = fr::one(); + + // Add some basic add gates + uint32_t a_idx = composer.add_variable(a); + fr b = fr::one(); + fr c = a + b; + fr d = a + c; + uint32_t b_idx = composer.add_variable(b); + uint32_t c_idx = composer.add_variable(c); + uint32_t d_idx = composer.add_variable(d); + for (size_t i = 0; i < 16; i++) { + composer.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); + composer.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 }); + } + + // Add a big add gate with use of next row to test q_arith = 2 + fr e = a + b + c + d; + uint32_t e_idx = composer.add_variable(e); + + uint32_t zero_idx = composer.get_zero_idx(); + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row + composer.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false); + + // Add some lookup gates (related to pedersen hashing) + barretenberg::fr pedersen_input_value = fr::random_element(); + const fr input_hi = uint256_t(pedersen_input_value).slice(126, 256); + const fr input_lo = uint256_t(pedersen_input_value).slice(0, 126); + const auto input_hi_index = composer.add_variable(input_hi); + const auto input_lo_index = composer.add_variable(input_lo); + + const auto sequence_data_hi = plookup::get_lookup_accumulators(plookup::MultiTableId::PEDERSEN_LEFT_HI, input_hi); + const auto sequence_data_lo = plookup::get_lookup_accumulators(plookup::MultiTableId::PEDERSEN_LEFT_LO, input_lo); + + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + composer.create_gates_from_plookup_accumulators( + plookup::MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + + // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) + a_idx = composer.add_variable(FF(0)); + b_idx = composer.add_variable(FF(1)); + c_idx = composer.add_variable(FF(2)); + d_idx = composer.add_variable(FF(3)); + composer.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + // Add an elliptic curve addition gate + grumpkin::g1::affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + grumpkin::g1::affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + + grumpkin::fq beta_scalar = grumpkin::fq::cube_root_of_unity(); + grumpkin::g1::affine_element p2_endo = p2; + p2_endo.x *= beta_scalar; + + grumpkin::g1::affine_element p3(grumpkin::g1::element(p1) - grumpkin::g1::element(p2_endo)); + + uint32_t x1 = composer.add_variable(p1.x); + uint32_t y1 = composer.add_variable(p1.y); + uint32_t x2 = composer.add_variable(p2.x); + uint32_t y2 = composer.add_variable(p2.y); + uint32_t x3 = composer.add_variable(p3.x); + uint32_t y3 = composer.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, beta_scalar, -1 }; + composer.create_ecc_add_gate(gate); + + // Add some RAM gates + uint32_t ram_values[8]{ + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + composer.add_variable(fr::random_element()), composer.add_variable(fr::random_element()), + }; + + size_t ram_id = composer.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + composer.init_RAM_element(ram_id, i, ram_values[i]); + } + + a_idx = composer.read_RAM_array(ram_id, composer.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + b_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + c_idx = composer.read_RAM_array(ram_id, composer.add_variable(1)); + + composer.write_RAM_array(ram_id, composer.add_variable(4), composer.add_variable(500)); + d_idx = composer.read_RAM_array(ram_id, composer.add_variable(4)); + + EXPECT_EQ(composer.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = composer.get_variable(a_idx) + composer.get_variable(b_idx) + composer.get_variable(c_idx) + + composer.get_variable(d_idx); + e_idx = composer.add_variable(e_value); + + composer.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); + composer.create_big_add_gate( + { + composer.get_zero_idx(), + composer.get_zero_idx(), + composer.get_zero_idx(), + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + + // Create a prover (it will compute proving key and witness) + auto prover = composer.create_prover(); + + // Generate eta, beta and gamma + fr eta = fr::random_element(); + fr beta = fr::random_element(); + fr gamma = fr::random_element(); + + // Compute public input delta + const auto public_inputs = composer.circuit_constructor.get_public_inputs(); + auto public_input_delta = + honk::compute_public_input_delta(public_inputs, beta, gamma, prover.key->circuit_size); + auto lookup_grand_product_delta = + honk::compute_lookup_grand_product_delta(beta, gamma, prover.key->circuit_size); + + sumcheck::RelationParameters relation_parameters{ + .eta = eta, + .beta = beta, + .gamma = gamma, + .public_input_delta = public_input_delta, + .lookup_grand_product_delta = lookup_grand_product_delta, + }; + + // Compute sorted witness-table accumulator + prover.key->sorted_accum = prover_library::compute_sorted_list_accumulator(prover.key, eta); + + // Add RAM/ROM memory records to wire four + prover_library::add_plookup_memory_records_to_wire_4(prover.key, eta); + + // Compute grand product polynomial + prover.key->z_perm = prover_library::compute_permutation_grand_product(prover.key, beta, gamma); + + // Compute lookup grand product polynomial + prover.key->z_lookup = prover_library::compute_lookup_grand_product(prover.key, eta, beta, gamma); + + ProverPolynomials prover_polynomials; + + prover_polynomials.w_l = prover.key->w_l; + prover_polynomials.w_r = prover.key->w_r; + prover_polynomials.w_o = prover.key->w_o; + prover_polynomials.w_4 = prover.key->w_4; + prover_polynomials.w_l_shift = prover.key->w_l.shifted(); + prover_polynomials.w_r_shift = prover.key->w_r.shifted(); + prover_polynomials.w_o_shift = prover.key->w_o.shifted(); + prover_polynomials.w_4_shift = prover.key->w_4.shifted(); + prover_polynomials.sorted_accum = prover.key->sorted_accum; + prover_polynomials.sorted_accum_shift = prover.key->sorted_accum.shifted(); + prover_polynomials.table_1 = prover.key->table_1; + prover_polynomials.table_2 = prover.key->table_2; + prover_polynomials.table_3 = prover.key->table_3; + prover_polynomials.table_4 = prover.key->table_4; + prover_polynomials.table_1_shift = prover.key->table_1.shifted(); + prover_polynomials.table_2_shift = prover.key->table_2.shifted(); + prover_polynomials.table_3_shift = prover.key->table_3.shifted(); + prover_polynomials.table_4_shift = prover.key->table_4.shifted(); + prover_polynomials.z_perm = prover.key->z_perm; + prover_polynomials.z_perm_shift = prover.key->z_perm.shifted(); + prover_polynomials.z_lookup = prover.key->z_lookup; + prover_polynomials.z_lookup_shift = prover.key->z_lookup.shifted(); + prover_polynomials.q_m = prover.key->q_m; + prover_polynomials.q_l = prover.key->q_l; + prover_polynomials.q_r = prover.key->q_r; + prover_polynomials.q_o = prover.key->q_o; + prover_polynomials.q_c = prover.key->q_c; + prover_polynomials.q_4 = prover.key->q_4; + prover_polynomials.q_arith = prover.key->q_arith; + prover_polynomials.q_sort = prover.key->q_sort; + prover_polynomials.q_elliptic = prover.key->q_elliptic; + prover_polynomials.q_aux = prover.key->q_aux; + prover_polynomials.q_lookup = prover.key->q_lookup; + prover_polynomials.sigma_1 = prover.key->sigma_1; + prover_polynomials.sigma_2 = prover.key->sigma_2; + prover_polynomials.sigma_3 = prover.key->sigma_3; + prover_polynomials.sigma_4 = prover.key->sigma_4; + prover_polynomials.id_1 = prover.key->id_1; + prover_polynomials.id_2 = prover.key->id_2; + prover_polynomials.id_3 = prover.key->id_3; + prover_polynomials.id_4 = prover.key->id_4; + prover_polynomials.lagrange_first = prover.key->lagrange_first; + prover_polynomials.lagrange_last = prover.key->lagrange_last; + + auto prover_transcript = ProverTranscript::init_empty(); + + auto sumcheck_prover = Sumcheck>(prover.key->circuit_size, prover_transcript); + + auto prover_output = sumcheck_prover.execute_prover(prover_polynomials, relation_parameters); + + auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + + auto sumcheck_verifier = Sumcheck>(prover.key->circuit_size, verifier_transcript); + + std::optional verifier_output = sumcheck_verifier.execute_verifier(relation_parameters); + + ASSERT_TRUE(verifier_output.has_value()); +} + } // namespace test_sumcheck_round diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_output.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_output.hpp index cfe3dfb09b..c83d85c15a 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_output.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_output.hpp @@ -10,16 +10,16 @@ namespace proof_system::honk::sumcheck { */ template struct SumcheckOutput { using FF = typename Flavor::FF; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; // u = (u_0, ..., u_{d-1}) std::vector challenge_point; // Evaluations in `u` of the polynomials used in Sumcheck - PurportedEvaluations purported_evaluations; + ClaimedEvaluations purported_evaluations; SumcheckOutput() : purported_evaluations(std::array()){}; - SumcheckOutput(const std::vector& _challenge_point, const PurportedEvaluations& _purported_evaluations) + SumcheckOutput(const std::vector& _challenge_point, const ClaimedEvaluations& _purported_evaluations) : challenge_point(_challenge_point) , purported_evaluations(_purported_evaluations){}; diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp index 0aea53047f..a90d422e51 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.hpp @@ -6,8 +6,9 @@ #include "polynomials/barycentric_data.hpp" #include "polynomials/univariate.hpp" #include "polynomials/pow.hpp" -#include "relations/relation.hpp" -#include "barretenberg/honk/flavor/ultra.hpp" // WORKTOO +#include "relations/relation_parameters.hpp" +#include "barretenberg/honk/flavor/ultra.hpp" +#include namespace proof_system::honk::sumcheck { @@ -53,100 +54,67 @@ namespace proof_system::honk::sumcheck { @todo TODO(#390): Template only on Flavor? Is it useful to have these decoupled? */ -template class... Relations> class SumcheckRound { +template class SumcheckRound { + + using Relations = typename Flavor::Relations; + using RelationUnivariates = typename Flavor::RelationUnivariates; + using RelationEvaluations = typename Flavor::RelationValues; public: using FF = typename Flavor::FF; template using ExtendedEdges = typename Flavor::template ExtendedEdges; - using PurportedEvaluations = typename Flavor::PurportedEvaluations; + using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; bool round_failed = false; size_t round_size; // a power of 2 - std::tuple...> relations; - static constexpr size_t NUM_RELATIONS = sizeof...(Relations); - static constexpr size_t MAX_RELATION_LENGTH = std::max({ Relations::RELATION_LENGTH... }); + Relations relations; + static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS; + static constexpr size_t MAX_RELATION_LENGTH = Flavor::MAX_RELATION_LENGTH; FF target_total_sum = 0; - // TODO(#224)(Cody): this barycentric stuff should be more built-in? - std::tuple::RELATION_LENGTH, MAX_RELATION_LENGTH>...> barycentric_utils; - std::tuple::RELATION_LENGTH>...> univariate_accumulators; - std::array relation_evaluations; + RelationUnivariates univariate_accumulators; + RelationEvaluations relation_evaluations; + ExtendedEdges extended_edges; - std::array, NUM_RELATIONS> extended_univariates; - // TODO(#224)(Cody): this should go away and we should use constexpr method to extend + // TODO(#224)(Cody): this should go away BarycentricData barycentric_2_to_max = BarycentricData(); // Prover constructor - SumcheckRound(size_t initial_round_size, auto&& relations) + SumcheckRound(size_t initial_round_size) : round_size(initial_round_size) - , relations(relations) - , barycentric_utils(BarycentricData::RELATION_LENGTH, MAX_RELATION_LENGTH>()...) - , univariate_accumulators(Univariate::RELATION_LENGTH>()...) - {} - - // Verifier constructor - explicit SumcheckRound(auto relations) - : relations(relations) - { - // FF's default constructor may not initialize to zero (e.g., barretenberg::fr), hence we can't rely on - // aggregate initialization of the evaluations array. - std::fill(relation_evaluations.begin(), relation_evaluations.end(), FF(0)); - }; - - /** - * @brief After computing the round univariate, it is necessary to zero-out the accumulators used to compute it. - */ - template void reset_accumulators() { - auto& univariate = std::get(univariate_accumulators); - std::fill(univariate.evaluations.begin(), univariate.evaluations.end(), FF(0)); - - if constexpr (idx + 1 < NUM_RELATIONS) { - reset_accumulators(); - } - }; - // IMPROVEMENT(Cody): This is kind of ugly. There should be a one-liner with folding - // or std::apply or something. + // Initialize univariate accumulators to 0 + zero_univariates(univariate_accumulators); + } - /** - * @brief Given a tuple t = (t_0, t_1, ..., t_{NUM_RELATIONS-1}) and a challenge α, - * modify the tuple in place to (t_0, αt_1, ..., α^{NUM_RELATIONS-1}t_{NUM_RELATIONS-1}). - */ - template void scale_tuple(auto& tuple, FF challenge, FF running_challenge) - { - std::get(tuple) *= running_challenge; - running_challenge *= challenge; - if constexpr (idx + 1 < NUM_RELATIONS) { - scale_tuple(tuple, challenge, running_challenge); - } - }; + // Verifier constructor + explicit SumcheckRound() { zero_elements(relation_evaluations); }; /** * @brief Given a tuple t = (t_0, t_1, ..., t_{NUM_RELATIONS-1}) and a challenge α, * return t_0 + αt_1 + ... + α^{NUM_RELATIONS-1}t_{NUM_RELATIONS-1}). * - * @tparam T : In practice, this is an FF or a Univariate. + * @tparam T : In practice, this is a Univariate. */ - template T batch_over_relations(FF challenge) + Univariate batch_over_relations(FF challenge) { FF running_challenge = 1; - scale_tuple<>(univariate_accumulators, challenge, running_challenge); - extend_univariate_accumulators<>(); - auto result = T(); - for (size_t i = 0; i < NUM_RELATIONS; ++i) { - result += extended_univariates[i]; - } + scale_univariates(univariate_accumulators, challenge, running_challenge); + + auto result = Univariate(); + extend_and_batch_univariates(univariate_accumulators, result); + + // Reset all univariate accumulators to 0 before beginning accumulation in the next round + zero_univariates(univariate_accumulators); return result; } /** - * @brief Evaluate some relations by evaluating each edge in the edge group at - * Univariate::length-many values. Store each value separately in the corresponding - * entry of relation_evals. + * @brief Extend each edge in the edge group at to max-relation-length-many values. * * @details Should only be called externally with relation_idx equal to 0. * In practice, multivariates is one of ProverPolynomials or FoldedPolynomials. @@ -162,23 +130,6 @@ template class... Relations> class SumcheckRo } } - /** - * @brief After executing each widget on each edge, producing a tuple of univariates of differing lenghths, - * extend all univariates to the max of the lenghths required by the largest relation. - * - * @tparam relation_idx - */ - template void extend_univariate_accumulators() - { - extended_univariates[relation_idx] = - std::get(barycentric_utils).extend(std::get(univariate_accumulators)); - - // Repeat for the next relation. - if constexpr (relation_idx + 1 < NUM_RELATIONS) { - extend_univariate_accumulators(); - } - } - /** * @brief Return the evaluations of the univariate restriction (S_l(X_l) in the thesis) at num_multivariates-many * values. Most likely this will end up being S_l(0), ... , S_l(t-1) where t is around 12. At the end, reset all @@ -203,11 +154,7 @@ template class... Relations> class SumcheckRo pow_challenge *= pow_univariate.zeta_pow_sqr; } - auto result = batch_over_relations>(alpha); - - reset_accumulators<>(); - - return result; + return batch_over_relations(alpha); } /** @@ -218,20 +165,17 @@ template class... Relations> class SumcheckRo * together, with appropriate scaling factors, produces the expected value of the full Honk relation. This value is * checked against the final value of the target total sum, defined as sigma_d. */ - FF compute_full_honk_relation_purported_value(PurportedEvaluations purported_evaluations, + FF compute_full_honk_relation_purported_value(ClaimedEvaluations purported_evaluations, const RelationParameters& relation_parameters, const PowUnivariate& pow_univariate, const FF alpha) { accumulate_relation_evaluations<>(purported_evaluations, relation_parameters); - // IMPROVEMENT(Cody): Reuse functions from univariate_accumulators batching? - FF running_challenge = 1; - FF output = 0; - for (auto& evals : relation_evaluations) { - output += evals * running_challenge; - running_challenge *= alpha; - } + auto running_challenge = FF(1); + auto output = FF(0); + scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output); + output *= pow_univariate.partial_evaluation_constant; return output; @@ -316,16 +260,146 @@ template class... Relations> class SumcheckRo */ template // TODO(#224)(Cody): Input should be an array? - void accumulate_relation_evaluations(PurportedEvaluations purported_evaluations, + void accumulate_relation_evaluations(ClaimedEvaluations purported_evaluations, const RelationParameters& relation_parameters) { std::get(relations).add_full_relation_value_contribution( - relation_evaluations[relation_idx], purported_evaluations, relation_parameters); + std::get(relation_evaluations), purported_evaluations, relation_parameters); // Repeat for the next relation. if constexpr (relation_idx + 1 < NUM_RELATIONS) { accumulate_relation_evaluations(purported_evaluations, relation_parameters); } } + + public: + /** + * Utility methods for tuple of tuples of Univariates + */ + + /** + * @brief Extend Univariates to specified size then sum them + * + * @tparam extended_size Size after extension + * @param tuple A tuple of tuples of Univariates + * @param result A Univariate of length extended_size + */ + template + static void extend_and_batch_univariates(auto& tuple, Univariate& result) + { + auto extend_and_sum = [&](auto& element) { + using Element = std::remove_reference_t; + // TODO(#224)(Cody): this barycentric stuff should be more built-in? + BarycentricData barycentric_utils; + result += barycentric_utils.extend(element); + }; + apply_to_tuple_of_tuples(tuple, extend_and_sum); + } + + /** + * @brief Set all coefficients of Univariates to zero + * + * @details After computing the round univariate, it is necessary to zero-out the accumulators used to compute it. + */ + static void zero_univariates(auto& tuple) + { + auto set_to_zero = [](auto& element) { + std::fill(element.evaluations.begin(), element.evaluations.end(), FF(0)); + }; + apply_to_tuple_of_tuples(tuple, set_to_zero); + } + + /** + * @brief Scale Univaraites by consecutive powers of the provided challenge + * + * @param tuple Tuple of tuples of Univariates + * @param challenge + * @param current_scalar power of the challenge + */ + static void scale_univariates(auto& tuple, const FF& challenge, FF current_scalar) + { + auto scale_by_consecutive_powers_of_challenge = [&](auto& element) { + element *= current_scalar; + current_scalar *= challenge; + }; + apply_to_tuple_of_tuples(tuple, scale_by_consecutive_powers_of_challenge); + } + + /** + * @brief General purpose method for applying an operation to a tuple of tuples of Univariates + * + * @tparam Operation Any operation valid on Univariates + * @tparam outer_idx Index into the outer tuple + * @tparam inner_idx Index into the inner tuple + * @param tuple A Tuple of tuples of Univariates + * @param operation Operation to apply to Univariates + */ + template + static void apply_to_tuple_of_tuples(auto& tuple, Operation&& operation) + { + auto& inner_tuple = std::get(tuple); + auto& univariate = std::get(inner_tuple); + + // Apply the specified operation to each Univariate + std::invoke(std::forward(operation), univariate); + + const size_t inner_size = std::tuple_size_v(tuple))>>; + const size_t outer_size = std::tuple_size_v>; + + // Recurse over inner and outer tuples + if constexpr (inner_idx + 1 < inner_size) { + apply_to_tuple_of_tuples(tuple, std::forward(operation)); + } else if constexpr (outer_idx + 1 < outer_size) { + apply_to_tuple_of_tuples(tuple, std::forward(operation)); + } + } + + /** + * Utility methods for tuple of arrays + */ + + /** + * @brief Set each element in a tuple of arrays to zero. + * @details FF's default constructor may not initialize to zero (e.g., barretenberg::fr), hence we can't rely on + * aggregate initialization of the evaluations array. + */ + template static void zero_elements(auto& tuple) + { + auto set_to_zero = [](auto& element) { std::fill(element.begin(), element.end(), FF(0)); }; + apply_to_tuple_of_arrays(set_to_zero, tuple); + }; + + /** + * @brief Scale elements by consecutive powers of the challenge then sum + * @param result Batched result + */ + static void scale_and_batch_elements(auto& tuple, const FF& challenge, FF current_scalar, FF& result) + { + auto scale_by_challenge_and_accumulate = [&](auto& element) { + for (auto& entry : element) { + result += entry * current_scalar; + current_scalar *= challenge; + } + }; + apply_to_tuple_of_arrays(scale_by_challenge_and_accumulate, tuple); + } + + /** + * @brief General purpose method for applying a tuple of arrays (of FFs) + * + * @tparam Operation Any operation valid on elements of the inner arrays (FFs) + * @param tuple Tuple of arrays (of FFs) + */ + template + static void apply_to_tuple_of_arrays(Operation&& operation, std::tuple& tuple) + { + auto& element = std::get(tuple); + + std::invoke(std::forward(operation), element); + + if constexpr (idx + 1 < sizeof...(Ts)) { + apply_to_tuple_of_arrays(operation, tuple); + } + } }; } // namespace proof_system::honk::sumcheck diff --git a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp index 97fefa6a48..c5e7260be4 100644 --- a/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp +++ b/cpp/src/barretenberg/honk/sumcheck/sumcheck_round.test.cpp @@ -1,7 +1,4 @@ #include "sumcheck_round.hpp" -#include "relations/arithmetic_relation.hpp" -#include "relations/grand_product_computation_relation.hpp" -#include "relations/grand_product_initialization_relation.hpp" #include "polynomials/univariate.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/numeric/random/engine.hpp" @@ -25,53 +22,13 @@ using namespace proof_system::honk::sumcheck; using Flavor = flavor::Standard; using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; -using PurportedEvaluations = typename Flavor::PurportedEvaluations; +using ClaimedEvaluations = typename Flavor::ClaimedEvaluations; const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; const size_t max_relation_length = 5; const size_t input_polynomial_length = 2; namespace test_sumcheck_round { -template -void construct_full_polynomials(ProverPolynomials& full_polynomials, - std::array& w_l, - std::array& w_r, - std::array& w_o, - std::array& z_perm, - std::array& z_perm_shift, - std::array& q_m, - std::array& q_l, - std::array& q_r, - std::array& q_o, - std::array& q_c, - std::array& sigma_1, - std::array& sigma_2, - std::array& sigma_3, - std::array& id_1, - std::array& id_2, - std::array& id_3, - std::array& lagrange_first, - std::array& lagrange_last) -{ - full_polynomials.w_l = w_l; - full_polynomials.w_r = w_r; - full_polynomials.w_o = w_o; - full_polynomials.z_perm = z_perm; - full_polynomials.z_perm_shift = z_perm_shift; - full_polynomials.q_m = q_m; - full_polynomials.q_l = q_l; - full_polynomials.q_r = q_r; - full_polynomials.q_o = q_o; - full_polynomials.q_c = q_c; - full_polynomials.sigma_1 = sigma_1; - full_polynomials.sigma_2 = sigma_2; - full_polynomials.sigma_3 = sigma_3; - full_polynomials.id_1 = id_1; - full_polynomials.id_2 = id_2; - full_polynomials.id_3 = id_3; - full_polynomials.lagrange_first = lagrange_first; - full_polynomials.lagrange_last = lagrange_last; -} // The below two methods are used in the test ComputeUnivariateProver static Univariate compute_round_univariate( @@ -80,51 +37,29 @@ static Univariate compute_round_univariate( const FF alpha) { size_t round_size = 1; - auto relations = std::tuple( - ArithmeticRelation(), GrandProductComputationRelation(), GrandProductInitializationRelation()); // Improvement(Cody): This is ugly? Maye supply some/all of this data through "flavor" class? - auto round = - SumcheckRound( - round_size, relations); - auto w_l = input_polynomials[0]; - auto w_r = input_polynomials[1]; - auto w_o = input_polynomials[2]; - auto z_perm = input_polynomials[3]; - auto z_perm_shift = input_polynomials[4]; - auto q_m = input_polynomials[5]; - auto q_l = input_polynomials[6]; - auto q_r = input_polynomials[7]; - auto q_o = input_polynomials[8]; - auto q_c = input_polynomials[9]; - auto sigma_1 = input_polynomials[10]; - auto sigma_2 = input_polynomials[11]; - auto sigma_3 = input_polynomials[12]; - auto id_1 = input_polynomials[13]; - auto id_2 = input_polynomials[14]; - auto id_3 = input_polynomials[15]; - auto lagrange_first = input_polynomials[16]; - auto lagrange_last = input_polynomials[17]; + auto round = SumcheckRound(round_size); ProverPolynomials full_polynomials; - construct_full_polynomials(full_polynomials, - w_l, - w_r, - w_o, - z_perm, - z_perm_shift, - q_m, - q_l, - q_r, - q_o, - q_c, - sigma_1, - sigma_2, - sigma_3, - id_1, - id_2, - id_3, - lagrange_first, - lagrange_last); + full_polynomials.w_l = input_polynomials[0]; + full_polynomials.w_r = input_polynomials[1]; + full_polynomials.w_o = input_polynomials[2]; + full_polynomials.z_perm = input_polynomials[3]; + full_polynomials.z_perm_shift = input_polynomials[4]; + full_polynomials.q_m = input_polynomials[5]; + full_polynomials.q_l = input_polynomials[6]; + full_polynomials.q_r = input_polynomials[7]; + full_polynomials.q_o = input_polynomials[8]; + full_polynomials.q_c = input_polynomials[9]; + full_polynomials.sigma_1 = input_polynomials[10]; + full_polynomials.sigma_2 = input_polynomials[11]; + full_polynomials.sigma_3 = input_polynomials[12]; + full_polynomials.id_1 = input_polynomials[13]; + full_polynomials.id_2 = input_polynomials[14]; + full_polynomials.id_3 = input_polynomials[15]; + full_polynomials.lagrange_first = input_polynomials[16]; + full_polynomials.lagrange_last = input_polynomials[17]; + PowUnivariate pow_zeta(1); Univariate round_univariate = round.compute_univariate(full_polynomials, relation_parameters, pow_zeta, alpha); @@ -187,7 +122,7 @@ static FF compute_full_purported_value(std::array& input_va const RelationParameters& relation_parameters, const FF alpha) { - PurportedEvaluations purported_evaluations; + ClaimedEvaluations purported_evaluations; purported_evaluations.w_l = input_values[0]; purported_evaluations.w_r = input_values[1]; purported_evaluations.w_o = input_values[2]; @@ -206,11 +141,8 @@ static FF compute_full_purported_value(std::array& input_va purported_evaluations.id_3 = input_values[15]; purported_evaluations.lagrange_first = input_values[16]; purported_evaluations.lagrange_last = input_values[17]; - auto relations = std::tuple( - ArithmeticRelation(), GrandProductComputationRelation(), GrandProductInitializationRelation()); - auto round = - SumcheckRound( - relations); + + auto round = SumcheckRound(); PowUnivariate pow_univariate(1); FF full_purported_value = round.compute_full_honk_relation_purported_value( purported_evaluations, relation_parameters, pow_univariate, alpha); @@ -340,4 +272,93 @@ TEST(SumcheckRound, ComputeUnivariateVerifier) run_test(/* is_random_input=*/true); } +/** + * @brief Test utility functions for applying operations to tuple of tuple of Univariates + * + */ +TEST(SumcheckRound, TupleOfTuplesOfUnivariates) +{ + using Flavor = proof_system::honk::flavor::Standard; + using FF = typename Flavor::FF; + + // Define three linear univariates of different sizes + Univariate univariate_1({ 1, 2, 3 }); + Univariate univariate_2({ 2, 4 }); + Univariate univariate_3({ 3, 4, 5, 6, 7 }); + const size_t MAX_LENGTH = 5; + + // Instantiate some barycentric extension utility classes + auto barycentric_util_1 = BarycentricData(); + auto barycentric_util_2 = BarycentricData(); + auto barycentric_util_3 = BarycentricData(); + + // Construct a tuple of tuples of the form { {univariate_1}, {univariate_2, univariate_3} } + auto tuple_of_tuples = std::make_tuple(std::make_tuple(univariate_1), std::make_tuple(univariate_2, univariate_3)); + + // Use scale_univariate_accumulators to scale by challenge powers + FF challenge = 5; + FF running_challenge = 1; + SumcheckRound::scale_univariates(tuple_of_tuples, challenge, running_challenge); + + // Use extend_and_batch_univariates to extend to MAX_LENGTH then accumulate + auto result = Univariate(); + SumcheckRound::extend_and_batch_univariates(tuple_of_tuples, result); + + // Repeat the batching process manually + auto result_expected = barycentric_util_1.extend(univariate_1) * 1 + + barycentric_util_2.extend(univariate_2) * challenge + + barycentric_util_3.extend(univariate_3) * challenge * challenge; + + // Compare final batched univarites + EXPECT_EQ(result, result_expected); + + // Reinitialize univariate accumulators to zero + SumcheckRound::zero_univariates(tuple_of_tuples); + + // Check that reinitialization was successful + Univariate expected_1({ 0, 0, 0 }); + Univariate expected_2({ 0, 0 }); + Univariate expected_3({ 0, 0, 0, 0, 0 }); + EXPECT_EQ(std::get<0>(std::get<0>(tuple_of_tuples)), expected_1); + EXPECT_EQ(std::get<0>(std::get<1>(tuple_of_tuples)), expected_2); + EXPECT_EQ(std::get<1>(std::get<1>(tuple_of_tuples)), expected_3); +} + +/** + * @brief Test utility functions for applying operations to tuple of std::arrays of field elements + * + */ +TEST(SumcheckRound, TuplesOfEvaluationArrays) +{ + using Flavor = proof_system::honk::flavor::Standard; + using FF = typename Flavor::FF; + + // Define two arrays of arbitrary elements + std::array evaluations_1 = { 4 }; + std::array evaluations_2 = { 6, 2 }; + + // Construct a tuple + auto tuple_of_arrays = std::make_tuple(evaluations_1, evaluations_2); + + // Use scale_and_batch_elements to scale by challenge powers + FF challenge = 5; + FF running_challenge = 1; + FF result = 0; + SumcheckRound::scale_and_batch_elements(tuple_of_arrays, challenge, running_challenge, result); + + // Repeat the batching process manually + auto result_expected = + evaluations_1[0] * 1 + evaluations_2[0] * challenge + evaluations_2[1] * challenge * challenge; + + // Compare batched result + EXPECT_EQ(result, result_expected); + + // Reinitialize univariate accumulators to zero + SumcheckRound::zero_elements(tuple_of_arrays); + + EXPECT_EQ(std::get<0>(tuple_of_arrays)[0], 0); + EXPECT_EQ(std::get<1>(tuple_of_arrays)[0], 0); + EXPECT_EQ(std::get<1>(tuple_of_arrays)[1], 0); +} + } // namespace test_sumcheck_round diff --git a/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp b/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp index a79d11c4de..2a55efb057 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp +++ b/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp @@ -19,7 +19,7 @@ struct circuit_data { : num_gates(0) {} - std::shared_ptr srs; + std::shared_ptr srs; std::shared_ptr proving_key; std::shared_ptr verification_key; size_t num_gates; @@ -38,7 +38,7 @@ inline bool exists(std::string const& path) template circuit_data get_circuit_data(std::string const& name, std::string const& path_name, - std::shared_ptr const& srs, + std::shared_ptr const& srs, std::string const& key_path, bool compute, bool save, diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp index 6be88c9280..49cb0e319c 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp @@ -9,7 +9,7 @@ #include "barretenberg/common/mem.hpp" #include "barretenberg/common/container.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" -#include "barretenberg/srs/reference_string/pippenger_reference_string.hpp" +#include "barretenberg/srs/global_crs.hpp" #include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" #include "barretenberg/join_split_example/types.hpp" @@ -22,15 +22,12 @@ extern "C" { WASM_EXPORT void join_split__init_proving_key(bool mock) { - // We know that we don't actually need any CRS to create a proving key, so just feed in a nothing. - // Hacky, but, right now it needs *something*. - auto crs_factory = std::make_shared(); - init_proving_key(crs_factory, mock); + init_proving_key(barretenberg::srs::get_crs_factory(), mock); } // WASM_EXPORT void join_split__init_proving_key_from_buffer(uint8_t const* pk_buf) // { -// std::shared_ptr crs; +// std::shared_ptr crs; // plonk::proving_key_data pk_data; // read(pk_buf, pk_data); // init_proving_key(crs, std::move(pk_data)); @@ -58,9 +55,7 @@ WASM_EXPORT uint32_t join_split__get_new_proving_key_data(uint8_t** output) WASM_EXPORT void join_split__init_verification_key(void* pippenger, uint8_t const* g2x) { - auto crs_factory = std::make_unique( - reinterpret_cast(pippenger), g2x); - init_verification_key(std::move(crs_factory)); + init_verification_key(barretenberg::srs::get_crs_factory()); } // WASM_EXPORT void join_split__init_verification_key_from_buffer(uint8_t const* vk_buf, uint8_t const* g2x) diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.cpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.cpp index 037799660b..402ac96af5 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.cpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.cpp @@ -59,7 +59,7 @@ join_split_tx noop_tx() return tx; } -circuit_data get_circuit_data(std::shared_ptr const& srs, bool mock) +circuit_data get_circuit_data(std::shared_ptr const& srs, bool mock) { std::cerr << "Getting join-split circuit data..." << std::endl; diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.hpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.hpp index 6c01a5b144..05c7aa46d3 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.hpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/compute_circuit_data.hpp @@ -10,7 +10,7 @@ join_split_tx noop_tx(); using circuit_data = proofs::circuit_data; -circuit_data get_circuit_data(std::shared_ptr const& srs, bool mock = false); +circuit_data get_circuit_data(std::shared_ptr const& srs, bool mock = false); } // namespace join_split } // namespace proofs diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp index 056f8df2fc..b561ba5429 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp @@ -14,7 +14,7 @@ using namespace proof_system::plonk::stdlib::merkle_tree; static std::shared_ptr proving_key; static std::shared_ptr verification_key; -void init_proving_key(std::shared_ptr const& crs_factory, bool mock) +void init_proving_key(std::shared_ptr const& crs_factory, bool mock) { if (proving_key) { return; @@ -41,7 +41,7 @@ void release_proving_key() proving_key.reset(); } -void init_verification_key(std::unique_ptr&& crs_factory) +void init_verification_key(std::shared_ptr const& crs_factory) { if (!proving_key) { std::abort(); diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp index db529a7826..f836684aba 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp @@ -1,17 +1,17 @@ #pragma once #include "join_split_tx.hpp" -#include "barretenberg/srs/reference_string/mem_reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/join_split_example/types.hpp" namespace join_split_example { namespace proofs { namespace join_split { -void init_proving_key(std::shared_ptr const& crs_factory, bool mock); +void init_proving_key(std::shared_ptr const& crs_factory, bool mock); void release_proving_key(); -void init_verification_key(std::unique_ptr&& crs_factory); +void init_verification_key(std::shared_ptr const& crs_factory); Prover new_join_split_prover(join_split_tx const& tx, bool mock); diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp index 440b4a7af4..064b48fdf7 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp @@ -143,9 +143,9 @@ class join_split_tests : public ::testing::Test { static constexpr size_t ACCOUNT_INDEX = 14; static void SetUpTestCase() { - auto null_crs_factory = std::make_shared(); + auto null_crs_factory = std::make_shared(); init_proving_key(null_crs_factory, false); - auto crs_factory = std::make_unique("../srs_db/ignition"); + auto crs_factory = std::make_unique("../srs_db/ignition"); init_verification_key(std::move(crs_factory)); info("vk hash: ", get_verification_key()->sha256_hash()); } diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp index 0294983f7c..4544bf1a27 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp @@ -25,9 +25,9 @@ class join_split_js_parity_tests : public ::testing::Test { protected: static void SetUpTestCase() { - auto null_crs_factory = std::make_shared(); + auto null_crs_factory = std::make_shared(); init_proving_key(null_crs_factory, false); - auto crs_factory = std::make_unique("../srs_db/ignition"); + auto crs_factory = std::make_unique("../srs_db/ignition"); init_verification_key(std::move(crs_factory)); info("vk hash: ", get_verification_key()->sha256_hash()); } diff --git a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_tx.test.cpp b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_tx.test.cpp index 60a83dcafd..a671dc164b 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_tx.test.cpp +++ b/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_tx.test.cpp @@ -5,7 +5,6 @@ #include "barretenberg/common/streams.hpp" #include "barretenberg/crypto/schnorr/schnorr.hpp" #include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/srs/reference_string/pippenger_reference_string.hpp" #include "barretenberg/srs/io.hpp" #include diff --git a/cpp/src/barretenberg/join_split_example/proofs/verify.hpp b/cpp/src/barretenberg/join_split_example/proofs/verify.hpp index e87a3e0bee..4543522014 100644 --- a/cpp/src/barretenberg/join_split_example/proofs/verify.hpp +++ b/cpp/src/barretenberg/join_split_example/proofs/verify.hpp @@ -27,7 +27,7 @@ template struct verify_result { template inline bool pairing_check(plonk::stdlib::recursion::aggregation_state> aggregation_state, - std::shared_ptr const& srs) + std::shared_ptr const& srs) { g1::affine_element P[2]; P[0].x = barretenberg::fq(aggregation_state.P0.x.get_value().lo); diff --git a/cpp/src/barretenberg/plonk/composer/composer_base.cpp b/cpp/src/barretenberg/plonk/composer/composer_base.cpp index 12bfd4f18f..71fccb746f 100644 --- a/cpp/src/barretenberg/plonk/composer/composer_base.cpp +++ b/cpp/src/barretenberg/plonk/composer/composer_base.cpp @@ -257,7 +257,7 @@ std::shared_ptr ComposerBase::compute_proving_key_base(const Compos circuit_proving_key = std::make_shared(subgroup_size, public_inputs.size(), crs, composer_type); for (size_t i = 0; i < num_selectors; ++i) { - std::vector& selector_values = selectors[i]; + auto& selector_values = selectors[i]; const auto& properties = selector_properties[i]; ASSERT(num_gates == selector_values.size()); @@ -314,7 +314,8 @@ std::shared_ptr ComposerBase::compute_proving_key_base(const Compos * (2) sets the polynomial manifest using the data from proving key. */ std::shared_ptr ComposerBase::compute_verification_key_base( - std::shared_ptr const& proving_key, std::shared_ptr const& vrs) + std::shared_ptr const& proving_key, + std::shared_ptr const& vrs) { auto circuit_verification_key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); @@ -362,7 +363,6 @@ template void ComposerBase::compute_witness_base(const si if (computed_witness) { return; } - const size_t total_num_gates = std::max(minimum_circuit_size, num_gates + public_inputs.size()); const size_t subgroup_size = get_circuit_subgroup_size(total_num_gates + NUM_RESERVED_GATES); diff --git a/cpp/src/barretenberg/plonk/composer/composer_base.hpp b/cpp/src/barretenberg/plonk/composer/composer_base.hpp index a3e57bc383..29330b085f 100644 --- a/cpp/src/barretenberg/plonk/composer/composer_base.hpp +++ b/cpp/src/barretenberg/plonk/composer/composer_base.hpp @@ -1,10 +1,11 @@ #pragma once +#include "barretenberg/common/slab_allocator.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/proof_system/arithmetization/gate_data.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" #include "barretenberg/plonk/proof_system/types/prover_settings.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" namespace proof_system::plonk { static constexpr uint32_t DUMMY_TAG = 0; @@ -51,9 +52,10 @@ class ComposerBase { }; ComposerBase() - : ComposerBase(std::shared_ptr(new FileReferenceStringFactory("../srs_db/ignition"))) + : ComposerBase(std::shared_ptr( + new barretenberg::srs::factories::FileCrsFactory("../srs_db/ignition"))) {} - ComposerBase(std::shared_ptr const& crs_factory, + ComposerBase(std::shared_ptr const& crs_factory, size_t num_selectors = 0, size_t size_hint = 0, std::vector selector_properties = {}) @@ -73,7 +75,7 @@ class ComposerBase { size_t size_hint = 0, std::vector selector_properties = {}) : num_gates(0) - , crs_factory_(std::make_unique("../srs_db/ignition")) + , crs_factory_(std::make_unique("../srs_db/ignition")) , num_selectors(num_selectors) , selectors(num_selectors) , selector_properties(selector_properties) @@ -115,7 +117,8 @@ class ComposerBase { const size_t num_reserved_gates = NUM_RESERVED_GATES); // This needs to be static as it may be used only to compute the selector commitments. static std::shared_ptr compute_verification_key_base( - std::shared_ptr const& proving_key, std::shared_ptr const& vrs); + std::shared_ptr const& proving_key, + std::shared_ptr const& vrs); virtual std::shared_ptr compute_proving_key() = 0; virtual std::shared_ptr compute_verification_key() = 0; virtual void compute_witness() = 0; @@ -186,6 +189,19 @@ class ComposerBase { barretenberg::fr get_public_input(const uint32_t index) const { return get_variable(public_inputs[index]); } + uint32_t get_public_input_index(const uint32_t witness_index) const + { + uint32_t result = static_cast(-1); + for (size_t i = 0; i < public_inputs.size(); ++i) { + if (real_variable_index[public_inputs[i]] == real_variable_index[witness_index]) { + result = static_cast(i); + break; + } + } + ASSERT(result != static_cast(-1)); + return result; + } + std::vector get_public_inputs() const { std::vector result; @@ -293,10 +309,10 @@ class ComposerBase { public: size_t num_gates; - std::vector w_l; - std::vector w_r; - std::vector w_o; - std::vector w_4; + std::vector> w_l; + std::vector> w_r; + std::vector> w_o; + std::vector> w_4; std::vector public_inputs; std::vector variables; std::vector next_var_index; // index of next variable in equivalence class (=REAL_VARIABLE if you're last) @@ -316,9 +332,9 @@ class ComposerBase { bool computed_witness = false; - std::shared_ptr crs_factory_; + std::shared_ptr crs_factory_; size_t num_selectors; - std::vector> selectors; + std::vector>> selectors; /** * @brief Contains the properties of each selector: * + name diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.cpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.cpp index 54b11e71db..f97e9cf2c0 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.cpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.cpp @@ -44,7 +44,8 @@ void compute_monomial_and_coset_selector_forms(plonk::proving_key* circuit_provi * (2) sets the polynomial manifest using the data from proving key. */ std::shared_ptr compute_verification_key_common( - std::shared_ptr const& proving_key, std::shared_ptr const& vrs) + std::shared_ptr const& proving_key, + std::shared_ptr const& vrs) { auto circuit_verification_key = std::make_shared( proving_key->circuit_size, proving_key->num_public_inputs, vrs, proving_key->composer_type); diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp index c704608a3a..21d32b8ad8 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp @@ -25,6 +25,7 @@ void compute_monomial_and_coset_selector_forms(plonk::proving_key* key, * (2) sets the polynomial manifest using the data from proving key. */ std::shared_ptr compute_verification_key_common( - std::shared_ptr const& proving_key, std::shared_ptr const& vrs); + std::shared_ptr const& proving_key, + std::shared_ptr const& vrs); } // namespace proof_system::plonk diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/standard_plonk_composer_helper.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/standard_plonk_composer_helper.hpp index 3c54be288c..c4438399c1 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/standard_plonk_composer_helper.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/standard_plonk_composer_helper.hpp @@ -1,7 +1,7 @@ #pragma once #include "barretenberg/plonk/flavor/flavor.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" @@ -23,21 +23,21 @@ class StandardPlonkComposerHelper { std::shared_ptr circuit_verification_key; // TODO(#218)(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs // at all - std::shared_ptr crs_factory_; + std::shared_ptr crs_factory_; std::vector recursive_proof_public_input_indices; bool contains_recursive_proof = false; bool computed_witness = false; StandardPlonkComposerHelper() - : StandardPlonkComposerHelper(std::shared_ptr( - new proof_system::FileReferenceStringFactory("../srs_db/ignition"))) + : StandardPlonkComposerHelper(std::shared_ptr( + new barretenberg::srs::factories::FileCrsFactory("../srs_db/ignition"))) {} - StandardPlonkComposerHelper(std::shared_ptr crs_factory) + StandardPlonkComposerHelper(std::shared_ptr crs_factory) : crs_factory_(std::move(crs_factory)) {} - StandardPlonkComposerHelper(std::unique_ptr&& crs_factory) + StandardPlonkComposerHelper(std::unique_ptr&& crs_factory) : crs_factory_(std::move(crs_factory)) {} StandardPlonkComposerHelper(std::shared_ptr p_key, diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/turbo_plonk_composer_helper.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/turbo_plonk_composer_helper.hpp index de35b01e80..8695f60c0e 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/turbo_plonk_composer_helper.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/turbo_plonk_composer_helper.hpp @@ -3,7 +3,7 @@ #include "barretenberg/plonk/flavor/flavor.hpp" #include "barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp" #include "barretenberg/proof_system/composer/composer_helper_lib.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" @@ -22,21 +22,21 @@ class TurboPlonkComposerHelper { // TODO(#218)(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs // at all - std::shared_ptr crs_factory_; + std::shared_ptr crs_factory_; std::vector recursive_proof_public_input_indices; bool contains_recursive_proof = false; bool computed_witness = false; TurboPlonkComposerHelper() - : TurboPlonkComposerHelper(std::shared_ptr( - new proof_system::FileReferenceStringFactory("../srs_db/ignition"))) + : TurboPlonkComposerHelper(std::shared_ptr( + new barretenberg::srs::factories::FileCrsFactory("../srs_db/ignition"))) {} - TurboPlonkComposerHelper(std::shared_ptr crs_factory) + TurboPlonkComposerHelper(std::shared_ptr crs_factory) : crs_factory_(std::move(crs_factory)) {} - TurboPlonkComposerHelper(std::unique_ptr&& crs_factory) + TurboPlonkComposerHelper(std::unique_ptr&& crs_factory) : crs_factory_(std::move(crs_factory)) {} TurboPlonkComposerHelper(std::shared_ptr p_key, std::shared_ptr v_key) diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp index 2cef06fc50..63a4f5d73f 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp @@ -3,7 +3,7 @@ #include "barretenberg/plonk/flavor/flavor.hpp" #include "barretenberg/proof_system/composer/composer_helper_lib.hpp" #include "barretenberg/plonk/composer/splitting_tmp/composer_helper/composer_helper_lib.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" @@ -29,7 +29,7 @@ class UltraPlonkComposerHelper { std::shared_ptr circuit_verification_key; // TODO(#218)(kesha): we need to put this into the commitment key, so that the composer doesn't have to handle srs // at all - std::shared_ptr crs_factory_; + std::shared_ptr crs_factory_; std::vector recursive_proof_public_input_indices; bool contains_recursive_proof = false; @@ -41,7 +41,7 @@ class UltraPlonkComposerHelper { // vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3. static constexpr size_t s_randomness = 3; - explicit UltraPlonkComposerHelper(std::shared_ptr crs_factory) + explicit UltraPlonkComposerHelper(std::shared_ptr crs_factory) : crs_factory_(std::move(crs_factory)) {} diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.hpp index 9dc96d2e2f..bd023af11d 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.hpp @@ -2,7 +2,7 @@ #include "composer_helper/standard_plonk_composer_helper.hpp" #include "barretenberg/proof_system/circuit_constructors/standard_circuit_constructor.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/transcript/manifest.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" @@ -42,18 +42,20 @@ class StandardPlonkComposer { , variables(circuit_constructor.variables){}; StandardPlonkComposer(std::string const& crs_path, const size_t size_hint = 0) - : StandardPlonkComposer( - std::unique_ptr(new proof_system::FileReferenceStringFactory(crs_path)), - size_hint){}; + : StandardPlonkComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), + size_hint){}; - StandardPlonkComposer(std::shared_ptr const& crs_factory, const size_t size_hint = 0) + StandardPlonkComposer(std::shared_ptr const& crs_factory, + const size_t size_hint = 0) : circuit_constructor(size_hint) , composer_helper(crs_factory) , num_gates(circuit_constructor.num_gates) , variables(circuit_constructor.variables) {} - StandardPlonkComposer(std::unique_ptr&& crs_factory, const size_t size_hint = 0) + StandardPlonkComposer(std::unique_ptr&& crs_factory, + const size_t size_hint = 0) : circuit_constructor(size_hint) , composer_helper(std::move(crs_factory)) , num_gates(circuit_constructor.num_gates) diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.test.cpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.test.cpp index f67d6622da..f3b6c908bb 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.test.cpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/standard_plonk_composer.test.cpp @@ -36,7 +36,7 @@ TEST(standard_plonk_composer_splitting_tmp, composer_from_serialized_keys) auto pk_data = from_buffer(pk_buf); auto vk_data = from_buffer(vk_buf); - auto crs = std::make_unique("../srs_db/ignition"); + auto crs = std::make_unique("../srs_db/ignition"); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); auto verification_key = std::make_shared(std::move(vk_data), crs->get_verifier_crs()); diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.hpp index 950163dae1..4dfa6c4e04 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.hpp @@ -42,17 +42,19 @@ class TurboPlonkComposer { , variables(circuit_constructor.variables){}; TurboPlonkComposer(std::string const& crs_path, const size_t size_hint = 0) - : TurboPlonkComposer( - std::unique_ptr(new proof_system::FileReferenceStringFactory(crs_path)), - size_hint){}; + : TurboPlonkComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), + size_hint){}; - TurboPlonkComposer(std::shared_ptr const& crs_factory, const size_t size_hint = 0) + TurboPlonkComposer(std::shared_ptr const& crs_factory, + const size_t size_hint = 0) : circuit_constructor(size_hint) , composer_helper(crs_factory) , num_gates(circuit_constructor.num_gates) , variables(circuit_constructor.variables){}; - TurboPlonkComposer(std::unique_ptr&& crs_factory, const size_t size_hint = 0) + TurboPlonkComposer(std::unique_ptr&& crs_factory, + const size_t size_hint = 0) : circuit_constructor(size_hint) , composer_helper(std::move(crs_factory)) , num_gates(circuit_constructor.num_gates) diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.test.cpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.test.cpp index d651b48bdf..e320a34022 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.test.cpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/turbo_plonk_composer.test.cpp @@ -39,7 +39,7 @@ TEST(turbo_plonk_composer_splitting_tmp, composer_from_serialized_keys) auto pk_data = from_buffer(pk_buf); auto vk_data = from_buffer(vk_buf); - auto crs = std::make_unique("../srs_db/ignition"); + auto crs = std::make_unique("../srs_db/ignition"); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); auto verification_key = std::make_shared(std::move(vk_data), crs->get_verifier_crs()); diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp index 703e037e64..7dad6f15bf 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp @@ -30,10 +30,12 @@ class UltraPlonkComposer { : UltraPlonkComposer("../srs_db/ignition", 0){}; UltraPlonkComposer(std::string const& crs_path, const size_t size_hint) - : UltraPlonkComposer(std::unique_ptr(new FileReferenceStringFactory(crs_path)), + : UltraPlonkComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), size_hint){}; - UltraPlonkComposer(std::shared_ptr const& crs_factory, const size_t size_hint) + UltraPlonkComposer(std::shared_ptr const& crs_factory, + const size_t size_hint) : circuit_constructor(size_hint) , composer_helper(crs_factory) , num_gates(circuit_constructor.num_gates){}; diff --git a/cpp/src/barretenberg/plonk/composer/standard_composer.hpp b/cpp/src/barretenberg/plonk/composer/standard_composer.hpp index f4c59f71a5..58cac114d2 100644 --- a/cpp/src/barretenberg/plonk/composer/standard_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/standard_composer.hpp @@ -3,7 +3,7 @@ #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" #include "barretenberg/transcript/manifest.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" namespace proof_system::plonk { enum StandardSelectors { QM, QC, Q1, Q2, Q3, NUM }; @@ -44,10 +44,12 @@ class StandardComposer : public ComposerBase { }; StandardComposer(std::string const& crs_path, const size_t size_hint = 0) - : StandardComposer(std::unique_ptr(new FileReferenceStringFactory(crs_path)), + : StandardComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), size_hint){}; - StandardComposer(std::shared_ptr const& crs_factory, const size_t size_hint = 0) + StandardComposer(std::shared_ptr const& crs_factory, + const size_t size_hint = 0) : ComposerBase(crs_factory, StandardSelectors::NUM, size_hint, standard_selector_properties()) { w_l.reserve(size_hint); @@ -57,7 +59,8 @@ class StandardComposer : public ComposerBase { zero_idx = put_constant_variable(fr::zero()); } - StandardComposer(std::unique_ptr&& crs_factory, const size_t size_hint = 0) + StandardComposer(std::unique_ptr&& crs_factory, + const size_t size_hint = 0) : ComposerBase(std::move(crs_factory), StandardSelectors::NUM, size_hint, standard_selector_properties()) { w_l.reserve(size_hint); diff --git a/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp b/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp index 71aec400e2..9d6c969c66 100644 --- a/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp +++ b/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp @@ -37,7 +37,7 @@ TEST(standard_composer, composer_from_serialized_keys) auto pk_data = from_buffer(pk_buf); auto vk_data = from_buffer(vk_buf); - auto crs = std::make_unique("../srs_db/ignition"); + auto crs = std::make_unique("../srs_db/ignition"); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); auto verification_key = std::make_shared(std::move(vk_data), crs->get_verifier_crs()); diff --git a/cpp/src/barretenberg/plonk/composer/turbo_composer.cpp b/cpp/src/barretenberg/plonk/composer/turbo_composer.cpp index f3339cf147..1db1f3af05 100644 --- a/cpp/src/barretenberg/plonk/composer/turbo_composer.cpp +++ b/cpp/src/barretenberg/plonk/composer/turbo_composer.cpp @@ -9,7 +9,7 @@ #include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" #include "../proof_system/widgets/transition_widgets/transition_widget.hpp" #include "../proof_system/widgets/transition_widgets/turbo_arithmetic_widget.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" using namespace barretenberg; using namespace proof_system; @@ -55,7 +55,9 @@ TurboComposer::TurboComposer() * vectors during initialization. * */ TurboComposer::TurboComposer(std::string const& crs_path, const size_t size_hint) - : TurboComposer(std::shared_ptr(new FileReferenceStringFactory(crs_path)), size_hint){}; + : TurboComposer(std::shared_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), + size_hint){}; /** * Turbo composer initialization, where you can specify the factory @@ -65,7 +67,8 @@ TurboComposer::TurboComposer(std::string const& crs_path, const size_t size_hint * @param size_hint Assumed number of gates. Used to allocate space for various member * vectors during initialization. * */ -TurboComposer::TurboComposer(std::shared_ptr const& crs_factory, const size_t size_hint) +TurboComposer::TurboComposer(std::shared_ptr const& crs_factory, + const size_t size_hint) : ComposerBase(crs_factory, TurboSelectors::NUM, size_hint, turbo_sel_props()) { w_l.reserve(size_hint); @@ -551,7 +554,7 @@ std::vector TurboComposer::decompose_into_base4_accumulators(const uin size_t num_quad_gates = (num_bits >> 3); num_quad_gates = (num_quad_gates << 3 == num_bits) ? num_quad_gates : num_quad_gates + 1; - std::vector* wires[4]{ &w_4, &w_o, &w_r, &w_l }; + decltype(w_4)* wires[4]{ &w_4, &w_o, &w_r, &w_l }; // num_quads = the number of accumulators used in the table, not including the output row. const size_t num_quads = (num_quad_gates << 2); diff --git a/cpp/src/barretenberg/plonk/composer/turbo_composer.hpp b/cpp/src/barretenberg/plonk/composer/turbo_composer.hpp index 4500b89953..102897339a 100644 --- a/cpp/src/barretenberg/plonk/composer/turbo_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/turbo_composer.hpp @@ -14,7 +14,8 @@ class TurboComposer : public ComposerBase { TurboComposer(); TurboComposer(std::string const& crs_path, const size_t size_hint = 0); - TurboComposer(std::shared_ptr const& crs_factory, const size_t size_hint = 0); + TurboComposer(std::shared_ptr const& crs_factory, + const size_t size_hint = 0); TurboComposer(std::shared_ptr const& p_key, std::shared_ptr const& v_key, size_t size_hint = 0); diff --git a/cpp/src/barretenberg/plonk/composer/turbo_composer.test.cpp b/cpp/src/barretenberg/plonk/composer/turbo_composer.test.cpp index 5e9bc0b756..78dc181161 100644 --- a/cpp/src/barretenberg/plonk/composer/turbo_composer.test.cpp +++ b/cpp/src/barretenberg/plonk/composer/turbo_composer.test.cpp @@ -38,7 +38,7 @@ TEST(turbo_composer, composer_from_serialized_keys) auto pk_data = from_buffer(pk_buf); auto vk_data = from_buffer(vk_buf); - auto crs = std::make_unique("../srs_db/ignition"); + auto crs = std::make_unique("../srs_db/ignition"); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); auto verification_key = std::make_shared(std::move(vk_data), crs->get_verifier_crs()); diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index ce0f4eac7b..a56a3af717 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -12,7 +12,7 @@ #include "barretenberg/plonk/proof_system/widgets/random_widgets/permutation_widget.hpp" #include "barretenberg/plonk/proof_system/widgets/random_widgets/plookup_widget.hpp" #include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/proof_system/plookup_tables/types.hpp" #include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" @@ -68,9 +68,12 @@ UltraComposer::UltraComposer() {} UltraComposer::UltraComposer(std::string const& crs_path, const size_t size_hint) - : UltraComposer(std::unique_ptr(new FileReferenceStringFactory(crs_path)), size_hint){}; + : UltraComposer(std::unique_ptr( + new barretenberg::srs::factories::FileCrsFactory(crs_path)), + size_hint){}; -UltraComposer::UltraComposer(std::shared_ptr const& crs_factory, const size_t size_hint) +UltraComposer::UltraComposer(std::shared_ptr const& crs_factory, + const size_t size_hint) : ComposerBase(crs_factory, UltraSelectors::NUM, size_hint, ultra_selector_properties()) { w_l.reserve(size_hint); @@ -86,7 +89,9 @@ UltraComposer::UltraComposer(std::shared_ptr const& p_key, size_t size_hint) : ComposerBase(p_key, v_key, UltraSelectors::NUM, size_hint, ultra_selector_properties()) { + w_l.reserve(size_hint); w_r.reserve(size_hint); + w_o.reserve(size_hint); w_4.reserve(size_hint); zero_idx = put_constant_variable(0); tau.insert({ DUMMY_TAG, DUMMY_TAG }); @@ -563,7 +568,6 @@ std::shared_ptr UltraComposer::compute_proving_key() // Compute selector polynomials and appropriate fft versions and put them in the proving key ComposerBase::compute_proving_key_base(type, tables_size + lookups_size, NUM_RESERVED_GATES); - const size_t subgroup_size = circuit_proving_key->circuit_size; polynomial poly_q_table_column_1(subgroup_size); diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp index eb0e5b0e92..c7e82be144 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp @@ -206,7 +206,8 @@ class UltraComposer : public ComposerBase { UltraComposer(); UltraComposer(std::string const& crs_path, const size_t size_hint = 0); - UltraComposer(std::shared_ptr const& crs_factory, const size_t size_hint = 0); + UltraComposer(std::shared_ptr const& crs_factory, + const size_t size_hint = 0); UltraComposer(std::shared_ptr const& p_key, std::shared_ptr const& v_key, size_t size_hint = 0); @@ -254,6 +255,23 @@ class UltraComposer : public ComposerBase { } } + /** + * @brief Update recursive_proof_public_input_indices with existing public inputs that represent a recursive proof + * + * @param proof_output_witness_indices + */ + void set_recursive_proof(const std::vector& proof_output_witness_indices) + { + if (contains_recursive_proof) { + failure("added recursive proof when one already exists"); + } + contains_recursive_proof = true; + for (size_t i = 0; i < proof_output_witness_indices.size(); ++i) { + recursive_proof_public_input_indices.push_back( + get_public_input_index(real_variable_index[proof_output_witness_indices[i]])); + } + } + void create_new_range_constraint(const uint32_t variable_index, const uint64_t target_range, std::string const msg = "create_new_range_constraint"); diff --git a/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp b/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp index 2b7f89ab0e..f4d015fbc4 100644 --- a/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp +++ b/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp @@ -10,7 +10,7 @@ #include "../../../proof_system/work_queue/work_queue.hpp" #include "../types/program_settings.hpp" #include "../../composer/composer_base.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/ecc/curves/bn254/fq12.hpp" #include "barretenberg/ecc/curves/bn254/pairing.hpp" @@ -36,8 +36,9 @@ TEST(commitment_scheme, kate_open) transcript::StandardTranscript inp_tx = transcript::StandardTranscript(transcript::Manifest()); plonk::KateCommitmentScheme newKate; - // std::shared_ptr crs_factory = (new FileReferenceStringFactory("../srs_db/ignition")); - auto file_crs = std::make_shared("../srs_db/ignition"); + // std::shared_ptr crs_factory = (new + // FileReferenceStringFactory("../srs_db/ignition")); + auto file_crs = std::make_shared("../srs_db/ignition"); auto crs = file_crs->get_prover_crs(n); auto circuit_proving_key = std::make_shared(n, 0, crs, ComposerType::STANDARD); work_queue queue(circuit_proving_key.get(), &inp_tx); @@ -94,7 +95,7 @@ TEST(commitment_scheme, kate_batch_open) transcript::StandardTranscript inp_tx = transcript::StandardTranscript(transcript::Manifest()); plonk::KateCommitmentScheme newKate; - auto file_crs = std::make_shared("../srs_db/ignition"); + auto file_crs = std::make_shared("../srs_db/ignition"); auto crs = file_crs->get_prover_crs(n); auto circuit_proving_key = std::make_shared(n, 0, crs, ComposerType::STANDARD); work_queue queue(circuit_proving_key.get(), &inp_tx); diff --git a/cpp/src/barretenberg/plonk/proof_system/prover/prover.test.cpp b/cpp/src/barretenberg/plonk/proof_system/prover/prover.test.cpp index 50a535f946..c110490e7a 100644 --- a/cpp/src/barretenberg/plonk/proof_system/prover/prover.test.cpp +++ b/cpp/src/barretenberg/plonk/proof_system/prover/prover.test.cpp @@ -4,7 +4,7 @@ #include "prover.hpp" #include -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" @@ -112,7 +112,7 @@ plonk::Prover generate_test_data(const size_t n) // even indices = mul gates, odd incides = add gates - auto reference_string = std::make_shared(n + 1, "../srs_db/ignition"); + auto reference_string = std::make_shared(n + 1, "../srs_db/ignition"); std::shared_ptr key = std::make_shared(n, 0, reference_string, ComposerType::STANDARD); polynomial w_l(n); diff --git a/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.cpp b/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.cpp index 4f2c5d533d..31033387f4 100644 --- a/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.cpp +++ b/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.cpp @@ -24,7 +24,7 @@ namespace proof_system::plonk { * */ proving_key::proving_key(const size_t num_gates, const size_t num_inputs, - std::shared_ptr const& crs, + std::shared_ptr const& crs, ComposerType type = ComposerType::STANDARD) // TODO(Cody): Don't use default for Honk : composer_type(type) , circuit_size(num_gates) @@ -44,7 +44,7 @@ proving_key::proving_key(const size_t num_gates, * @param data * @param crs */ -proving_key::proving_key(proving_key_data&& data, std::shared_ptr const& crs) +proving_key::proving_key(proving_key_data&& data, std::shared_ptr const& crs) : composer_type(data.composer_type) , circuit_size(data.circuit_size) , num_public_inputs(data.num_public_inputs) diff --git a/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.hpp b/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.hpp index 0714da1565..3a50731748 100644 --- a/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.hpp +++ b/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.hpp @@ -7,7 +7,7 @@ #include "barretenberg/proof_system/polynomial_store/polynomial_store.hpp" // #include "barretenberg/proof_system/polynomial_store/polynomial_store_wasm.hpp" // #include "barretenberg/proof_system/polynomial_store/polynomial_store_cache.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/plonk/proof_system/constants.hpp" #include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" #include @@ -33,11 +33,11 @@ struct proving_key { RELATIVE_LOOKUP, }; - proving_key(proving_key_data&& data, std::shared_ptr const& crs); + proving_key(proving_key_data&& data, std::shared_ptr const& crs); proving_key(const size_t num_gates, const size_t num_inputs, - std::shared_ptr const& crs, + std::shared_ptr const& crs, ComposerType type); proving_key(std::ostream& is, std::string const& crs_path); @@ -60,7 +60,7 @@ struct proving_key { // The reference_string object contains the monomial SRS. We can access it using: // Monomial SRS: reference_string->get_monomial_points() - std::shared_ptr reference_string; + std::shared_ptr reference_string; barretenberg::polynomial quotient_polynomial_parts[plonk::NUM_QUOTIENT_PARTS]; diff --git a/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp b/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp index f620b33617..84d2c2365c 100644 --- a/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp +++ b/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp @@ -22,7 +22,7 @@ TEST(proving_key, proving_key_from_serialized_key) plonk::proving_key& p_key = *composer.compute_proving_key(); auto pk_buf = to_buffer(p_key); auto pk_data = from_buffer(pk_buf); - auto crs = std::make_unique("../srs_db/ignition"); + auto crs = std::make_unique("../srs_db/ignition"); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); @@ -58,7 +58,7 @@ TEST(proving_key, proving_key_from_serialized_key_ultra) plonk::proving_key& p_key = *composer.compute_proving_key(); auto pk_buf = to_buffer(p_key); auto pk_data = from_buffer(pk_buf); - auto crs = std::make_unique("../srs_db/ignition"); + auto crs = std::make_unique("../srs_db/ignition"); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); diff --git a/cpp/src/barretenberg/plonk/proof_system/types/polynomial_manifest.hpp b/cpp/src/barretenberg/plonk/proof_system/types/polynomial_manifest.hpp index c16aeaafdf..e2b4cc6e10 100644 --- a/cpp/src/barretenberg/plonk/proof_system/types/polynomial_manifest.hpp +++ b/cpp/src/barretenberg/plonk/proof_system/types/polynomial_manifest.hpp @@ -200,7 +200,7 @@ class PolynomialManifest { }; } - const std::vector& get() { return manifest; }; + const std::vector& get() const { return manifest; }; size_t size() const { return manifest.size(); } diff --git a/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp b/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp index 6e072abbb9..e60160615a 100644 --- a/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp +++ b/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp @@ -49,7 +49,7 @@ barretenberg::fr compress_native_evaluation_domain(barretenberg::evaluation_doma * @param hash_index generator index to use during pedersen compression * @returns a field containing the compression */ -barretenberg::fr verification_key_data::compress_native(const size_t hash_index) +barretenberg::fr verification_key_data::compress_native(const size_t hash_index) const { barretenberg::evaluation_domain eval_domain = barretenberg::evaluation_domain(circuit_size); @@ -87,7 +87,7 @@ barretenberg::fr verification_key_data::compress_native(const size_t hash_index) verification_key::verification_key(const size_t num_gates, const size_t num_inputs, - std::shared_ptr const& crs, + std::shared_ptr const& crs, uint32_t composer_type_) : composer_type(composer_type_) , circuit_size(num_gates) @@ -98,7 +98,8 @@ verification_key::verification_key(const size_t num_gates, , polynomial_manifest(composer_type) {} -verification_key::verification_key(verification_key_data&& data, std::shared_ptr const& crs) +verification_key::verification_key(verification_key_data&& data, + std::shared_ptr const& crs) : composer_type(data.composer_type) , circuit_size(data.circuit_size) , log_circuit_size(numeric::get_msb(data.circuit_size)) diff --git a/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.hpp b/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.hpp index 8d0c3db094..d56909181c 100644 --- a/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.hpp +++ b/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.hpp @@ -1,7 +1,7 @@ #pragma once #include #include "barretenberg/common/streams.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/global_crs.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/crypto/sha256/sha256.hpp" @@ -25,7 +25,7 @@ struct verification_key_data { commitments, contains_recursive_proof, recursive_proof_public_input_indices); - barretenberg::fr compress_native(size_t const hash_index = 0); + barretenberg::fr compress_native(size_t const hash_index = 0) const; }; template inline void read(B& buf, verification_key_data& key) @@ -50,6 +50,16 @@ template inline void write(B& buf, verification_key_data const& key write(buf, key.recursive_proof_public_input_indices); } +inline std::ostream& operator<<(std::ostream& os, verification_key_data const& key) +{ + return os << "key.composer_type: " << key.composer_type << "\n" + << "key.circuit_size: " << static_cast(key.circuit_size) << "\n" + << "key.num_public_inputs: " << static_cast(key.num_public_inputs) << "\n" + << "key.commitments: " << key.commitments << "\n" + << "key.contains_recursive_proof: " << key.contains_recursive_proof << "\n" + << "key.recursive_proof_public_input_indices: " << key.recursive_proof_public_input_indices << "\n"; +}; + inline bool operator==(verification_key_data const& lhs, verification_key_data const& rhs) { return lhs.composer_type == rhs.composer_type && lhs.circuit_size == rhs.circuit_size && @@ -59,11 +69,13 @@ inline bool operator==(verification_key_data const& lhs, verification_key_data c struct verification_key { // default constructor needed for msgpack unpack verification_key() = default; - verification_key(verification_key_data&& data, std::shared_ptr const& crs); + verification_key(verification_key_data&& data, + std::shared_ptr const& crs); verification_key(const size_t num_gates, const size_t num_inputs, - std::shared_ptr const& crs, + std::shared_ptr const& crs, uint32_t composer_type); + verification_key(const verification_key& other); verification_key(verification_key&& other); verification_key& operator=(verification_key&& other); @@ -72,6 +84,18 @@ struct verification_key { sha256::hash sha256_hash(); + verification_key_data as_data() const + { + return { + .composer_type = composer_type, + .circuit_size = (uint32_t)circuit_size, + .num_public_inputs = (uint32_t)num_public_inputs, + .commitments = commitments, + .contains_recursive_proof = contains_recursive_proof, + .recursive_proof_public_input_indices = recursive_proof_public_input_indices, + }; + } + uint32_t composer_type; size_t circuit_size; size_t log_circuit_size; @@ -79,7 +103,7 @@ struct verification_key { barretenberg::evaluation_domain domain; - std::shared_ptr reference_string; + std::shared_ptr reference_string; std::map commitments; @@ -92,27 +116,64 @@ struct verification_key { bool contains_recursive_proof = false; std::vector recursive_proof_public_input_indices; size_t program_width = 3; + + // for serialization: update with new fields + void msgpack_pack(auto& packer) const + { + verification_key_data data = { composer_type, + static_cast(circuit_size), + static_cast(num_public_inputs), + commitments, + contains_recursive_proof, + recursive_proof_public_input_indices }; + packer.pack(data); + } + void msgpack_unpack(auto obj) + { + verification_key_data data = obj; + *this = verification_key{ std::move(data), barretenberg::srs::get_crs_factory()->get_verifier_crs() }; + } }; +// specialize schema serialization +inline void msgpack_schema(auto& packer, proof_system::plonk::verification_key const&) +{ + packer.pack_schema(proof_system::plonk::verification_key_data{}); +} + +template inline void read(B& buf, verification_key& key) +{ + using serialize::read; + verification_key_data vk_data; + read(buf, vk_data); + key = verification_key{ std::move(vk_data), barretenberg::srs::get_crs_factory()->get_verifier_crs() }; +} + +template inline void read(B& buf, std::shared_ptr& key) +{ + using serialize::read; + verification_key_data vk_data; + read(buf, vk_data); + key = std::make_shared(std::move(vk_data), + barretenberg::srs::get_crs_factory()->get_verifier_crs()); +} + template inline void write(B& buf, verification_key const& key) { using serialize::write; - write(buf, key.composer_type); - write(buf, static_cast(key.circuit_size)); - write(buf, static_cast(key.num_public_inputs)); - write(buf, key.commitments); - write(buf, key.contains_recursive_proof); - write(buf, key.recursive_proof_public_input_indices); + write(buf, key.as_data()); } inline std::ostream& operator<<(std::ostream& os, verification_key const& key) { - return os << "key.composer_type: " << key.composer_type << "\n" - << "key.circuit_size: " << static_cast(key.circuit_size) << "\n" - << "key.num_public_inputs: " << static_cast(key.num_public_inputs) << "\n" - << "key.commitments: " << key.commitments << "\n" - << "key.contains_recursive_proof: " << key.contains_recursive_proof << "\n" - << "key.recursive_proof_public_input_indices: " << key.recursive_proof_public_input_indices << "\n"; + return os << key.as_data(); }; } // namespace proof_system::plonk + +// help our msgpack schema compiler with this struct +// Alias verification_key as verification_key_data +inline void msgpack_schema_pack(auto& packer, proof_system::plonk::verification_key const&) +{ + msgpack_schema_pack(packer, proof_system::plonk::verification_key_data{}); +} \ No newline at end of file diff --git a/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp b/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp index b61c4017f1..8ed2df86c3 100644 --- a/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp +++ b/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp @@ -7,7 +7,7 @@ #include "verifier.hpp" #include "barretenberg/ecc/curves/bn254/scalar_multiplication/scalar_multiplication.hpp" #include -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" @@ -40,7 +40,7 @@ plonk::Verifier generate_verifier(std::shared_ptr circuit_proving_k state)); } - auto crs = std::make_shared("../srs_db/ignition"); + auto crs = std::make_shared("../srs_db/ignition"); std::shared_ptr circuit_verification_key = std::make_shared(circuit_proving_key->circuit_size, circuit_proving_key->num_public_inputs, @@ -76,7 +76,7 @@ plonk::Prover generate_test_data(const size_t n) // even indices = mul gates, odd incides = add gates - auto crs = std::make_shared(n + 1, "../srs_db/ignition"); + auto crs = std::make_shared(n + 1, "../srs_db/ignition"); std::shared_ptr key = std::make_shared(n, 0, crs, ComposerType::STANDARD); polynomial w_l(n); diff --git a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp index a5c432199f..176da27a55 100644 --- a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp +++ b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.hpp @@ -2,6 +2,7 @@ #include #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" namespace proof_system { @@ -19,7 +20,7 @@ namespace proof_system { template std::shared_ptr initialize_proving_key( const typename Flavor::CircuitConstructor& circuit_constructor, - ReferenceStringFactory* crs_factory, + barretenberg::srs::factories::CrsFactory* crs_factory, const size_t minimum_circuit_size, const size_t num_randomized_gates, ComposerType composer_type) diff --git a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.test.cpp b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.test.cpp index 720705b7f0..7ec2df661f 100644 --- a/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.test.cpp +++ b/cpp/src/barretenberg/proof_system/composer/composer_helper_lib.test.cpp @@ -3,7 +3,7 @@ #include "barretenberg/honk/flavor/standard.hpp" // TODO: needed? #include "barretenberg/proof_system/composer/composer_helper_lib.hpp" #include "barretenberg/proof_system/types/composer_type.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" namespace proof_system::test_composer_lib { @@ -13,7 +13,7 @@ class ComposerLibTests : public ::testing::Test { using FF = typename Flavor::FF; Flavor::CircuitConstructor circuit_constructor; Flavor::ProvingKey proving_key = []() { - auto crs_factory = ReferenceStringFactory(); + auto crs_factory = barretenberg::srs::factories::CrsFactory(); auto crs = crs_factory.get_prover_crs(4); return Flavor::ProvingKey(/*circuit_size=*/4, /*num_public_inputs=*/0, crs, ComposerType::STANDARD); }(); @@ -25,7 +25,7 @@ TEST_F(ComposerLibTests, InitializeProvingKey) EXPECT_EQ(circuit_constructor.get_circuit_subgroup_size(7), 8); - ReferenceStringFactory crs_factory; + barretenberg::srs::factories::CrsFactory crs_factory; auto pk = initialize_proving_key(circuit_constructor, &crs_factory, diff --git a/cpp/src/barretenberg/proof_system/composer/permutation_helper.test.cpp b/cpp/src/barretenberg/proof_system/composer/permutation_helper.test.cpp index 57103c69ae..1b9491b7b4 100644 --- a/cpp/src/barretenberg/proof_system/composer/permutation_helper.test.cpp +++ b/cpp/src/barretenberg/proof_system/composer/permutation_helper.test.cpp @@ -4,7 +4,7 @@ #include "barretenberg/proof_system/composer/composer_helper_lib.hpp" #include "barretenberg/proof_system/composer/permutation_helper.hpp" #include "barretenberg/proof_system/types/composer_type.hpp" -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" namespace proof_system::test_composer_lib { @@ -13,7 +13,7 @@ class PermutationHelperTests : public ::testing::Test { using Flavor = honk::flavor::Standard; using FF = typename Flavor::FF; Flavor::CircuitConstructor circuit_constructor; - ReferenceStringFactory crs_factory = ReferenceStringFactory(); + barretenberg::srs::factories::CrsFactory crs_factory = barretenberg::srs::factories::CrsFactory(); std::shared_ptr proving_key; virtual void SetUp() diff --git a/cpp/src/barretenberg/proof_system/flavor/flavor.hpp b/cpp/src/barretenberg/proof_system/flavor/flavor.hpp index 047102b599..b963fd9288 100644 --- a/cpp/src/barretenberg/proof_system/flavor/flavor.hpp +++ b/cpp/src/barretenberg/proof_system/flavor/flavor.hpp @@ -57,7 +57,6 @@ * empty slots. This is a conscious choice to limit complexity. Note that there is very little memory cost here since * the DataType size in that case is small. * - * @todo TODO(#394): Folded polynomials should use polynomial class. * @todo TODO(#395): Getters should return arrays? * @todo TODO(#396): Access specifiers? * @todo TODO(#397): Use more handle types? @@ -68,9 +67,11 @@ #include #include #include -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/proof_system/types/composer_type.hpp" +#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" namespace proof_system::honk::flavor { @@ -142,13 +143,13 @@ class ProvingKey_ : public PrecomputedPolynomials, public WitnessPolynomials { bool contains_recursive_proof; std::vector recursive_proof_public_input_indices; - std::shared_ptr crs; + std::shared_ptr crs; barretenberg::EvaluationDomain evaluation_domain; ProvingKey_() = default; ProvingKey_(const size_t circuit_size, const size_t num_public_inputs, - std::shared_ptr const& crs, + std::shared_ptr const& crs, ComposerType composer_type) { this->crs = crs; @@ -175,12 +176,12 @@ class ProvingKey_ : public PrecomputedPolynomials, public WitnessPolynomials { */ template class VerificationKey_ : public PrecomputedCommitments { public: - std::shared_ptr vrs; + std::shared_ptr vrs; VerificationKey_() = default; VerificationKey_(const size_t circuit_size, const size_t num_public_inputs, - std::shared_ptr const& vrs, + std::shared_ptr const& vrs, ComposerType composer_type) { this->circuit_size = circuit_size; @@ -214,6 +215,89 @@ class AllEntities_ : public Entities_ { }; }; +/** + * @brief Recursive utility function to find max RELATION_LENGTH over tuple of Relations + * + */ +template static constexpr size_t get_max_relation_length() +{ + if constexpr (Index >= std::tuple_size::value) { + return 0; // Return 0 when reach end of the tuple + } else { + constexpr size_t current_length = std::tuple_element::type::RELATION_LENGTH; + constexpr size_t next_length = get_max_relation_length(); + return (current_length > next_length) ? current_length : next_length; + } +} + +/** + * @brief Recursive utility function to construct tuple of tuple of Univariates + * @details This is the container for storing the univariate contributions from each identity in each relation. Each + * Relation contributes a tuple with num-identities many Univariates and there are num-relations many tuples in the + * outer tuple. + */ +template static constexpr auto create_relation_univariates_container() +{ + if constexpr (Index >= std::tuple_size::value) { + return std::tuple<>{}; // Return empty when reach end of the tuple + } else { + using UnivariateTuple = typename std::tuple_element_t::RelationUnivariates; + return std::tuple_cat(std::tuple{}, + create_relation_univariates_container()); + } +} + +/** + * @brief Recursive utility function to construct tuple of arrays + * @details Container for storing value of each identity in each relation. Each Relation contributes an array of + * length num-identities. + */ +template static constexpr auto create_relation_values_container() +{ + if constexpr (Index >= std::tuple_size::value) { + return std::tuple<>{}; // Return empty when reach end of the tuple + } else { + using ValuesArray = typename std::tuple_element_t::RelationValues; + return std::tuple_cat(std::tuple{}, create_relation_values_container()); + } +} + +/** + * @brief Recursive helper function to instantiate BarycentricData to extend each Relation in a tuple + * @details Instantiate with lengths 2, 3, ... ExtendedLength + * @note The purpose of this function is simply to instantiate some BarycentricData so that the static member + * arrays are computed at compile time. It thus does not need a return value. It's awkward however to make + * void functions execute at compile time so we make it return true upon completion and wrap the call in a + * static_assert to ensure it has executed correctly. + */ +template static constexpr bool instantiate_barycentric_utils() +{ + if constexpr (Length > ExtendedLength) { // include ExtendedLength + return true; // Return true when finished + } else { + // We dont need to keep the result, we just want to ensure compile time computation of static members + [[maybe_unused]] auto barycentric_data = sumcheck::BarycentricData{}; + return instantiate_barycentric_utils(); + } +} + +/** + * @brief Recursive helper function to construct BarycentricData to extend each Relation in a tuple + * + */ +template +static constexpr auto create_barycentric_utils() +{ + if constexpr (Index >= std::tuple_size::value) { + return std::tuple<>{}; // Return empty when reach end of the tuple + } else { + constexpr size_t relation_length = std::tuple_element_t::RELATION_LENGTH; + using BarycentricType = sumcheck::BarycentricData; + return std::tuple_cat(std::tuple{}, + create_barycentric_utils()); + } +} + } // namespace proof_system::honk::flavor // Forward declare honk flavors @@ -244,7 +328,7 @@ concept IsAnyOf = (std::same_as || ...); template concept IsPlonkFlavor = IsAnyOf; -template +template concept IsHonkFlavor = IsAnyOf; // clang-format on } // namespace proof_system diff --git a/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt b/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt index 0dbb3b2d5e..bf448229a8 100644 --- a/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt +++ b/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt @@ -1,4 +1,4 @@ -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) +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 srs) add_executable(solidity_key_gen key_gen.cpp) diff --git a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp index 7274600b84..693418182f 100644 --- a/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp +++ b/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp @@ -110,6 +110,7 @@ template class RecursiveCircuit { 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]; diff --git a/cpp/src/barretenberg/srs/c_bind.cpp b/cpp/src/barretenberg/srs/c_bind.cpp new file mode 100644 index 0000000000..2542d3542a --- /dev/null +++ b/cpp/src/barretenberg/srs/c_bind.cpp @@ -0,0 +1,23 @@ +#include "c_bind.hpp" +#include "global_crs.hpp" +#include "./io.hpp" +#include +#include +#include + +using namespace barretenberg; + +/** + * WARNING: The SRS is not encoded the same way as all the read/write methods encode. + * Have to use the old school io functions to parse the buffers. + */ +WASM_EXPORT void srs_init_srs(uint8_t const* points_buf, uint32_t const* num_points, uint8_t const* g2_point_buf) +{ + auto points = std::vector(ntohl(*num_points)); + barretenberg::io::read_g1_elements_from_buffer(points.data(), (char*)points_buf, points.size() * 64); + + g2::affine_element g2_point; + io::read_g2_elements_from_buffer(&g2_point, (char*)g2_point_buf, 128); + + barretenberg::srs::init_crs_factory(points, g2_point); +} diff --git a/cpp/src/barretenberg/srs/c_bind.hpp b/cpp/src/barretenberg/srs/c_bind.hpp new file mode 100644 index 0000000000..a0e800aaa5 --- /dev/null +++ b/cpp/src/barretenberg/srs/c_bind.hpp @@ -0,0 +1,4 @@ +#include +#include + +WASM_EXPORT void srs_init_srs(uint8_t const* points_buf, uint32_t const* num_points, uint8_t const* g2_point_buf); diff --git a/cpp/src/barretenberg/srs/factories/crs_factory.hpp b/cpp/src/barretenberg/srs/factories/crs_factory.hpp new file mode 100644 index 0000000000..a849d7c392 --- /dev/null +++ b/cpp/src/barretenberg/srs/factories/crs_factory.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "barretenberg/common/mem.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/ecc/curves/bn254/g2.hpp" +#include + +namespace barretenberg::pairing { +struct miller_lines; +} // namespace barretenberg::pairing + +namespace barretenberg::srs::factories { + +/** + * A prover crs representation. + */ +class ProverCrs { + public: + virtual ~ProverCrs() = default; + ; + + /** + * Returns the monomial points in a form to be consumed by scalar_multiplication pippenger algorithm. + */ + virtual barretenberg::g1::affine_element* get_monomial_points() = 0; + virtual size_t get_monomial_size() const = 0; +}; + +class VerifierCrs { + public: + virtual ~VerifierCrs() = default; + ; + + virtual barretenberg::g2::affine_element get_g2x() const = 0; + + virtual barretenberg::pairing::miller_lines const* get_precomputed_g2_lines() const = 0; +}; + +/** + * A factory class to return the prover crs and verifier crs on request. + * You can construct an empty placeholder factory, because composers need to be given a factory at construction time. + */ +class CrsFactory { + public: + CrsFactory() = default; + CrsFactory(CrsFactory&& other) = default; + virtual ~CrsFactory() = default; + virtual std::shared_ptr get_prover_crs(size_t) { return nullptr; } + virtual std::shared_ptr get_verifier_crs() { return nullptr; } +}; + +} // namespace barretenberg::srs::factories diff --git a/cpp/src/barretenberg/srs/factories/file_crs_factory.cpp b/cpp/src/barretenberg/srs/factories/file_crs_factory.cpp new file mode 100644 index 0000000000..649cff9f64 --- /dev/null +++ b/cpp/src/barretenberg/srs/factories/file_crs_factory.cpp @@ -0,0 +1,73 @@ +#include "file_crs_factory.hpp" +#include "../io.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/ecc/curves/bn254/pairing.hpp" +#include "barretenberg/ecc/curves/bn254/scalar_multiplication/pippenger.hpp" + +namespace barretenberg::srs::factories { + +FileProverCrs::FileProverCrs(const size_t num_points, std::string const& path) + : num_points(num_points) +{ + monomials_ = scalar_multiplication::point_table_alloc(num_points); + + io::read_transcript_g1(monomials_, num_points, path); + scalar_multiplication::generate_pippenger_point_table(monomials_, monomials_, num_points); +} + +g1::affine_element* FileProverCrs::get_monomial_points() +{ + return monomials_; +} + +size_t FileProverCrs::get_monomial_size() const +{ + return num_points; +} + +FileVerifierCrs::FileVerifierCrs(std::string const& path) + : precomputed_g2_lines( + (barretenberg::pairing::miller_lines*)(aligned_alloc(64, sizeof(barretenberg::pairing::miller_lines) * 2))) +{ + + barretenberg::io::read_transcript_g2(g2_x, path); + barretenberg::pairing::precompute_miller_lines(barretenberg::g2::one, precomputed_g2_lines[0]); + barretenberg::pairing::precompute_miller_lines(g2_x, precomputed_g2_lines[1]); +} + +FileVerifierCrs::~FileVerifierCrs() +{ + aligned_free(precomputed_g2_lines); +} + +g2::affine_element FileVerifierCrs::get_g2x() const +{ + return g2_x; +} + +pairing::miller_lines const* FileVerifierCrs::get_precomputed_g2_lines() const +{ + return precomputed_g2_lines; +} + +FileCrsFactory::FileCrsFactory(std::string path, size_t initial_degree) + : path_(std::move(path)) + , degree_(initial_degree) + , verifier_crs_(std::make_shared(path_)) +{} + +std::shared_ptr FileCrsFactory::get_prover_crs(size_t degree) +{ + if (degree != degree_ || !prover_crs_) { + prover_crs_ = std::make_shared(degree, path_); + degree_ = degree; + } + return prover_crs_; +} + +std::shared_ptr FileCrsFactory::get_verifier_crs() +{ + return verifier_crs_; +} + +} // namespace barretenberg::srs::factories \ No newline at end of file diff --git a/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp b/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp new file mode 100644 index 0000000000..96cc306e24 --- /dev/null +++ b/cpp/src/barretenberg/srs/factories/file_crs_factory.hpp @@ -0,0 +1,55 @@ +#pragma once +#include "crs_factory.hpp" +#include +#include + +namespace barretenberg::srs::factories { + +class FileProverCrs : public ProverCrs { + public: + FileProverCrs(const size_t num_points, std::string const& path); + + g1::affine_element* get_monomial_points() override; + + size_t get_monomial_size() const override; + + private: + size_t num_points; + g1::affine_element* monomials_; +}; + +class FileVerifierCrs : public VerifierCrs { + public: + FileVerifierCrs(std::string const& path); + + ~FileVerifierCrs(); + + g2::affine_element get_g2x() const override; + + pairing::miller_lines const* get_precomputed_g2_lines() const override; + + private: + g2::affine_element g2_x; + pairing::miller_lines* precomputed_g2_lines; +}; + +/** + * Create reference strings given a path to a directory of transcript files. + */ +class FileCrsFactory : public CrsFactory { + public: + FileCrsFactory(std::string path, size_t initial_degree = 0); + FileCrsFactory(FileCrsFactory&& other) = default; + + std::shared_ptr get_prover_crs(size_t degree) override; + + std::shared_ptr get_verifier_crs() override; + + private: + std::string path_; + size_t degree_; + std::shared_ptr prover_crs_; + std::shared_ptr verifier_crs_; +}; + +} // namespace barretenberg::srs::factories diff --git a/cpp/src/barretenberg/srs/factories/mem_crs_factory.cpp b/cpp/src/barretenberg/srs/factories/mem_crs_factory.cpp new file mode 100644 index 0000000000..8971551c7f --- /dev/null +++ b/cpp/src/barretenberg/srs/factories/mem_crs_factory.cpp @@ -0,0 +1,73 @@ +#include "mem_crs_factory.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/ecc/curves/bn254/pairing.hpp" +#include "barretenberg/ecc/curves/bn254/scalar_multiplication/pippenger.hpp" + +namespace { + +using namespace barretenberg; +using namespace barretenberg::srs::factories; + +class MemProverCrs : public ProverCrs { + public: + MemProverCrs(std::vector const& points) + : num_points(points.size()) + { + monomials_ = scalar_multiplication::point_table_alloc(num_points); + std::copy(points.begin(), points.end(), monomials_); + scalar_multiplication::generate_pippenger_point_table(monomials_, monomials_, num_points); + } + + ~MemProverCrs() { aligned_free(monomials_); } + + g1::affine_element* get_monomial_points() override { return monomials_; } + + size_t get_monomial_size() const override { return num_points; } + + private: + size_t num_points; + g1::affine_element* monomials_; +}; + +class MemVerifierCrs : public VerifierCrs { + public: + MemVerifierCrs(g2::affine_element const& g2_point) + : g2_x(g2_point) + { + precomputed_g2_lines = + (pairing::miller_lines*)(aligned_alloc(64, sizeof(barretenberg::pairing::miller_lines) * 2)); + barretenberg::pairing::precompute_miller_lines(barretenberg::g2::one, precomputed_g2_lines[0]); + barretenberg::pairing::precompute_miller_lines(g2_x, precomputed_g2_lines[1]); + } + + ~MemVerifierCrs() { aligned_free(precomputed_g2_lines); } + + g2::affine_element get_g2x() const override { return g2_x; } + + pairing::miller_lines const* get_precomputed_g2_lines() const override { return precomputed_g2_lines; } + + private: + g2::affine_element g2_x; + pairing::miller_lines* precomputed_g2_lines; +}; + +} // namespace + +namespace barretenberg::srs::factories { + +MemCrsFactory::MemCrsFactory(std::vector const& points, g2::affine_element const g2_point) + : prover_crs_(std::make_shared(points)) + , verifier_crs_(std::make_shared(g2_point)) +{} + +std::shared_ptr MemCrsFactory::get_prover_crs(size_t) +{ + return prover_crs_; +} + +std::shared_ptr MemCrsFactory::get_verifier_crs() +{ + return verifier_crs_; +} + +} // namespace barretenberg::srs::factories \ No newline at end of file diff --git a/cpp/src/barretenberg/srs/factories/mem_crs_factory.hpp b/cpp/src/barretenberg/srs/factories/mem_crs_factory.hpp new file mode 100644 index 0000000000..0cdcf16b20 --- /dev/null +++ b/cpp/src/barretenberg/srs/factories/mem_crs_factory.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "crs_factory.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/ecc/curves/bn254/g2.hpp" +#include +#include + +namespace barretenberg::srs::factories { + +/** + * Create reference strings given pointers to in memory buffers. + */ +class MemCrsFactory : public CrsFactory { + public: + MemCrsFactory(std::vector const& points, g2::affine_element const g2_point); + MemCrsFactory(MemCrsFactory&& other) = default; + + std::shared_ptr get_prover_crs(size_t degree) override; + + std::shared_ptr get_verifier_crs() override; + + private: + std::shared_ptr prover_crs_; + std::shared_ptr verifier_crs_; +}; + +} // namespace barretenberg::srs::factories diff --git a/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp b/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp new file mode 100644 index 0000000000..6efcfe184e --- /dev/null +++ b/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp @@ -0,0 +1,44 @@ +#include "file_crs_factory.hpp" +#include "mem_crs_factory.hpp" +#include "../io.hpp" +#include "barretenberg/ecc/curves/bn254/pairing.hpp" +#include +#include + +using namespace barretenberg; +using namespace barretenberg::srs::factories; + +TEST(reference_string, mem_file_consistency) +{ + // Load 1024 from file. + auto file_crs = FileCrsFactory("../srs_db/ignition", 1024); + + // Use low level io lib to read 1024 from file. + std::vector points(1024); + io::read_transcript_g1(points.data(), 1024, "../srs_db/ignition"); + + g2::affine_element g2_point; + io::read_transcript_g2(g2_point, "../srs_db/ignition"); + + MemCrsFactory mem_crs(points, g2_point); + auto file_prover_crs = file_crs.get_prover_crs(1024); + auto mem_prover_crs = mem_crs.get_prover_crs(1024); + file_prover_crs->get_monomial_size(); + + EXPECT_EQ(mem_prover_crs->get_monomial_size(), file_prover_crs->get_monomial_size()); + + EXPECT_EQ(memcmp(mem_prover_crs->get_monomial_points(), + file_prover_crs->get_monomial_points(), + sizeof(g1::affine_element) * 1024 * 2), + 0); + + auto file_verifier_crs = file_crs.get_verifier_crs(); + auto mem_verifier_crs = file_crs.get_verifier_crs(); + + EXPECT_EQ(mem_verifier_crs->get_g2x(), file_verifier_crs->get_g2x()); + + EXPECT_EQ(memcmp(mem_verifier_crs->get_precomputed_g2_lines(), + file_verifier_crs->get_precomputed_g2_lines(), + sizeof(barretenberg::pairing::miller_lines) * 2), + 0); +} diff --git a/cpp/src/barretenberg/srs/global_crs.cpp b/cpp/src/barretenberg/srs/global_crs.cpp new file mode 100644 index 0000000000..f86cf924d3 --- /dev/null +++ b/cpp/src/barretenberg/srs/global_crs.cpp @@ -0,0 +1,28 @@ +#include "./global_crs.hpp" +#include "./factories/mem_crs_factory.hpp" +#include "./factories/file_crs_factory.hpp" +#include "barretenberg/common/throw_or_abort.hpp" + +namespace { +std::shared_ptr crs_factory; +} + +namespace barretenberg::srs { + +void init_crs_factory(std::vector const& points, g2::affine_element const g2_point) +{ + crs_factory = std::make_shared(points, g2_point); +} + +std::shared_ptr get_crs_factory() +{ + if (!crs_factory) { +#ifdef __wasm__ + throw_or_abort("You need to initalize the global CRS with a call to init_crs_factory(...)!"); +#else + crs_factory = std::make_shared("../srs_db/ignition"); +#endif + } + return crs_factory; +} +} // namespace barretenberg::srs \ No newline at end of file diff --git a/cpp/src/barretenberg/srs/global_crs.hpp b/cpp/src/barretenberg/srs/global_crs.hpp new file mode 100644 index 0000000000..68f657805a --- /dev/null +++ b/cpp/src/barretenberg/srs/global_crs.hpp @@ -0,0 +1,9 @@ +#include "./factories/crs_factory.hpp" + +namespace barretenberg::srs { + +void init_crs_factory(std::vector const& points, + barretenberg::g2::affine_element const g2_point); + +std::shared_ptr get_crs_factory(); +} // namespace barretenberg::srs \ No newline at end of file diff --git a/cpp/src/barretenberg/srs/reference_string/file_reference_string.cpp b/cpp/src/barretenberg/srs/reference_string/file_reference_string.cpp deleted file mode 100644 index 99f09c776c..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/file_reference_string.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "file_reference_string.hpp" -#include "../io.hpp" - -#include "barretenberg/ecc/curves/bn254/pairing.hpp" - -namespace proof_system { - -VerifierFileReferenceString::VerifierFileReferenceString(std::string const& path) - : precomputed_g2_lines( - (barretenberg::pairing::miller_lines*)(aligned_alloc(64, sizeof(barretenberg::pairing::miller_lines) * 2))) -{ - - barretenberg::io::read_transcript_g2(g2_x, path); - barretenberg::pairing::precompute_miller_lines(barretenberg::g2::one, precomputed_g2_lines[0]); - barretenberg::pairing::precompute_miller_lines(g2_x, precomputed_g2_lines[1]); -} - -VerifierFileReferenceString::~VerifierFileReferenceString() -{ - aligned_free(precomputed_g2_lines); -} - -} // namespace proof_system diff --git a/cpp/src/barretenberg/srs/reference_string/file_reference_string.hpp b/cpp/src/barretenberg/srs/reference_string/file_reference_string.hpp deleted file mode 100644 index ef6bebfc0a..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/file_reference_string.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Create reference strings given a path to a directory of transcript files. - */ -#pragma once -#include "reference_string.hpp" - -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/ecc/curves/bn254/g2.hpp" -#include "barretenberg/ecc/curves/bn254/scalar_multiplication/pippenger.hpp" - -#include -#include - -namespace barretenberg::pairing { -struct miller_lines; -} // namespace barretenberg::pairing - -namespace proof_system { - -using namespace barretenberg; - -class VerifierFileReferenceString : public VerifierReferenceString { - public: - VerifierFileReferenceString(std::string const& path); - ~VerifierFileReferenceString(); - - g2::affine_element get_g2x() const override { return g2_x; } - - pairing::miller_lines const* get_precomputed_g2_lines() const override { return precomputed_g2_lines; } - - private: - g2::affine_element g2_x; - pairing::miller_lines* precomputed_g2_lines; -}; - -class FileReferenceString : public ProverReferenceString { - public: - FileReferenceString(const size_t num_points, std::string const& path) - : num_points(num_points) - , pippenger_(path, num_points) - {} - - g1::affine_element* get_monomial_points() override { return pippenger_.get_point_table(); } - - size_t get_monomial_size() const override { return num_points; } - - private: - size_t num_points; - scalar_multiplication::Pippenger pippenger_; -}; - -class FileReferenceStringFactory : public ReferenceStringFactory { - public: - FileReferenceStringFactory(std::string path) - : path_(std::move(path)) - {} - - FileReferenceStringFactory(FileReferenceStringFactory&& other) = default; - - std::shared_ptr get_prover_crs(size_t degree) override - { - return std::make_shared(degree, path_); - } - - std::shared_ptr get_verifier_crs() override - { - return std::make_shared(path_); - } - - private: - std::string path_; -}; - -class DynamicFileReferenceStringFactory : public ReferenceStringFactory { - public: - DynamicFileReferenceStringFactory(std::string path, size_t initial_degree = 0) - : path_(std::move(path)) - , degree_(initial_degree) - , verifier_crs_(std::make_shared(path_)) - {} - - DynamicFileReferenceStringFactory(DynamicFileReferenceStringFactory&& other) = default; - - std::shared_ptr get_prover_crs(size_t degree) override - { - if (degree != degree_) { - prover_crs_ = std::make_shared(degree, path_); - degree_ = degree; - } - return prover_crs_; - } - - std::shared_ptr get_verifier_crs() override { return verifier_crs_; } - - private: - std::string path_; - size_t degree_; - std::shared_ptr prover_crs_; - std::shared_ptr verifier_crs_; -}; - -} // namespace proof_system diff --git a/cpp/src/barretenberg/srs/reference_string/mem_reference_string.cpp b/cpp/src/barretenberg/srs/reference_string/mem_reference_string.cpp deleted file mode 100644 index 0a9c71b40a..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/mem_reference_string.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "mem_reference_string.hpp" -#include "../io.hpp" - -#include "barretenberg/common/streams.hpp" -#include "barretenberg/ecc/curves/bn254/pairing.hpp" - -#include - -namespace proof_system { - -VerifierMemReferenceString::VerifierMemReferenceString(uint8_t const* g2x) - : precomputed_g2_lines( - (barretenberg::pairing::miller_lines*)(aligned_alloc(64, sizeof(barretenberg::pairing::miller_lines) * 2))) -{ - barretenberg::io::read_g2_elements_from_buffer(&g2_x, (char*)g2x, 128); - - barretenberg::pairing::precompute_miller_lines(barretenberg::g2::one, precomputed_g2_lines[0]); - barretenberg::pairing::precompute_miller_lines(g2_x, precomputed_g2_lines[1]); -} - -VerifierMemReferenceString::~VerifierMemReferenceString() -{ - aligned_free(precomputed_g2_lines); -} - -} // namespace proof_system diff --git a/cpp/src/barretenberg/srs/reference_string/mem_reference_string.hpp b/cpp/src/barretenberg/srs/reference_string/mem_reference_string.hpp deleted file mode 100644 index 608446fa77..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/mem_reference_string.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Create reference strings given a buffer containing network formatted g1 or g2 points. - */ -#pragma once - -#include "reference_string.hpp" - -#include "barretenberg/ecc/curves/bn254/scalar_multiplication/pippenger.hpp" - -namespace barretenberg::pairing { -struct miller_lines; -} // namespace barretenberg::pairing - -namespace proof_system { - -using namespace barretenberg; - -class VerifierMemReferenceString : public VerifierReferenceString { - public: - VerifierMemReferenceString(uint8_t const* g2x); - ~VerifierMemReferenceString() override; - - g2::affine_element get_g2x() const override { return g2_x; } - - pairing::miller_lines const* get_precomputed_g2_lines() const override { return precomputed_g2_lines; } - - private: - g2::affine_element g2_x; - pairing::miller_lines* precomputed_g2_lines; -}; - -} // namespace proof_system diff --git a/cpp/src/barretenberg/srs/reference_string/mem_reference_string.test.cpp b/cpp/src/barretenberg/srs/reference_string/mem_reference_string.test.cpp deleted file mode 100644 index 18701cc537..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/mem_reference_string.test.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "file_reference_string.hpp" -#include "mem_reference_string.hpp" - -#include "barretenberg/ecc/curves/bn254/pairing.hpp" - -#include - -#include - -TEST(reference_string, mem_file_consistency) -{ - std::ifstream transcript; - int NUM_POINTS_IN_TRANSCRIPT = 5040001; - transcript.open("../srs_db/ignition/monomial/transcript00.dat", std::ifstream::binary); - std::vector monomials(32768 * 64); - std::vector g2x(128); - transcript.seekg(28); - transcript.read((char*)monomials.data(), 32768 * 64); - transcript.seekg(28 + NUM_POINTS_IN_TRANSCRIPT * 64); - transcript.read((char*)g2x.data(), 128); - transcript.close(); - - auto mem_verifier = std::make_unique(g2x.data()); - - auto file_crs = std::make_unique("../srs_db/ignition"); - auto file_verifier = file_crs->get_verifier_crs(); - - EXPECT_EQ(mem_verifier->get_g2x(), file_verifier->get_g2x()); - EXPECT_EQ(memcmp(mem_verifier->get_precomputed_g2_lines(), - file_verifier->get_precomputed_g2_lines(), - sizeof(barretenberg::pairing::miller_lines) * 2), - 0); -} diff --git a/cpp/src/barretenberg/srs/reference_string/pippenger_reference_string.hpp b/cpp/src/barretenberg/srs/reference_string/pippenger_reference_string.hpp deleted file mode 100644 index 53c6867018..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/pippenger_reference_string.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Create reference strings given a Pippenger instance containing point table formatted monomials. - * Does not take ownership of the given buffer. - */ -#pragma once -#include "mem_reference_string.hpp" - -namespace barretenberg::pairing { -struct miller_lines; -} // namespace barretenberg::pairing - -namespace proof_system { - -using namespace barretenberg; - -class PippengerReferenceString : public ProverReferenceString { - public: - PippengerReferenceString(scalar_multiplication::Pippenger* pippenger) - : pippenger_(pippenger) - {} - - size_t get_monomial_size() const override { return pippenger_->get_num_points(); } - g1::affine_element* get_monomial_points() override { return pippenger_->get_point_table(); } - - private: - scalar_multiplication::Pippenger* pippenger_; -}; - -class PippengerReferenceStringFactory : public ReferenceStringFactory { - public: - PippengerReferenceStringFactory(scalar_multiplication::Pippenger* pippenger, uint8_t const* g2x) - : pippenger_(pippenger) - , g2x_(g2x) - {} - - PippengerReferenceStringFactory(PippengerReferenceStringFactory&& other) = default; - - std::shared_ptr get_prover_crs(size_t degree) override - { - ASSERT(degree <= pippenger_->get_num_points()); - return std::make_shared(pippenger_); - } - - std::shared_ptr get_verifier_crs() override - { - return std::make_shared(g2x_); - } - - private: - scalar_multiplication::Pippenger* pippenger_; - uint8_t const* g2x_; -}; - -} // namespace proof_system diff --git a/cpp/src/barretenberg/srs/reference_string/reference_string.hpp b/cpp/src/barretenberg/srs/reference_string/reference_string.hpp deleted file mode 100644 index c389a0819a..0000000000 --- a/cpp/src/barretenberg/srs/reference_string/reference_string.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "barretenberg/common/mem.hpp" -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/ecc/curves/bn254/g2.hpp" - -#include - -namespace barretenberg::pairing { -struct miller_lines; -} // namespace barretenberg::pairing - -namespace proof_system { - -class VerifierReferenceString { - public: - virtual ~VerifierReferenceString() = default; - ; - - virtual barretenberg::g2::affine_element get_g2x() const = 0; - - virtual barretenberg::pairing::miller_lines const* get_precomputed_g2_lines() const = 0; -}; - -class ProverReferenceString { - public: - virtual ~ProverReferenceString() = default; - ; - - virtual barretenberg::g1::affine_element* get_monomial_points() = 0; - virtual size_t get_monomial_size() const = 0; -}; - -// A placeholder factory. Exists because composers need to be given a factory at construction time. -// TODO: Refactor Composer code to only need CRS when actually needed. -class ReferenceStringFactory { - public: - ReferenceStringFactory() = default; - ReferenceStringFactory(ReferenceStringFactory&& other) = default; - virtual ~ReferenceStringFactory() = default; - virtual std::shared_ptr get_prover_crs(size_t) { return nullptr; } - virtual std::shared_ptr get_verifier_crs() { return nullptr; } -}; - -} // namespace proof_system diff --git a/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.bench.cpp b/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.bench.cpp index 8726b6ecc6..11847b6dbd 100644 --- a/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.bench.cpp +++ b/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.bench.cpp @@ -4,7 +4,7 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/plonk/composer/turbo_composer.hpp" -#include "barretenberg/srs/reference_string/file_reference_string.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" #define BARRETENBERG_SRS_PATH "../srs_db/ignition" diff --git a/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp b/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp index 4330c5b6b4..551d767446 100644 --- a/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp +++ b/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp @@ -472,7 +472,7 @@ template class element { { num_points = points.size(); num_fives = num_points / 5; - + num_sixes = 0; // size-6 table is expensive and only benefits us if creating them reduces the number of total tables if (num_fives * 5 == (num_points - 1)) { num_fives -= 1; diff --git a/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp b/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp index 40889aefec..86e98acf9e 100644 --- a/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp +++ b/cpp/src/barretenberg/stdlib/primitives/bool/bool.hpp @@ -1,10 +1,8 @@ #pragma once #include "../composers/composers_fwd.hpp" #include "../witness/witness.hpp" -#include "barretenberg/honk/composer/standard_honk_composer.hpp" -namespace proof_system::plonk { -namespace stdlib { +namespace proof_system::plonk::stdlib { template class bool_t { public: @@ -78,7 +76,5 @@ template inline std::ostream& operator<<(std::ostream& os, bool_t; -} // namespace stdlib -} // namespace proof_system::plonk +} // namespace proof_system::plonk::stdlib diff --git a/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp b/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp index a157c9022d..18e8ae164d 100644 --- a/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp +++ b/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp @@ -1,5 +1,6 @@ #pragma once -#include "barretenberg/plonk/composer/composer_base.hpp" +#include +#include #include "barretenberg/ecc/curves/bn254/fr.hpp" namespace proof_system::plonk { diff --git a/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp b/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp index 9db2f12dc9..87e55977d0 100644 --- a/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp +++ b/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp @@ -49,6 +49,54 @@ template class Transcript { // } } + /** + * @brief Construct a new Transcript object using a proof represented as a field_pt vector + * + * N.B. If proof is represented as a uint8_t vector, Transcript will convert into witnesses in-situ. + * Use this constructor method if the proof is *already present* as circuit witnesses! + * @param in_context + * @param input_manifest + * @param field_buffer + * @param num_public_inputs + */ + Transcript(Composer* in_context, + const transcript::Manifest input_manifest, + const std::vector& field_buffer, + const size_t num_public_inputs) + : context(in_context) + , transcript_base(input_manifest, transcript::HashType::PlookupPedersenBlake3s, 16) + , current_challenge(in_context) + { + size_t count = 0; + + const auto num_rounds = input_manifest.get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (auto manifest_element : input_manifest.get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + add_field_element(manifest_element.name, field_buffer[count++]); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + const auto x_lo = field_buffer[count++]; + const auto x_hi = field_buffer[count++]; + const auto y_lo = field_buffer[count++]; + const auto y_hi = field_buffer[count++]; + fq_pt x(x_lo, x_hi); + fq_pt y(y_lo, y_hi); + group_pt element(x, y); + add_group_element(manifest_element.name, element); + } else { + ASSERT(manifest_element.name == "public_inputs"); + std::vector public_inputs; + for (size_t i = 0; i < num_public_inputs; ++i) { + public_inputs.emplace_back(field_buffer[count++]); + } + add_field_element_vector(manifest_element.name, public_inputs); + } + } + } + } + } + transcript::Manifest get_manifest() const { return transcript_base.get_manifest(); } int check_field_element_cache(const std::string& element_name) const diff --git a/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp b/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp index 0c91945554..3d05b572a6 100644 --- a/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp +++ b/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" @@ -178,6 +178,20 @@ template struct PedersenPreimage }; template struct evaluation_domain { + static evaluation_domain from_field_elements(const std::vector>& fields) + { + evaluation_domain domain; + domain.root = fields[0]; + + domain.root_inverse = domain.root.invert(); + domain.domain = fields[1]; + domain.domain_inverse = domain.domain.invert(); + domain.generator = fields[2]; + domain.generator_inverse = domain.generator.invert(); + domain.size = domain.domain; + return domain; + } + static evaluation_domain from_witness(Composer* ctx, const barretenberg::evaluation_domain& input) { evaluation_domain domain; @@ -213,20 +227,63 @@ template struct evaluation_domain { uint32 size; }; -/** - * @brief Converts a 'native' verification key into a standard library type, instantiating the `input_key` parameter as - * circuit variables. This allows the recursive verifier to accept arbitrary verification keys, where the circuit being - * verified is not fixed as part of the recursive circuit. - */ template struct verification_key { using Composer = typename Curve::Composer; + + static std::shared_ptr from_field_elements( + Composer* ctx, + const std::vector>& fields, + bool inner_proof_contains_recursive_proof = false, + std::array recursive_proof_public_input_indices = {}) + { + std::vector fields_raw; + std::shared_ptr key = std::make_shared(); + key->context = ctx; + + key->polynomial_manifest = PolynomialManifest(Composer::type); + key->domain = evaluation_domain::from_field_elements({ fields[0], fields[1], fields[2] }); + + key->n = fields[3]; + key->num_public_inputs = fields[4]; + + // NOTE: For now `contains_recursive_proof` and `recursive_proof_public_input_indices` need to be circuit + // constants! + key->contains_recursive_proof = inner_proof_contains_recursive_proof; + for (size_t i = 0; i < 16; ++i) { + auto x = recursive_proof_public_input_indices[i]; + key->recursive_proof_public_input_indices.emplace_back(x); + } + + size_t count = 22; + for (const auto& descriptor : key->polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + + const auto x_lo = fields[count++]; + const auto x_hi = fields[count++]; + const auto y_lo = fields[count++]; + const auto y_hi = fields[count++]; + const typename Curve::fq_ct x(x_lo, x_hi); + const typename Curve::fq_ct y(y_lo, y_hi); + const typename Curve::g1_ct element(x, y); + + key->commitments.insert({ std::string(descriptor.commitment_label), element }); + } + } + + return key; + } + + /** + * @brief Converts a 'native' verification key into a standard library type, instantiating the `input_key` parameter + * as circuit variables. This allows the recursive verifier to accept arbitrary verification keys, where the circuit + * being verified is not fixed as part of the recursive circuit. + */ static std::shared_ptr from_witness(Composer* ctx, const std::shared_ptr& input_key) { std::shared_ptr key = std::make_shared(); // Native data: key->context = ctx; - key->base_key = input_key; key->reference_string = input_key->reference_string; key->polynomial_manifest = input_key->polynomial_manifest; @@ -234,7 +291,8 @@ template struct verification_key { key->n = witness_t(ctx, barretenberg::fr(input_key->circuit_size)); key->num_public_inputs = witness_t(ctx, input_key->num_public_inputs); key->domain = evaluation_domain::from_witness(ctx, input_key->domain); - key->contains_recursive_proof = witness_t(ctx, input_key->contains_recursive_proof); + key->contains_recursive_proof = input_key->contains_recursive_proof; + key->recursive_proof_public_input_indices = input_key->recursive_proof_public_input_indices; for (const auto& [tag, value] : input_key->commitments) { // We do not perform on_curve() circuit checks when constructing the Curve::g1_ct element. // The assumption is that the circuit creator is honest and that the verification key hash (or some other @@ -254,19 +312,18 @@ template struct verification_key { { std::shared_ptr key = std::make_shared(); key->context = ctx; - key->base_key = input_key; key->n = field_t(ctx, input_key->circuit_size); key->num_public_inputs = field_t(ctx, input_key->num_public_inputs); - key->contains_recursive_proof = bool_t(ctx, input_key->contains_recursive_proof); + key->contains_recursive_proof = input_key->contains_recursive_proof; + key->recursive_proof_public_input_indices = input_key->recursive_proof_public_input_indices; key->domain = evaluation_domain::from_constants(ctx, input_key->domain); - key->reference_string = input_key->reference_string; - for (const auto& [tag, value] : input_key->commitments) { key->commitments.insert({ tag, typename Curve::g1_ct(value) }); } + key->reference_string = input_key->reference_string; key->polynomial_manifest = input_key->polynomial_manifest; return key; @@ -380,23 +437,19 @@ template struct verification_key { field_t num_public_inputs; field_t z_pow_n; - // NOTE: This does not strictly need to be a circuit type. It can be used to check in the circuit - // if a proof contains any aggregated state. - bool_t contains_recursive_proof; - evaluation_domain domain; std::map commitments; // Native data: - std::shared_ptr reference_string; + std::shared_ptr reference_string; PolynomialManifest polynomial_manifest; - + // Used to check in the circuit if a proof contains any aggregated state. + bool contains_recursive_proof = false; + std::vector recursive_proof_public_input_indices; size_t program_width = 4; - - std::shared_ptr base_key; Composer* context; }; diff --git a/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.test.cpp b/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.test.cpp index 755d751ff2..692b5425b9 100644 --- a/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.test.cpp +++ b/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.test.cpp @@ -56,7 +56,7 @@ TYPED_TEST(VerificationKeyFixture, vk_data_vs_recursion_compress_native) verification_key_data vk_data = TestFixture::rand_vk_data(); verification_key_data vk_data_copy = vk_data; - auto file_crs = std::make_unique("../srs_db/ignition"); + auto file_crs = std::make_unique("../srs_db/ignition"); auto file_verifier = file_crs->get_verifier_crs(); auto native_vk = std::make_shared(std::move(vk_data_copy), file_verifier); @@ -76,7 +76,7 @@ TYPED_TEST(VerificationKeyFixture, compress_vs_compress_native) verification_key_data vk_data = TestFixture::rand_vk_data(); - auto file_crs = std::make_unique("../srs_db/ignition"); + auto file_crs = std::make_unique("../srs_db/ignition"); auto file_verifier = file_crs->get_verifier_crs(); auto native_vk = std::make_shared(std::move(vk_data), file_verifier); diff --git a/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp b/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp index 009e732b20..244aa0950c 100644 --- a/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp +++ b/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp @@ -181,6 +181,25 @@ aggregation_state verify_proof(typename Curve::Composer* context, const transcript::Manifest& manifest, const plonk::proof& proof, const aggregation_state previous_output = aggregation_state()) +{ + using Composer = typename Curve::Composer; + + key->program_width = program_settings::program_width; + + Transcript transcript = Transcript(context, proof.proof_data, manifest); + + return verify_proof_(context, key, transcript, previous_output); +} + +/** + * Refer to src/barretenberg/plonk/proof_system/verifier/verifier.cpp verify_proof() for the native implementation, + * which includes detailed comments. + */ +template +aggregation_state verify_proof_(typename Curve::Composer* context, + std::shared_ptr> key, + Transcript& transcript, + const aggregation_state previous_output = aggregation_state()) { using fr_ct = typename Curve::fr_ct; using fq_ct = typename Curve::fq_ct; @@ -189,7 +208,6 @@ aggregation_state verify_proof(typename Curve::Composer* context, key->program_width = program_settings::program_width; - Transcript transcript = Transcript(context, proof.proof_data, manifest); std::map kate_g1_elements; std::map kate_fr_elements_at_zeta; std::map kate_fr_elements_at_zeta_large; @@ -231,6 +249,7 @@ aggregation_state verify_proof(typename Curve::Composer* context, fr_ct u = transcript.get_challenge_field_element("separator", 0); fr_ct batch_opening_scalar; + populate_kate_element_map, program_settings>(context, key.get(), transcript, @@ -311,10 +330,6 @@ aggregation_state verify_proof(typename Curve::Composer* context, rhs_scalars.push_back(random_separator); } - // Check if recursive proof information is correctly set. - key->contains_recursive_proof.assert_equal(key->base_key->contains_recursive_proof, - "contains_recursive_proof is incorrectly set"); - /** * N.B. if this key contains a recursive proof, then ALL potential verification keys being verified by the outer *circuit must ALSO contain a recursive proof (this is not a concern if the key is being generated from circuit @@ -322,7 +337,7 @@ aggregation_state verify_proof(typename Curve::Composer* context, *code path should be used with extreme caution if the verification key is not being generated from circuit *constants **/ - if (key->base_key->contains_recursive_proof) { + if (key->contains_recursive_proof) { const auto public_inputs = transcript.get_field_element_vector("public_inputs"); const auto recover_fq_from_public_inputs = [&public_inputs](const size_t idx0, const size_t idx1, const size_t idx2, const size_t idx3) { @@ -339,22 +354,22 @@ aggregation_state verify_proof(typename Curve::Composer* context, fr_ct recursion_separator_challenge = transcript.get_challenge_field_element("separator", 2); - const auto x0 = recover_fq_from_public_inputs(key->base_key->recursive_proof_public_input_indices[0], - key->base_key->recursive_proof_public_input_indices[1], - key->base_key->recursive_proof_public_input_indices[2], - key->base_key->recursive_proof_public_input_indices[3]); - const auto y0 = recover_fq_from_public_inputs(key->base_key->recursive_proof_public_input_indices[4], - key->base_key->recursive_proof_public_input_indices[5], - key->base_key->recursive_proof_public_input_indices[6], - key->base_key->recursive_proof_public_input_indices[7]); - const auto x1 = recover_fq_from_public_inputs(key->base_key->recursive_proof_public_input_indices[8], - key->base_key->recursive_proof_public_input_indices[9], - key->base_key->recursive_proof_public_input_indices[10], - key->base_key->recursive_proof_public_input_indices[11]); - const auto y1 = recover_fq_from_public_inputs(key->base_key->recursive_proof_public_input_indices[12], - key->base_key->recursive_proof_public_input_indices[13], - key->base_key->recursive_proof_public_input_indices[14], - key->base_key->recursive_proof_public_input_indices[15]); + const auto x0 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[0], + key->recursive_proof_public_input_indices[1], + key->recursive_proof_public_input_indices[2], + key->recursive_proof_public_input_indices[3]); + const auto y0 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[4], + key->recursive_proof_public_input_indices[5], + key->recursive_proof_public_input_indices[6], + key->recursive_proof_public_input_indices[7]); + const auto x1 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[8], + key->recursive_proof_public_input_indices[9], + key->recursive_proof_public_input_indices[10], + key->recursive_proof_public_input_indices[11]); + const auto y1 = recover_fq_from_public_inputs(key->recursive_proof_public_input_indices[12], + key->recursive_proof_public_input_indices[13], + key->recursive_proof_public_input_indices[14], + key->recursive_proof_public_input_indices[15]); opening_elements.push_back(g1_ct(x0, y0)); opening_scalars.push_back(recursion_separator_challenge); diff --git a/cpp/src/barretenberg/transcript/transcript.cpp b/cpp/src/barretenberg/transcript/transcript.cpp index 8f597c454b..1371a08eac 100644 --- a/cpp/src/barretenberg/transcript/transcript.cpp +++ b/cpp/src/barretenberg/transcript/transcript.cpp @@ -94,7 +94,10 @@ Transcript::Transcript(const std::vector& input_transcript, } // Check that the total required size is equal to the size of the input_transcript if (totalRequiredSize != input_transcript.size()) - throw_or_abort("Serialized transcript does not contain the required number of bytes"); + throw_or_abort(format("Serialized transcript does not contain the required number of bytes: ", + totalRequiredSize, + " != ", + input_transcript.size())); for (size_t i = 0; i < num_rounds; ++i) { for (auto manifest_element : input_manifest.get_round_manifest(i).elements) { diff --git a/cpp/src/msgpack-c/.clang-format b/cpp/src/msgpack-c/.clang-format new file mode 100644 index 0000000000..a43d914ec3 --- /dev/null +++ b/cpp/src/msgpack-c/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: false \ No newline at end of file diff --git a/exports.json b/exports.json index 623ac44eb8..60fb981dd1 100644 --- a/exports.json +++ b/exports.json @@ -463,17 +463,105 @@ "isAsync": false }, { - "functionName": "ecc_new_pippenger", + "functionName": "srs_init_srs", "inArgs": [ { - "name": "points", + "name": "points_buf", "type": "const uint8_t *" }, { "name": "num_points", "type": "const uint32_t *" + }, + { + "name": "g2_point_buf", + "type": "const uint8_t *" + } + ], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "examples_simple_create_and_verify_proof", + "inArgs": [], + "outArgs": [ + { + "name": "valid", + "type": "bool *" + } + ], + "isAsync": false + }, + { + "functionName": "test_threads", + "inArgs": [ + { + "name": "threads", + "type": "const uint32_t *" + }, + { + "name": "iterations", + "type": "const uint32_t *" } ], + "outArgs": [ + { + "name": "out", + "type": "uint32_t *" + } + ], + "isAsync": false + }, + { + "functionName": "test_thread_abort", + "inArgs": [], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "test_abort", + "inArgs": [], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "common_init_slab_allocator", + "inArgs": [ + { + "name": "circuit_size", + "type": "const uint32_t *" + } + ], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "acir_get_circuit_sizes", + "inArgs": [ + { + "name": "constraint_system_buf", + "type": "const uint8_t *" + } + ], + "outArgs": [ + { + "name": "exact", + "type": "uint32_t *" + }, + { + "name": "total", + "type": "uint32_t *" + }, + { + "name": "subgroup", + "type": "uint32_t *" + } + ], + "isAsync": false + }, + { + "functionName": "acir_new_acir_composer", + "inArgs": [], "outArgs": [ { "name": "out", @@ -483,10 +571,10 @@ "isAsync": false }, { - "functionName": "ecc_delete_pippenger", + "functionName": "acir_delete_acir_composer", "inArgs": [ { - "name": "pippenger", + "name": "acir_composer_ptr", "type": "in_ptr" } ], @@ -494,103 +582,195 @@ "isAsync": false }, { - "functionName": "ecc_pippenger_unsafe", + "functionName": "acir_create_circuit", "inArgs": [ { - "name": "pippenger_ptr", + "name": "acir_composer_ptr", "type": "in_ptr" }, { - "name": "scalars_ptr", - "type": "in_ptr" + "name": "constraint_system_buf", + "type": "const uint8_t *" }, { - "name": "from", + "name": "size_hint", "type": "const uint32_t *" + } + ], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "acir_init_proving_key", + "inArgs": [ + { + "name": "acir_composer_ptr", + "type": "in_ptr" + }, + { + "name": "constraint_system_buf", + "type": "const uint8_t *" }, { - "name": "range", + "name": "size_hint", "type": "const uint32_t *" } ], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "acir_create_proof", + "inArgs": [ + { + "name": "acir_composer_ptr", + "type": "in_ptr" + }, + { + "name": "constraint_system_buf", + "type": "const uint8_t *" + }, + { + "name": "witness_buf", + "type": "const uint8_t *" + }, + { + "name": "is_recursive", + "type": "const bool *" + } + ], "outArgs": [ { - "name": "result_ptr", - "type": "affine_element::out_buf" + "name": "out", + "type": "uint8_t **" } ], "isAsync": false }, { - "functionName": "ecc_g1_sum", + "functionName": "acir_load_verification_key", "inArgs": [ { - "name": "points_ptr", + "name": "acir_composer_ptr", "type": "in_ptr" }, { - "name": "num_points", - "type": "const uint32_t *" + "name": "vk_buf", + "type": "const uint8_t *" + } + ], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "acir_init_verification_key", + "inArgs": [ + { + "name": "acir_composer_ptr", + "type": "in_ptr" + } + ], + "outArgs": [], + "isAsync": false + }, + { + "functionName": "acir_get_verification_key", + "inArgs": [ + { + "name": "acir_composer_ptr", + "type": "in_ptr" } ], "outArgs": [ { - "name": "result_ptr", - "type": "affine_element::out_buf" + "name": "out", + "type": "uint8_t **" } ], "isAsync": false }, { - "functionName": "examples_simple_create_and_verify_proof", + "functionName": "acir_verify_proof", "inArgs": [ { - "name": "pippenger", + "name": "acir_composer_ptr", "type": "in_ptr" }, { - "name": "g2x", + "name": "proof_buf", "type": "const uint8_t *" + }, + { + "name": "is_recursive", + "type": "const bool *" } ], "outArgs": [ { - "name": "valid", + "name": "result", "type": "bool *" } ], "isAsync": false }, { - "functionName": "test_threads", + "functionName": "acir_get_solidity_verifier", "inArgs": [ { - "name": "threads", - "type": "const uint32_t *" - }, - { - "name": "iterations", - "type": "const uint32_t *" + "name": "acir_composer_ptr", + "type": "in_ptr" } ], "outArgs": [ { "name": "out", - "type": "uint32_t *" + "type": "out_str_buf" } ], "isAsync": false }, { - "functionName": "test_thread_abort", - "inArgs": [], - "outArgs": [], + "functionName": "acir_serialize_proof_into_fields", + "inArgs": [ + { + "name": "acir_composer_ptr", + "type": "in_ptr" + }, + { + "name": "proof_buf", + "type": "const uint8_t *" + }, + { + "name": "num_inner_public_inputs", + "type": "const uint32_t *" + } + ], + "outArgs": [ + { + "name": "out", + "type": "fr::vec_out_buf" + } + ], "isAsync": false }, { - "functionName": "test_abort", - "inArgs": [], - "outArgs": [], + "functionName": "acir_serialize_verification_key_into_fields", + "inArgs": [ + { + "name": "acir_composer_ptr", + "type": "in_ptr" + } + ], + "outArgs": [ + { + "name": "out_vkey", + "type": "fr::vec_out_buf" + }, + { + "name": "out_key_hash", + "type": "fr::out_buf" + } + ], "isAsync": false } ] diff --git a/scripts/bindgen.sh b/scripts/bindgen.sh index 94150775c3..1a2034a213 100755 --- a/scripts/bindgen.sh +++ b/scripts/bindgen.sh @@ -1,7 +1,6 @@ #!/bin/bash set -eu -(cd ./cpp && cmake --build --preset wasm-threads) #find ./cpp/src -type f -name "c_bind*.hpp" | ./scripts/decls_json.py > exports.json cat ./scripts/c_bind_files.txt | ./scripts/decls_json.py > exports.json (cd ./ts && yarn ts-node-esm ./src/bindgen/index.ts ../exports.json > ./src/barretenberg_api/index.ts) diff --git a/scripts/c_bind_files.txt b/scripts/c_bind_files.txt index a0bbba84e3..a84057549b 100644 --- a/scripts/c_bind_files.txt +++ b/scripts/c_bind_files.txt @@ -2,6 +2,7 @@ ./cpp/src/barretenberg/crypto/pedersen_hash/c_bind.hpp ./cpp/src/barretenberg/crypto/blake2s/c_bind.hpp ./cpp/src/barretenberg/crypto/schnorr/c_bind.hpp -./cpp/src/barretenberg/ecc/c_bind.hpp +./cpp/src/barretenberg/srs/c_bind.hpp ./cpp/src/barretenberg/examples/c_bind.hpp ./cpp/src/barretenberg/common/c_bind.hpp +./cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp diff --git a/ts/README.md b/ts/README.md index c25f356420..a65bad3250 100644 --- a/ts/README.md +++ b/ts/README.md @@ -1,3 +1,116 @@ -# Barretenberg.js +# bb.js -Javascript bindings for barretenberg WASM. +Prover/verifier executable and API for barretenberg. Default cli arguments are appropriate for running within Noir +project structures. + +## Performance and limitations + +Max circuit size is 2^19 gates (524,288). This is due to the underlying WASM 4GB memory limit. This should improve +with future proving systems, and/or introduction of wasm64. + +If running from terminal, or within browser where you can set shared memory CORS headers, multithreading is enabled. +Note there are two independent WASM builds, one with threading enabled and one without. This is because the shared +memory flag is set within the WASM itself. If you're running in a context where you can't have shared memory, we want +to fallback to single threaded performance. + +Performance for 2^19: + +- 16 core x86: ~13s. +- 10 core M1 Mac Pro: ~18s. + +Linear scaling was observed up to 32 cores, however we limit to 16 as 2^19 runs out of memory with 32 cores. +This maybe resolvable. + +## Using as a standalone binary + +### Installing + +To install the package globally for running as a terminal application: + +``` +npm install -g @aztec/bb.js@alpha +``` + +This will install `bb.js` into your path. + +### Usage + +Run `bb.js` for further usage information, you'll see e.g. + +``` +% bb.js +Usage: bb.js [options] [command] + +Options: + -v, --verbose enable verbose logging (default: false) + -h, --help display help for command + +Commands: + prove_and_verify [options] Generate a proof and verify it. Process exits with success or failure code. + prove [options] Generate a proof and write it to a file. + gates [options] Print gate count to standard output. + verify [options] Verify a proof. Process exists with success or failure code. + contract [options] Output solidity verification key contract. + write_vk [options] Output verification key. + proof_as_fields [options] Return the proof as fields elements + vk_as_fields [options] Return the verifiation key represented as fields elements. Also return the verification key hash. + help [command] display help for command +``` + +## Using as a library + +### Installing + +To install as a package to be used as a library: + +``` +npm install @aztec/bb.js@alpha +``` + +or with yarn + +``` +yarn add @aztec/bb.js@alpha +``` + +### Usage + +To create a multithreaded version of the API: + +```typescript +const api = await newBarretenbergApiAsync(/* num_threads */); +// Use. +const input = Buffer.from('hello world!'); +const result = await api.blake2s(input); +await api.destroy(); +``` + +All methods are asynchronous. If no threads are specified, will default to number of cores with a maximum of 16. +If `1` is specified, fallback to non multi-threaded wasm that doesn't need shared memory. + +You can also create a synchronous version of the api that also has no multi-threading. This is only useful in the +browser if you don't call any multi-threaded functions. It's probably best to just always use async version of the api +unless you're really trying to avoid the small overhead of worker communication. + +```typescript +const api = await newBarretenbergApiSync(); +// Use. +const input = Buffer.from('hello world!'); +const result = api.blake2s(input); +await api.destroy(); +``` + +See `src/main.ts` for one example of how to use. + +## Development + +Create a symlink to the root script `bb.js-dev` in your path. You can now run the current state of the code from +anywhere in your filesystem with no `yarn build` required. + +If you change the C++ code run `yarn build:wasm`. + +To run the tests run `yarn test`. + +To run a continuous "stress tests" run `yarn simple_test` to do 10 full pk/proof/vk iterations. + +To run the same test in the browser run `yarn serve`, navigate to appropriate URL and open the console. diff --git a/ts/bb.js-dev b/ts/bb.js-dev new file mode 100755 index 0000000000..5255fe4b37 --- /dev/null +++ b/ts/bb.js-dev @@ -0,0 +1,6 @@ +#!/bin/sh +# Add a symlink to this somewhere in your path. +# Now you can run bb.js-dev anywhere to execute latest code, no 'yarn build' required. +SCRIPT_PATH=$(dirname $(realpath $0)) +export TS_NODE_PROJECT="$SCRIPT_PATH/tsconfig.json" +NODE_OPTIONS="--loader $SCRIPT_PATH/node_modules/ts-node/esm/transpile-only.mjs --no-warnings" node $SCRIPT_PATH/src/main.ts $@ diff --git a/ts/package.json b/ts/package.json index aa866a07d6..6bcbcd5dff 100644 --- a/ts/package.json +++ b/ts/package.json @@ -1,17 +1,23 @@ { - "name": "@aztec/barretenberg.js", - "version": "0.0.0", + "name": "@aztec/bb.js", + "version": "0.0.1-alpha.1", "type": "module", "typedoc": { "entryPoint": "./src/index.ts", - "displayName": "Barretenberg.js", + "displayName": "bb.js", "tsconfig": "./tsconfig.json" }, + "bin": "./dest/main.js", + "files": [ + "src/", + "dest/", + "README.md" + ], "scripts": { "clean": "rm -rf ./dest .tsbuildinfo", - "build": "yarn clean && yarn build:wasm && tsc -b && webpack", + "build": "yarn clean && yarn build:wasm && tsc -b && webpack && chmod +x ./dest/main.js", "build:dev": "tsc -b --watch", - "build:wasm": "cd ../cpp && cmake --preset wasm-threads && cmake --build --preset wasm-threads", + "build:wasm": "cd ../cpp && cmake --preset wasm-threads && cmake --build --preset wasm-threads && cmake --preset wasm && cmake --build --preset wasm", "serve": "webpack serve", "formatting": "prettier --check ./src && eslint --max-warnings 0 ./src", "formatting:fix": "prettier -w ./src", @@ -36,7 +42,10 @@ "rootDir": "./src" }, "dependencies": { - "bigint-buffer": "^1.1.5", + "comlink": "^4.4.1", + "commander": "^10.0.1", + "debug": "^4.3.4", + "ts-node": "^10.9.1", "tslib": "^2.4.0" }, "devDependencies": { @@ -49,9 +58,7 @@ "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", "buffer": "^6.0.3", - "comlink": "^4.4.1", "copy-webpack-plugin": "^11.0.0", - "debug": "^4.3.4", "eslint": "^8.35.0", "eslint-config-prettier": "^8.8.0", "html-webpack-plugin": "^5.5.1", @@ -61,7 +68,6 @@ "resolve-typescript-plugin": "^2.0.1", "ts-jest": "^29.1.0", "ts-loader": "^9.4.2", - "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.82.1", "webpack-cli": "^5.1.1", diff --git a/ts/src/barretenberg-threads.wasm b/ts/src/barretenberg-threads.wasm new file mode 120000 index 0000000000..1474d5ebb4 --- /dev/null +++ b/ts/src/barretenberg-threads.wasm @@ -0,0 +1 @@ +../../cpp/build-wasm-threads/bin/barretenberg.wasm \ No newline at end of file diff --git a/ts/src/barretenberg.wasm b/ts/src/barretenberg.wasm new file mode 120000 index 0000000000..69e221f70e --- /dev/null +++ b/ts/src/barretenberg.wasm @@ -0,0 +1 @@ +../../cpp/build-wasm/bin/barretenberg.wasm \ No newline at end of file diff --git a/ts/src/barretenberg_api/blake2s.test.ts b/ts/src/barretenberg_api/blake2s.test.ts index d046c8e551..47fa77dbcc 100644 --- a/ts/src/barretenberg_api/blake2s.test.ts +++ b/ts/src/barretenberg_api/blake2s.test.ts @@ -1,5 +1,4 @@ -import { BarretenbergBinderSync } from '../barretenberg_binder/index.js'; -import { BarretenbergWasm } from '../barretenberg_wasm/index.js'; +import { newBarretenbergApiSync } from '../factory/index.js'; import { Buffer32, Fr } from '../types/index.js'; import { BarretenbergApiSync } from './index.js'; @@ -7,7 +6,7 @@ describe('blake2s', () => { let api: BarretenbergApiSync; beforeAll(async () => { - api = new BarretenbergApiSync(new BarretenbergBinderSync(await BarretenbergWasm.new(1))); + api = await newBarretenbergApiSync(); }); afterAll(async () => { diff --git a/ts/src/barretenberg_api/common.test.ts b/ts/src/barretenberg_api/common.test.ts index 40a8dc0301..29ce69fbba 100644 --- a/ts/src/barretenberg_api/common.test.ts +++ b/ts/src/barretenberg_api/common.test.ts @@ -1,23 +1,21 @@ -import { BarretenbergBinderSync } from '../barretenberg_binder/index.js'; -import { BarretenbergWasm } from '../barretenberg_wasm/index.js'; -import { BarretenbergApiSync } from './index.js'; +import { BarretenbergApiAsync, newBarretenbergApiAsync } from '../factory/index.js'; describe('env', () => { - let api: BarretenbergApiSync; + let api: BarretenbergApiAsync; beforeAll(async () => { - api = new BarretenbergApiSync(new BarretenbergBinderSync(await BarretenbergWasm.new(3))); + api = await newBarretenbergApiAsync(3); }); afterAll(async () => { await api.destroy(); }); - it('thread test', () => { + it('thread test', async () => { // Main thread doesn't do anything in this test, so -1. - const threads = api.binder.wasm.getNumThreads() - 1; + const threads = (await api.getNumThreads()) - 1; const iterations = 100000; - const result = api.testThreads(threads, iterations); + const result = await api.testThreads(threads, iterations); expect(result).toBe(iterations); }); }); diff --git a/ts/src/barretenberg_api/index.ts b/ts/src/barretenberg_api/index.ts index dc8ea807f7..3e27fe74ae 100644 --- a/ts/src/barretenberg_api/index.ts +++ b/ts/src/barretenberg_api/index.ts @@ -1,7 +1,7 @@ // WARNING: FILE CODE GENERATED BY BINDGEN UTILITY. DO NOT EDIT! /* eslint-disable @typescript-eslint/no-unused-vars */ import { BarretenbergBinder, BarretenbergBinderSync } from '../barretenberg_binder/index.js'; -import { BufferDeserializer, NumberDeserializer, VectorDeserializer, BoolDeserializer } from '../serialize/index.js'; +import { BufferDeserializer, NumberDeserializer, VectorDeserializer, BoolDeserializer, StringDeserializer } from '../serialize/index.js'; import { Fr, Fq, Point, Buffer32, Buffer128, Ptr } from '../types/index.js'; export class BarretenbergApi { @@ -37,11 +37,7 @@ export class BarretenbergApi { } async pedersenCompressWithHashIndex(inputsBuffer: Fr[], hashIndex: number): Promise { - const result = await this.binder.callWasmExport( - 'pedersen_compress_with_hash_index', - [inputsBuffer, hashIndex], - [Fr], - ); + const result = await this.binder.callWasmExport('pedersen_compress_with_hash_index', [inputsBuffer, hashIndex], [Fr]); return result[0]; } @@ -76,11 +72,7 @@ export class BarretenbergApi { } async pedersenHashMultipleWithHashIndex(inputsBuffer: Fr[], hashIndex: number): Promise { - const result = await this.binder.callWasmExport( - 'pedersen_hash_multiple_with_hash_index', - [inputsBuffer, hashIndex], - [Fr], - ); + const result = await this.binder.callWasmExport('pedersen_hash_multiple_with_hash_index', [inputsBuffer, hashIndex], [Fr]); return result[0]; } @@ -110,126 +102,134 @@ export class BarretenbergApi { } async schnorrConstructSignature(message: Uint8Array, privateKey: Fr): Promise<[Buffer32, Buffer32]> { - const result = await this.binder.callWasmExport( - 'schnorr_construct_signature', - [message, privateKey], - [Buffer32, Buffer32], - ); + const result = await this.binder.callWasmExport('schnorr_construct_signature', [message, privateKey], [Buffer32, Buffer32]); return result as any; } async schnorrVerifySignature(message: Uint8Array, pubKey: Point, sigS: Buffer32, sigE: Buffer32): Promise { - const result = await this.binder.callWasmExport( - 'schnorr_verify_signature', - [message, pubKey, sigS, sigE], - [BoolDeserializer()], - ); + const result = await this.binder.callWasmExport('schnorr_verify_signature', [message, pubKey, sigS, sigE], [BoolDeserializer()]); return result[0]; } async schnorrMultisigCreateMultisigPublicKey(privateKey: Fq): Promise { - const result = await this.binder.callWasmExport( - 'schnorr_multisig_create_multisig_public_key', - [privateKey], - [Buffer128], - ); + const result = await this.binder.callWasmExport('schnorr_multisig_create_multisig_public_key', [privateKey], [Buffer128]); return result[0]; } async schnorrMultisigValidateAndCombineSignerPubkeys(signerPubkeyBuf: Buffer128[]): Promise<[Point, boolean]> { - const result = await this.binder.callWasmExport( - 'schnorr_multisig_validate_and_combine_signer_pubkeys', - [signerPubkeyBuf], - [Point, BoolDeserializer()], - ); + const result = await this.binder.callWasmExport('schnorr_multisig_validate_and_combine_signer_pubkeys', [signerPubkeyBuf], [Point, BoolDeserializer()]); return result as any; } async schnorrMultisigConstructSignatureRound1(): Promise<[Buffer128, Buffer128]> { - const result = await this.binder.callWasmExport( - 'schnorr_multisig_construct_signature_round_1', - [], - [Buffer128, Buffer128], - ); + const result = await this.binder.callWasmExport('schnorr_multisig_construct_signature_round_1', [], [Buffer128, Buffer128]); return result as any; } - async schnorrMultisigConstructSignatureRound2( - message: Uint8Array, - privateKey: Fq, - signerRoundOnePrivateBuf: Buffer128, - signerPubkeysBuf: Buffer128[], - roundOnePublicBuf: Buffer128[], - ): Promise<[Fq, boolean]> { - const result = await this.binder.callWasmExport( - 'schnorr_multisig_construct_signature_round_2', - [message, privateKey, signerRoundOnePrivateBuf, signerPubkeysBuf, roundOnePublicBuf], - [Fq, BoolDeserializer()], - ); + async schnorrMultisigConstructSignatureRound2(message: Uint8Array, privateKey: Fq, signerRoundOnePrivateBuf: Buffer128, signerPubkeysBuf: Buffer128[], roundOnePublicBuf: Buffer128[]): Promise<[Fq, boolean]> { + const result = await this.binder.callWasmExport('schnorr_multisig_construct_signature_round_2', [message, privateKey, signerRoundOnePrivateBuf, signerPubkeysBuf, roundOnePublicBuf], [Fq, BoolDeserializer()]); return result as any; } - async schnorrMultisigCombineSignatures( - message: Uint8Array, - signerPubkeysBuf: Buffer128[], - roundOneBuf: Buffer128[], - roundTwoBuf: Fr[], - ): Promise<[Buffer32, Buffer32, boolean]> { - const result = await this.binder.callWasmExport( - 'schnorr_multisig_combine_signatures', - [message, signerPubkeysBuf, roundOneBuf, roundTwoBuf], - [Buffer32, Buffer32, BoolDeserializer()], - ); + async schnorrMultisigCombineSignatures(message: Uint8Array, signerPubkeysBuf: Buffer128[], roundOneBuf: Buffer128[], roundTwoBuf: Fr[]): Promise<[Buffer32, Buffer32, boolean]> { + const result = await this.binder.callWasmExport('schnorr_multisig_combine_signatures', [message, signerPubkeysBuf, roundOneBuf, roundTwoBuf], [Buffer32, Buffer32, BoolDeserializer()]); return result as any; } - async eccNewPippenger(points: Uint8Array, numPoints: number): Promise { - const result = await this.binder.callWasmExport('ecc_new_pippenger', [points, numPoints], [Ptr]); + async srsInitSrs(pointsBuf: Uint8Array, numPoints: number, g2PointBuf: Uint8Array): Promise { + const result = await this.binder.callWasmExport('srs_init_srs', [pointsBuf, numPoints, g2PointBuf], []); + return; + } + + async examplesSimpleCreateAndVerifyProof(): Promise { + const result = await this.binder.callWasmExport('examples_simple_create_and_verify_proof', [], [BoolDeserializer()]); return result[0]; } - async eccDeletePippenger(pippenger: Ptr): Promise { - const result = await this.binder.callWasmExport('ecc_delete_pippenger', [pippenger], []); + async testThreads(threads: number, iterations: number): Promise { + const result = await this.binder.callWasmExport('test_threads', [threads, iterations], [NumberDeserializer()]); + return result[0]; + } + + async testThreadAbort(): Promise { + const result = await this.binder.callWasmExport('test_thread_abort', [], []); return; } - async eccPippengerUnsafe(pippengerPtr: Ptr, scalarsPtr: Ptr, from: number, range: number): Promise { - const result = await this.binder.callWasmExport( - 'ecc_pippenger_unsafe', - [pippengerPtr, scalarsPtr, from, range], - [Point], - ); - return result[0]; + async testAbort(): Promise { + const result = await this.binder.callWasmExport('test_abort', [], []); + return; } - async eccG1Sum(pointsPtr: Ptr, numPoints: number): Promise { - const result = await this.binder.callWasmExport('ecc_g1_sum', [pointsPtr, numPoints], [Point]); - return result[0]; + async commonInitSlabAllocator(circuitSize: number): Promise { + const result = await this.binder.callWasmExport('common_init_slab_allocator', [circuitSize], []); + return; + } + + async acirGetCircuitSizes(constraintSystemBuf: Uint8Array): Promise<[number, number, number]> { + const result = await this.binder.callWasmExport('acir_get_circuit_sizes', [constraintSystemBuf], [NumberDeserializer(), NumberDeserializer(), NumberDeserializer()]); + return result as any; } - async examplesSimpleCreateAndVerifyProof(pippenger: Ptr, g2x: Uint8Array): Promise { - const result = await this.binder.callWasmExport( - 'examples_simple_create_and_verify_proof', - [pippenger, g2x], - [BoolDeserializer()], - ); + async acirNewAcirComposer(): Promise { + const result = await this.binder.callWasmExport('acir_new_acir_composer', [], [Ptr]); return result[0]; } - async testThreads(threads: number, iterations: number): Promise { - const result = await this.binder.callWasmExport('test_threads', [threads, iterations], [NumberDeserializer()]); + async acirDeleteAcirComposer(acirComposerPtr: Ptr): Promise { + const result = await this.binder.callWasmExport('acir_delete_acir_composer', [acirComposerPtr], []); + return; + } + + async acirCreateCircuit(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, sizeHint: number): Promise { + const result = await this.binder.callWasmExport('acir_create_circuit', [acirComposerPtr, constraintSystemBuf, sizeHint], []); + return; + } + + async acirInitProvingKey(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, sizeHint: number): Promise { + const result = await this.binder.callWasmExport('acir_init_proving_key', [acirComposerPtr, constraintSystemBuf, sizeHint], []); + return; + } + + async acirCreateProof(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array, isRecursive: boolean): Promise { + const result = await this.binder.callWasmExport('acir_create_proof', [acirComposerPtr, constraintSystemBuf, witnessBuf, isRecursive], [BufferDeserializer()]); return result[0]; } - async testThreadAbort(): Promise { - const result = await this.binder.callWasmExport('test_thread_abort', [], []); + async acirLoadVerificationKey(acirComposerPtr: Ptr, vkBuf: Uint8Array): Promise { + const result = await this.binder.callWasmExport('acir_load_verification_key', [acirComposerPtr, vkBuf], []); return; } - async testAbort(): Promise { - const result = await this.binder.callWasmExport('test_abort', [], []); + async acirInitVerificationKey(acirComposerPtr: Ptr): Promise { + const result = await this.binder.callWasmExport('acir_init_verification_key', [acirComposerPtr], []); return; } + + async acirGetVerificationKey(acirComposerPtr: Ptr): Promise { + const result = await this.binder.callWasmExport('acir_get_verification_key', [acirComposerPtr], [BufferDeserializer()]); + return result[0]; + } + + async acirVerifyProof(acirComposerPtr: Ptr, proofBuf: Uint8Array, isRecursive: boolean): Promise { + const result = await this.binder.callWasmExport('acir_verify_proof', [acirComposerPtr, proofBuf, isRecursive], [BoolDeserializer()]); + return result[0]; + } + + async acirGetSolidityVerifier(acirComposerPtr: Ptr): Promise { + const result = await this.binder.callWasmExport('acir_get_solidity_verifier', [acirComposerPtr], [StringDeserializer()]); + return result[0]; + } + + async acirSerializeProofIntoFields(acirComposerPtr: Ptr, proofBuf: Uint8Array, numInnerPublicInputs: number): Promise { + const result = await this.binder.callWasmExport('acir_serialize_proof_into_fields', [acirComposerPtr, proofBuf, numInnerPublicInputs], [VectorDeserializer(Fr)]); + return result[0]; + } + + async acirSerializeVerificationKeyIntoFields(acirComposerPtr: Ptr): Promise<[Fr[], Fr]> { + const result = await this.binder.callWasmExport('acir_serialize_verification_key_into_fields', [acirComposerPtr], [VectorDeserializer(Fr), Fr]); + return result as any; + } } export class BarretenbergApiSync { @@ -300,11 +300,7 @@ export class BarretenbergApiSync { } pedersenHashMultipleWithHashIndex(inputsBuffer: Fr[], hashIndex: number): Fr { - const result = this.binder.callWasmExport( - 'pedersen_hash_multiple_with_hash_index', - [inputsBuffer, hashIndex], - [Fr], - ); + const result = this.binder.callWasmExport('pedersen_hash_multiple_with_hash_index', [inputsBuffer, hashIndex], [Fr]); return result[0]; } @@ -334,20 +330,12 @@ export class BarretenbergApiSync { } schnorrConstructSignature(message: Uint8Array, privateKey: Fr): [Buffer32, Buffer32] { - const result = this.binder.callWasmExport( - 'schnorr_construct_signature', - [message, privateKey], - [Buffer32, Buffer32], - ); + const result = this.binder.callWasmExport('schnorr_construct_signature', [message, privateKey], [Buffer32, Buffer32]); return result as any; } schnorrVerifySignature(message: Uint8Array, pubKey: Point, sigS: Buffer32, sigE: Buffer32): boolean { - const result = this.binder.callWasmExport( - 'schnorr_verify_signature', - [message, pubKey, sigS, sigE], - [BoolDeserializer()], - ); + const result = this.binder.callWasmExport('schnorr_verify_signature', [message, pubKey, sigS, sigE], [BoolDeserializer()]); return result[0]; } @@ -357,93 +345,117 @@ export class BarretenbergApiSync { } schnorrMultisigValidateAndCombineSignerPubkeys(signerPubkeyBuf: Buffer128[]): [Point, boolean] { - const result = this.binder.callWasmExport( - 'schnorr_multisig_validate_and_combine_signer_pubkeys', - [signerPubkeyBuf], - [Point, BoolDeserializer()], - ); + const result = this.binder.callWasmExport('schnorr_multisig_validate_and_combine_signer_pubkeys', [signerPubkeyBuf], [Point, BoolDeserializer()]); return result as any; } schnorrMultisigConstructSignatureRound1(): [Buffer128, Buffer128] { - const result = this.binder.callWasmExport( - 'schnorr_multisig_construct_signature_round_1', - [], - [Buffer128, Buffer128], - ); + const result = this.binder.callWasmExport('schnorr_multisig_construct_signature_round_1', [], [Buffer128, Buffer128]); return result as any; } - schnorrMultisigConstructSignatureRound2( - message: Uint8Array, - privateKey: Fq, - signerRoundOnePrivateBuf: Buffer128, - signerPubkeysBuf: Buffer128[], - roundOnePublicBuf: Buffer128[], - ): [Fq, boolean] { - const result = this.binder.callWasmExport( - 'schnorr_multisig_construct_signature_round_2', - [message, privateKey, signerRoundOnePrivateBuf, signerPubkeysBuf, roundOnePublicBuf], - [Fq, BoolDeserializer()], - ); + schnorrMultisigConstructSignatureRound2(message: Uint8Array, privateKey: Fq, signerRoundOnePrivateBuf: Buffer128, signerPubkeysBuf: Buffer128[], roundOnePublicBuf: Buffer128[]): [Fq, boolean] { + const result = this.binder.callWasmExport('schnorr_multisig_construct_signature_round_2', [message, privateKey, signerRoundOnePrivateBuf, signerPubkeysBuf, roundOnePublicBuf], [Fq, BoolDeserializer()]); return result as any; } - schnorrMultisigCombineSignatures( - message: Uint8Array, - signerPubkeysBuf: Buffer128[], - roundOneBuf: Buffer128[], - roundTwoBuf: Fr[], - ): [Buffer32, Buffer32, boolean] { - const result = this.binder.callWasmExport( - 'schnorr_multisig_combine_signatures', - [message, signerPubkeysBuf, roundOneBuf, roundTwoBuf], - [Buffer32, Buffer32, BoolDeserializer()], - ); + schnorrMultisigCombineSignatures(message: Uint8Array, signerPubkeysBuf: Buffer128[], roundOneBuf: Buffer128[], roundTwoBuf: Fr[]): [Buffer32, Buffer32, boolean] { + const result = this.binder.callWasmExport('schnorr_multisig_combine_signatures', [message, signerPubkeysBuf, roundOneBuf, roundTwoBuf], [Buffer32, Buffer32, BoolDeserializer()]); return result as any; } - eccNewPippenger(points: Uint8Array, numPoints: number): Ptr { - const result = this.binder.callWasmExport('ecc_new_pippenger', [points, numPoints], [Ptr]); + srsInitSrs(pointsBuf: Uint8Array, numPoints: number, g2PointBuf: Uint8Array): void { + const result = this.binder.callWasmExport('srs_init_srs', [pointsBuf, numPoints, g2PointBuf], []); + return; + } + + examplesSimpleCreateAndVerifyProof(): boolean { + const result = this.binder.callWasmExport('examples_simple_create_and_verify_proof', [], [BoolDeserializer()]); return result[0]; } - eccDeletePippenger(pippenger: Ptr): void { - const result = this.binder.callWasmExport('ecc_delete_pippenger', [pippenger], []); + testThreads(threads: number, iterations: number): number { + const result = this.binder.callWasmExport('test_threads', [threads, iterations], [NumberDeserializer()]); + return result[0]; + } + + testThreadAbort(): void { + const result = this.binder.callWasmExport('test_thread_abort', [], []); return; } - eccPippengerUnsafe(pippengerPtr: Ptr, scalarsPtr: Ptr, from: number, range: number): Point { - const result = this.binder.callWasmExport('ecc_pippenger_unsafe', [pippengerPtr, scalarsPtr, from, range], [Point]); - return result[0]; + testAbort(): void { + const result = this.binder.callWasmExport('test_abort', [], []); + return; } - eccG1Sum(pointsPtr: Ptr, numPoints: number): Point { - const result = this.binder.callWasmExport('ecc_g1_sum', [pointsPtr, numPoints], [Point]); - return result[0]; + commonInitSlabAllocator(circuitSize: number): void { + const result = this.binder.callWasmExport('common_init_slab_allocator', [circuitSize], []); + return; + } + + acirGetCircuitSizes(constraintSystemBuf: Uint8Array): [number, number, number] { + const result = this.binder.callWasmExport('acir_get_circuit_sizes', [constraintSystemBuf], [NumberDeserializer(), NumberDeserializer(), NumberDeserializer()]); + return result as any; } - examplesSimpleCreateAndVerifyProof(pippenger: Ptr, g2x: Uint8Array): boolean { - const result = this.binder.callWasmExport( - 'examples_simple_create_and_verify_proof', - [pippenger, g2x], - [BoolDeserializer()], - ); + acirNewAcirComposer(): Ptr { + const result = this.binder.callWasmExport('acir_new_acir_composer', [], [Ptr]); return result[0]; } - testThreads(threads: number, iterations: number): number { - const result = this.binder.callWasmExport('test_threads', [threads, iterations], [NumberDeserializer()]); + acirDeleteAcirComposer(acirComposerPtr: Ptr): void { + const result = this.binder.callWasmExport('acir_delete_acir_composer', [acirComposerPtr], []); + return; + } + + acirCreateCircuit(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, sizeHint: number): void { + const result = this.binder.callWasmExport('acir_create_circuit', [acirComposerPtr, constraintSystemBuf, sizeHint], []); + return; + } + + acirInitProvingKey(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, sizeHint: number): void { + const result = this.binder.callWasmExport('acir_init_proving_key', [acirComposerPtr, constraintSystemBuf, sizeHint], []); + return; + } + + acirCreateProof(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array, isRecursive: boolean): Uint8Array { + const result = this.binder.callWasmExport('acir_create_proof', [acirComposerPtr, constraintSystemBuf, witnessBuf, isRecursive], [BufferDeserializer()]); return result[0]; } - testThreadAbort(): void { - const result = this.binder.callWasmExport('test_thread_abort', [], []); + acirLoadVerificationKey(acirComposerPtr: Ptr, vkBuf: Uint8Array): void { + const result = this.binder.callWasmExport('acir_load_verification_key', [acirComposerPtr, vkBuf], []); return; } - testAbort(): void { - const result = this.binder.callWasmExport('test_abort', [], []); + acirInitVerificationKey(acirComposerPtr: Ptr): void { + const result = this.binder.callWasmExport('acir_init_verification_key', [acirComposerPtr], []); return; } + + acirGetVerificationKey(acirComposerPtr: Ptr): Uint8Array { + const result = this.binder.callWasmExport('acir_get_verification_key', [acirComposerPtr], [BufferDeserializer()]); + return result[0]; + } + + acirVerifyProof(acirComposerPtr: Ptr, proofBuf: Uint8Array, isRecursive: boolean): boolean { + const result = this.binder.callWasmExport('acir_verify_proof', [acirComposerPtr, proofBuf, isRecursive], [BoolDeserializer()]); + return result[0]; + } + + acirGetSolidityVerifier(acirComposerPtr: Ptr): string { + const result = this.binder.callWasmExport('acir_get_solidity_verifier', [acirComposerPtr], [StringDeserializer()]); + return result[0]; + } + + acirSerializeProofIntoFields(acirComposerPtr: Ptr, proofBuf: Uint8Array, numInnerPublicInputs: number): Fr[] { + const result = this.binder.callWasmExport('acir_serialize_proof_into_fields', [acirComposerPtr, proofBuf, numInnerPublicInputs], [VectorDeserializer(Fr)]); + return result[0]; + } + + acirSerializeVerificationKeyIntoFields(acirComposerPtr: Ptr): [Fr[], Fr] { + const result = this.binder.callWasmExport('acir_serialize_verification_key_into_fields', [acirComposerPtr], [VectorDeserializer(Fr), Fr]); + return result as any; + } } diff --git a/ts/src/barretenberg_api/pedersen.test.ts b/ts/src/barretenberg_api/pedersen.test.ts index 24a4633a21..3e812f5ae7 100644 --- a/ts/src/barretenberg_api/pedersen.test.ts +++ b/ts/src/barretenberg_api/pedersen.test.ts @@ -1,5 +1,4 @@ -import { BarretenbergBinderSync } from '../barretenberg_binder/index.js'; -import { BarretenbergWasm } from '../barretenberg_wasm/barretenberg_wasm.js'; +import { newBarretenbergApiSync } from '../factory/index.js'; import { Fr } from '../types/index.js'; import { BarretenbergApiSync } from './index.js'; @@ -7,7 +6,7 @@ describe('pedersen', () => { let api: BarretenbergApiSync; beforeAll(async () => { - api = new BarretenbergApiSync(new BarretenbergBinderSync(await BarretenbergWasm.new(1))); + api = await newBarretenbergApiSync(); api.pedersenHashInit(); }); @@ -22,7 +21,7 @@ describe('pedersen', () => { it('pedersenPlookupCompressFields', () => { const result = api.pedersenPlookupCompressFields(new Fr(4n), new Fr(8n)); - expect(result).toEqual(new Fr(7508407170365331152493586290597472346478280823936748458450026785528968221772n)); + expect(result).toEqual(new Fr(21568810706345846819294487214368613840251909831689369685420108292337497444070n)); }); it('pedersenCompress', () => { @@ -32,7 +31,7 @@ describe('pedersen', () => { it('pedersenPlookupCompress', () => { const result = api.pedersenPlookupCompress([new Fr(4n), new Fr(8n), new Fr(12n)]); - expect(result).toEqual(new Fr(641613987782189905475142047603559162464012327378197326488471789040703504911n)); + expect(result).toEqual(new Fr(4213911891650716450883144878301329379460622830501147795631256054071351353887n)); }); it('pedersenCompressWithHashIndex', () => { @@ -47,7 +46,7 @@ describe('pedersen', () => { it('pedersenPlookupCommit', () => { const result = api.pedersenPlookupCommit([new Fr(4n), new Fr(8n)]); - expect(result).toEqual(new Fr(7508407170365331152493586290597472346478280823936748458450026785528968221772n)); + expect(result).toEqual(new Fr(21568810706345846819294487214368613840251909831689369685420108292337497444070n)); }); it('pedersenBufferToField', () => { diff --git a/ts/src/barretenberg_api/schnorr.test.ts b/ts/src/barretenberg_api/schnorr.test.ts index a990421f9a..2d8e9e6650 100644 --- a/ts/src/barretenberg_api/schnorr.test.ts +++ b/ts/src/barretenberg_api/schnorr.test.ts @@ -1,15 +1,14 @@ import { TextEncoder } from 'util'; import { Buffer128, Buffer32, Fr, Point } from '../types/index.js'; import { BarretenbergApiSync } from './index.js'; -import { BarretenbergBinderSync } from '../barretenberg_binder/index.js'; -import { BarretenbergWasm } from '../barretenberg_wasm/barretenberg_wasm.js'; +import { newBarretenbergApiSync } from '../factory/index.js'; describe('schnorr', () => { const msg = Buffer.from(new TextEncoder().encode('The quick brown dog jumped over the lazy fox.')); let api: BarretenbergApiSync; beforeAll(async () => { - api = new BarretenbergApiSync(new BarretenbergBinderSync(await BarretenbergWasm.new(1))); + api = await newBarretenbergApiSync(); api.pedersenInit(); }); diff --git a/ts/src/barretenberg_wasm/barretenberg.wasm b/ts/src/barretenberg_wasm/barretenberg.wasm deleted file mode 120000 index f6e5fe2c73..0000000000 --- a/ts/src/barretenberg_wasm/barretenberg.wasm +++ /dev/null @@ -1 +0,0 @@ -../../../cpp/build-wasm/bin/barretenberg.wasm \ No newline at end of file diff --git a/ts/src/barretenberg_wasm/barretenberg_wasm.test.ts b/ts/src/barretenberg_wasm/barretenberg_wasm.test.ts index 2f7fb078ce..2cf1517083 100644 --- a/ts/src/barretenberg_wasm/barretenberg_wasm.test.ts +++ b/ts/src/barretenberg_wasm/barretenberg_wasm.test.ts @@ -5,7 +5,7 @@ describe('barretenberg wasm', () => { let wasm!: BarretenbergWasm; beforeAll(async () => { - wasm = await BarretenbergWasm.new(1); + wasm = await BarretenbergWasm.new(); }); afterAll(async () => { diff --git a/ts/src/barretenberg_wasm/barretenberg_wasm.ts b/ts/src/barretenberg_wasm/barretenberg_wasm.ts index c91eeb4710..d94b32f989 100644 --- a/ts/src/barretenberg_wasm/barretenberg_wasm.ts +++ b/ts/src/barretenberg_wasm/barretenberg_wasm.ts @@ -5,17 +5,10 @@ import { Remote, proxy } from 'comlink'; import { randomBytes } from '../random/index.js'; // Webpack config swaps this import with ./browser/index.js // You can toggle between these two imports to sanity check the type-safety. -import { - fetchCode, - getNumCpu, - createWorker, - getRemoteBarretenbergWasm, - threadLogger, - throwOrAbort, -} from './node/index.js'; +import { fetchCode, getNumCpu, createWorker, getRemoteBarretenbergWasm, threadLogger, killSelf } from './node/index.js'; // import { fetchCode, getNumCpu, createWorker, randomBytes } from './browser/index.js'; -const debug = createDebug('wasm'); +const debug = createDebug('bb.js:wasm'); EventEmitter.defaultMaxListeners = 30; @@ -27,11 +20,12 @@ export class BarretenbergWasm { private remoteWasms: BarretenbergWasmWorker[] = []; private nextWorker = 0; private nextThreadId = 1; + private isThread = false; private logger: (msg: string) => void = debug; - public static async new(threads = Math.min(getNumCpu(), this.MAX_THREADS)) { + public static async new() { const barretenberg = new BarretenbergWasm(); - await barretenberg.init(threads); + await barretenberg.init(1); return barretenberg; } @@ -69,9 +63,12 @@ export class BarretenbergWasm { `threads: ${threads}`, ); - this.memory = new WebAssembly.Memory({ initial, maximum, shared: true }); + this.memory = new WebAssembly.Memory({ initial, maximum, shared: threads > 1 }); - const { instance, module } = await WebAssembly.instantiate(await fetchCode(), this.getImportObj(this.memory)); + // Annoyingly the wasm declares if it's memory is shared or not. So now we need two wasms if we want to be + // able to fallback on "non shared memory" situations. + const code = await fetchCode(threads > 1 ? 'barretenberg-threads.wasm' : 'barretenberg.wasm'); + const { instance, module } = await WebAssembly.instantiate(code, this.getImportObj(this.memory)); this.instance = instance; @@ -90,6 +87,7 @@ export class BarretenbergWasm { * Init as worker thread. */ public async initThread(module: WebAssembly.Module, memory: WebAssembly.Memory) { + this.isThread = true; this.logger = threadLogger() || this.logger; this.memory = memory; this.instance = await WebAssembly.instantiate(module, this.getImportObj(this.memory)); @@ -124,7 +122,7 @@ export class BarretenbergWasm { proc_exit: () => { this.logger('HUNG: proc_exit was called. This is caused by unstable experimental wasi pthreads. Try again.'); this.logger(new Error().stack!); - throwOrAbort(); + killSelf(); }, }, wasi: { @@ -184,7 +182,11 @@ export class BarretenbergWasm { const message = `WASM function ${name} aborted, error: ${err}`; this.logger(message); this.logger(err.stack); - throwOrAbort(); + if (this.isThread) { + killSelf(); + } else { + throw err; + } } } diff --git a/ts/src/barretenberg_wasm/browser/index.ts b/ts/src/barretenberg_wasm/browser/index.ts index 81c4340cca..0b89ff9505 100644 --- a/ts/src/barretenberg_wasm/browser/index.ts +++ b/ts/src/barretenberg_wasm/browser/index.ts @@ -2,8 +2,8 @@ import { wrap } from 'comlink'; import { BarretenbergWasmWorker, type BarretenbergWasm } from '../barretenberg_wasm.js'; import debug from 'debug'; -export async function fetchCode() { - const res = await fetch('/barretenberg.wasm'); +export async function fetchCode(name: string) { + const res = await fetch('/' + name); return await res.arrayBuffer(); } @@ -27,9 +27,6 @@ export function threadLogger(): ((msg: string) => void) | undefined { return undefined; } -export function throwOrAbort() { - if (self?.close) { - self.close(); - } - throw new Error('throwOrAbort called.'); +export function killSelf() { + self.close(); } diff --git a/ts/src/barretenberg_wasm/node/index.ts b/ts/src/barretenberg_wasm/node/index.ts index dbc437e371..7285cbda50 100644 --- a/ts/src/barretenberg_wasm/node/index.ts +++ b/ts/src/barretenberg_wasm/node/index.ts @@ -8,14 +8,14 @@ import { wrap } from 'comlink'; import { nodeEndpoint } from './node_endpoint.js'; import { writeSync } from 'fs'; -export async function fetchCode() { +export async function fetchCode(name: string) { const __dirname = dirname(fileURLToPath(import.meta.url)); - return await readFile(__dirname + '/../barretenberg.wasm'); + return await readFile(__dirname + '/../../' + name); } export function createWorker() { const __dirname = dirname(fileURLToPath(import.meta.url)); - return new Worker(__dirname + `/worker.ts`); + return new Worker(__dirname + `/worker.js`); } export function getRemoteBarretenbergWasm(worker: Worker): BarretenbergWasmWorker { @@ -38,7 +38,7 @@ export function threadLogger(): ((msg: string) => void) | undefined { }; } -export function throwOrAbort(): never { +export function killSelf(): never { // Extordinarily hard process termination. Due to how parent threads block on child threads etc, even process.exit // doesn't seem to be able to abort the process. The following does. process.kill(process.pid); diff --git a/ts/src/bindgen/mappings.ts b/ts/src/bindgen/mappings.ts index ad9427516e..2b6c2ffa6d 100644 --- a/ts/src/bindgen/mappings.ts +++ b/ts/src/bindgen/mappings.ts @@ -2,6 +2,8 @@ const typeMap: { [key: string]: string } = { in_ptr: 'Ptr', out_ptr: 'Ptr', + 'barretenberg::fr::in_buf': 'Fr', + 'barretenberg::fr::vec_in_buf': 'Fr[]', 'fr::in_buf': 'Fr', 'fr::out_buf': 'Fr', 'fr::vec_in_buf': 'Fr[]', diff --git a/ts/src/bindgen/typescript.ts b/ts/src/bindgen/typescript.ts index 630335d3f5..5dda779bd8 100644 --- a/ts/src/bindgen/typescript.ts +++ b/ts/src/bindgen/typescript.ts @@ -10,7 +10,7 @@ export function generateTypeScriptCode(filename: string) { let output = `// WARNING: FILE CODE GENERATED BY BINDGEN UTILITY. DO NOT EDIT! /* eslint-disable @typescript-eslint/no-unused-vars */ import { BarretenbergBinder, BarretenbergBinderSync } from '../barretenberg_binder/index.js'; -import { BufferDeserializer, NumberDeserializer, VectorDeserializer, BoolDeserializer } from '../serialize/index.js'; +import { BufferDeserializer, NumberDeserializer, VectorDeserializer, BoolDeserializer, StringDeserializer } from '../serialize/index.js'; import { Fr, Fq, Point, Buffer32, Buffer128, Ptr } from '../types/index.js'; export class BarretenbergApi { diff --git a/ts/src/crs/browser/cached_net_crs.ts b/ts/src/crs/browser/cached_net_crs.ts index 3152933d3b..d2822d68a2 100644 --- a/ts/src/crs/browser/cached_net_crs.ts +++ b/ts/src/crs/browser/cached_net_crs.ts @@ -1,3 +1,4 @@ +import { concatenateUint8Arrays, numToUInt32BE } from '../../serialize/index.js'; import { NetCrs } from '../net_crs.js'; import { get, set } from 'idb-keyval'; diff --git a/ts/src/crs/node/index.ts b/ts/src/crs/node/index.ts index 7598b10148..f66646c96b 100644 --- a/ts/src/crs/node/index.ts +++ b/ts/src/crs/node/index.ts @@ -1,3 +1,4 @@ +import { concatenateUint8Arrays, numToUInt32BE } from '../../serialize/serialize.js'; import { NetCrs } from '../net_crs.js'; import { FileCrs } from './file_crs.js'; diff --git a/ts/src/examples/simple.rawtest.ts b/ts/src/examples/simple.rawtest.ts index 4d9ff24c75..5998376f23 100644 --- a/ts/src/examples/simple.rawtest.ts +++ b/ts/src/examples/simple.rawtest.ts @@ -1,28 +1,30 @@ -import { BarretenbergWasm } from '../barretenberg_wasm/index.js'; import { Crs } from '../crs/index.js'; import createDebug from 'debug'; -import { BarretenbergApi } from '../barretenberg_api/index.js'; -import { BarretenbergBinder } from '../barretenberg_binder/index.js'; +import { newBarretenbergApiAsync } from '../factory/index.js'; +import { RawBuffer } from '../types/index.js'; createDebug.enable('*'); const debug = createDebug('simple_test'); async function main() { + const CIRCUIT_SIZE = 2 ** 19; + debug('starting test...'); - const { wasm, worker } = await BarretenbergWasm.newWorker(); - const api = new BarretenbergApi(new BarretenbergBinder(wasm)); + const api = await newBarretenbergApiAsync(); + + // Important to init slab allocator as first thing, to ensure maximum memory efficiency. + await api.commonInitSlabAllocator(CIRCUIT_SIZE); // Plus 1 needed! - const crs = await Crs.new(2 ** 19 + 1); - const pippengerPtr = await api.eccNewPippenger(crs.getG1Data(), crs.numPoints); + const crs = await Crs.new(CIRCUIT_SIZE + 1); + await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); for (let i = 0; i < 10; ++i) { debug(`iteration ${i} starting...`); - await api.examplesSimpleCreateAndVerifyProof(pippengerPtr, crs.getG2Data()); + await api.examplesSimpleCreateAndVerifyProof(); } - await wasm.destroy(); - await worker.terminate(); + await api.destroy(); debug('test complete.'); } diff --git a/ts/src/examples/simple.test.ts b/ts/src/examples/simple.test.ts index a79fe4c449..c32496fdfc 100644 --- a/ts/src/examples/simple.test.ts +++ b/ts/src/examples/simple.test.ts @@ -1,13 +1,19 @@ -import { BarretenbergApiSync } from '../barretenberg_api/index.js'; -import { BarretenbergWasm } from '../barretenberg_wasm/index.js'; -import { BarretenbergBinderSync } from '../barretenberg_binder/index.js'; import { Crs } from '../index.js'; +import { BarretenbergApiAsync, newBarretenbergApiAsync } from '../factory/index.js'; +import { RawBuffer } from '../types/index.js'; describe('simple', () => { - let api: BarretenbergApiSync; + let api: BarretenbergApiAsync; beforeAll(async () => { - api = new BarretenbergApiSync(new BarretenbergBinderSync(await BarretenbergWasm.new())); + api = await newBarretenbergApiAsync(); + + // Important to init slab allocator as first thing, to ensure maximum memory efficiency. + const CIRCUIT_SIZE = 2 ** 19; + await api.commonInitSlabAllocator(CIRCUIT_SIZE); + + const crs = await Crs.new(2 ** 19 + 1); + await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); }, 20000); afterAll(async () => { @@ -15,9 +21,7 @@ describe('simple', () => { }); it('should construct 512k gate proof', async () => { - const crs = await Crs.new(2 ** 19 + 1); - const pippengerPtr = api.eccNewPippenger(crs.getG1Data(), crs.numPoints); - const valid = api.examplesSimpleCreateAndVerifyProof(pippengerPtr, crs.getG2Data()); + const valid = await api.examplesSimpleCreateAndVerifyProof(); expect(valid).toBe(true); }, 60000); }); diff --git a/ts/src/factory/index.ts b/ts/src/factory/index.ts new file mode 100644 index 0000000000..9daae9189c --- /dev/null +++ b/ts/src/factory/index.ts @@ -0,0 +1,36 @@ +import { BarretenbergApi, BarretenbergApiSync } from '../barretenberg_api/index.js'; +import { BarretenbergBinder, BarretenbergBinderSync } from '../barretenberg_binder/index.js'; +import { BarretenbergWasm, BarretenbergWasmWorker } from '../barretenberg_wasm/index.js'; + +/** + * Returns a single threaded, synchronous, barretenberg api. + * Can be used on the main thread to perform small light-weight requests like hashing etc. + */ +export async function newBarretenbergApiSync() { + return new BarretenbergApiSync(new BarretenbergBinderSync(await BarretenbergWasm.new())); +} + +export class BarretenbergApiAsync extends BarretenbergApi { + constructor(private worker: any, private wasm: BarretenbergWasmWorker) { + super(new BarretenbergBinder(wasm)); + } + + async getNumThreads() { + return await this.wasm.getNumThreads(); + } + + async destroy() { + await this.wasm.destroy(); + await this.worker.terminate(); + } +} + +/** + * Returns a multi threaded, asynchronous, barretenberg api. + * It runs in a worker, and so can be used within the browser to execute long running, multi-threaded requests + * like proof construction etc. + */ +export async function newBarretenbergApiAsync(threads?: number) { + const { wasm, worker } = await BarretenbergWasm.newWorker(threads); + return new BarretenbergApiAsync(worker, wasm); +} diff --git a/ts/src/index.ts b/ts/src/index.ts index b6df75a32a..686cf4af06 100644 --- a/ts/src/index.ts +++ b/ts/src/index.ts @@ -1,3 +1,5 @@ export * from './crs/index.js'; export * from './barretenberg_wasm/index.js'; export * from './barretenberg_api/index.js'; +export * from './factory/index.js'; +export { RawBuffer } from './types/index.js'; diff --git a/ts/src/main.ts b/ts/src/main.ts new file mode 100755 index 0000000000..dc8c5c50cd --- /dev/null +++ b/ts/src/main.ts @@ -0,0 +1,336 @@ +#!/usr/bin/env -S node --no-warnings +import { Crs, BarretenbergApiAsync, newBarretenbergApiAsync, RawBuffer } from './index.js'; +import createDebug from 'debug'; +import { readFileSync, writeFileSync } from 'fs'; +import { gunzipSync } from 'zlib'; +import { numToUInt32BE } from './serialize/serialize.js'; +import { Command } from 'commander'; + +createDebug.log = console.error.bind(console); +const debug = createDebug('bb.js'); + +// Maximum we support. +const MAX_CIRCUIT_SIZE = 2 ** 19; + +function getBytecode(jsonPath: string) { + const json = readFileSync(jsonPath, 'utf-8'); + const parsed = JSON.parse(json); + const buffer = Buffer.from(parsed.bytecode, 'base64'); + const decompressed = gunzipSync(buffer); + return decompressed; +} + +function getWitness(witnessPath: string) { + const data = readFileSync(witnessPath); + return Buffer.concat([numToUInt32BE(data.length / 32), data]); +} + +async function getCircuitSize(jsonPath: string, api: BarretenbergApiAsync) { + const bytecode = getBytecode(jsonPath); + const [exact, total, subgroup] = await api.acirGetCircuitSizes(new RawBuffer(bytecode)); + return { exact, total, subgroup }; +} + +async function init(jsonPath: string) { + const api = await newBarretenbergApiAsync(); + + // First compute circuit size. + const circuitSizes = await getCircuitSize(jsonPath, api); + debug(`circuit size: ${circuitSizes.total}`); + + if (circuitSizes.subgroup > MAX_CIRCUIT_SIZE) { + throw new Error(`Circuit size of ${circuitSizes.subgroup} exceeds max supported of ${MAX_CIRCUIT_SIZE}`); + } + + // Plus 1 needed! (Move +1 into Crs?) + const crs = await Crs.new(circuitSizes.subgroup + 1); + + // Important to init slab allocator as first thing, to ensure maximum memory efficiency. + await api.commonInitSlabAllocator(circuitSizes.subgroup); + + // Load CRS into wasm global CRS state. + // TODO: Make RawBuffer be default behaviour, and have a specific Vector type for when wanting length prefixed. + await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); + + const acirComposer = await api.acirNewAcirComposer(); + return { api, acirComposer, circuitSize: circuitSizes.subgroup }; +} + +async function initLite() { + const api = await newBarretenbergApiAsync(1); + + // Plus 1 needed! (Move +1 into Crs?) + const crs = await Crs.new(1); + + // Load CRS into wasm global CRS state. + await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); + + const acirComposer = await api.acirNewAcirComposer(); + return { api, acirComposer }; +} + +export async function proveAndVerify(jsonPath: string, witnessPath: string, isRecursive: boolean) { + const { api, acirComposer, circuitSize } = await init(jsonPath); + try { + debug('initing proving key...'); + const bytecode = getBytecode(jsonPath); + await api.acirInitProvingKey(acirComposer, new RawBuffer(bytecode), circuitSize); + + // const circuitSize = await api.acirGetExactCircuitSize(acirComposer); + // debug(`circuit size: ${circuitSize}`); + + debug('initing verification key...'); + await api.acirInitVerificationKey(acirComposer); + + debug(`creating proof...`); + const witness = getWitness(witnessPath); + const proof = await api.acirCreateProof(acirComposer, new RawBuffer(bytecode), new RawBuffer(witness), isRecursive); + debug(`done.`); + + const verified = await api.acirVerifyProof(acirComposer, proof, isRecursive); + console.log(`verified: ${verified}`); + return verified; + } finally { + await api.destroy(); + } +} + +export async function prove(jsonPath: string, witnessPath: string, isRecursive: boolean, outputPath: string) { + const { api, acirComposer, circuitSize } = await init(jsonPath); + try { + debug('initing proving key...'); + const bytecode = getBytecode(jsonPath); + await api.acirInitProvingKey(acirComposer, new RawBuffer(bytecode), circuitSize); + + // const circuitSize = await api.acirGetExactCircuitSize(acirComposer); + // debug(`circuit size: ${circuitSize}`); + + debug(`creating proof...`); + const witness = getWitness(witnessPath); + const proof = await api.acirCreateProof(acirComposer, new RawBuffer(bytecode), new RawBuffer(witness), isRecursive); + debug(`done.`); + + writeFileSync(outputPath, proof); + console.log(`proof written to: ${outputPath}`); + } finally { + await api.destroy(); + } +} + +export async function gateCount(jsonPath: string) { + const api = await newBarretenbergApiAsync(1); + try { + const circuitSizes = await getCircuitSize(jsonPath, api); + console.log(`${circuitSizes.exact}`); + } finally { + await api.destroy(); + } +} + +export async function verify(jsonPath: string, proofPath: string, isRecursive: boolean, vkPath?: string) { + if (vkPath) { + const { api, acirComposer } = await initLite(); + try { + await api.acirLoadVerificationKey(acirComposer, new RawBuffer(readFileSync(vkPath))); + const verified = await api.acirVerifyProof(acirComposer, readFileSync(proofPath), isRecursive); + console.log(`verified: ${verified}`); + return verified; + } finally { + await api.destroy(); + } + } else { + const { api, acirComposer, circuitSize } = await init(jsonPath); + try { + debug('initing proving key...'); + const bytecode = getBytecode(jsonPath); + await api.acirInitProvingKey(acirComposer, new RawBuffer(bytecode), circuitSize); + + debug('initing verification key...'); + await api.acirInitVerificationKey(acirComposer); + + const verified = await api.acirVerifyProof(acirComposer, readFileSync(proofPath), isRecursive); + console.log(`verified: ${verified}`); + return verified; + } finally { + await api.destroy(); + } + } +} + +export async function contract(jsonPath: string, outputPath: string) { + const { api, acirComposer, circuitSize } = await init(jsonPath); + try { + debug('initing proving key...'); + const bytecode = getBytecode(jsonPath); + await api.acirInitProvingKey(acirComposer, new RawBuffer(bytecode), circuitSize); + + debug('initing verification key...'); + await api.acirInitVerificationKey(acirComposer); + + const contract = await api.acirGetSolidityVerifier(acirComposer); + if (outputPath === '-') { + console.log(contract); + } else { + writeFileSync(outputPath, contract); + console.log(`contract written to: ${outputPath}`); + } + } finally { + await api.destroy(); + } +} + +export async function writeVk(jsonPath: string, outputPath: string) { + const { api, acirComposer, circuitSize } = await init(jsonPath); + try { + debug('initing proving key...'); + const bytecode = getBytecode(jsonPath); + await api.acirInitProvingKey(acirComposer, new RawBuffer(bytecode), circuitSize); + + debug('initing verification key...'); + const vk = await api.acirGetVerificationKey(acirComposer); + if (outputPath === '-') { + process.stdout.write(vk); + } else { + writeFileSync(outputPath, vk); + console.log(`vk written to: ${outputPath}`); + } + } finally { + await api.destroy(); + } +} + +export async function proofAsFields(proofPath: string, numInnerPublicInputs: number, outputPath: string) { + const { api, acirComposer } = await initLite(); + + try { + debug('serializing proof byte array into field elements'); + const proofAsFields = await api.acirSerializeProofIntoFields( + acirComposer, + readFileSync(proofPath), + numInnerPublicInputs, + ); + + writeFileSync(outputPath, JSON.stringify(proofAsFields.map(f => f.toString()))); + debug('done.'); + } finally { + await api.destroy(); + } +} + +export async function vkAsFields(vkPath: string, vkeyOutputPath: string) { + const { api, acirComposer } = await initLite(); + + try { + debug('serializing vk byte array into field elements'); + await api.acirLoadVerificationKey(acirComposer, new RawBuffer(readFileSync(vkPath))); + const [vkAsFields, vkHash] = await api.acirSerializeVerificationKeyIntoFields(acirComposer); + const output = [vkHash, ...vkAsFields].map(f => f.toString()); + writeFileSync(vkeyOutputPath, JSON.stringify(output)); + debug('done.'); + } finally { + await api.destroy(); + } +} + +// nargo use bb.js: backend -> bb.js +// backend prove --data-dir data --witness /foo/bar/witness.tr --json /foo/bar/main.json +// backend verify ... +// backend get_total_num_gates --data-dir data --json /foo/bar/main.json +// backend get_sol_contract --data-dir data --json /foo/bar/main.json --output +// backend get_features +// OPTIONAL stateful backend: +// backend start +// backend stop + +const program = new Command(); + +program.option('-v, --verbose', 'enable verbose logging', false); + +function handleGlobalOptions() { + if (program.opts().verbose) { + createDebug.enable('bb.js*'); + } +} + +program + .command('prove_and_verify') + .description('Generate a proof and verify it. Process exits with success or failure code.') + .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') + .option('-w, --witness-path ', 'Specify the witness path', './target/witness.tr') + .option('-r, --recursive', 'prove and verify using recursive prover and verifier', false) + .action(async ({ jsonPath, witnessPath, recursive }) => { + handleGlobalOptions(); + const result = await proveAndVerify(jsonPath, witnessPath, recursive); + process.exit(result ? 0 : 1); + }); + +program + .command('prove') + .description('Generate a proof and write it to a file.') + .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') + .option('-w, --witness-path ', 'Specify the witness path', './target/witness.tr') + .option('-r, --recursive', 'prove using recursive prover', false) + .option('-o, --output-dir ', 'Specify the proof output dir', './proofs') + .requiredOption('-n, --name ', 'Output file name.') + .action(async ({ jsonPath, witnessPath, recursive, outputDir, name }) => { + handleGlobalOptions(); + await prove(jsonPath, witnessPath, recursive, outputDir + '/' + name); + }); + +program + .command('gates') + .description('Print gate count to standard output.') + .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') + .action(async ({ jsonPath }) => { + await gateCount(jsonPath); + }); + +program + .command('verify') + .description('Verify a proof. Process exists with success or failure code.') + .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') + .requiredOption('-p, --proof-path ', 'Specify the path to the proof') + .option('-r, --recursive', 'prove using recursive prover', false) + .option('-k, --vk ', 'path to a verification key. avoids recomputation.') + .action(async ({ jsonPath, proofPath, recursive, vk }) => { + await verify(jsonPath, proofPath, recursive, vk); + }); + +program + .command('contract') + .description('Output solidity verification key contract.') + .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') + .option('-o, --output-path ', 'Specify the path to write the contract', '-') + .action(async ({ jsonPath, outputPath }) => { + await contract(jsonPath, outputPath); + }); + +program + .command('write_vk') + .description('Output verification key.') + .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') + .requiredOption('-o, --output-path ', 'Specify the path to write the key') + .action(async ({ jsonPath, outputPath }) => { + await writeVk(jsonPath, outputPath); + }); + +program + .command('proof_as_fields') + .description('Return the proof as fields elements') + .requiredOption('-p, --proof-path ', 'Specify the proof path') + .requiredOption('-n, --num-public-inputs ', 'Specify the number of public inputs') + .requiredOption('-o, --output-path ', 'Specify the JSON path to write the proof fields') + .action(async ({ proofPath, numPublicInputs, outputPath }) => { + await proofAsFields(proofPath, numPublicInputs, outputPath); + }); + +program + .command('vk_as_fields') + .description('Return the verifiation key represented as fields elements. Also return the verification key hash.') + .requiredOption('-i, --input-path ', 'Specifies the vk path (output from write_vk)') + .requiredOption('-o, --output-path ', 'Specify the JSON path to write the verification key fields and key hash') + .action(async ({ inputPath, outputPath }) => { + await vkAsFields(inputPath, outputPath); + }); + +program.name('bb.js').parse(process.argv); diff --git a/ts/src/serialize/buffer_reader.ts b/ts/src/serialize/buffer_reader.ts index 97f0c233ee..46f6560879 100644 --- a/ts/src/serialize/buffer_reader.ts +++ b/ts/src/serialize/buffer_reader.ts @@ -61,7 +61,7 @@ export class BufferReader { } public readString(): string { - return this.readBuffer().toString(); + return new TextDecoder().decode(this.readBuffer()); } public readBuffer(): Uint8Array { diff --git a/ts/src/serialize/serialize.ts b/ts/src/serialize/serialize.ts index 0161989401..b09caac6b0 100644 --- a/ts/src/serialize/serialize.ts +++ b/ts/src/serialize/serialize.ts @@ -1,3 +1,5 @@ +import { RawBuffer } from '../types/raw_buffer.js'; + // For serializing bool. export function boolToBuffer(b: boolean) { const buf = new Uint8Array(1); @@ -33,7 +35,7 @@ export function numToUInt8(n: number) { return buf; } -function concatenateUint8Arrays(arrayOfUint8Arrays: Uint8Array[]) { +export function concatenateUint8Arrays(arrayOfUint8Arrays: Uint8Array[]) { const totalLength = arrayOfUint8Arrays.reduce((prev, curr) => prev + curr.length, 0); const result = new Uint8Array(totalLength); let length = 0; @@ -44,6 +46,10 @@ function concatenateUint8Arrays(arrayOfUint8Arrays: Uint8Array[]) { return result; } +export function uint8ArrayToHexString(uint8Array: Uint8Array) { + return uint8Array.reduce((accumulator, byte) => accumulator + byte.toString(16).padStart(2, '0'), ''); +} + // For serializing a buffer as a vector. export function serializeBufferToVector(buf: Uint8Array) { return concatenateUint8Arrays([numToInt32BE(buf.length), buf]); @@ -133,6 +139,8 @@ export type Bufferable = boolean | Uint8Array | number | string | { toBuffer: () export function serializeBufferable(obj: Bufferable): Uint8Array { if (Array.isArray(obj)) { return serializeBufferArrayToVector(obj.map(serializeBufferable)); + } else if (obj instanceof RawBuffer) { + return obj; } else if (obj instanceof Uint8Array) { return serializeBufferToVector(obj); } else if (typeof obj === 'boolean') { diff --git a/ts/src/serialize/serialize.ts.bak b/ts/src/serialize/serialize.ts.bak deleted file mode 100644 index bb5e3d677f..0000000000 --- a/ts/src/serialize/serialize.ts.bak +++ /dev/null @@ -1,132 +0,0 @@ -import { toBigIntBE, toBufferBE } from 'bigint-buffer'; - -// For serializing bool. -export function boolToBuffer(b: boolean) { - const buf = Buffer.alloc(1); - buf.writeUInt8(b ? 1 : 0); - return buf; -} - -// For serializing numbers to 32 bit little-endian form. -export function numToUInt32LE(n: number, bufferSize = 4) { - const buf = Buffer.alloc(bufferSize); - buf.writeUInt32LE(n, bufferSize - 4); - return buf; -} - -// For serializing numbers to 32 bit big-endian form. -export function numToUInt32BE(n: number, bufferSize = 4) { - const buf = Buffer.alloc(bufferSize); - buf.writeUInt32BE(n, bufferSize - 4); - return buf; -} - -// For serializing signed numbers to 32 bit big-endian form. -export function numToInt32BE(n: number, bufferSize = 4) { - const buf = Buffer.alloc(bufferSize); - buf.writeInt32BE(n, bufferSize - 4); - return buf; -} - -// For serializing numbers to 32 bit big-endian form. -export function numToUInt8(n: number) { - const bufferSize = 1; - const buf = Buffer.alloc(bufferSize); - buf.writeUInt8(n, 0); - return buf; -} - -// For serializing a buffer as a vector. -export function serializeBufferToVector(buf: Buffer) { - const lengthBuf = Buffer.alloc(4); - lengthBuf.writeUInt32BE(buf.length, 0); - return Buffer.concat([lengthBuf, buf]); -} - -export function serializeBigInt(n: bigint, width = 32) { - return toBufferBE(n, width); -} - -export function deserializeBigInt(buf: Buffer, offset = 0, width = 32) { - return { elem: toBigIntBE(buf.slice(offset, offset + width)), adv: width }; -} - -export function serializeDate(date: Date) { - return serializeBigInt(BigInt(date.getTime()), 8); -} - -export function deserializeBufferFromVector(vector: Buffer, offset = 0) { - const length = vector.readUInt32BE(offset); - const adv = 4 + length; - return { elem: vector.slice(offset + 4, offset + adv), adv }; -} - -export function deserializeBool(buf: Buffer, offset = 0) { - const adv = 1; - return { elem: buf.readUInt8(offset), adv }; -} - -export function deserializeUInt32(buf: Buffer, offset = 0) { - const adv = 4; - return { elem: buf.readUInt32BE(offset), adv }; -} - -export function deserializeInt32(buf: Buffer, offset = 0) { - const adv = 4; - return { elem: buf.readInt32BE(offset), adv }; -} - -export function deserializeField(buf: Buffer, offset = 0) { - const adv = 32; - return { elem: buf.slice(offset, offset + adv), adv }; -} - -// For serializing an array of fixed length elements. -export function serializeBufferArrayToVector(arr: Buffer[]) { - const lengthBuf = Buffer.alloc(4); - lengthBuf.writeUInt32BE(arr.length, 0); - return Buffer.concat([lengthBuf, ...arr]); -} - -export function deserializeArrayFromVector( - deserialize: (buf: Buffer, offset: number) => { elem: T; adv: number }, - vector: Buffer, - offset = 0, -) { - let pos = offset; - const size = vector.readUInt32BE(pos); - pos += 4; - const arr = new Array(size); - for (let i = 0; i < size; ++i) { - const { elem, adv } = deserialize(vector, pos); - pos += adv; - arr[i] = elem; - } - return { elem: arr, adv: pos - offset }; -} - -/** A type that can be written to a buffer. */ -export type Bufferable = boolean | Buffer | number | string | { toBuffer: () => Buffer } | Bufferable[]; - -/** - * Serializes a list of objects contiguously for calling into wasm. - * @param objs - Objects to serialize. - * @returns A buffer list with the concatenation of all fields. - */ -export function serializeBufferable(obj: Bufferable): Buffer { - if (Array.isArray(obj)) { - return serializeBufferArrayToVector(obj.map(serializeBufferable)); - } else if (Buffer.isBuffer(obj)) { - return serializeBufferToVector(obj); - } else if (typeof obj === 'boolean') { - return boolToBuffer(obj); - } else if (typeof obj === 'number') { - return numToUInt32BE(obj); - } else if (typeof obj === 'bigint') { - return serializeBigInt(obj); - } else if (typeof obj === 'string') { - return serializeBufferToVector(Buffer.from(obj)); - } else { - return obj.toBuffer(); - } -} diff --git a/ts/src/types/fields.ts b/ts/src/types/fields.ts index b1ac2ef438..a0b095813d 100644 --- a/ts/src/types/fields.ts +++ b/ts/src/types/fields.ts @@ -1,6 +1,6 @@ import { randomBytes } from '../random/index.js'; import { toBigIntBE, toBufferBE } from '../bigint-array/index.js'; -import { BufferReader } from '../serialize/index.js'; +import { BufferReader, uint8ArrayToHexString } from '../serialize/index.js'; export class Fr { static ZERO = new Fr(0n); @@ -38,7 +38,7 @@ export class Fr { } toString() { - return '0x' + this.value.toString(16); + return '0x' + uint8ArrayToHexString(this.toBuffer()); } equals(rhs: Fr) { diff --git a/ts/src/types/index.ts b/ts/src/types/index.ts index 423c75d125..cc5bba551c 100644 --- a/ts/src/types/index.ts +++ b/ts/src/types/index.ts @@ -2,3 +2,4 @@ export * from './ptr.js'; export * from './fields.js'; export * from './point.js'; export * from './fixed_size_buffer.js'; +export * from './raw_buffer.js'; diff --git a/ts/src/types/raw_buffer.ts b/ts/src/types/raw_buffer.ts new file mode 100644 index 0000000000..de2696ee62 --- /dev/null +++ b/ts/src/types/raw_buffer.ts @@ -0,0 +1,3 @@ +// Used when the data is to be sent exactly as is. i.e. no length prefix will be added. +// This is useful for sending structured data that can be parsed-as-you-go, as opposed to just an array of bytes. +export class RawBuffer extends Uint8Array {} diff --git a/ts/webpack.config.js b/ts/webpack.config.js index 91813fcbc7..5c8623b230 100644 --- a/ts/webpack.config.js +++ b/ts/webpack.config.js @@ -41,6 +41,10 @@ export default { from: `../cpp/build-wasm/bin/barretenberg.wasm`, to: 'barretenberg.wasm', }, + { + from: `../cpp/build-wasm-threads/bin/barretenberg.wasm`, + to: 'barretenberg-threads.wasm', + }, ], }), ], diff --git a/ts/yarn.lock b/ts/yarn.lock index a2ae89854a..0b068d22d7 100644 --- a/ts/yarn.lock +++ b/ts/yarn.lock @@ -15,9 +15,9 @@ __metadata: languageName: node linkType: hard -"@aztec/barretenberg.js@workspace:.": +"@aztec/bb.js@workspace:.": version: 0.0.0-use.local - resolution: "@aztec/barretenberg.js@workspace:." + resolution: "@aztec/bb.js@workspace:." dependencies: "@jest/globals": ^29.4.3 "@types/debug": ^4.1.7 @@ -27,9 +27,9 @@ __metadata: "@types/source-map-support": ^0.5.6 "@typescript-eslint/eslint-plugin": ^5.54.1 "@typescript-eslint/parser": ^5.54.1 - bigint-buffer: ^1.1.5 buffer: ^6.0.3 comlink: ^4.4.1 + commander: ^10.0.1 copy-webpack-plugin: ^11.0.0 debug: ^4.3.4 eslint: ^8.35.0 @@ -47,10 +47,12 @@ __metadata: webpack: ^5.82.1 webpack-cli: ^5.1.1 webpack-dev-server: ^4.15.0 + bin: + bb.js: ./dest/main.js languageName: unknown linkType: soft -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.18.6, @babel/code-frame@npm:^7.21.4": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4": version: 7.21.4 resolution: "@babel/code-frame@npm:7.21.4" dependencies: @@ -59,67 +61,67 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.21.4": - version: 7.21.4 - resolution: "@babel/compat-data@npm:7.21.4" - checksum: 5f8b98c66f2ffba9f3c3a82c0cf354c52a0ec5ad4797b370dc32bdcd6e136ac4febe5e93d76ce76e175632e2dbf6ce9f46319aa689fcfafa41b6e49834fa4b66 +"@babel/compat-data@npm:^7.22.0": + version: 7.22.3 + resolution: "@babel/compat-data@npm:7.22.3" + checksum: eb001646f41459f42ccb0d39ee8bb3c3c495bc297234817044c0002689c625e3159a6678c53fd31bd98cf21f31472b73506f350fc6906e3bdfa49cb706e2af8d languageName: node linkType: hard "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": - version: 7.21.4 - resolution: "@babel/core@npm:7.21.4" + version: 7.22.1 + resolution: "@babel/core@npm:7.22.1" dependencies: "@ampproject/remapping": ^2.2.0 "@babel/code-frame": ^7.21.4 - "@babel/generator": ^7.21.4 - "@babel/helper-compilation-targets": ^7.21.4 - "@babel/helper-module-transforms": ^7.21.2 - "@babel/helpers": ^7.21.0 - "@babel/parser": ^7.21.4 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.4 - "@babel/types": ^7.21.4 + "@babel/generator": ^7.22.0 + "@babel/helper-compilation-targets": ^7.22.1 + "@babel/helper-module-transforms": ^7.22.1 + "@babel/helpers": ^7.22.0 + "@babel/parser": ^7.22.0 + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.1 + "@babel/types": ^7.22.0 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.2 semver: ^6.3.0 - checksum: a3beebb2cc79908a02f27a07dc381bcb34e8ecc58fa99f568ad0934c49e12111fc977ee9c5b51eb7ea2da66f63155d37c4dd96b6472eaeecfc35843ccb56bf3d + checksum: bbe45e791f223a7e692d2ea6597a73f48050abd24b119c85c48ac6504c30ce63343a2ea3f79b5847bf4b409ddd8a68b6cdc4f0272ded1d2ef6f6b1e9663432f0 languageName: node linkType: hard -"@babel/generator@npm:^7.21.4, @babel/generator@npm:^7.7.2": - version: 7.21.4 - resolution: "@babel/generator@npm:7.21.4" +"@babel/generator@npm:^7.22.0, @babel/generator@npm:^7.22.3, @babel/generator@npm:^7.7.2": + version: 7.22.3 + resolution: "@babel/generator@npm:7.22.3" dependencies: - "@babel/types": ^7.21.4 + "@babel/types": ^7.22.3 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 9ffbb526a53bb8469b5402f7b5feac93809b09b2a9f82fcbfcdc5916268a65dae746a1f2479e03ba4fb0776facd7c892191f63baa61ab69b2cfdb24f7b92424d + checksum: ccb6426ca5b5a38f0d47a3ac9628e223d2aaaa489cbf90ffab41468795c22afe86855f68a58667f0f2673949f1810d4d5a57b826c17984eab3e28fdb34a909e6 languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.21.4": - version: 7.21.4 - resolution: "@babel/helper-compilation-targets@npm:7.21.4" +"@babel/helper-compilation-targets@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/helper-compilation-targets@npm:7.22.1" dependencies: - "@babel/compat-data": ^7.21.4 + "@babel/compat-data": ^7.22.0 "@babel/helper-validator-option": ^7.21.0 browserslist: ^4.21.3 lru-cache: ^5.1.1 semver: ^6.3.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: bf9c7d3e7e6adff9222c05d898724cd4ee91d7eb9d52222c7ad2a22955620c2872cc2d9bdf0e047df8efdb79f4e3af2a06b53f509286145feccc4d10ddc318be + checksum: a686a01bd3288cf95ca26faa27958d34c04e2501c4b0858c3a6558776dec20317b5635f33d64c5a635b6fbdfe462a85c30d4bfa0ae7e7ffe3467e4d06442d7c8 languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/helper-environment-visitor@npm:7.18.9" - checksum: b25101f6162ddca2d12da73942c08ad203d7668e06663df685634a8fde54a98bc015f6f62938e8554457a592a024108d45b8f3e651fd6dcdb877275b73cc4420 +"@babel/helper-environment-visitor@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/helper-environment-visitor@npm:7.22.1" + checksum: a6b4bb5505453bff95518d361ac1de393f0029aeb8b690c70540f4317934c53c43cc4afcda8c752ffa8c272e63ed6b929a56eca28e4978424177b24238b21bf9 languageName: node linkType: hard @@ -142,7 +144,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.18.6": +"@babel/helper-module-imports@npm:^7.21.4": version: 7.21.4 resolution: "@babel/helper-module-imports@npm:7.21.4" dependencies: @@ -151,35 +153,35 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.21.2": - version: 7.21.2 - resolution: "@babel/helper-module-transforms@npm:7.21.2" +"@babel/helper-module-transforms@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/helper-module-transforms@npm:7.22.1" dependencies: - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-module-imports": ^7.18.6 - "@babel/helper-simple-access": ^7.20.2 + "@babel/helper-environment-visitor": ^7.22.1 + "@babel/helper-module-imports": ^7.21.4 + "@babel/helper-simple-access": ^7.21.5 "@babel/helper-split-export-declaration": ^7.18.6 "@babel/helper-validator-identifier": ^7.19.1 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.2 - "@babel/types": ^7.21.2 - checksum: 8a1c129a4f90bdf97d8b6e7861732c9580f48f877aaaafbc376ce2482febebcb8daaa1de8bc91676d12886487603f8c62a44f9e90ee76d6cac7f9225b26a49e1 + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.1 + "@babel/types": ^7.22.0 + checksum: dfa084211a93c9f0174ab07385fdbf7831bbf5c1ff3d4f984effc489f48670825ad8b817b9e9d2ec6492fde37ed6518c15944e9dd7a60b43a3d9874c9250f5f8 languageName: node linkType: hard "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.20.2 - resolution: "@babel/helper-plugin-utils@npm:7.20.2" - checksum: f6cae53b7fdb1bf3abd50fa61b10b4470985b400cc794d92635da1e7077bb19729f626adc0741b69403d9b6e411cddddb9c0157a709cc7c4eeb41e663be5d74b + version: 7.21.5 + resolution: "@babel/helper-plugin-utils@npm:7.21.5" + checksum: 6f086e9a84a50ea7df0d5639c8f9f68505af510ea3258b3c8ac8b175efdfb7f664436cb48996f71791a1350ba68f47ad3424131e8e718c5e2ad45564484cbb36 languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.20.2": - version: 7.20.2 - resolution: "@babel/helper-simple-access@npm:7.20.2" +"@babel/helper-simple-access@npm:^7.21.5": + version: 7.21.5 + resolution: "@babel/helper-simple-access@npm:7.21.5" dependencies: - "@babel/types": ^7.20.2 - checksum: ad1e96ee2e5f654ffee2369a586e5e8d2722bf2d8b028a121b4c33ebae47253f64d420157b9f0a8927aea3a9e0f18c0103e74fdd531815cf3650a0a4adca11a1 + "@babel/types": ^7.21.5 + checksum: ad212beaa24be3864c8c95bee02f840222457ccf5419991e2d3e3e39b0f75b77e7e857e0bf4ed428b1cd97acefc87f3831bdb0b9696d5ad0557421f398334fc3 languageName: node linkType: hard @@ -192,10 +194,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.19.4": - version: 7.19.4 - resolution: "@babel/helper-string-parser@npm:7.19.4" - checksum: b2f8a3920b30dfac81ec282ac4ad9598ea170648f8254b10f475abe6d944808fb006aab325d3eb5a8ad3bea8dfa888cfa6ef471050dae5748497c110ec060943 +"@babel/helper-string-parser@npm:^7.21.5": + version: 7.21.5 + resolution: "@babel/helper-string-parser@npm:7.21.5" + checksum: 36c0ded452f3858e67634b81960d4bde1d1cd2a56b82f4ba2926e97864816021c885f111a7cf81de88a0ed025f49d84a393256700e9acbca2d99462d648705d8 languageName: node linkType: hard @@ -213,14 +215,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.21.0": - version: 7.21.0 - resolution: "@babel/helpers@npm:7.21.0" +"@babel/helpers@npm:^7.22.0": + version: 7.22.3 + resolution: "@babel/helpers@npm:7.22.3" dependencies: - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.0 - "@babel/types": ^7.21.0 - checksum: 9370dad2bb665c551869a08ac87c8bdafad53dbcdce1f5c5d498f51811456a3c005d9857562715151a0f00b2e912ac8d89f56574f837b5689f5f5072221cdf54 + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.1 + "@babel/types": ^7.22.3 + checksum: 385289ee8b87cf9af448bbb9fcf747f6e67600db5f7f64eb4ad97761ee387819bf2212b6a757008286c6bfacf4f3fc0b6de88686f2e517a70fb59996bdfbd1e9 languageName: node linkType: hard @@ -235,12 +237,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.4": - version: 7.21.4 - resolution: "@babel/parser@npm:7.21.4" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.9, @babel/parser@npm:^7.22.0, @babel/parser@npm:^7.22.4": + version: 7.22.4 + resolution: "@babel/parser@npm:7.22.4" bin: parser: ./bin/babel-parser.js - checksum: de610ecd1bff331766d0c058023ca11a4f242bfafefc42caf926becccfb6756637d167c001987ca830dd4b34b93c629a4cef63f8c8c864a8564cdfde1989ac77 + checksum: 0ca6d3a2d9aae2504ba1bc494704b64a83140884f7379f609de69bd39b60adb58a4f8ec692fe53fef8657dd82705d01b7e6efb65e18296326bdd66f71d52d9a9 languageName: node linkType: hard @@ -398,43 +400,43 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.20.7, @babel/template@npm:^7.3.3": - version: 7.20.7 - resolution: "@babel/template@npm:7.20.7" +"@babel/template@npm:^7.20.7, @babel/template@npm:^7.21.9, @babel/template@npm:^7.3.3": + version: 7.21.9 + resolution: "@babel/template@npm:7.21.9" dependencies: - "@babel/code-frame": ^7.18.6 - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - checksum: 2eb1a0ab8d415078776bceb3473d07ab746e6bb4c2f6ca46ee70efb284d75c4a32bb0cd6f4f4946dec9711f9c0780e8e5d64b743208deac6f8e9858afadc349e + "@babel/code-frame": ^7.21.4 + "@babel/parser": ^7.21.9 + "@babel/types": ^7.21.5 + checksum: 6ec2c60d4d53b2a9230ab82c399ba6525df87e9a4e01e4b111e071cbad283b1362e7c99a1bc50027073f44f2de36a495a89c27112c4e7efe7ef9c8d9c84de2ec languageName: node linkType: hard -"@babel/traverse@npm:^7.21.0, @babel/traverse@npm:^7.21.2, @babel/traverse@npm:^7.21.4, @babel/traverse@npm:^7.7.2": - version: 7.21.4 - resolution: "@babel/traverse@npm:7.21.4" +"@babel/traverse@npm:^7.22.1, @babel/traverse@npm:^7.7.2": + version: 7.22.4 + resolution: "@babel/traverse@npm:7.22.4" dependencies: "@babel/code-frame": ^7.21.4 - "@babel/generator": ^7.21.4 - "@babel/helper-environment-visitor": ^7.18.9 + "@babel/generator": ^7.22.3 + "@babel/helper-environment-visitor": ^7.22.1 "@babel/helper-function-name": ^7.21.0 "@babel/helper-hoist-variables": ^7.18.6 "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.21.4 - "@babel/types": ^7.21.4 + "@babel/parser": ^7.22.4 + "@babel/types": ^7.22.4 debug: ^4.1.0 globals: ^11.1.0 - checksum: f22f067c2d9b6497abf3d4e53ea71f3aa82a21f2ed434dd69b8c5767f11f2a4c24c8d2f517d2312c9e5248e5c69395fdca1c95a2b3286122c75f5783ddb6f53c + checksum: 9560ae22092d5a7c52849145dd3e5aed2ffb73d61255e70e19e3fbd06bcbafbbdecea28df40a42ee3b60b01e85a42224ec841df93e867547e329091cc2f2bb6f languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.2, @babel/types@npm:^7.21.4, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": - version: 7.21.4 - resolution: "@babel/types@npm:7.21.4" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.22.0, @babel/types@npm:^7.22.3, @babel/types@npm:^7.22.4, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": + version: 7.22.4 + resolution: "@babel/types@npm:7.22.4" dependencies: - "@babel/helper-string-parser": ^7.19.4 + "@babel/helper-string-parser": ^7.21.5 "@babel/helper-validator-identifier": ^7.19.1 to-fast-properties: ^2.0.0 - checksum: 587bc55a91ce003b0f8aa10d70070f8006560d7dc0360dc0406d306a2cb2a10154e2f9080b9c37abec76907a90b330a536406cb75e6bdc905484f37b75c73219 + checksum: ffe36bb4f4a99ad13c426a98c3b508d70736036cae4e471d9c862e3a579847ed4f480686af0fce2633f6f7c0f0d3bf02da73da36e7edd3fde0b2061951dcba9a languageName: node linkType: hard @@ -473,33 +475,33 @@ __metadata: linkType: hard "@eslint-community/regexpp@npm:^4.4.0": - version: 4.5.0 - resolution: "@eslint-community/regexpp@npm:4.5.0" - checksum: 99c01335947dbd7f2129e954413067e217ccaa4e219fe0917b7d2bd96135789384b8fedbfb8eb09584d5130b27a7b876a7150ab7376f51b3a0c377d5ce026a10 + version: 4.5.1 + resolution: "@eslint-community/regexpp@npm:4.5.1" + checksum: 6d901166d64998d591fab4db1c2f872981ccd5f6fe066a1ad0a93d4e11855ecae6bfb76660869a469563e8882d4307228cebd41142adb409d182f2966771e57e languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.0.2": - version: 2.0.2 - resolution: "@eslint/eslintrc@npm:2.0.2" +"@eslint/eslintrc@npm:^2.0.3": + version: 2.0.3 + resolution: "@eslint/eslintrc@npm:2.0.3" dependencies: ajv: ^6.12.4 debug: ^4.3.2 - espree: ^9.5.1 + espree: ^9.5.2 globals: ^13.19.0 ignore: ^5.2.0 import-fresh: ^3.2.1 js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: cfcf5e12c7b2c4476482e7f12434e76eae16fcd163ee627309adb10b761e5caa4a4e52ed7be464423320ff3d11eca5b50de5bf8be3e25834222470835dd5c801 + checksum: ddc51f25f8524d8231db9c9bf03177e503d941a332e8d5ce3b10b09241be4d5584a378a529a27a527586bfbccf3031ae539eb891352033c340b012b4d0c81d92 languageName: node linkType: hard -"@eslint/js@npm:8.38.0": - version: 8.38.0 - resolution: "@eslint/js@npm:8.38.0" - checksum: 1f28987aa8c9cd93e23384e16c7220863b39b5dc4b66e46d7cdbccce868040f455a98d24cd8b567a884f26545a0555b761f7328d4a00c051e7ef689cbea5fce1 +"@eslint/js@npm:8.41.0": + version: 8.41.0 + resolution: "@eslint/js@npm:8.41.0" + checksum: af013d70fe8d0429cdf5cd8b5dcc6fc384ed026c1eccb0cfe30f5849b968ab91645111373fd1b83282b38955b1bdfbe667c1a7dbda3b06cae753521223cad775 languageName: node linkType: hard @@ -922,21 +924,21 @@ __metadata: languageName: node linkType: hard -"@sinonjs/commons@npm:^2.0.0": - version: 2.0.0 - resolution: "@sinonjs/commons@npm:2.0.0" +"@sinonjs/commons@npm:^3.0.0": + version: 3.0.0 + resolution: "@sinonjs/commons@npm:3.0.0" dependencies: type-detect: 4.0.8 - checksum: 5023ba17edf2b85ed58262313b8e9b59e23c6860681a9af0200f239fe939e2b79736d04a260e8270ddd57196851dde3ba754d7230be5c5234e777ae2ca8af137 + checksum: b4b5b73d4df4560fb8c0c7b38c7ad4aeabedd362f3373859d804c988c725889cde33550e4bcc7cd316a30f5152a2d1d43db71b6d0c38f5feef71fd8d016763f8 languageName: node linkType: hard "@sinonjs/fake-timers@npm:^10.0.2": - version: 10.0.2 - resolution: "@sinonjs/fake-timers@npm:10.0.2" + version: 10.2.0 + resolution: "@sinonjs/fake-timers@npm:10.2.0" dependencies: - "@sinonjs/commons": ^2.0.0 - checksum: c62aa98e7cefda8dedc101ce227abc888dc46b8ff9706c5f0a8dfd9c3ada97d0a5611384738d9ba0b26b59f99c2ba24efece8e779bb08329e9e87358fa309824 + "@sinonjs/commons": ^3.0.0 + checksum: 586c76e1dd90d03b0c4e754f2011325b38ac6055878c81c52434c900f36d9d245438c96ef69e08e28d9fbecf2335fb347b67850962d8b6e539dd7359d8c62802 languageName: node linkType: hard @@ -969,22 +971,22 @@ __metadata: linkType: hard "@tsconfig/node16@npm:^1.0.2": - version: 1.0.3 - resolution: "@tsconfig/node16@npm:1.0.3" - checksum: 3a8b657dd047495b7ad23437d6afd20297ce90380ff0bdee93fc7d39a900dbd8d9e26e53ff6b465e7967ce2adf0b218782590ce9013285121e6a5928fbd6819f + version: 1.0.4 + resolution: "@tsconfig/node16@npm:1.0.4" + checksum: 202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff languageName: node linkType: hard "@types/babel__core@npm:^7.1.14": - version: 7.20.0 - resolution: "@types/babel__core@npm:7.20.0" + version: 7.20.1 + resolution: "@types/babel__core@npm:7.20.1" dependencies: "@babel/parser": ^7.20.7 "@babel/types": ^7.20.7 "@types/babel__generator": "*" "@types/babel__template": "*" "@types/babel__traverse": "*" - checksum: 49b601a0a7637f1f387442c8156bd086cfd10ff4b82b0e1994e73a6396643b5435366fb33d6b604eade8467cca594ef97adcbc412aede90bb112ebe88d0ad6df + checksum: 9fcd9691a33074802d9057ff70b0e3ff3778f52470475b68698a0f6714fbe2ccb36c16b43dc924eb978cd8a81c1f845e5ff4699e7a47606043b539eb8c6331a8 languageName: node linkType: hard @@ -1008,11 +1010,11 @@ __metadata: linkType: hard "@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.18.3 - resolution: "@types/babel__traverse@npm:7.18.3" + version: 7.20.0 + resolution: "@types/babel__traverse@npm:7.20.0" dependencies: - "@babel/types": ^7.3.0 - checksum: d20953338b2f012ab7750932ece0a78e7d1645b0a6ff42d49be90f55e9998085da1374a9786a7da252df89555c6586695ba4d1d4b4e88ab2b9f306bcd35e00d3 + "@babel/types": ^7.20.7 + checksum: 030d647a61baa70aff5bc1193227694098191578e45e18720db3a14614f1827664d609630a668ad75cddffd7b80cd14a55455364239d1f14ea55f1f4d7d2c9ef languageName: node linkType: hard @@ -1055,11 +1057,11 @@ __metadata: linkType: hard "@types/debug@npm:^4.1.7": - version: 4.1.7 - resolution: "@types/debug@npm:4.1.7" + version: 4.1.8 + resolution: "@types/debug@npm:4.1.8" dependencies: "@types/ms": "*" - checksum: 0a7b89d8ed72526858f0b61c6fd81f477853e8c4415bb97f48b1b5545248d2ae389931680b94b393b993a7cfe893537a200647d93defe6d87159b96812305adc + checksum: a9a9bb40a199e9724aa944e139a7659173a9b274798ea7efbc277cb084bc37d32fc4c00877c3496fac4fed70a23243d284adb75c00b5fdabb38a22154d18e5df languageName: node linkType: hard @@ -1081,12 +1083,12 @@ __metadata: linkType: hard "@types/eslint@npm:*": - version: 8.37.0 - resolution: "@types/eslint@npm:8.37.0" + version: 8.40.0 + resolution: "@types/eslint@npm:8.40.0" dependencies: "@types/estree": "*" "@types/json-schema": "*" - checksum: 06d3b3fba12004294591b5c7a52e3cec439472195da54e096076b1f2ddfbb8a445973b9681046dd530a6ac31eca502f635abc1e3ce37d03513089358e6f822ee + checksum: bab41d7f590182e743853cdd5bf5359cbc4240df986223457c8a5f5674743a3fe2a8626704b65bf9121dfa0ce0a0efd760da8339cc329018f229d4d2d6ee1c43 languageName: node linkType: hard @@ -1098,14 +1100,14 @@ __metadata: linkType: hard "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33": - version: 4.17.34 - resolution: "@types/express-serve-static-core@npm:4.17.34" + version: 4.17.35 + resolution: "@types/express-serve-static-core@npm:4.17.35" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: 3b5242e7d6cfecca5300635fd2af0f63aca3a92754da79a4a355c4d85b57099aa2cabb1c8557fc38a8a9e6f0be996339140ad017e5be405ea1b877a8294a136d + checksum: cc8995d10c6feda475ec1b3a0e69eb0f35f21ab6b49129ad5c6f279e0bc5de8175bc04ec51304cb79a43eec3ed2f5a1e01472eb6d5f827b8c35c6ca8ad24eb6e languageName: node linkType: hard @@ -1172,19 +1174,19 @@ __metadata: linkType: hard "@types/jest@npm:^29.4.0": - version: 29.5.0 - resolution: "@types/jest@npm:29.5.0" + version: 29.5.2 + resolution: "@types/jest@npm:29.5.2" dependencies: expect: ^29.0.0 pretty-format: ^29.0.0 - checksum: cd877e5c56d299cceb8bfdcbb1a77723c706750dd3c3bc47403bc3599b8faff590a3b009c68bb5b11bf7a8c77d1fb01de5e124329b4a08e65f1cdda28b0ecdb8 + checksum: 7d205599ea3cccc262bad5cc173d3242d6bf8138c99458509230e4ecef07a52d6ddcde5a1dbd49ace655c0af51d2dbadef3748697292ea4d86da19d9e03e19c0 languageName: node linkType: hard "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.11 - resolution: "@types/json-schema@npm:7.0.11" - checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d + version: 7.0.12 + resolution: "@types/json-schema@npm:7.0.12" + checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 languageName: node linkType: hard @@ -1209,17 +1211,24 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^18.7.23": - version: 18.15.11 - resolution: "@types/node@npm:18.15.11" - checksum: 977b4ad04708897ff0eb049ecf82246d210939c82461922d20f7d2dcfd81bbc661582ba3af28869210f7e8b1934529dcd46bff7d448551400f9d48b9d3bddec3 +"@types/node@npm:*": + version: 20.2.5 + resolution: "@types/node@npm:20.2.5" + checksum: 38ce7c7e9d76880dc632f71d71e0d5914fcda9d5e9a7095d6c339abda55ca4affb0f2a882aeb29398f8e09d2c5151f0b6586c81c8ccdfe529c34b1ea3337425e + languageName: node + linkType: hard + +"@types/node@npm:^18.7.23": + version: 18.16.16 + resolution: "@types/node@npm:18.16.16" + checksum: 0efad726dd1e0bef71c392c708fc5d78c5b39c46b0ac5186fee74de4ccb1b2e847b3fa468da67d62812f56569da721b15bf31bdc795e6c69b56c73a45079ed2d languageName: node linkType: hard "@types/prettier@npm:^2.1.5": - version: 2.7.2 - resolution: "@types/prettier@npm:2.7.2" - checksum: b47d76a5252265f8d25dd2fe2a5a61dc43ba0e6a96ffdd00c594cb4fd74c1982c2e346497e3472805d97915407a09423804cc2110a0b8e1b22cffcab246479b7 + version: 2.7.3 + resolution: "@types/prettier@npm:2.7.3" + checksum: 705384209cea6d1433ff6c187c80dcc0b95d99d5c5ce21a46a9a58060c527973506822e428789d842761e0280d25e3359300f017fbe77b9755bc772ab3dc2f83 languageName: node linkType: hard @@ -1245,9 +1254,9 @@ __metadata: linkType: hard "@types/semver@npm:^7.3.12": - version: 7.3.13 - resolution: "@types/semver@npm:7.3.13" - checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0 + version: 7.5.0 + resolution: "@types/semver@npm:7.5.0" + checksum: 0a64b9b9c7424d9a467658b18dd70d1d781c2d6f033096a6e05762d20ebbad23c1b69b0083b0484722aabf35640b78ccc3de26368bcae1129c87e9df028a22e2 languageName: node linkType: hard @@ -1331,13 +1340,13 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^5.54.1": - version: 5.57.1 - resolution: "@typescript-eslint/eslint-plugin@npm:5.57.1" + version: 5.59.8 + resolution: "@typescript-eslint/eslint-plugin@npm:5.59.8" dependencies: "@eslint-community/regexpp": ^4.4.0 - "@typescript-eslint/scope-manager": 5.57.1 - "@typescript-eslint/type-utils": 5.57.1 - "@typescript-eslint/utils": 5.57.1 + "@typescript-eslint/scope-manager": 5.59.8 + "@typescript-eslint/type-utils": 5.59.8 + "@typescript-eslint/utils": 5.59.8 debug: ^4.3.4 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 @@ -1350,43 +1359,43 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3ea842ef9615e298e28c6687c4dc285577ea0995944410553b3ca514ce9d437534b6e89114e9398c1a370324afe7a4a251c8c49540bb3bf13dcadde9ada3ecc2 + checksum: 3e05cd06149ec3741c3c2fb638e2d19a55687b4614a5c8820433db82997687650297e51c17828d320162ccf4241798cf5712c405561e7605cb17e984a6967f7b languageName: node linkType: hard "@typescript-eslint/parser@npm:^5.54.1": - version: 5.57.1 - resolution: "@typescript-eslint/parser@npm:5.57.1" + version: 5.59.8 + resolution: "@typescript-eslint/parser@npm:5.59.8" dependencies: - "@typescript-eslint/scope-manager": 5.57.1 - "@typescript-eslint/types": 5.57.1 - "@typescript-eslint/typescript-estree": 5.57.1 + "@typescript-eslint/scope-manager": 5.59.8 + "@typescript-eslint/types": 5.59.8 + "@typescript-eslint/typescript-estree": 5.59.8 debug: ^4.3.4 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: db61a12a67bc45d814297e7f089768c0849f18162b330279aa15121223ec3b18d80df4c327f4ca0a40a7bddb9150ba1a9379fce00bc0e4a10cc189d04e36f0e3 + checksum: bac9f09d8552086ceb882a7b87ce4d98dfaa41579249216c75d97e3fc07af33cddc4cbbd07a127a5823c826a258882643aaf658bec19cb2a434002b55c5f0d12 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.57.1": - version: 5.57.1 - resolution: "@typescript-eslint/scope-manager@npm:5.57.1" +"@typescript-eslint/scope-manager@npm:5.59.8": + version: 5.59.8 + resolution: "@typescript-eslint/scope-manager@npm:5.59.8" dependencies: - "@typescript-eslint/types": 5.57.1 - "@typescript-eslint/visitor-keys": 5.57.1 - checksum: 4f03d54372f0591fbc5f6e0267a6f1b73e3012e8a319c1893829e0b8e71f882e17a696995dc8b11e700162daf74444fd2d8f55dba314e1a95221a9d3eabcfb2b + "@typescript-eslint/types": 5.59.8 + "@typescript-eslint/visitor-keys": 5.59.8 + checksum: e1e810ee991cfeb433330b04ee949bb6784abe4dbdb7d9480aa7a7536671b4fec914b7803edf662516c8ecb1b31dcff126797f9923270a529c26e2b00b0ea96f languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.57.1": - version: 5.57.1 - resolution: "@typescript-eslint/type-utils@npm:5.57.1" +"@typescript-eslint/type-utils@npm:5.59.8": + version: 5.59.8 + resolution: "@typescript-eslint/type-utils@npm:5.59.8" dependencies: - "@typescript-eslint/typescript-estree": 5.57.1 - "@typescript-eslint/utils": 5.57.1 + "@typescript-eslint/typescript-estree": 5.59.8 + "@typescript-eslint/utils": 5.59.8 debug: ^4.3.4 tsutils: ^3.21.0 peerDependencies: @@ -1394,23 +1403,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 06fab95315fc1ffdaaa011e6ec1ae538826ef3d9b422e2c926dbe9b83e55d9e8bdaa07c43317a4c0a59b40a24c5c48a7c8284e6a18780475a65894b1b949fc23 + checksum: d9fde31397da0f0e62a5568f64bad99d06bcd324b7e3aac7fd997a3d045a0fe4c084b2e85d440e0a39645acd2269ad6593f196399c2c0f880d293417fec894e3 languageName: node linkType: hard -"@typescript-eslint/types@npm:5.57.1": - version: 5.57.1 - resolution: "@typescript-eslint/types@npm:5.57.1" - checksum: 21789eb697904bbb44a18df961d5918e7c5bd90c79df3a8b8b835da81d0c0f42c7eeb2d05f77cafe49a7367ae7f549a0c8281656ea44b6dc56ae1bf19a3a1eae +"@typescript-eslint/types@npm:5.59.8": + version: 5.59.8 + resolution: "@typescript-eslint/types@npm:5.59.8" + checksum: 559473d5601c849eb0da1874a2ac67c753480beed484ad6f6cda62fa6023273f2c3005c7f2864d9c2afb7c6356412d0d304b57db10c53597207f18a7f6cd4f18 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.57.1": - version: 5.57.1 - resolution: "@typescript-eslint/typescript-estree@npm:5.57.1" +"@typescript-eslint/typescript-estree@npm:5.59.8": + version: 5.59.8 + resolution: "@typescript-eslint/typescript-estree@npm:5.59.8" dependencies: - "@typescript-eslint/types": 5.57.1 - "@typescript-eslint/visitor-keys": 5.57.1 + "@typescript-eslint/types": 5.59.8 + "@typescript-eslint/visitor-keys": 5.59.8 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -1419,35 +1428,35 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: bf96520f6de562838a40c3f009fc61fbee5369621071cd0d1dba4470b2b2f746cf79afe4ffa3fbccb8913295a2fbb3d89681d5178529e8da4987c46ed4e5cbed + checksum: d93371cc866f573a6a1ddc0eb10d498a8e59f36763a99ce21da0737fff2b4c942eef1587216aad273f8d896ebc0b19003677cba63a27d2646aa2c087638963eb languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.57.1": - version: 5.57.1 - resolution: "@typescript-eslint/utils@npm:5.57.1" +"@typescript-eslint/utils@npm:5.59.8": + version: 5.59.8 + resolution: "@typescript-eslint/utils@npm:5.59.8" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@types/json-schema": ^7.0.9 "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.57.1 - "@typescript-eslint/types": 5.57.1 - "@typescript-eslint/typescript-estree": 5.57.1 + "@typescript-eslint/scope-manager": 5.59.8 + "@typescript-eslint/types": 5.59.8 + "@typescript-eslint/typescript-estree": 5.59.8 eslint-scope: ^5.1.1 semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 12e55144c8087f4e8f0f22e5693f3901b81bb7899dec42c7bfe540ac672a802028b688884bb43bd67bcf3cd3546a7205d207afcd948c731c19f551ea61267205 + checksum: cbaa057485c7f52c45d0dfb4f5a8e9273abccb1c52dcb4426a79f9e71d2c1062cf2525bad6d4aca5ec42db3fe723d749843bcade5a323bde7fbe4b5d5b5d5c3b languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.57.1": - version: 5.57.1 - resolution: "@typescript-eslint/visitor-keys@npm:5.57.1" +"@typescript-eslint/visitor-keys@npm:5.59.8": + version: 5.59.8 + resolution: "@typescript-eslint/visitor-keys@npm:5.59.8" dependencies: - "@typescript-eslint/types": 5.57.1 + "@typescript-eslint/types": 5.59.8 eslint-visitor-keys: ^3.3.0 - checksum: d187dfac044b7c0f24264a9ba5eebcf6651412d840b4aaba8eacabff7e771babcd67c738525b1f7c9eb8c94b7edfe7658f6de99f5fdc9745e409c538c1374674 + checksum: 6bfa7918dbb0e08d8a7404aeeef7bcd1a85736dc8d01614d267c0c5ec10f94d2746b50a945bf5c82c54fda67926e8deaeba8565c919da17f725fc11209ef8987 languageName: node linkType: hard @@ -1666,7 +1675,7 @@ __metadata: languageName: node linkType: hard -"acorn-import-assertions@npm:^1.7.6": +"acorn-import-assertions@npm:^1.9.0": version: 1.9.0 resolution: "acorn-import-assertions@npm:1.9.0" peerDependencies: @@ -2006,16 +2015,6 @@ __metadata: languageName: node linkType: hard -"bigint-buffer@npm:^1.1.5": - version: 1.1.5 - resolution: "bigint-buffer@npm:1.1.5" - dependencies: - bindings: ^1.3.0 - node-gyp: latest - checksum: d010c9f57758bcdaccb435d88b483ffcc95fe8bbc6e7fb3a44fb5221f29c894ffaf4a3c5a4a530e0e7d6608203c2cde9b79ee4f2386cd6d4462d1070bc8c9f4e - languageName: node - linkType: hard - "binary-extensions@npm:^2.0.0": version: 2.2.0 resolution: "binary-extensions@npm:2.2.0" @@ -2023,15 +2022,6 @@ __metadata: languageName: node linkType: hard -"bindings@npm:^1.3.0": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: 1.0.0 - checksum: 65b6b48095717c2e6105a021a7da4ea435aa8d3d3cd085cb9e85bcb6e5773cf318c4745c3f7c504412855940b585bdf9b918236612a1c7a7942491de176f1ae7 - languageName: node - linkType: hard - "body-parser@npm:1.20.1": version: 1.20.1 resolution: "body-parser@npm:1.20.1" @@ -2100,16 +2090,16 @@ __metadata: linkType: hard "browserslist@npm:^4.14.5, browserslist@npm:^4.21.3": - version: 4.21.5 - resolution: "browserslist@npm:4.21.5" + version: 4.21.7 + resolution: "browserslist@npm:4.21.7" dependencies: - caniuse-lite: ^1.0.30001449 - electron-to-chromium: ^1.4.284 - node-releases: ^2.0.8 - update-browserslist-db: ^1.0.10 + caniuse-lite: ^1.0.30001489 + electron-to-chromium: ^1.4.411 + node-releases: ^2.0.12 + update-browserslist-db: ^1.0.11 bin: browserslist: cli.js - checksum: 9755986b22e73a6a1497fd8797aedd88e04270be33ce66ed5d85a1c8a798292a65e222b0f251bafa1c2522261e237d73b08b58689d4920a607e5a53d56dc4706 + checksum: 3d0d025e6d381c4db5e71b538258952660ba574c060832095f182a9877ca798836fa550736269e669a2080e486f0cfdf5d3bcf2769b9f7cf123f6c6b8c005f8f languageName: node linkType: hard @@ -2229,10 +2219,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001449": - version: 1.0.30001476 - resolution: "caniuse-lite@npm:1.0.30001476" - checksum: 4e8b233b349330598ac8e4b77515901011ed687b0d0042b78b06cd520ba31953dbacca62348662e912f3b67892fb12406b928caed4233ab53b1603235802bc7c +"caniuse-lite@npm:^1.0.30001489": + version: 1.0.30001492 + resolution: "caniuse-lite@npm:1.0.30001492" + checksum: 261869f910ec905ab6aa5a754e4ae57da8c5c33f3b723db2fa21840da307667bff61057aef3abaca32091c1561c254dd3a807c0fdb054cdc9e7e3ba495a55e20 languageName: node linkType: hard @@ -2801,10 +2791,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.284": - version: 1.4.356 - resolution: "electron-to-chromium@npm:1.4.356" - checksum: 5a61003c574f5fb6d32dcfc0ae2220a45a6a395ccadd9495c8227e9c33f36ea97cb34aa925c2b039d17dfea5a8040825026db2df01a352d2d1c0037f53dbeebb +"electron-to-chromium@npm:^1.4.411": + version: 1.4.416 + resolution: "electron-to-chromium@npm:1.4.416" + checksum: a1804fe6f1955b3b80519bf2feb69d5e2111914e824cdacdff85545dba48da44d16f43d5fb702ff4cfc9148f7d0be7cd2669cb5e939b0ed13ee9772cae3edfd4 languageName: node linkType: hard @@ -2838,13 +2828,13 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.14.0": - version: 5.14.0 - resolution: "enhanced-resolve@npm:5.14.0" +"enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.14.1": + version: 5.14.1 + resolution: "enhanced-resolve@npm:5.14.1" dependencies: graceful-fs: ^4.2.4 tapable: ^2.2.0 - checksum: fff1aaebbf376371e5df4502e111967f6247c37611ad3550e4e7fca657f6dcb29ef7ffe88bf14e5010b78997f1ddd984a8db97af87ee0a5477771398fd326f5b + checksum: ad2a31928b6649eed40d364838449587f731baa63863e83d2629bebaa8be1eabac18b90f89c1784bc805b0818363e99b22547159edd485d7e5ccf18cdc640642 languageName: node linkType: hard @@ -2950,31 +2940,31 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^7.1.1": - version: 7.1.1 - resolution: "eslint-scope@npm:7.1.1" +"eslint-scope@npm:^7.2.0": + version: 7.2.0 + resolution: "eslint-scope@npm:7.2.0" dependencies: esrecurse: ^4.3.0 estraverse: ^5.2.0 - checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e + checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.0": - version: 3.4.0 - resolution: "eslint-visitor-keys@npm:3.4.0" - checksum: 33159169462d3989321a1ec1e9aaaf6a24cc403d5d347e9886d1b5bfe18ffa1be73bdc6203143a28a606b142b1af49787f33cff0d6d0813eb5f2e8d2e1a6043c +"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1": + version: 3.4.1 + resolution: "eslint-visitor-keys@npm:3.4.1" + checksum: f05121d868202736b97de7d750847a328fcfa8593b031c95ea89425333db59676ac087fa905eba438d0a3c5769632f828187e0c1a0d271832a2153c1d3661c2c languageName: node linkType: hard "eslint@npm:^8.35.0": - version: 8.38.0 - resolution: "eslint@npm:8.38.0" + version: 8.41.0 + resolution: "eslint@npm:8.41.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.4.0 - "@eslint/eslintrc": ^2.0.2 - "@eslint/js": 8.38.0 + "@eslint/eslintrc": ^2.0.3 + "@eslint/js": 8.41.0 "@humanwhocodes/config-array": ^0.11.8 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -2984,9 +2974,9 @@ __metadata: debug: ^4.3.2 doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 - eslint-scope: ^7.1.1 - eslint-visitor-keys: ^3.4.0 - espree: ^9.5.1 + eslint-scope: ^7.2.0 + eslint-visitor-keys: ^3.4.1 + espree: ^9.5.2 esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 @@ -2994,13 +2984,12 @@ __metadata: find-up: ^5.0.0 glob-parent: ^6.0.2 globals: ^13.19.0 - grapheme-splitter: ^1.0.4 + graphemer: ^1.4.0 ignore: ^5.2.0 import-fresh: ^3.0.0 imurmurhash: ^0.1.4 is-glob: ^4.0.0 is-path-inside: ^3.0.3 - js-sdsl: ^4.1.4 js-yaml: ^4.1.0 json-stable-stringify-without-jsonify: ^1.0.1 levn: ^0.4.1 @@ -3013,18 +3002,18 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 73b6d9b650d0434aa7c07d0a1802f099b086ee70a8d8ba7be730439a26572a5eb71def12125c82942be2ec8ee5be38a6f1b42a13e40d4b67f11a148ec9e263eb + checksum: 09979a6f8451dcc508a7005b6670845c8a518376280b3fd96657a406b8b6ef29d0e480d1ba11b4eb48da93d607e0c55c9b877676fe089d09973ec152354e23b2 languageName: node linkType: hard -"espree@npm:^9.5.1": - version: 9.5.1 - resolution: "espree@npm:9.5.1" +"espree@npm:^9.5.2": + version: 9.5.2 + resolution: "espree@npm:9.5.2" dependencies: acorn: ^8.8.0 acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.4.0 - checksum: cdf6e43540433d917c4f2ee087c6e987b2063baa85a1d9cdaf51533d78275ebd5910c42154e7baf8e3e89804b386da0a2f7fad2264d8f04420e7506bf87b3b88 + eslint-visitor-keys: ^3.4.1 + checksum: 6506289d6eb26471c0b383ee24fee5c8ae9d61ad540be956b3127be5ce3bf687d2ba6538ee5a86769812c7c552a9d8239e8c4d150f9ea056c6d5cbe8399c03c1 languageName: node linkType: hard @@ -3251,13 +3240,6 @@ __metadata: languageName: node linkType: hard -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 - languageName: node - linkType: hard - "fill-range@npm:^7.0.1": version: 7.0.1 resolution: "fill-range@npm:7.0.1" @@ -3353,9 +3335,9 @@ __metadata: linkType: hard "fs-monkey@npm:^1.0.3": - version: 1.0.3 - resolution: "fs-monkey@npm:1.0.3" - checksum: cf50804833f9b88a476911ae911fe50f61a98d986df52f890bd97e7262796d023698cb2309fa9b74fdd8974f04315b648748a0a8ee059e7d5257b293bfc409c0 + version: 1.0.4 + resolution: "fs-monkey@npm:1.0.4" + checksum: 8b254c982905c0b7e028eab22b410dc35a5c0019c1c860456f5f54ae6a61666e1cb8c6b700d6c88cc873694c00953c935847b9959cc4dcf274aacb8673c1e8bf languageName: node linkType: hard @@ -3423,13 +3405,14 @@ __metadata: linkType: hard "get-intrinsic@npm:^1.0.2": - version: 1.2.0 - resolution: "get-intrinsic@npm:1.2.0" + version: 1.2.1 + resolution: "get-intrinsic@npm:1.2.1" dependencies: function-bind: ^1.1.1 has: ^1.0.3 + has-proto: ^1.0.1 has-symbols: ^1.0.3 - checksum: 78fc0487b783f5c58cf2dccafc3ae656ee8d2d8062a8831ce4a95e7057af4587a1d4882246c033aca0a7b4965276f4802b45cc300338d1b77a73d3e3e3f4877d + checksum: 5b61d88552c24b0cf6fa2d1b3bc5459d7306f699de060d76442cce49a4721f52b8c560a33ab392cf5575b7810277d54ded9d4d39a1ea61855619ebc005aa7e5f languageName: node linkType: hard @@ -3556,6 +3539,13 @@ __metadata: languageName: node linkType: hard +"graphemer@npm:^1.4.0": + version: 1.4.0 + resolution: "graphemer@npm:1.4.0" + checksum: bab8f0be9b568857c7bec9fda95a89f87b783546d02951c40c33f84d05bb7da3fd10f863a9beb901463669b6583173a8c8cc6d6b306ea2b9b9d5d3d943c3a673 + languageName: node + linkType: hard + "handle-thing@npm:^2.0.0": version: 2.0.1 resolution: "handle-thing@npm:2.0.1" @@ -3577,6 +3567,13 @@ __metadata: languageName: node linkType: hard +"has-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "has-proto@npm:1.0.1" + checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e + languageName: node + linkType: hard + "has-symbols@npm:^1.0.3": version: 1.0.3 resolution: "has-symbols@npm:1.0.3" @@ -3919,9 +3916,9 @@ __metadata: linkType: hard "ipaddr.js@npm:^2.0.1": - version: 2.0.1 - resolution: "ipaddr.js@npm:2.0.1" - checksum: dd194a394a843d470f88d17191b0948f383ed1c8e320813f850c336a0fcb5e9215d97ec26ca35ab4fbbd31392c8b3467f3e8344628029ed3710b2ff6b5d1034e + version: 2.1.0 + resolution: "ipaddr.js@npm:2.1.0" + checksum: 807a054f2bd720c4d97ee479d6c9e865c233bea21f139fb8dabd5a35c4226d2621c42e07b4ad94ff3f82add926a607d8d9d37c625ad0319f0e08f9f2bd1968e2 languageName: node linkType: hard @@ -3941,12 +3938,12 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.11.0": - version: 2.11.0 - resolution: "is-core-module@npm:2.11.0" +"is-core-module@npm:^2.12.0": + version: 2.12.1 + resolution: "is-core-module@npm:2.12.1" dependencies: has: ^1.0.3 - checksum: f96fd490c6b48eb4f6d10ba815c6ef13f410b0ba6f7eb8577af51697de523e5f2cd9de1c441b51d27251bf0e4aebc936545e33a5d26d5d51f28d25698d4a8bab + checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 languageName: node linkType: hard @@ -4568,13 +4565,6 @@ __metadata: languageName: node linkType: hard -"js-sdsl@npm:^4.1.4": - version: 4.4.0 - resolution: "js-sdsl@npm:4.4.0" - checksum: 7bb08a2d746ab7ff742720339aa006c631afe05e77d11eda988c1c35fae8e03e492e4e347e883e786e3ce6170685d4780c125619111f0730c11fdb41b04059c7 - languageName: node - linkType: hard - "js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -4999,10 +4989,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^4.0.0": - version: 4.2.5 - resolution: "minipass@npm:4.2.5" - checksum: 4f9c19af23a5d4a9e7156feefc9110634b178a8cff8f8271af16ec5ebf7e221725a97429952c856f5b17b30c2065ebd24c81722d90c93d2122611d75b952b48f +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea languageName: node linkType: hard @@ -5130,10 +5120,10 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.8": - version: 2.0.10 - resolution: "node-releases@npm:2.0.10" - checksum: d784ecde25696a15d449c4433077f5cce620ed30a1656c4abf31282bfc691a70d9618bae6868d247a67914d1be5cc4fde22f65a05f4398cdfb92e0fc83cadfbc +"node-releases@npm:^2.0.12": + version: 2.0.12 + resolution: "node-releases@npm:2.0.12" + checksum: b8c56db82c4642a0f443332b331a4396dae452a2ac5a65c8dbd93ef89ecb2fbb0da9d42ac5366d4764973febadca816cf7587dad492dce18d2a6b2af59cda260 languageName: node linkType: hard @@ -5448,11 +5438,11 @@ __metadata: linkType: hard "prettier@npm:^2.8.4": - version: 2.8.7 - resolution: "prettier@npm:2.8.7" + version: 2.8.8 + resolution: "prettier@npm:2.8.8" bin: prettier: bin-prettier.js - checksum: fdc8f2616f099f5f0d685907f4449a70595a0fc1d081a88919604375989e0d5e9168d6121d8cc6861f21990b31665828e00472544d785d5940ea08a17660c3a6 + checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 languageName: node linkType: hard @@ -5529,9 +5519,9 @@ __metadata: linkType: hard "pure-rand@npm:^6.0.0": - version: 6.0.1 - resolution: "pure-rand@npm:6.0.1" - checksum: 4bb565399993b815658a72e359f574ce4f04827a42a905105d61163ae86f456d91595a0e4241e7bce04328fae0638ae70ac0428d93ecb55971c465bd084f8648 + version: 6.0.2 + resolution: "pure-rand@npm:6.0.2" + checksum: 79de33876a4f515d759c48e98d00756bbd916b4ea260cc572d7adfa4b62cace9952e89f0241d0410214554503d25061140fe325c66f845213d2b1728ba8d413e languageName: node linkType: hard @@ -5713,28 +5703,28 @@ __metadata: linkType: hard "resolve@npm:^1.20.0": - version: 1.22.2 - resolution: "resolve@npm:1.22.2" + version: 1.22.3 + resolution: "resolve@npm:1.22.3" dependencies: - is-core-module: ^2.11.0 + is-core-module: ^2.12.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: 7e5df75796ebd429445d102d5824482ee7e567f0070b2b45897b29bb4f613dcbc262e0257b8aeedb3089330ccaea0d6a0464df1a77b2992cf331dcda0f4cb549 + checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 languageName: node linkType: hard "resolve@patch:resolve@^1.20.0#~builtin": - version: 1.22.2 - resolution: "resolve@patch:resolve@npm%3A1.22.2#~builtin::version=1.22.2&hash=c3c19d" + version: 1.22.3 + resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" dependencies: - is-core-module: ^2.11.0 + is-core-module: ^2.12.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: 66cc788f13b8398de18eb4abb3aed90435c84bb8935953feafcf7231ba4cd191b2c10b4a87b1e9681afc34fb138c705f91f7330ff90bfa36f457e5584076a2b8 + checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 languageName: node linkType: hard @@ -5839,14 +5829,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.x, semver@npm:^7.3.5, semver@npm:^7.3.7": - version: 7.3.8 - resolution: "semver@npm:7.3.8" +"semver@npm:7.x, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7": + version: 7.5.1 + resolution: "semver@npm:7.5.1" dependencies: lru-cache: ^6.0.0 bin: semver: bin/semver.js - checksum: ba9c7cbbf2b7884696523450a61fee1a09930d888b7a8d7579025ad93d459b2d1949ee5bbfeb188b2be5f4ac163544c5e98491ad6152df34154feebc2cc337c1 + checksum: d16dbedad53c65b086f79524b9ef766bf38670b2395bdad5c957f824dcc566b624988013564f4812bcace3f9d405355c3635e2007396a39d1bffc71cfec4a2fc languageName: node linkType: hard @@ -5859,17 +5849,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.4": - version: 7.5.0 - resolution: "semver@npm:7.5.0" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b - languageName: node - linkType: hard - "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" @@ -6262,22 +6241,22 @@ __metadata: linkType: hard "tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.13 - resolution: "tar@npm:6.1.13" + version: 6.1.15 + resolution: "tar@npm:6.1.15" dependencies: chownr: ^2.0.0 fs-minipass: ^2.0.0 - minipass: ^4.0.0 + minipass: ^5.0.0 minizlib: ^2.1.1 mkdirp: ^1.0.3 yallist: ^4.0.0 - checksum: 8a278bed123aa9f53549b256a36b719e317c8b96fe86a63406f3c62887f78267cea9b22dc6f7007009738509800d4a4dccc444abd71d762287c90f35b002eb1c + checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 languageName: node linkType: hard "terser-webpack-plugin@npm:^5.3.7": - version: 5.3.8 - resolution: "terser-webpack-plugin@npm:5.3.8" + version: 5.3.9 + resolution: "terser-webpack-plugin@npm:5.3.9" dependencies: "@jridgewell/trace-mapping": ^0.3.17 jest-worker: ^27.4.5 @@ -6293,13 +6272,13 @@ __metadata: optional: true uglify-js: optional: true - checksum: 0ffc2a1949b1fd60ef9c815c4629b9817656db612bb58c5db96e3b04204c86afd142b115392e48733364edc7bf95131f54c10174c05f046ba8f2adead6b06c3c + checksum: 41705713d6f9cb83287936b21e27c658891c78c4392159f5148b5623f0e8c48559869779619b058382a4c9758e7820ea034695e57dc7c474b4962b79f553bc5f languageName: node linkType: hard "terser@npm:^5.10.0, terser@npm:^5.16.8": - version: 5.17.3 - resolution: "terser@npm:5.17.3" + version: 5.17.6 + resolution: "terser@npm:5.17.6" dependencies: "@jridgewell/source-map": ^0.3.2 acorn: ^8.5.0 @@ -6307,7 +6286,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 6b5a859bf9707f34be6e4c567437bc4e47e9364eec37a48b0ae3bff46bb510ef43caf543a23a89b8f43eca47c90a6759105add171fdb0d768dd639deb4545ac9 + checksum: 9c0ab0261a99a61c5f53d05d4ecc7f68c552bae6af481464fdd596bc9d7e89ce8e21b1833cb3ce06ad5f658e2b226081d543e4fe6e324b2cdf03ee8b7eeec01a languageName: node linkType: hard @@ -6400,8 +6379,8 @@ __metadata: linkType: hard "ts-loader@npm:^9.4.2": - version: 9.4.2 - resolution: "ts-loader@npm:9.4.2" + version: 9.4.3 + resolution: "ts-loader@npm:9.4.3" dependencies: chalk: ^4.1.0 enhanced-resolve: ^5.0.0 @@ -6410,7 +6389,7 @@ __metadata: peerDependencies: typescript: "*" webpack: ^5.0.0 - checksum: 6f306ee4c615c2a159fb177561e3fb86ca2cbd6c641e710d408a64b4978e1ff3f2c9733df07bff27d3f82efbfa7c287523d4306049510c7485ac2669a9c37eb0 + checksum: 139ed53bc60717d0ca231cdffbdef7566b9feda11c72fecc697983113f1266ccca2e1cdf191f841a43afa6b87d6afe57a0caf4feecf02f30845aa7ac6f2411a4 languageName: node linkType: hard @@ -6452,7 +6431,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.5.0, tslib@npm:^2.0.3, tslib@npm:^2.4.0": +"tslib@npm:2.5.0": version: 2.5.0 resolution: "tslib@npm:2.5.0" checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 @@ -6466,6 +6445,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.0.3, tslib@npm:^2.4.0": + version: 2.5.2 + resolution: "tslib@npm:2.5.2" + checksum: 4d3c1e238b94127ed0e88aa0380db3c2ddae581dc0f4bae5a982345e9f50ee5eda90835b8bfba99b02df10a5734470be197158c36f9129ac49fdc14a6a9da222 + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -6562,17 +6548,17 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.10": - version: 1.0.10 - resolution: "update-browserslist-db@npm:1.0.10" +"update-browserslist-db@npm:^1.0.11": + version: 1.0.11 + resolution: "update-browserslist-db@npm:1.0.11" dependencies: escalade: ^3.1.1 picocolors: ^1.0.0 peerDependencies: browserslist: ">= 4.21.0" bin: - browserslist-lint: cli.js - checksum: 12db73b4f63029ac407b153732e7cd69a1ea8206c9100b482b7d12859cd3cd0bc59c602d7ae31e652706189f1acb90d42c53ab24a5ba563ed13aebdddc5561a0 + update-browserslist-db: cli.js + checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 languageName: node linkType: hard @@ -6763,12 +6749,12 @@ __metadata: linkType: hard "webpack-merge@npm:^5.7.3": - version: 5.8.0 - resolution: "webpack-merge@npm:5.8.0" + version: 5.9.0 + resolution: "webpack-merge@npm:5.9.0" dependencies: clone-deep: ^4.0.1 wildcard: ^2.0.0 - checksum: 88786ab91013f1bd2a683834ff381be81c245a4b0f63304a5103e90f6653f44dab496a0768287f8531761f8ad957d1f9f3ccb2cb55df0de1bd9ee343e079da26 + checksum: 64fe2c23aacc5f19684452a0e84ec02c46b990423aee6fcc5c18d7d471155bd14e9a6adb02bd3656eb3e0ac2532c8e97d69412ad14c97eeafe32fa6d10050872 languageName: node linkType: hard @@ -6780,8 +6766,8 @@ __metadata: linkType: hard "webpack@npm:^5.82.1": - version: 5.82.1 - resolution: "webpack@npm:5.82.1" + version: 5.85.0 + resolution: "webpack@npm:5.85.0" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.0 @@ -6789,10 +6775,10 @@ __metadata: "@webassemblyjs/wasm-edit": ^1.11.5 "@webassemblyjs/wasm-parser": ^1.11.5 acorn: ^8.7.1 - acorn-import-assertions: ^1.7.6 + acorn-import-assertions: ^1.9.0 browserslist: ^4.14.5 chrome-trace-event: ^1.0.2 - enhanced-resolve: ^5.14.0 + enhanced-resolve: ^5.14.1 es-module-lexer: ^1.2.1 eslint-scope: 5.1.1 events: ^3.2.0 @@ -6812,7 +6798,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 747ee7ebd238c15249c2652060e3c6ca6d62cc66dcf7e4e2824ecd4875b7ea5e01fce8f4179080a3e84dfdb3c8d0992700444c7c5a05ef47b38c0623d3ac76de + checksum: b013be9fbc7f6810d1f229f570c70710ddbc7290f817411acffe4214b2b6c783a041ab1f2005d9e1109f4ab21c136f0f8d8c067a5fb64f20a82dcbc1ee0d3f42 languageName: node linkType: hard @@ -6940,8 +6926,8 @@ __metadata: linkType: hard "yargs@npm:^17.3.1": - version: 17.7.1 - resolution: "yargs@npm:17.7.1" + version: 17.7.2 + resolution: "yargs@npm:17.7.2" dependencies: cliui: ^8.0.1 escalade: ^3.1.1 @@ -6950,7 +6936,7 @@ __metadata: string-width: ^4.2.3 y18n: ^5.0.5 yargs-parser: ^21.1.1 - checksum: 3d8a43c336a4942bc68080768664aca85c7bd406f018bad362fd255c41c8f4e650277f42fd65d543fce99e084124ddafee7bbfc1a5c6a8fda4cec78609dcf8d4 + checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a languageName: node linkType: hard