From ebf3411ff00ed65f4e18defa7fa5189ff0a85a80 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 09:05:16 +0000 Subject: [PATCH 01/18] Passing around crs is painful and buggy, leverage the global crs. --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 44 +++++++++---------- .../dsl/acir_proofs/acir_composer.cpp | 9 ++-- .../dsl/acir_proofs/acir_composer.hpp | 19 +++----- .../barretenberg/dsl/acir_proofs/c_bind.cpp | 7 ++- .../barretenberg/examples/simple/simple.cpp | 5 +-- .../plonk/composer/ultra_composer.cpp | 7 ++- .../plonk/composer/ultra_composer.hpp | 6 +-- 7 files changed, 43 insertions(+), 54 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 81c4a2bfb49a..dfcd63d8d3ca 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -53,11 +53,11 @@ acir_format::acir_format get_constraint_system(std::string const& bytecode_path) */ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessPath, bool recursive) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); auto witness = get_witness(witnessPath); - auto proof = acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive); - auto verified = acir_composer->verify_proof(proof, recursive); + auto proof = acir_composer.create_proof(constraint_system, witness, recursive); + auto verified = acir_composer.verify_proof(proof, recursive); vinfo("verified: ", verified); return verified; @@ -80,10 +80,10 @@ void prove(const std::string& bytecodePath, bool recursive, const std::string& outputPath) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); auto witness = get_witness(witnessPath); - auto proof = acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive); + auto proof = acir_composer.create_proof(constraint_system, witness, recursive); if (outputPath == "-") { writeRawBytesToStdout(proof); @@ -104,10 +104,10 @@ void prove(const std::string& bytecodePath, */ void gateCount(const std::string& bytecodePath) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); - acir_composer->create_circuit(constraint_system); - auto gate_count = acir_composer->get_total_circuit_size(); + acir_composer.create_circuit(constraint_system); + auto gate_count = acir_composer.get_total_circuit_size(); writeUint64AsRawBytesToStdout(static_cast(gate_count)); vinfo("gate count: ", gate_count); @@ -131,10 +131,10 @@ void gateCount(const std::string& bytecodePath) */ bool verify(const std::string& proof_path, bool recursive, const std::string& vk_path) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto vk_data = from_buffer(read_file(vk_path)); - acir_composer->load_verification_key(barretenberg::srs::get_crs_factory(), std::move(vk_data)); - auto verified = acir_composer->verify_proof(read_file(proof_path), recursive); + acir_composer.load_verification_key(std::move(vk_data)); + auto verified = acir_composer.verify_proof(read_file(proof_path), recursive); vinfo("verified: ", verified); @@ -153,10 +153,10 @@ bool verify(const std::string& proof_path, bool recursive, const std::string& vk */ void writeVk(const std::string& bytecodePath, const std::string& outputPath) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); - acir_composer->init_proving_key(srs::get_crs_factory(), constraint_system); - auto vk = acir_composer->init_verification_key(); + acir_composer.init_proving_key(constraint_system); + auto vk = acir_composer.init_verification_key(); auto serialized_vk = to_buffer(*vk); if (outputPath == "-") { writeRawBytesToStdout(serialized_vk); @@ -182,10 +182,10 @@ void writeVk(const std::string& bytecodePath, const std::string& outputPath) */ void contract(const std::string& output_path, const std::string& vk_path) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto vk_data = from_buffer(read_file(vk_path)); - acir_composer->load_verification_key(barretenberg::srs::get_crs_factory(), std::move(vk_data)); - auto contract = acir_composer->get_solidity_verifier(); + acir_composer.load_verification_key(std::move(vk_data)); + auto contract = acir_composer.get_solidity_verifier(); if (output_path == "-") { writeStringToStdout(contract); @@ -223,9 +223,9 @@ void contract(const std::string& output_path, const std::string& vk_path) */ void proofAsFields(const std::string& proof_path, std::string const& vk_path, const std::string& output_path) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto vk_data = from_buffer(read_file(vk_path)); - auto data = acir_composer->serialize_proof_into_fields(read_file(proof_path), vk_data.num_public_inputs); + auto data = acir_composer.serialize_proof_into_fields(read_file(proof_path), vk_data.num_public_inputs); auto json = format("[", join(map(data, [](auto fr) { return format("\"", fr, "\""); })), "]"); if (output_path == "-") { @@ -252,10 +252,10 @@ void proofAsFields(const std::string& proof_path, std::string const& vk_path, co */ void vkAsFields(const std::string& vk_path, const std::string& output_path) { - auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); + acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto vk_data = from_buffer(read_file(vk_path)); - acir_composer->load_verification_key(barretenberg::srs::get_crs_factory(), std::move(vk_data)); - auto data = acir_composer->serialize_verification_key_into_fields(); + acir_composer.load_verification_key(std::move(vk_data)); + auto data = acir_composer.serialize_verification_key_into_fields(); // We need to move vk_hash to the front... std::rotate(data.begin(), data.end() - 1, data.end()); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index 29463a06db7f..07a3578b0d13 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -108,13 +108,10 @@ std::shared_ptr AcirComposer::init_verifi return verification_key_; } -void AcirComposer::load_verification_key( - std::shared_ptr> const& crs_factory, - proof_system::plonk::verification_key_data&& data) +void AcirComposer::load_verification_key(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_); + verification_key_ = std::make_shared( + std::move(data), srs::get_crs_factory()->get_verifier_crs()); } bool AcirComposer::verify_proof(std::vector const& proof, bool is_recursive) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp index 25814e78d918..f4e125478bae 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp @@ -14,18 +14,13 @@ class 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); - - 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); + void init_proving_key(acir_format::acir_format& constraint_system); + + std::vector create_proof(acir_format::acir_format& constraint_system, + acir_format::WitnessVector& witness, + bool is_recursive); + + void load_verification_key(proof_system::plonk::verification_key_data&& data); std::shared_ptr init_verification_key(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index 1af145e2978c..0bdfbb519d2f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -35,7 +35,7 @@ WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* auto acir_composer = reinterpret_cast(*acir_composer_ptr); auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec)); - acir_composer->init_proving_key(barretenberg::srs::get_crs_factory(), constraint_system); + acir_composer->init_proving_key(constraint_system); } WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, @@ -48,8 +48,7 @@ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec)); auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto proof_data = - acir_composer->create_proof(barretenberg::srs::get_crs_factory(), constraint_system, witness, *is_recursive); + auto proof_data = acir_composer->create_proof(constraint_system, witness, *is_recursive); *out = to_heap_buffer(proof_data); } @@ -57,7 +56,7 @@ WASM_EXPORT void acir_load_verification_key(in_ptr acir_composer_ptr, uint8_t co { 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)); + acir_composer->load_verification_key(std::move(vk_data)); } WASM_EXPORT void acir_init_verification_key(in_ptr acir_composer_ptr) diff --git a/barretenberg/cpp/src/barretenberg/examples/simple/simple.cpp b/barretenberg/cpp/src/barretenberg/examples/simple/simple.cpp index 19af6aa0d691..ad35fa0ee950 100644 --- a/barretenberg/cpp/src/barretenberg/examples/simple/simple.cpp +++ b/barretenberg/cpp/src/barretenberg/examples/simple/simple.cpp @@ -19,8 +19,7 @@ void build_circuit(Builder& builder) } } -BuilderComposerPtrs create_builder_and_composer( - std::shared_ptr> const& crs_factory) +BuilderComposerPtrs create_builder_and_composer() { // WARNING: Size hint is essential to perform 512k circuits! auto builder = std::make_unique(CIRCUIT_SIZE); @@ -36,7 +35,7 @@ BuilderComposerPtrs create_builder_and_composer( info("composer gates: ", builder->get_num_gates()); info("computing proving key..."); - auto composer = std::make_unique(crs_factory); + auto composer = std::make_unique(); auto pk = composer->compute_proving_key(*builder); return { builder.release(), composer.release() }; diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index 7b0ded945c83..1026193bdf7e 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -375,10 +375,11 @@ std::shared_ptr UltraComposer::compute_proving_key(CircuitBuilder& const size_t minimum_circuit_size = tables_size + lookups_size; const size_t num_randomized_gates = NUM_RESERVED_GATES; + auto crs_factory = srs::get_crs_factory(); // Initialize circuit_proving_key // TODO(#392)(Kesha): replace composer types. circuit_proving_key = initialize_proving_key( - circuit_constructor, crs_factory_.get(), minimum_circuit_size, num_randomized_gates, CircuitType::ULTRA); + circuit_constructor, crs_factory.get(), minimum_circuit_size, num_randomized_gates, CircuitType::ULTRA); construct_selector_polynomials(circuit_constructor, circuit_proving_key.get()); @@ -491,10 +492,12 @@ std::shared_ptr UltraComposer::compute_verification_key return circuit_verification_key; } + auto crs_factory = srs::get_crs_factory(); + if (!circuit_proving_key) { compute_proving_key(circuit_constructor); } - circuit_verification_key = compute_verification_key_common(circuit_proving_key, crs_factory_->get_verifier_crs()); + circuit_verification_key = compute_verification_key_common(circuit_proving_key, crs_factory->get_verifier_crs()); circuit_verification_key->circuit_type = CircuitType::ULTRA; diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp index fcea9028d830..e539db4c47b9 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp @@ -27,7 +27,6 @@ class UltraComposer { std::shared_ptr circuit_verification_key; // The crs_factory holds the path to the srs and exposes methods to extract the srs elements - std::shared_ptr> crs_factory_; bool computed_witness = false; @@ -37,11 +36,8 @@ class UltraComposer { // vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3. static constexpr size_t s_randomness = 3; - UltraComposer() { crs_factory_ = barretenberg::srs::get_crs_factory(); } + UltraComposer() = default; - explicit UltraComposer(std::shared_ptr> crs_factory) - : crs_factory_(std::move(crs_factory)) - {} UltraComposer(std::shared_ptr p_key, std::shared_ptr v_key) : circuit_proving_key(std::move(p_key)) From d3551c85bcaf8bbd32d71072c7d310b0482d289a Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 09:07:15 +0000 Subject: [PATCH 02/18] Stop whinging about this ownership stuff. --- barretenberg/cpp/.clangd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/.clangd b/barretenberg/cpp/.clangd index 06f5d0d0590b..e09234d9e7a7 100644 --- a/barretenberg/cpp/.clangd +++ b/barretenberg/cpp/.clangd @@ -1,4 +1,4 @@ -CompileFlags: # Tweak the parse settings +CompileFlags: # Tweak the parse settings Remove: -fconstexpr-ops-limit=* --- # Applies all barretenberg source files @@ -42,7 +42,7 @@ Diagnostics: - misc-non-private-member-variables-in-classes - cppcoreguidelines-non-private-member-variables-in-classes # We have many `for` loops that violate this part of the bounds safety profile - - cppcoreguidelines-pro-bounds-constant-array-index + - cppcoreguidelines-pro-bounds-constant-array-index # Large diff; we often `use` an entire namespace. - google-build-using-namespace # Large diff @@ -59,6 +59,8 @@ Diagnostics: - readability-function-cognitive-complexity # It is often nicer to not be explicit - google-explicit-constructor + # Not honouring. + - cppcoreguidelines-owning-memory --- # this divider is necessary # Disable some checks for Google Test/Bench @@ -69,5 +71,4 @@ Diagnostics: # these checks get triggered by the Google macros Remove: - cppcoreguidelines-avoid-non-const-global-variables - - cppcoreguidelines-owning-memory - - cppcoreguidelines-special-member-functions \ No newline at end of file + - cppcoreguidelines-special-member-functions From e67f0803fe5668de714a84bfc3c09829564a1bc4 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 09:59:06 +0000 Subject: [PATCH 03/18] Build circuit to determine size of crs to load. --- barretenberg/acir_tests/flows/all_cmds.sh | 8 ++-- .../cpp/src/barretenberg/bb/file_io.hpp | 5 +- .../cpp/src/barretenberg/bb/get_crs.hpp | 2 +- barretenberg/cpp/src/barretenberg/bb/main.cpp | 48 ++++++++++++------- .../dsl/acir_proofs/acir_composer.hpp | 1 + 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/barretenberg/acir_tests/flows/all_cmds.sh b/barretenberg/acir_tests/flows/all_cmds.sh index dda4353fb6f0..c7ee147f6203 100755 --- a/barretenberg/acir_tests/flows/all_cmds.sh +++ b/barretenberg/acir_tests/flows/all_cmds.sh @@ -19,6 +19,8 @@ $BIN verify -k vk -p proof $FLAGS # Check supplemental functions. # Grep to determine success. $BIN contract -k vk $BFLAG -o - | grep "Verification Key Hash" > /dev/null -# Use jq to determine success. -$BIN proof_as_fields -k vk -p proof -o - | jq . > /dev/null -$BIN vk_as_fields -k vk -o - > vk_as_fields | jq . > /dev/null \ No newline at end of file +# Use jq to determine success, and also check result not empty. +OUTPUT=$($BIN proof_as_fields -k vk -p proof -o - | jq .) +[ -n "$OUTPUT" ] || exit 1 +OUTPUT=$($BIN vk_as_fields -k vk -o - | jq .) +[ -n "$OUTPUT" ] || exit 1 \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/bb/file_io.hpp b/barretenberg/cpp/src/barretenberg/bb/file_io.hpp index 09009ebbd2b2..31796e57ffa3 100644 --- a/barretenberg/cpp/src/barretenberg/bb/file_io.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/file_io.hpp @@ -1,9 +1,10 @@ #pragma once #include #include +#include #include -inline std::vector read_file(const std::string& filename) +inline std::vector read_file(const std::string& filename, size_t bytes = 0) { // Open the file in binary mode and move to the end. std::ifstream file(filename, std::ios::binary | std::ios::ate); @@ -12,7 +13,7 @@ inline std::vector read_file(const std::string& filename) } // Get the file size. - std::streamsize size = file.tellg(); + std::streamsize size = bytes == 0 ? (std::streamsize)file.tellg() : (std::streamsize)bytes; if (size <= 0) { throw std::runtime_error("File is empty or there's an error reading it: " + filename); } diff --git a/barretenberg/cpp/src/barretenberg/bb/get_crs.hpp b/barretenberg/cpp/src/barretenberg/bb/get_crs.hpp index b4269d3ad3d3..1c205f2f3e88 100644 --- a/barretenberg/cpp/src/barretenberg/bb/get_crs.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/get_crs.hpp @@ -65,7 +65,7 @@ inline std::vector get_g1_data(const std::file } if (size >= num_points) { vinfo("using cached crs at: ", path); - auto data = read_file(path / "g1.dat"); + auto data = read_file(path / "g1.dat", 28 + num_points * 64); auto points = std::vector(num_points); auto size_of_points_in_bytes = num_points * 64; barretenberg::srs::IO::read_affine_elements_from_buffer( diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index dfcd63d8d3ca..8657385bfdde 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -13,17 +13,29 @@ #include using namespace barretenberg; -// Transcript downloading code only supports fetching and parsing the first transcript file. -const uint32_t MAX_CIRCUIT_SIZE = 1 << 22; std::string CRS_PATH = "./crs"; bool verbose = false; -void init() +acir_proofs::AcirComposer init(acir_format::acir_format& constraint_system) { + acir_proofs::AcirComposer acir_composer(0, verbose); + acir_composer.create_circuit(constraint_system); + auto subgroup_size = acir_composer.get_circuit_subgroup_size(); + // Must +1! - auto g1_data = get_g1_data(CRS_PATH, MAX_CIRCUIT_SIZE + 1); + auto g1_data = get_g1_data(CRS_PATH, subgroup_size + 1); auto g2_data = get_g2_data(CRS_PATH); srs::init_crs_factory(g1_data, g2_data); + + return acir_composer; +} + +acir_proofs::AcirComposer init() +{ + acir_proofs::AcirComposer acir_composer(0, verbose); + auto g2_data = get_g2_data(CRS_PATH); + srs::init_crs_factory({}, g2_data); + return acir_composer; } acir_format::WitnessVector get_witness(std::string const& witness_path) @@ -53,9 +65,10 @@ acir_format::acir_format get_constraint_system(std::string const& bytecode_path) */ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessPath, bool recursive) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); auto witness = get_witness(witnessPath); + auto acir_composer = init(constraint_system); + auto proof = acir_composer.create_proof(constraint_system, witness, recursive); auto verified = acir_composer.verify_proof(proof, recursive); @@ -80,9 +93,9 @@ void prove(const std::string& bytecodePath, bool recursive, const std::string& outputPath) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); auto witness = get_witness(witnessPath); + auto acir_composer = init(constraint_system); auto proof = acir_composer.create_proof(constraint_system, witness, recursive); if (outputPath == "-") { @@ -104,9 +117,8 @@ void prove(const std::string& bytecodePath, */ void gateCount(const std::string& bytecodePath) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); - acir_composer.create_circuit(constraint_system); + auto acir_composer = init(constraint_system); auto gate_count = acir_composer.get_total_circuit_size(); writeUint64AsRawBytesToStdout(static_cast(gate_count)); @@ -131,7 +143,9 @@ void gateCount(const std::string& bytecodePath) */ bool verify(const std::string& proof_path, bool recursive, const std::string& vk_path) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); + auto g2_data = get_g2_data(CRS_PATH); + srs::init_crs_factory({}, g2_data); + acir_proofs::AcirComposer acir_composer(1, verbose); auto vk_data = from_buffer(read_file(vk_path)); acir_composer.load_verification_key(std::move(vk_data)); auto verified = acir_composer.verify_proof(read_file(proof_path), recursive); @@ -153,8 +167,8 @@ bool verify(const std::string& proof_path, bool recursive, const std::string& vk */ void writeVk(const std::string& bytecodePath, const std::string& outputPath) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_constraint_system(bytecodePath); + auto acir_composer = init(constraint_system); acir_composer.init_proving_key(constraint_system); auto vk = acir_composer.init_verification_key(); auto serialized_vk = to_buffer(*vk); @@ -182,7 +196,7 @@ void writeVk(const std::string& bytecodePath, const std::string& outputPath) */ void contract(const std::string& output_path, const std::string& vk_path) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); + auto acir_composer = init(); auto vk_data = from_buffer(read_file(vk_path)); acir_composer.load_verification_key(std::move(vk_data)); auto contract = acir_composer.get_solidity_verifier(); @@ -223,7 +237,7 @@ void contract(const std::string& output_path, const std::string& vk_path) */ void proofAsFields(const std::string& proof_path, std::string const& vk_path, const std::string& output_path) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); + auto acir_composer = init(); auto vk_data = from_buffer(read_file(vk_path)); auto data = acir_composer.serialize_proof_into_fields(read_file(proof_path), vk_data.num_public_inputs); auto json = format("[", join(map(data, [](auto fr) { return format("\"", fr, "\""); })), "]"); @@ -252,7 +266,7 @@ void proofAsFields(const std::string& proof_path, std::string const& vk_path, co */ void vkAsFields(const std::string& vk_path, const std::string& output_path) { - acir_proofs::AcirComposer acir_composer(MAX_CIRCUIT_SIZE, verbose); + auto acir_composer = init(); auto vk_data = from_buffer(read_file(vk_path)); acir_composer.load_verification_key(std::move(vk_data)); auto data = acir_composer.serialize_verification_key_into_fields(); @@ -338,17 +352,17 @@ int main(int argc, char* argv[]) if (command == "--version") { writeStringToStdout(BB_VERSION); return 0; - } else if (command == "info") { + } + if (command == "info") { std::string output_path = getOption(args, "-o", "info.json"); acvmInfo(output_path); return 0; } - init(); - if (command == "prove_and_verify") { return proveAndVerify(bytecode_path, witness_path, recursive) ? 0 : 1; - } else if (command == "prove") { + } + if (command == "prove") { std::string output_path = getOption(args, "-o", "./proofs/proof"); prove(bytecode_path, witness_path, recursive, output_path); } else if (command == "gates") { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp index f4e125478bae..58696e4ad253 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp @@ -29,6 +29,7 @@ class AcirComposer { 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_; }; + size_t get_circuit_subgroup_size() { return circuit_subgroup_size_; }; std::vector serialize_proof_into_fields(std::vector const& proof, size_t num_inner_public_inputs); From 5737a73c6ab75379e96f92d3208c260c7aa23e0b Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 10:02:57 +0000 Subject: [PATCH 04/18] Remove redundency in format. Remove composer as member in acir_composer. --- .../dsl/acir_format/acir_format.cpp | 134 ++++-------------- .../dsl/acir_format/block_constraint.cpp | 2 +- .../dsl/acir_proofs/acir_composer.cpp | 90 +++++------- .../dsl/acir_proofs/acir_composer.hpp | 1 - 4 files changed, 60 insertions(+), 167 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 250efe82ecd0..59b5192a6452 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -11,29 +11,30 @@ void read_witness(Builder& builder, WitnessVector const& witness) } } -void create_circuit(Builder& builder, acir_format const& constraint_system) +void add_public_vars(Builder& builder, acir_format const& constraint_system) { - if (constraint_system.public_inputs.size() > constraint_system.varnum) { - info("create_circuit: too many public inputs!"); - } - 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 if (std::find(constraint_system.public_inputs.begin(), constraint_system.public_inputs.end(), i) != constraint_system.public_inputs.end()) { + builder.add_public_variable(0); + } else { builder.add_variable(0); } } +} +void build_constraints(Builder& builder, acir_format const& constraint_system, bool has_valid_witness_assignments) +{ // Add arithmetic gates for (const auto& constraint : constraint_system.constraints) { builder.create_poly_gate(constraint); } - // Add and constraint + // Add logic constraint for (const auto& constraint : constraint_system.logic_constraints) { create_logic_gate( builder, constraint.a, constraint.b, constraint.result, constraint.num_bits, constraint.is_xor_gate); @@ -54,14 +55,14 @@ void create_circuit(Builder& builder, acir_format const& constraint_system) create_schnorr_verify_constraints(builder, constraint); } - // Add ECDSA K1 constraints + // Add ECDSA k1 constraints for (const auto& constraint : constraint_system.ecdsa_k1_constraints) { - create_ecdsa_k1_verify_constraints(builder, constraint, false); + create_ecdsa_k1_verify_constraints(builder, constraint, has_valid_witness_assignments); } - // Add ECDSA R1 constraints + // Add ECDSA r1 constraints for (const auto& constraint : constraint_system.ecdsa_r1_constraints) { - create_ecdsa_r1_verify_constraints(builder, constraint, false); + create_ecdsa_r1_verify_constraints(builder, constraint, has_valid_witness_assignments); } // Add blake2s constraints @@ -94,13 +95,13 @@ void create_circuit(Builder& builder, acir_format const& constraint_system) // Add block constraints for (const auto& constraint : constraint_system.block_constraints) { - create_block_constraints(builder, constraint, false); + create_block_constraints(builder, constraint, has_valid_witness_assignments); } // 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(builder, constraint); + create_recursion_constraints(builder, constraint, has_valid_witness_assignments); // 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 @@ -113,6 +114,16 @@ void create_circuit(Builder& builder, acir_format const& constraint_system) } } +void create_circuit(Builder& builder, acir_format const& constraint_system) +{ + if (constraint_system.public_inputs.size() > constraint_system.varnum) { + info("create_circuit: too many public inputs!"); + } + + add_public_vars(builder, constraint_system); + build_constraints(builder, constraint_system, false); +} + Builder create_circuit(const acir_format& constraint_system, size_t size_hint) { Builder builder(size_hint); @@ -135,104 +146,9 @@ void create_circuit_with_witness(Builder& builder, acir_format const& constraint info("create_circuit_with_witness: too many public inputs!"); } - 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 - - if (std::find(constraint_system.public_inputs.begin(), constraint_system.public_inputs.end(), i) != - constraint_system.public_inputs.end()) { - - builder.add_public_variable(0); - - } else { - builder.add_variable(0); - } - } - + add_public_vars(builder, constraint_system); read_witness(builder, witness); - - // Add arithmetic gates - for (const auto& constraint : constraint_system.constraints) { - builder.create_poly_gate(constraint); - } - - // Add logic constraint - for (const auto& constraint : constraint_system.logic_constraints) { - create_logic_gate( - builder, constraint.a, constraint.b, constraint.result, constraint.num_bits, constraint.is_xor_gate); - } - - // Add range constraint - for (const auto& constraint : constraint_system.range_constraints) { - builder.create_range_constraint(constraint.witness, constraint.num_bits, ""); - } - - // Add sha256 constraints - for (const auto& constraint : constraint_system.sha256_constraints) { - create_sha256_constraints(builder, constraint); - } - - // Add schnorr constraints - for (const auto& constraint : constraint_system.schnorr_constraints) { - create_schnorr_verify_constraints(builder, constraint); - } - - // Add ECDSA k1 constraints - for (const auto& constraint : constraint_system.ecdsa_k1_constraints) { - create_ecdsa_k1_verify_constraints(builder, constraint); - } - - // Add ECDSA r1 constraints - for (const auto& constraint : constraint_system.ecdsa_r1_constraints) { - create_ecdsa_r1_verify_constraints(builder, constraint); - } - - // Add blake2s constraints - for (const auto& constraint : constraint_system.blake2s_constraints) { - create_blake2s_constraints(builder, constraint); - } - - // Add keccak constraints - for (const auto& constraint : constraint_system.keccak_constraints) { - create_keccak_constraints(builder, constraint); - } - for (const auto& constraint : constraint_system.keccak_var_constraints) { - create_keccak_var_constraints(builder, constraint); - } - - // Add pedersen constraints - for (const auto& constraint : constraint_system.pedersen_constraints) { - create_pedersen_constraint(builder, constraint); - } - - // Add fixed base scalar mul constraints - for (const auto& constraint : constraint_system.fixed_base_scalar_mul_constraints) { - create_fixed_base_constraint(builder, constraint); - } - - // Add hash to field constraints - for (const auto& constraint : constraint_system.hash_to_field_constraints) { - create_hash_to_field_constraints(builder, constraint); - } - - // Add block constraints - for (const auto& constraint : constraint_system.block_constraints) { - create_block_constraints(builder, 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(builder, 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()); - builder.set_recursive_proof(proof_output_witness_indices); - } - } + build_constraints(builder, constraint_system, true); } } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp index 9eb908f0b00c..882d1ac14edb 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp @@ -55,7 +55,7 @@ void create_block_constraints(Builder& builder, const BlockConstraint constraint field_ct value = poly_to_field_ct(op.value, builder); field_ct index = poly_to_field_ct(op.index, builder); if (has_valid_witness_assignments == false) { - index = field_ct(0); + index = field_ct::from_witness(&builder, 0); } if (op.access_type == 0) { value.assert_equal(table.read(index)); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index 07a3578b0d13..c5afdc100462 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -12,88 +12,60 @@ namespace acir_proofs { AcirComposer::AcirComposer(size_t size_hint, bool verbose) - : composer_(/*p_key=*/0, /*v_key=*/0) - , size_hint_(size_hint) + : size_hint_(size_hint) , verbose_(verbose) {} void AcirComposer::create_circuit(acir_format::acir_format& constraint_system) { + if (builder_.get_num_gates() > 1) { + return; + } + vinfo("building circuit..."); builder_ = acir_format::create_circuit(constraint_system, 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_ = builder_.get_num_gates(); total_circuit_size_ = builder_.get_total_circuit_size(); circuit_subgroup_size_ = builder_.get_circuit_subgroup_size(total_circuit_size_); size_hint_ = circuit_subgroup_size_; + vinfo("gates: ", builder_.get_total_circuit_size()); } -void AcirComposer::init_proving_key( - std::shared_ptr> const& crs_factory, - acir_format::acir_format& constraint_system) +void AcirComposer::init_proving_key(acir_format::acir_format& constraint_system) { - vinfo("building circuit... ", size_hint_); - builder_ = acir_format::Builder(size_hint_); - acir_format::create_circuit(builder_, constraint_system); - - // 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_ = builder_.get_num_gates(); - total_circuit_size_ = builder_.get_total_circuit_size(); - circuit_subgroup_size_ = builder_.get_circuit_subgroup_size(total_circuit_size_); - - composer_ = acir_format::Composer(crs_factory); + create_circuit(constraint_system); + acir_format::Composer composer; vinfo("computing proving key..."); - proving_key_ = composer_.compute_proving_key(builder_); + proving_key_ = composer.compute_proving_key(builder_); } -std::vector AcirComposer::create_proof( - std::shared_ptr> const& crs_factory, - acir_format::acir_format& constraint_system, - acir_format::WitnessVector& witness, - bool is_recursive) +std::vector AcirComposer::create_proof(acir_format::acir_format& constraint_system, + acir_format::WitnessVector& witness, + bool is_recursive) { - // Release prior memory first. - composer_ = acir_format::Composer(/*p_key=*/0, /*v_key=*/0); - - vinfo("building circuit..."); + vinfo("building circuit with witness..."); + builder_ = acir_format::Builder(size_hint_); create_circuit_with_witness(builder_, constraint_system, witness); vinfo("gates: ", builder_.get_total_circuit_size()); - composer_ = [&]() { + auto composer = [&]() { if (proving_key_) { - auto composer = acir_format::Composer(proving_key_, verification_key_); - // You can't produce the verification key unless you manually set the crs. Which seems like a bug. - composer_.crs_factory_ = crs_factory; - return composer; - } else { - return acir_format::Composer(crs_factory); + return acir_format::Composer(proving_key_, nullptr); } - }(); - if (!proving_key_) { + + acir_format::Composer composer; vinfo("computing proving key..."); - proving_key_ = composer_.compute_proving_key(builder_); + proving_key_ = composer.compute_proving_key(builder_); vinfo("done."); - } - - // 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(); + return composer; + }(); vinfo("creating proof..."); std::vector proof; if (is_recursive) { - auto prover = composer_.create_prover(builder_); + auto prover = composer.create_prover(builder_); proof = prover.construct_proof().proof_data; } else { - auto prover = composer_.create_ultra_with_keccak_prover(builder_); + auto prover = composer.create_ultra_with_keccak_prover(builder_); proof = prover.construct_proof().proof_data; } vinfo("done."); @@ -102,8 +74,12 @@ std::vector AcirComposer::create_proof( std::shared_ptr AcirComposer::init_verification_key() { + if (!proving_key_) { + throw_or_abort("Compute proving key first."); + } vinfo("computing verification key..."); - verification_key_ = composer_.compute_verification_key(builder_); + acir_format::Composer composer(proving_key_, nullptr); + verification_key_ = composer.compute_verification_key(builder_); vinfo("done."); return verification_key_; } @@ -116,9 +92,11 @@ void AcirComposer::load_verification_key(proof_system::plonk::verification_key_d bool AcirComposer::verify_proof(std::vector const& proof, bool is_recursive) { + acir_format::Composer composer(proving_key_, verification_key_); + if (!verification_key_) { vinfo("computing verification key..."); - verification_key_ = composer_.compute_verification_key(builder_); + verification_key_ = composer.compute_verification_key(builder_); vinfo("done."); } @@ -126,10 +104,10 @@ bool AcirComposer::verify_proof(std::vector const& proof, bool is_recur builder_.public_inputs.resize((proof.size() - 2144) / 32); if (is_recursive) { - auto verifier = composer_.create_verifier(builder_); + auto verifier = composer.create_verifier(builder_); return verifier.verify_proof({ proof }); } else { - auto verifier = composer_.create_ultra_with_keccak_verifier(builder_); + auto verifier = composer.create_ultra_with_keccak_verifier(builder_); return verifier.verify_proof({ proof }); } } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp index 58696e4ad253..32b678268e38 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp @@ -38,7 +38,6 @@ class AcirComposer { private: acir_format::Builder builder_; - acir_format::Composer composer_; size_t size_hint_; size_t exact_circuit_size_; size_t total_circuit_size_; From c42ddf2eb24f4cb5245df2753fbd2bfdfc36d134 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 10:07:25 +0000 Subject: [PATCH 05/18] Benchmarking acir tests. --- barretenberg/acir_tests/bench_acir_tests.sh | 16 +++ .../acir_tests/flows/prove_and_verify.sh | 2 +- barretenberg/acir_tests/run_acir_tests.sh | 15 ++- barretenberg/cpp/src/barretenberg/bb/main.cpp | 19 ++++ .../cpp/src/barretenberg/common/benchmark.hpp | 105 ++++++++++++++++++ .../cpp/src/barretenberg/common/timer.hpp | 9 ++ .../barretenberg/env/hardware_concurrency.cpp | 11 +- .../plonk/composer/ultra_composer.hpp | 3 - 8 files changed, 170 insertions(+), 10 deletions(-) create mode 100755 barretenberg/acir_tests/bench_acir_tests.sh create mode 100644 barretenberg/cpp/src/barretenberg/common/benchmark.hpp diff --git a/barretenberg/acir_tests/bench_acir_tests.sh b/barretenberg/acir_tests/bench_acir_tests.sh new file mode 100755 index 000000000000..1cd9e8d36e88 --- /dev/null +++ b/barretenberg/acir_tests/bench_acir_tests.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +(BENCHMARK_FD=3 ./run_acir_tests.sh $@ 3>&1 > /dev/null) | jq -r 'select(.name == "proof_construction_time") | [.acir_test, .value] | @tsv' | awk 'BEGIN { + FS="\t"; + print "+--------------------------+-----------+"; + print "| Test | Time (ms) |"; + print "+--------------------------+-----------+"; +} +{ + # Truncate name to 24 characters + name = substr($1, 1, 24); + printf("| %-24s | %9s |\n", name, $2); +} +END { + print "+--------------------------+-----------+"; +}' \ No newline at end of file diff --git a/barretenberg/acir_tests/flows/prove_and_verify.sh b/barretenberg/acir_tests/flows/prove_and_verify.sh index 216c3742a65a..ac78ecc53d7d 100755 --- a/barretenberg/acir_tests/flows/prove_and_verify.sh +++ b/barretenberg/acir_tests/flows/prove_and_verify.sh @@ -4,5 +4,5 @@ set -eu if [ -n "$VERBOSE" ]; then $BIN prove_and_verify -v -c $CRS_PATH -b ./target/acir.gz else - $BIN prove_and_verify -c $CRS_PATH -b ./target/acir.gz > /dev/null 2>&1 + $BIN prove_and_verify -c $CRS_PATH -b ./target/acir.gz fi \ No newline at end of file diff --git a/barretenberg/acir_tests/run_acir_tests.sh b/barretenberg/acir_tests/run_acir_tests.sh index e495580dd971..6121588d3919 100755 --- a/barretenberg/acir_tests/run_acir_tests.sh +++ b/barretenberg/acir_tests/run_acir_tests.sh @@ -9,7 +9,7 @@ FLOW=${FLOW:-prove_and_verify} CRS_PATH=~/.bb-crs BRANCH=master VERBOSE=${VERBOSE:-} -NAMED_TEST=${1:-} +TEST_NAMES=("$@") FLOW_SCRIPT=$(realpath ./flows/${FLOW}.sh) @@ -47,12 +47,15 @@ function test() { cd $1 set +e + start=$(date +%s%3N) $FLOW_SCRIPT result=$? + end=$(date +%s%3N) + duration=$((end - start)) set -eu if [ $result -eq 0 ]; then - echo -e "\033[32mPASSED\033[0m" + echo -e "\033[32mPASSED\033[0m ($duration ms)" else echo -e "\033[31mFAILED\033[0m" exit 1 @@ -61,9 +64,11 @@ function test() { cd .. } -if [ -n "$NAMED_TEST" ]; then - echo -n "Testing $NAMED_TEST... " - test $NAMED_TEST +if [ "${#TEST_NAMES[@]}" -ne 0 ]; then + for NAMED_TEST in "${TEST_NAMES[@]}"; do + echo -n "Testing $NAMED_TEST... " + test $NAMED_TEST + done else for TEST_NAME in $(find -maxdepth 1 -type d -not -path '.' | sed 's|^\./||'); do echo -n "Testing $TEST_NAME... " diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 8657385bfdde..795f1137f476 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -1,9 +1,13 @@ +#include "barretenberg/dsl/acir_format/acir_format.hpp" +#include "barretenberg/dsl/types.hpp" #include "config.hpp" #include "get_bytecode.hpp" #include "get_crs.hpp" #include "get_witness.hpp" #include "log.hpp" +#include #include +#include #include #include #include @@ -15,6 +19,10 @@ using namespace barretenberg; std::string CRS_PATH = "./crs"; bool verbose = false; +bool benchmark = false; + +const std::filesystem::path current_path = std::filesystem::current_path(); +const auto current_dir = current_path.filename().string(); acir_proofs::AcirComposer init(acir_format::acir_format& constraint_system) { @@ -69,7 +77,18 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP auto witness = get_witness(witnessPath); auto acir_composer = init(constraint_system); + Timer pk_timer; + acir_composer.init_proving_key(constraint_system); + write_benchmark("pk_construction_time", pk_timer.milliseconds(), "acir_test", current_dir); + + Timer proof_timer; auto proof = acir_composer.create_proof(constraint_system, witness, recursive); + write_benchmark("proof_construction_time", proof_timer.milliseconds(), "acir_test", current_dir); + + Timer vk_timer; + acir_composer.init_verification_key(); + write_benchmark("vk_construction_time", vk_timer.milliseconds(), "acir_test", current_dir); + auto verified = acir_composer.verify_proof(proof, recursive); vinfo("verified: ", verified); diff --git a/barretenberg/cpp/src/barretenberg/common/benchmark.hpp b/barretenberg/cpp/src/barretenberg/common/benchmark.hpp new file mode 100644 index 000000000000..5d3034bbe6fd --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/common/benchmark.hpp @@ -0,0 +1,105 @@ +#include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/env/hardware_concurrency.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace { +/** + * If user provides the env var BENCHMARK_FD write benchmarks to this fd, otherwise default to -1 (disable). + * e.g: + * BENCHMARK_FD=3 bb 3> benchmarks.jsonl + */ +auto bfd = []() { + try { + static auto bfd_str = std::getenv("BENCHMARK_FD"); + int bfd = bfd_str ? (int)std::stoul(bfd_str) : -1; + if (bfd >= 0 && (fcntl(bfd, F_GETFD) == -1 || errno == EBADF)) { + throw_or_abort("fd is not open. Did you redirect in your shell?"); + } + return bfd; + } catch (std::exception const& e) { + std::string inner_msg = e.what(); + throw_or_abort("Invalid BENCHMARK_FD: " + inner_msg); + } +}(); +} // namespace + +template struct TypeTraits; + +template struct TypeTraits::value>::type> { + static const char* type; +}; + +template +const char* TypeTraits::value>::type>::type = "number"; + +template <> struct TypeTraits { + static const char* type; +}; + +const char* TypeTraits::type = "string"; + +template <> struct TypeTraits { + static const char* type; +}; + +const char* TypeTraits::type = "number"; + +template <> struct TypeTraits { + static const char* type; +}; + +const char* TypeTraits::type = "bool"; + +// Helper function to get the current timestamp in the desired format +std::string getCurrentTimestamp() +{ + std::time_t now = std::time(nullptr); + std::tm* now_tm = std::gmtime(&now); + char buf[21] = { 0 }; + strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", now_tm); + return std::string(buf); +} + +template std::string toString(const T& value) +{ + std::ostringstream oss; + oss << value; + return oss.str(); +} + +void appendToStream(std::ostringstream&) +{ + // base case: do nothing +} + +template +void appendToStream(std::ostringstream& oss, const K& key, const V& value, Args... args) +{ + oss << ", \"" << key << "\": \"" << toString(value) << "\""; + appendToStream(oss, args...); // recursively process the remaining arguments +} + +template void write_benchmark(const std::string& name, const T& value, Args... args) +{ + if (bfd == -1) { + return; + } + std::ostringstream oss; + oss << "{\"timestamp\": \"" << getCurrentTimestamp() << "\", " + << "\"name\": \"" << name << "\", " + << "\"type\": \"" << TypeTraits::type << "\", " + << "\"value\": " << value << ", " + << "\"threads\": " << env_hardware_concurrency(); + + appendToStream(oss, args...); // unpack and append the key-value pairs + + oss << "}" << std::endl; + const std::string& tmp = oss.str(); + write((int)bfd, tmp.c_str(), tmp.size()); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/timer.hpp b/barretenberg/cpp/src/barretenberg/common/timer.hpp index b291b3f213e4..b4d760e4393d 100644 --- a/barretenberg/cpp/src/barretenberg/common/timer.hpp +++ b/barretenberg/cpp/src/barretenberg/common/timer.hpp @@ -55,6 +55,15 @@ class Timer { return nanos; } + /** + * @brief Return the number of nanoseconds elapsed since the start of the timer. + */ + [[nodiscard]] int64_t milliseconds() const + { + int64_t nanos = nanoseconds(); + return nanos / 1000000; + } + /** * @brief Return the number of seconds elapsed since the start of the timer. */ diff --git a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp index 82df4687674b..e0023acf925f 100644 --- a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp +++ b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp @@ -1,10 +1,19 @@ #include "hardware_concurrency.hpp" +#include +#include +#include #include extern "C" { uint32_t env_hardware_concurrency() { - return std::thread::hardware_concurrency(); + try { + static auto val = std::getenv("HARDWARE_CONCURRENCY"); + static const uint32_t cores = val ? (uint32_t)std::stoul(val) : std::thread::hardware_concurrency(); + return cores; + } catch (std::exception const&) { + throw std::runtime_error("HARDWARE_CONCURRENCY invalid."); + } } } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp index e539db4c47b9..5dd90ca3492a 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp @@ -26,8 +26,6 @@ class UltraComposer { std::shared_ptr circuit_proving_key; std::shared_ptr circuit_verification_key; - // The crs_factory holds the path to the srs and exposes methods to extract the srs elements - bool computed_witness = false; // This variable controls the amount with which the lookup table and witness values need to be shifted @@ -38,7 +36,6 @@ class UltraComposer { UltraComposer() = default; - UltraComposer(std::shared_ptr p_key, std::shared_ptr v_key) : circuit_proving_key(std::move(p_key)) , circuit_verification_key(std::move(v_key)) From 66ea7af37318ff7b7e1a705a614f656dc1d51fcb Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 19:08:06 +0000 Subject: [PATCH 06/18] Builds. --- .../dsl/acir_proofs/acir_composer.cpp | 20 ++-- .../cpp/src/barretenberg/examples/c_bind.cpp | 2 +- .../barretenberg/examples/simple/simple.hpp | 3 +- .../examples/simple/simple.test.cpp | 4 +- .../proofs/compute_circuit_data.hpp | 4 +- .../proofs/join_split/c_bind.cpp | 98 ------------------- .../proofs/join_split/c_bind.h | 3 - .../proofs/join_split/join_split.cpp | 13 +-- .../proofs/join_split/join_split.hpp | 5 +- .../proofs/join_split/join_split.test.cpp | 5 +- .../join_split/join_split_js_parity.test.cpp | 8 +- 11 files changed, 25 insertions(+), 140 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.h diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index 07a3578b0d13..5019324e2986 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -31,9 +31,7 @@ void AcirComposer::create_circuit(acir_format::acir_format& constraint_system) size_hint_ = circuit_subgroup_size_; } -void AcirComposer::init_proving_key( - std::shared_ptr> const& crs_factory, - acir_format::acir_format& constraint_system) +void AcirComposer::init_proving_key(acir_format::acir_format& constraint_system) { vinfo("building circuit... ", size_hint_); builder_ = acir_format::Builder(size_hint_); @@ -47,16 +45,14 @@ void AcirComposer::init_proving_key( total_circuit_size_ = builder_.get_total_circuit_size(); circuit_subgroup_size_ = builder_.get_circuit_subgroup_size(total_circuit_size_); - composer_ = acir_format::Composer(crs_factory); + composer_ = acir_format::Composer(); vinfo("computing proving key..."); proving_key_ = composer_.compute_proving_key(builder_); } -std::vector AcirComposer::create_proof( - std::shared_ptr> const& crs_factory, - acir_format::acir_format& constraint_system, - acir_format::WitnessVector& witness, - bool is_recursive) +std::vector AcirComposer::create_proof(acir_format::acir_format& constraint_system, + acir_format::WitnessVector& witness, + bool is_recursive) { // Release prior memory first. composer_ = acir_format::Composer(/*p_key=*/0, /*v_key=*/0); @@ -67,12 +63,10 @@ std::vector AcirComposer::create_proof( composer_ = [&]() { if (proving_key_) { - auto composer = acir_format::Composer(proving_key_, verification_key_); - // You can't produce the verification key unless you manually set the crs. Which seems like a bug. - composer_.crs_factory_ = crs_factory; + auto composer = acir_format::Composer(proving_key_, nullptr); return composer; } else { - return acir_format::Composer(crs_factory); + return acir_format::Composer(); } }(); if (!proving_key_) { diff --git a/barretenberg/cpp/src/barretenberg/examples/c_bind.cpp b/barretenberg/cpp/src/barretenberg/examples/c_bind.cpp index 23129857262c..53f373658feb 100644 --- a/barretenberg/cpp/src/barretenberg/examples/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/examples/c_bind.cpp @@ -6,7 +6,7 @@ using namespace proof_system::plonk::stdlib::types; WASM_EXPORT void examples_simple_create_and_verify_proof(bool* valid) { - auto ptrs = examples::simple::create_builder_and_composer(barretenberg::srs::get_crs_factory()); + auto ptrs = examples::simple::create_builder_and_composer(); auto proof = examples::simple::create_proof(ptrs); *valid = examples::simple::verify_proof(ptrs, proof); examples::simple::delete_builder_and_composer(ptrs); diff --git a/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp b/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp index 0932708bf216..264d328d2d20 100644 --- a/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp +++ b/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp @@ -12,8 +12,7 @@ struct BuilderComposerPtrs { Composer* composer; }; -BuilderComposerPtrs create_builder_and_composer( - std::shared_ptr> const& crs_factory); +BuilderComposerPtrs create_builder_and_composer(); proof create_proof(BuilderComposerPtrs pair); diff --git a/barretenberg/cpp/src/barretenberg/examples/simple/simple.test.cpp b/barretenberg/cpp/src/barretenberg/examples/simple/simple.test.cpp index a43c3de45033..17689497a750 100644 --- a/barretenberg/cpp/src/barretenberg/examples/simple/simple.test.cpp +++ b/barretenberg/cpp/src/barretenberg/examples/simple/simple.test.cpp @@ -8,8 +8,8 @@ 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 ptrs = create_builder_and_composer(crs_factory); + srs::init_crs_factory(srs_path); + auto ptrs = create_builder_and_composer(); auto proof = create_proof(ptrs); bool valid = verify_proof(ptrs, proof); delete_builder_and_composer(ptrs); diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp index 40f39d24e4e9..cdf0dbeb1712 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/compute_circuit_data.hpp @@ -56,9 +56,9 @@ circuit_data get_circuit_data(std::string const& name, circuit_data data; data.srs = srs; data.mock = mock; - Composer composer(srs); + Composer composer; Builder builder; - Composer mock_proof_composer(srs); + Composer mock_proof_composer; Builder mock_builder; BenchmarkInfoCollator benchmark_collator; diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp deleted file mode 100644 index fcddcbfdb942..000000000000 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include - -#include "../mock/mock_circuit.hpp" -#include "barretenberg/common/container.hpp" -#include "barretenberg/common/mem.hpp" -#include "barretenberg/common/streams.hpp" -#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" -#include "barretenberg/join_split_example/types.hpp" -#include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" -#include "barretenberg/srs/global_crs.hpp" -#include "c_bind.h" -#include "compute_signing_data.hpp" -#include "join_split.hpp" - -using namespace barretenberg; -using namespace join_split_example::proofs::join_split; - -WASM_EXPORT void join_split__init_proving_key(bool 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; -// plonk::proving_key_data pk_data; -// read(pk_buf, pk_data); -// init_proving_key(crs, std::move(pk_data)); -// } - -WASM_EXPORT void join_split__release_key() -{ - release_proving_key(); -} - -WASM_EXPORT uint32_t join_split__get_new_proving_key_data(uint8_t** output) -{ - // Computing the size of the serialized key is non trivial. We know it's ~331mb. - // Allocate a buffer large enough to hold it, and abort if we overflow. - // This is to keep memory usage down. - - auto proving_key = get_proving_key(); - auto buffer = to_buffer(*proving_key); - auto raw_buf = (uint8_t*)malloc(buffer.size()); - memcpy(raw_buf, (void*)buffer.data(), buffer.size()); - *output = raw_buf; - - return static_cast(buffer.size()); -} - -WASM_EXPORT void join_split__init_verification_key(void* /*unused*/, uint8_t const* /*unused*/) -{ - 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) -// { -// auto crs = std::make_shared(g2x); -// plonk::verification_key_data vk_data; -// read(vk_buf, vk_data); -// init_verification_key(crs, std::move(vk_data)); -// } - -WASM_EXPORT uint32_t join_split__get_new_verification_key_data(uint8_t** output) -{ - auto buffer = to_buffer(*get_verification_key()); - auto raw_buf = (uint8_t*)malloc(buffer.size()); - memcpy(raw_buf, (void*)buffer.data(), buffer.size()); - *output = raw_buf; - return static_cast(buffer.size()); -} - -WASM_EXPORT void join_split__compute_signing_data(uint8_t const* join_split_tx_buf, uint8_t* output) -{ - auto tx = from_buffer(join_split_tx_buf); - auto signing_data = compute_signing_data(tx); - barretenberg::fr::serialize_to_buffer(signing_data, output); -} - -WASM_EXPORT void* join_split__new_prover(uint8_t const* join_split_buf, bool mock) -{ - auto tx = from_buffer(join_split_buf); - auto prover = new_join_split_prover(tx, mock); - auto heapProver = new join_split_example::Prover(std::move(prover)); - return heapProver; -} - -WASM_EXPORT void join_split__delete_prover(void* prover) -{ - delete reinterpret_cast(prover); -} - -WASM_EXPORT bool join_split__verify_proof(uint8_t* proof, uint32_t length) -{ - plonk::proof pp = { std::vector(proof, proof + length) }; - return verify_proof(pp); -} diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.h b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.h deleted file mode 100644 index cd7390b1dad1..000000000000 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/c_bind.h +++ /dev/null @@ -1,3 +0,0 @@ -#include - -WASM_EXPORT uint32_t join_split__get_new_proving_key_data(uint8_t** output); diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp index 1da1caee45fe..c4c52a1be381 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.cpp @@ -14,8 +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(bool mock) { if (proving_key) { return; @@ -27,12 +26,12 @@ void init_proving_key(std::shared_ptr> const& crs_factory) +void init_verification_key() { if (!proving_key) { std::abort(); } - // Patch the 'nothing' reference string fed to init_proving_key. - proving_key->reference_string = crs_factory->get_prover_crs(proving_key->circuit_size + 1); verification_key = - proof_system::plonk::compute_verification_key_common(proving_key, crs_factory->get_verifier_crs()); + proof_system::plonk::compute_verification_key_common(proving_key, srs::get_crs_factory()->get_verifier_crs()); } Prover new_join_split_prover(join_split_tx const& tx, bool mock) diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp index 1d4a1dd5fa7a..a436d99f884a 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.hpp @@ -7,12 +7,11 @@ 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(bool mock); void release_proving_key(); -void init_verification_key(std::shared_ptr> const& crs_factory); +void init_verification_key(); Prover new_join_split_prover(join_split_tx const& tx, bool mock); diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp index 8b86c4d1641a..ef41bcfbf674 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp @@ -44,11 +44,10 @@ class join_split_tests : public ::testing::Test { static void SetUpTestCase() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); - auto null_crs_factory = std::make_shared>(); - init_proving_key(null_crs_factory, false); + init_proving_key(false); auto crs_factory = std::make_unique>("../srs_db/ignition"); - init_verification_key(std::move(crs_factory)); + init_verification_key(); info("vk hash: ", get_verification_key()->sha256_hash()); } diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp index f23bceef85f2..ba601d934474 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split_js_parity.test.cpp @@ -25,11 +25,9 @@ class join_split_js_parity_tests : public ::testing::Test { protected: static void SetUpTestCase() { - auto null_crs_factory = std::make_shared>(); - init_proving_key(null_crs_factory, false); - auto crs_factory = - std::make_unique>("../srs_db/ignition"); - init_verification_key(std::move(crs_factory)); + srs::init_crs_factory("../srs_db/ignition"); + init_proving_key(false); + init_verification_key(); info("vk hash: ", get_verification_key()->sha256_hash()); } From 9f0987dc9a7ad69c9637d1ca491216c956e0ddb4 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 19:15:33 +0000 Subject: [PATCH 07/18] Formatting. --- .../cpp/src/barretenberg/plonk/composer/ultra_composer.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp index e539db4c47b9..0d365a6c0c4c 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp @@ -38,7 +38,6 @@ class UltraComposer { UltraComposer() = default; - UltraComposer(std::shared_ptr p_key, std::shared_ptr v_key) : circuit_proving_key(std::move(p_key)) , circuit_verification_key(std::move(v_key)) From 91ed471db2af7ffdff7fa336495c7329145d7e5e Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 19:48:30 +0000 Subject: [PATCH 08/18] Fix oopsie. --- .../cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index 5019324e2986..da774efecd32 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -106,6 +106,7 @@ void AcirComposer::load_verification_key(proof_system::plonk::verification_key_d { verification_key_ = std::make_shared( std::move(data), srs::get_crs_factory()->get_verifier_crs()); + composer_ = acir_format::Composer(proving_key_, verification_key_); } bool AcirComposer::verify_proof(std::vector const& proof, bool is_recursive) From ff25df277cd542c71a59d9e65339c0ea197c4442 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 20:10:10 +0000 Subject: [PATCH 09/18] use init --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 8657385bfdde..169dc6a10f49 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -143,9 +143,7 @@ void gateCount(const std::string& bytecodePath) */ bool verify(const std::string& proof_path, bool recursive, const std::string& vk_path) { - auto g2_data = get_g2_data(CRS_PATH); - srs::init_crs_factory({}, g2_data); - acir_proofs::AcirComposer acir_composer(1, verbose); + auto acir_composer = init(); auto vk_data = from_buffer(read_file(vk_path)); acir_composer.load_verification_key(std::move(vk_data)); auto verified = acir_composer.verify_proof(read_file(proof_path), recursive); From 68426899f040a3069bd75b2860da70d1590d6a35 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 20:15:14 +0000 Subject: [PATCH 10/18] Fix. --- .../cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index da774efecd32..8ed136b7b6e8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -58,6 +58,7 @@ std::vector AcirComposer::create_proof(acir_format::acir_format& constr composer_ = acir_format::Composer(/*p_key=*/0, /*v_key=*/0); vinfo("building circuit..."); + builder_ = acir_format::Builder(size_hint_); create_circuit_with_witness(builder_, constraint_system, witness); vinfo("gates: ", builder_.get_total_circuit_size()); From 99a13b4750b37926f7e3955e9ff6feb84ee3db8b Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 22:11:02 +0000 Subject: [PATCH 11/18] Benchmarks. --- barretenberg/README.md | 36 +++++++++++++++++++ barretenberg/acir_tests/bench_acir_tests.sh | 30 ++++++++++++---- barretenberg/cpp/src/barretenberg/bb/main.cpp | 1 - 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/barretenberg/README.md b/barretenberg/README.md index a6487a68e6d2..ebce0d6de68d 100644 --- a/barretenberg/README.md +++ b/barretenberg/README.md @@ -7,6 +7,42 @@ As the spec solidifies, this should be less of an issue. Aztec and Barretenberg **This code is highly experimental, use at your own risk!** +### Benchmarks! + +Time includes building of circuit and proof construction. Ignores proving key construction. + +``` ++--------------------------+---------+-----------+ +| Test | Threads | Time (ms) | ++--------------------------+---------+-----------+ +| sha256 | 1 | 5876 | +| sha256 | 4 | 1686 | +| sha256 | 16 | 626 | +| sha256 | 32 | 493 | +| sha256 | 64 | 398 | +| ecdsa_secp256k1 | 1 | 7355 | +| ecdsa_secp256k1 | 4 | 2279 | +| ecdsa_secp256k1 | 16 | 913 | +| ecdsa_secp256k1 | 32 | 704 | +| ecdsa_secp256k1 | 64 | 597 | +| ecdsa_secp256r1 | 1 | 12109 | +| ecdsa_secp256r1 | 4 | 3913 | +| ecdsa_secp256r1 | 16 | 1630 | +| ecdsa_secp256r1 | 32 | 1398 | +| ecdsa_secp256r1 | 64 | 1167 | +| schnorr | 1 | 6003 | +| schnorr | 4 | 1703 | +| schnorr | 16 | 600 | +| schnorr | 32 | 528 | +| schnorr | 64 | 410 | +| double_verify_proof | 1 | 47509 | +| double_verify_proof | 4 | 17473 | +| double_verify_proof | 16 | 7956 | +| double_verify_proof | 32 | 6741 | +| double_verify_proof | 64 | 6168 | ++--------------------------+---------+-----------+ +``` + ### Dependencies - cmake >= 3.24 diff --git a/barretenberg/acir_tests/bench_acir_tests.sh b/barretenberg/acir_tests/bench_acir_tests.sh index 1cd9e8d36e88..0a1258d53401 100755 --- a/barretenberg/acir_tests/bench_acir_tests.sh +++ b/barretenberg/acir_tests/bench_acir_tests.sh @@ -1,16 +1,32 @@ #!/bin/bash -(BENCHMARK_FD=3 ./run_acir_tests.sh $@ 3>&1 > /dev/null) | jq -r 'select(.name == "proof_construction_time") | [.acir_test, .value] | @tsv' | awk 'BEGIN { +TEST_NAMES=("$@") +THREADS=(1 4 16 32 64) +BENCHMARKS=$(mktemp) + +if [ "${#TEST_NAMES[@]}" -eq 0 ]; then + TEST_NAMES=(sha256 ecdsa_secp256k1 ecdsa_secp256r1 schnorr double_verify_proof) +fi + +for TEST in ${TEST_NAMES[@]}; do + for HC in ${THREADS[@]}; do + HARDWARE_CONCURRENCY=$HC BENCHMARK_FD=3 ./run_acir_tests.sh $TEST 3>>$BENCHMARKS + done +done + +cat $BENCHMARKS | jq -r 'select(.name == "proof_construction_time") | [.acir_test, .threads, .value] | @tsv' | awk 'BEGIN { FS="\t"; - print "+--------------------------+-----------+"; - print "| Test | Time (ms) |"; - print "+--------------------------+-----------+"; + print "+--------------------------+---------+-----------+"; + print "| Test | Threads | Time (ms) |"; + print "+--------------------------+---------+-----------+"; } { # Truncate name to 24 characters name = substr($1, 1, 24); - printf("| %-24s | %9s |\n", name, $2); + printf("| %-24s | %7s | %9s |\n", name, $2, $3); } END { - print "+--------------------------+-----------+"; -}' \ No newline at end of file + print "+--------------------------+---------+-----------+"; +}' + +rm $BENCHMARKS \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 4c88a095bdeb..2221ab206e97 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -19,7 +19,6 @@ using namespace barretenberg; std::string CRS_PATH = "./crs"; bool verbose = false; -bool benchmark = false; const std::filesystem::path current_path = std::filesystem::current_path(); const auto current_dir = current_path.filename().string(); From 4f3db63dfc70f1a01d1446d3c18a764c078077b2 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 10 Oct 2023 22:30:25 +0000 Subject: [PATCH 12/18] Use throw_or_abort. --- barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp index e0023acf925f..60ca711b808a 100644 --- a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp +++ b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp @@ -1,4 +1,5 @@ #include "hardware_concurrency.hpp" +#include #include #include #include @@ -13,7 +14,7 @@ uint32_t env_hardware_concurrency() static const uint32_t cores = val ? (uint32_t)std::stoul(val) : std::thread::hardware_concurrency(); return cores; } catch (std::exception const&) { - throw std::runtime_error("HARDWARE_CONCURRENCY invalid."); + throw_or_abort("HARDWARE_CONCURRENCY invalid."); } } } \ No newline at end of file From e2f08f759e044464bdfa79b347f8bd11c33c4115 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Wed, 11 Oct 2023 07:42:43 +0000 Subject: [PATCH 13/18] Fix. --- .../cpp/src/barretenberg/env/hardware_concurrency.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp index 60ca711b808a..43aac0e9e8b8 100644 --- a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp +++ b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp @@ -9,12 +9,16 @@ extern "C" { uint32_t env_hardware_concurrency() { +#ifdef __wasm__ try { +#endif static auto val = std::getenv("HARDWARE_CONCURRENCY"); static const uint32_t cores = val ? (uint32_t)std::stoul(val) : std::thread::hardware_concurrency(); return cores; +#ifdef __wasm__ } catch (std::exception const&) { - throw_or_abort("HARDWARE_CONCURRENCY invalid."); + throw std::runtime_error("HARDWARE_CONCURRENCY invalid."); } +#endif } } \ No newline at end of file From 7e5dc9fbf394b5413f275a527f435f83177e31e0 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Wed, 11 Oct 2023 07:44:15 +0000 Subject: [PATCH 14/18] Build wasms independently or failures are confusing. --- barretenberg/cpp/dockerfiles/Dockerfile.wasm-linux-clang | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/dockerfiles/Dockerfile.wasm-linux-clang b/barretenberg/cpp/dockerfiles/Dockerfile.wasm-linux-clang index 8be67fce55d4..bdcd6d3edc77 100644 --- a/barretenberg/cpp/dockerfiles/Dockerfile.wasm-linux-clang +++ b/barretenberg/cpp/dockerfiles/Dockerfile.wasm-linux-clang @@ -4,11 +4,8 @@ WORKDIR /usr/src/barretenberg/cpp COPY ./scripts/install-wasi-sdk.sh ./scripts/install-wasi-sdk.sh RUN ./scripts/install-wasi-sdk.sh COPY . . -# Building both wasm's in parallel reduces build from 120s to 80s. -RUN (cmake --preset wasm && cmake --build --preset wasm) & \ - (cmake --preset wasm-threads && cmake --build --preset wasm-threads) & \ - wait - +RUN cmake --preset wasm && cmake --build --preset wasm +RUN cmake --preset wasm-threads && cmake --build --preset wasm-threads FROM scratch WORKDIR /usr/src/barretenberg/cpp From 204652932c3cced2c3fae0e42ad9740a7723a608 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Wed, 11 Oct 2023 07:54:40 +0000 Subject: [PATCH 15/18] Fix. --- .../cpp/src/barretenberg/env/hardware_concurrency.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp index 43aac0e9e8b8..3aedfcbd83c9 100644 --- a/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp +++ b/barretenberg/cpp/src/barretenberg/env/hardware_concurrency.cpp @@ -9,13 +9,13 @@ extern "C" { uint32_t env_hardware_concurrency() { -#ifdef __wasm__ +#ifndef __wasm__ try { #endif static auto val = std::getenv("HARDWARE_CONCURRENCY"); static const uint32_t cores = val ? (uint32_t)std::stoul(val) : std::thread::hardware_concurrency(); return cores; -#ifdef __wasm__ +#ifndef __wasm__ } catch (std::exception const&) { throw std::runtime_error("HARDWARE_CONCURRENCY invalid."); } From 547d27c847dabda06566370e4d4d28d4ac31d4ed Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Wed, 11 Oct 2023 09:32:31 +0000 Subject: [PATCH 16/18] Nice formatting. --- barretenberg/README.md | 45 ++++++------------ barretenberg/acir_tests/bench_acir_tests.sh | 51 +++++++++++++++++---- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/barretenberg/README.md b/barretenberg/README.md index ebce0d6de68d..687d312021cd 100644 --- a/barretenberg/README.md +++ b/barretenberg/README.md @@ -9,38 +9,19 @@ As the spec solidifies, this should be less of an issue. Aztec and Barretenberg ### Benchmarks! -Time includes building of circuit and proof construction. Ignores proving key construction. - -``` -+--------------------------+---------+-----------+ -| Test | Threads | Time (ms) | -+--------------------------+---------+-----------+ -| sha256 | 1 | 5876 | -| sha256 | 4 | 1686 | -| sha256 | 16 | 626 | -| sha256 | 32 | 493 | -| sha256 | 64 | 398 | -| ecdsa_secp256k1 | 1 | 7355 | -| ecdsa_secp256k1 | 4 | 2279 | -| ecdsa_secp256k1 | 16 | 913 | -| ecdsa_secp256k1 | 32 | 704 | -| ecdsa_secp256k1 | 64 | 597 | -| ecdsa_secp256r1 | 1 | 12109 | -| ecdsa_secp256r1 | 4 | 3913 | -| ecdsa_secp256r1 | 16 | 1630 | -| ecdsa_secp256r1 | 32 | 1398 | -| ecdsa_secp256r1 | 64 | 1167 | -| schnorr | 1 | 6003 | -| schnorr | 4 | 1703 | -| schnorr | 16 | 600 | -| schnorr | 32 | 528 | -| schnorr | 64 | 410 | -| double_verify_proof | 1 | 47509 | -| double_verify_proof | 4 | 17473 | -| double_verify_proof | 16 | 7956 | -| double_verify_proof | 32 | 6741 | -| double_verify_proof | 64 | 6168 | -+--------------------------+---------+-----------+ +Table represents time to build circuit and proof for each test on n threads. +Ignores proving key construction. + +``` ++--------------------------+-----------+-----------+-----------+-----------+-----------+ +| Test | 1 | 4 | 16 | 32 | 64 | ++--------------------------+-----------+-----------+-----------+-----------+-----------+ +| sha256 | 5869 | 1668 | 750 | 491 | 366 | +| ecdsa_secp256k1 | 5968 | 1872 | 940 | 669 | 602 | +| ecdsa_secp256r1 | 12017 | 3688 | 1651 | 1350 | 1126 | +| schnorr | 6006 | 1674 | 689 | 502 | 423 | +| double_verify_proof | 47137 | 16044 | 7907 | 6934 | 6043 | ++--------------------------+-----------+-----------+-----------+-----------+-----------+ ``` ### Dependencies diff --git a/barretenberg/acir_tests/bench_acir_tests.sh b/barretenberg/acir_tests/bench_acir_tests.sh index 0a1258d53401..b0eaa240e6ab 100755 --- a/barretenberg/acir_tests/bench_acir_tests.sh +++ b/barretenberg/acir_tests/bench_acir_tests.sh @@ -14,19 +14,50 @@ for TEST in ${TEST_NAMES[@]}; do done done -cat $BENCHMARKS | jq -r 'select(.name == "proof_construction_time") | [.acir_test, .threads, .value] | @tsv' | awk 'BEGIN { - FS="\t"; - print "+--------------------------+---------+-----------+"; - print "| Test | Threads | Time (ms) |"; - print "+--------------------------+---------+-----------+"; +# Build results into string with \n delimited rows and space delimited values. +TABLE_DATA="" +for TEST in ${TEST_NAMES[@]}; do + TABLE_DATA+="$TEST" + for HC in "${THREADS[@]}"; do + RESULT=$(cat $BENCHMARKS | jq -r --arg test "$TEST" --argjson hc $HC 'select(.name == "proof_construction_time" and .acir_test == $test and .threads == $hc) | .value') + TABLE_DATA+=" $RESULT" + done + TABLE_DATA+=$'\n' +done + +# Trim the trailing newline. +TABLE_DATA="${TABLE_DATA%$'\n'}" + +echo +echo Table represents time to build circuit and proof for each test on n threads. +echo Ignores proving key construction. +echo +# Use awk to print the table +echo -e "$TABLE_DATA" | awk -v threads="${THREADS[*]}" 'BEGIN { + split(threads, t, " "); + len_threads = length(t); + print "+--------------------------+" genseparator(len_threads); + print "| Test |" genthreadheaders(t, len_threads); + print "+--------------------------+" genseparator(len_threads); } { - # Truncate name to 24 characters - name = substr($1, 1, 24); - printf("| %-24s | %7s | %9s |\n", name, $2, $3); + printf("| %-24s |", $1); + for (i = 2; i <= len_threads+1; i++) { + printf " %9s |", $(i); + } + print ""; } END { - print "+--------------------------+---------+-----------+"; -}' + print "+--------------------------+" genseparator(len_threads); +} +function genseparator(len, res) { + for (i = 1; i <= len; i++) res = res "-----------+"; + return res; +} +function genthreadheaders(t, len, res) { + for (i = 1; i <= len; i++) res = res sprintf(" %9s |", t[i]); + return res; +} +' rm $BENCHMARKS \ No newline at end of file From 1b7420ee1f28c6ea0ce24348f8fa8f2c59aaa116 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Wed, 11 Oct 2023 09:35:36 +0000 Subject: [PATCH 17/18] Units. --- barretenberg/README.md | 2 +- barretenberg/acir_tests/bench_acir_tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/README.md b/barretenberg/README.md index 687d312021cd..206b797f6457 100644 --- a/barretenberg/README.md +++ b/barretenberg/README.md @@ -9,7 +9,7 @@ As the spec solidifies, this should be less of an issue. Aztec and Barretenberg ### Benchmarks! -Table represents time to build circuit and proof for each test on n threads. +Table represents time in ms to build circuit and proof for each test on n threads. Ignores proving key construction. ``` diff --git a/barretenberg/acir_tests/bench_acir_tests.sh b/barretenberg/acir_tests/bench_acir_tests.sh index b0eaa240e6ab..07fab9ab898b 100755 --- a/barretenberg/acir_tests/bench_acir_tests.sh +++ b/barretenberg/acir_tests/bench_acir_tests.sh @@ -29,7 +29,7 @@ done TABLE_DATA="${TABLE_DATA%$'\n'}" echo -echo Table represents time to build circuit and proof for each test on n threads. +echo Table represents time in ms to build circuit and proof for each test on n threads. echo Ignores proving key construction. echo # Use awk to print the table From aa0ace2c2aa790bdca12c266eb318a483a453661 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Thu, 19 Oct 2023 13:59:59 +0000 Subject: [PATCH 18/18] Add wasm benchmarks. --- barretenberg/README.md | 34 +++++++++++---- barretenberg/acir_tests/bench_acir_tests.sh | 18 ++++---- barretenberg/cpp/src/barretenberg/bb/main.cpp | 2 + barretenberg/ts/README.md | 23 +++++++---- barretenberg/ts/src/benchmark/index.ts | 26 ++++++++++++ barretenberg/ts/src/benchmark/timer.ts | 41 +++++++++++++++++++ barretenberg/ts/src/main.ts | 22 ++++++++-- 7 files changed, 138 insertions(+), 28 deletions(-) create mode 100644 barretenberg/ts/src/benchmark/index.ts create mode 100644 barretenberg/ts/src/benchmark/timer.ts diff --git a/barretenberg/README.md b/barretenberg/README.md index 206b797f6457..c8a3d1fab03d 100644 --- a/barretenberg/README.md +++ b/barretenberg/README.md @@ -12,16 +12,32 @@ As the spec solidifies, this should be less of an issue. Aztec and Barretenberg Table represents time in ms to build circuit and proof for each test on n threads. Ignores proving key construction. +#### x86_64 + +``` ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +| Test | Gate Count | Subgroup Size | 1 | 4 | 16 | 32 | 64 | ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +| sha256 | 38799 | 65536 | 5947 | 1653 | 729 | 476 | 388 | +| ecdsa_secp256k1 | 41049 | 65536 | 6005 | 2060 | 963 | 693 | 583 | +| ecdsa_secp256r1 | 67331 | 131072 | 12186 | 3807 | 1612 | 1351 | 1137 | +| schnorr | 33740 | 65536 | 5817 | 1696 | 688 | 532 | 432 | +| double_verify_proof | 505513 | 524288 | 47841 | 15824 | 7970 | 6784 | 6082 | ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +``` + +#### WASM + ``` -+--------------------------+-----------+-----------+-----------+-----------+-----------+ -| Test | 1 | 4 | 16 | 32 | 64 | -+--------------------------+-----------+-----------+-----------+-----------+-----------+ -| sha256 | 5869 | 1668 | 750 | 491 | 366 | -| ecdsa_secp256k1 | 5968 | 1872 | 940 | 669 | 602 | -| ecdsa_secp256r1 | 12017 | 3688 | 1651 | 1350 | 1126 | -| schnorr | 6006 | 1674 | 689 | 502 | 423 | -| double_verify_proof | 47137 | 16044 | 7907 | 6934 | 6043 | -+--------------------------+-----------+-----------+-----------+-----------+-----------+ ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +| Test | Gate Count | Subgroup Size | 1 | 4 | 16 | 32 | 64 | ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +| sha256 | 38799 | 65536 | 18764 | 5116 | 1854 | 1524 | 1635 | +| ecdsa_secp256k1 | 41049 | 65536 | 19129 | 5595 | 2255 | 2097 | 2166 | +| ecdsa_secp256r1 | 67331 | 131072 | 38815 | 11257 | 4744 | 3633 | 3702 | +| schnorr | 33740 | 65536 | 18649 | 5244 | 2019 | 1498 | 1702 | +| double_verify_proof | 505513 | 524288 | 149652 | 45702 | 20811 | 16979 | 15679 | ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ ``` ### Dependencies diff --git a/barretenberg/acir_tests/bench_acir_tests.sh b/barretenberg/acir_tests/bench_acir_tests.sh index 07fab9ab898b..b338e82e30b2 100755 --- a/barretenberg/acir_tests/bench_acir_tests.sh +++ b/barretenberg/acir_tests/bench_acir_tests.sh @@ -17,7 +17,11 @@ done # Build results into string with \n delimited rows and space delimited values. TABLE_DATA="" for TEST in ${TEST_NAMES[@]}; do - TABLE_DATA+="$TEST" + GATE_COUNT=$(jq -r --arg test "$TEST" 'select(.name == "gate_count" and .acir_test == $test) | .value' $BENCHMARKS | uniq) + SUBGROUP_SIZE=$(jq -r --arg test "$TEST" 'select(.name == "subgroup_size" and .acir_test == $test) | .value' $BENCHMARKS | uniq) + # Name in col 1, gate count in col 2, subgroup size in col 3. + TABLE_DATA+="$TEST $GATE_COUNT $SUBGROUP_SIZE" + # Each thread timing in subsequent cols. for HC in "${THREADS[@]}"; do RESULT=$(cat $BENCHMARKS | jq -r --arg test "$TEST" --argjson hc $HC 'select(.name == "proof_construction_time" and .acir_test == $test and .threads == $hc) | .value') TABLE_DATA+=" $RESULT" @@ -36,19 +40,19 @@ echo echo -e "$TABLE_DATA" | awk -v threads="${THREADS[*]}" 'BEGIN { split(threads, t, " "); len_threads = length(t); - print "+--------------------------+" genseparator(len_threads); - print "| Test |" genthreadheaders(t, len_threads); - print "+--------------------------+" genseparator(len_threads); + print "+--------------------------+------------+---------------+" genseparator(len_threads); + print "| Test | Gate Count | Subgroup Size |" genthreadheaders(t, len_threads); + print "+--------------------------+------------+---------------+" genseparator(len_threads); } { - printf("| %-24s |", $1); - for (i = 2; i <= len_threads+1; i++) { + printf("| %-24s | %-10s | %-13s |", $1, $2, $3); + for (i = 4; i <= len_threads+3; i++) { printf " %9s |", $(i); } print ""; } END { - print "+--------------------------+" genseparator(len_threads); + print "+--------------------------+------------+---------------+" genseparator(len_threads); } function genseparator(len, res) { for (i = 1; i <= len; i++) res = res "-----------+"; diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 2221ab206e97..57289874c849 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -79,6 +79,8 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP Timer pk_timer; acir_composer.init_proving_key(constraint_system); write_benchmark("pk_construction_time", pk_timer.milliseconds(), "acir_test", current_dir); + write_benchmark("gate_count", acir_composer.get_total_circuit_size(), "acir_test", current_dir); + write_benchmark("subgroup_size", acir_composer.get_circuit_subgroup_size(), "acir_test", current_dir); Timer proof_timer; auto proof = acir_composer.create_proof(constraint_system, witness, recursive); diff --git a/barretenberg/ts/README.md b/barretenberg/ts/README.md index 2993b8c91322..42cd716059af 100644 --- a/barretenberg/ts/README.md +++ b/barretenberg/ts/README.md @@ -13,17 +13,22 @@ Note there are two independent WASM builds, one with threading enabled and one w 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 (small witness generation phase): +The following output is from `bench_acir_tests.sh` script. -- 16 core (not hyperthreads) x86: ~15s. -- 10 core M1 Mac Pro: ~20s. +Table represents time in ms to build circuit and proof for each test on n threads. +Ignores proving key construction. -Linear scaling was observed up to 32 cores. - -Witness generation phase is not multithreaded, and an interesting 512k circuit can take ~12s. This results in: - -- 16 core (not hyperthreads) x86: ~28s. -- 10 core M1 Mac Pro: ~32s. +``` ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +| Test | Gate Count | Subgroup Size | 1 | 4 | 16 | 32 | 64 | ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +| sha256 | 38799 | 65536 | 18764 | 5116 | 1854 | 1524 | 1635 | +| ecdsa_secp256k1 | 41049 | 65536 | 19129 | 5595 | 2255 | 2097 | 2166 | +| ecdsa_secp256r1 | 67331 | 131072 | 38815 | 11257 | 4744 | 3633 | 3702 | +| schnorr | 33740 | 65536 | 18649 | 5244 | 2019 | 1498 | 1702 | +| double_verify_proof | 505513 | 524288 | 149652 | 45702 | 20811 | 16979 | 15679 | ++--------------------------+------------+---------------+-----------+-----------+-----------+-----------+-----------+ +``` ## Using as a standalone binary diff --git a/barretenberg/ts/src/benchmark/index.ts b/barretenberg/ts/src/benchmark/index.ts new file mode 100644 index 000000000000..20752349100c --- /dev/null +++ b/barretenberg/ts/src/benchmark/index.ts @@ -0,0 +1,26 @@ +import * as fs from 'fs'; +export * from './timer.js'; + +const bfd = (() => { + const bfdStr = process.env.BENCHMARK_FD; + const bfd = bfdStr ? parseInt(bfdStr) : -1; + if (bfd >= 0 && !fs.fstatSync(bfd)) { + throw new Error('fd is not open. Did you redirect in your shell?'); + } + return bfd; +})(); + +export function writeBenchmark(name: string, value: T, labels: Record = {}) { + if (bfd === -1) { + return; + } + const data = { + timestamp: new Date().toISOString(), + name, + type: typeof value, + value, + ...labels, + }; + const jsonl = JSON.stringify(data) + '\n'; + fs.writeSync(bfd, jsonl); +} diff --git a/barretenberg/ts/src/benchmark/timer.ts b/barretenberg/ts/src/benchmark/timer.ts new file mode 100644 index 000000000000..b74be9819ea6 --- /dev/null +++ b/barretenberg/ts/src/benchmark/timer.ts @@ -0,0 +1,41 @@ +/** + * Timer class to measure time intervals in milliseconds and seconds. + * Upon instantiation, it stores the current timestamp as the starting point. + * The 'ms()' method returns the elapsed time in milliseconds, + * while the 's()' method returns the elapsed time in seconds. + * + * @example + * const timer = new Timer(); + * setTimeout(() =\> \{ + * console.log(`Elapsed time: ${timer.ms()} ms`); + * \}, 1000); + */ +export class Timer { + private start: number; + + constructor() { + this.start = new Date().getTime(); + } + + /** + * Returns the elapsed time in milliseconds since the Timer instance was created. + * Provides a simple and convenient way to measure the time duration between two events + * or monitor performance of specific code sections. + * + * @returns The elapsed time in milliseconds. + */ + public ms() { + return new Date().getTime() - this.start; + } + + /** + * Returns the time elapsed since the Timer instance was created, in seconds. + * The value is calculated by subtracting the initial start time from the current time + * and dividing the result by 1000 to convert milliseconds to seconds. + * + * @returns The elapsed time in seconds. + */ + public s() { + return (new Date().getTime() - this.start) / 1000; + } +} diff --git a/barretenberg/ts/src/main.ts b/barretenberg/ts/src/main.ts index e362fddee820..a985ea59e796 100755 --- a/barretenberg/ts/src/main.ts +++ b/barretenberg/ts/src/main.ts @@ -5,6 +5,8 @@ import { readFileSync, writeFileSync } from 'fs'; import { gunzipSync } from 'zlib'; import { Command } from 'commander'; import { acvmInfoJson } from './info.js'; +import { Timer, writeBenchmark } from './benchmark/index.js'; +import path from 'path'; createDebug.log = console.error.bind(console); const debug = createDebug('bb.js'); @@ -15,6 +17,7 @@ const debug = createDebug('bb.js'); // aware of this discrepancy, when creating proofs in bb versus // creating the same proofs in the node CLI. const MAX_CIRCUIT_SIZE = 2 ** 19; +const threads = +process.env.HARDWARE_CONCURRENCY! || undefined; function getBytecode(bytecodePath: string) { const encodedCircuit = readFileSync(bytecodePath); @@ -41,7 +44,7 @@ async function computeCircuitSize(bytecodePath: string, api: Barretenberg) { } async function init(bytecodePath: string, crsPath: string) { - const api = await Barretenberg.new(); + const api = await Barretenberg.new(threads); const circuitSize = await getGates(bytecodePath, api); const subgroupSize = Math.pow(2, Math.ceil(Math.log2(circuitSize))); @@ -63,7 +66,7 @@ async function init(bytecodePath: string, crsPath: string) { await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); const acirComposer = await api.acirNewAcirComposer(subgroupSize); - return { api, acirComposer, circuitSize: subgroupSize }; + return { api, acirComposer, circuitSize, subgroupSize }; } async function initLite() { @@ -80,12 +83,24 @@ async function initLite() { } export async function proveAndVerify(bytecodePath: string, witnessPath: string, crsPath: string, isRecursive: boolean) { - const { api, acirComposer } = await init(bytecodePath, crsPath); + /* eslint-disable camelcase */ + const acir_test = path.basename(process.cwd()); + + const { api, acirComposer, circuitSize, subgroupSize } = await init(bytecodePath, crsPath); try { debug(`creating proof...`); const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); + + const pkTimer = new Timer(); + await api.acirInitProvingKey(acirComposer, bytecode); + writeBenchmark('pk_construction_time', pkTimer.ms(), { acir_test, threads }); + writeBenchmark('gate_count', circuitSize, { acir_test, threads }); + writeBenchmark('subgroup_size', subgroupSize, { acir_test, threads }); + + const proofTimer = new Timer(); const proof = await api.acirCreateProof(acirComposer, bytecode, witness, isRecursive); + writeBenchmark('proof_construction_time', proofTimer.ms(), { acir_test, threads }); debug(`verifying...`); const verified = await api.acirVerifyProof(acirComposer, proof, isRecursive); @@ -94,6 +109,7 @@ export async function proveAndVerify(bytecodePath: string, witnessPath: string, } finally { await api.destroy(); } + /* eslint-enable camelcase */ } export async function prove(