From c145757a13ba4ff881c4bb05c4caaee7351053b3 Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Tue, 7 May 2024 11:04:09 -0400 Subject: [PATCH] feat: Reproducible ClientIVC proofs (#6227) As part of my work on https://github.com/AztecProtocol/aztec-packages/pull/6218, I integrated deterministic randomness in order to have reproducible Goblin IVC proofs. This PR isolate those changes. In also includes some changes I made in order to verify that the same work gives us reproducible Client IVC proofs. Along the way I recognize that serialization of Client IVC proofs was broken (translation evaluations were not included). I fixed this as well. --- .../barretenberg/client_ivc/client_ivc.cpp | 2 +- .../barretenberg/client_ivc/client_ivc.hpp | 17 ++++++++++++- .../eccvm/eccvm_circuit_builder.test.cpp | 24 +++++++++---------- .../eccvm/eccvm_trace_checker.cpp | 6 ++--- .../eccvm/eccvm_trace_checker.hpp | 2 +- .../cpp/src/barretenberg/goblin/goblin.hpp | 17 +++++++------ .../src/barretenberg/goblin/mock_circuits.hpp | 5 ++-- .../goblin/translation_evaluations.hpp | 10 +++++--- .../barretenberg/numeric/random/engine.cpp | 8 +++---- .../barretenberg/numeric/random/engine.hpp | 3 ++- .../stdlib/encryption/ecdsa/ecdsa_impl.hpp | 6 ++++- .../goblin_ultra_circuit_builder.cpp | 2 +- .../stdlib_circuit_builders/mock_circuits.hpp | 19 ++++++++------- .../ultra_honk/ultra_composer.test.cpp | 4 ---- 14 files changed, 76 insertions(+), 49 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index eef0001e0c2..da85699eb47 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -53,7 +53,7 @@ bool ClientIVC::verify(Proof& proof, const std::vector& ver // Decider verification ClientIVC::FoldingVerifier folding_verifier({ verifier_instances[0], verifier_instances[1] }); - auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.fold_proof); + auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.folding_proof); ClientIVC::DeciderVerifier decider_verifier(verifier_accumulator); bool decision = decider_verifier.verify_proof(proof.decider_proof); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index f2e0ee309c3..6ef9a8676b6 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -37,9 +37,24 @@ class ClientIVC { // A full proof for the IVC scheme struct Proof { - FoldProof fold_proof; // final fold proof + FoldProof folding_proof; // final fold proof HonkProof decider_proof; Goblin::Proof goblin_proof; + + std::vector to_buffer() const + { + size_t proof_size = folding_proof.size() + decider_proof.size() + goblin_proof.size(); + + std::vector result; + result.reserve(proof_size); + const auto insert = [&result](const std::vector& buf) { + result.insert(result.end(), buf.begin(), buf.end()); + }; + insert(folding_proof); + insert(decider_proof); + insert(goblin_proof.to_buffer()); + return result; + } }; struct PrecomputedVerificationKeys { diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp index 253c1af019c..b5cb7698360 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_circuit_builder.test.cpp @@ -39,7 +39,7 @@ TEST(ECCVMCircuitBuilderTests, BaseCase) op_queue->mul_accumulate(c, x); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -53,7 +53,7 @@ TEST(ECCVMCircuitBuilderTests, Add) op_queue->add_accumulate(a); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -68,7 +68,7 @@ TEST(ECCVMCircuitBuilderTests, Mul) op_queue->mul_accumulate(a, x); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -89,7 +89,7 @@ TEST(ECCVMCircuitBuilderTests, ShortMul) op_queue->eq_and_reset(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -106,7 +106,7 @@ TEST(ECCVMCircuitBuilderTests, EqFails) op_queue->add_erroneous_equality_op_for_testing(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, false); } @@ -117,7 +117,7 @@ TEST(ECCVMCircuitBuilderTests, EmptyRow) op_queue->empty_row_for_testing(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -134,7 +134,7 @@ TEST(ECCVMCircuitBuilderTests, EmptyRowBetweenOps) op_queue->eq_and_reset(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -150,7 +150,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithEq) op_queue->eq_and_reset(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -167,7 +167,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithAdd) op_queue->add_accumulate(a); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -184,7 +184,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithMul) op_queue->mul_accumulate(a, x); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -202,7 +202,7 @@ TEST(ECCVMCircuitBuilderTests, EndWithNoop) op_queue->empty_row_for_testing(); ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } @@ -240,6 +240,6 @@ TEST(ECCVMCircuitBuilderTests, MSM) compute_msms(j, op_queue); } ECCVMCircuitBuilder circuit{ op_queue }; - bool result = ECCVMTraceChecker::check(circuit); + bool result = ECCVMTraceChecker::check(circuit, &engine); EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp index c8acc2400be..24c440f3303 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.cpp @@ -9,10 +9,10 @@ using Builder = typename ECCVMFlavor::CircuitBuilder; using FF = typename ECCVMFlavor::FF; using ProverPolynomials = typename ECCVMFlavor::ProverPolynomials; -bool ECCVMTraceChecker::check(Builder& builder) +bool ECCVMTraceChecker::check(Builder& builder, numeric::RNG* engine_ptr) { - const FF gamma = FF::random_element(); - const FF beta = FF::random_element(); + const FF gamma = FF::random_element(engine_ptr); + const FF beta = FF::random_element(engine_ptr); const FF beta_sqr = beta.sqr(); const FF beta_cube = beta_sqr * beta; auto eccvm_set_permutation_delta = diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp index 1dc84fb33e8..fdb918dee41 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_trace_checker.hpp @@ -4,6 +4,6 @@ namespace bb { class ECCVMTraceChecker { public: - static bool check(ECCVMCircuitBuilder&); + static bool check(ECCVMCircuitBuilder&, numeric::RNG* engine_ptr = nullptr); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index f8b6adc61dd..3823a510059 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -52,21 +52,24 @@ class Goblin { HonkProof eccvm_proof; HonkProof translator_proof; TranslationEvaluations translation_evaluations; - std::vector to_buffer() + + size_t size() const { - // ACIRHACK: so much copying and duplication added here and elsewhere - std::vector translation_evaluations_buf; // = translation_evaluations.to_buffer(); - size_t proof_size = - merge_proof.size() + eccvm_proof.size() + translator_proof.size() + translation_evaluations_buf.size(); + return merge_proof.size() + eccvm_proof.size() + translator_proof.size() + TranslationEvaluations::size(); + }; - std::vector result(proof_size); + std::vector to_buffer() const + { + // ACIRHACK: so much copying and duplication added here and elsewhere + std::vector result; + result.reserve(size()); const auto insert = [&result](const std::vector& buf) { result.insert(result.end(), buf.begin(), buf.end()); }; insert(merge_proof); insert(eccvm_proof); insert(translator_proof); - insert(translation_evaluations_buf); + insert(translation_evaluations.to_buffer()); return result; } }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index e6457060f6f..46586ff58da 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -17,6 +17,7 @@ #include "barretenberg/stdlib_circuit_builders/mock_circuits.hpp" namespace bb { + class GoblinMockCircuits { public: using Curve = curve::BN254; @@ -120,8 +121,8 @@ class GoblinMockCircuits { { // Add some arbitrary ecc op gates for (size_t i = 0; i < 3; ++i) { - auto point = Point::random_element(); - auto scalar = FF::random_element(); + auto point = Point::random_element(&engine); + auto scalar = FF::random_element(&engine); builder.queue_ecc_add_accum(point); builder.queue_ecc_mul_accum(point, scalar); } diff --git a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp index 6dcee0e24fd..5495504296d 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp @@ -1,14 +1,18 @@ #pragma once #include "barretenberg/ecc/curves/bn254/fq.hpp" +#include "barretenberg/ecc/fields/field_conversion.hpp" namespace bb { struct TranslationEvaluations { fq op, Px, Py, z1, z2; - std::vector to_buffer() + static constexpr uint32_t NUM_EVALUATIONS = 5; + static size_t size() { return field_conversion::calc_num_bn254_frs() * NUM_EVALUATIONS; } + std::vector to_buffer() const { - std::vector result(5 * sizeof(fq)); + std::vector result; + result.reserve(size()); const auto insert = [&result](const fq& elt) { - std::vector buf = elt.to_buffer(); + std::vector buf = field_conversion::convert_to_bn254_frs(elt); result.insert(result.end(), buf.begin(), buf.end()); }; insert(op); diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp index e8b5c4a940a..0c3604cb92a 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.cpp @@ -79,7 +79,7 @@ class DebugEngine : public RNG { : engine(std::mt19937_64(12345)) {} - DebugEngine(std::seed_seq& seed) + DebugEngine(std::uint_fast64_t seed) : engine(std::mt19937_64(seed)) {} @@ -116,12 +116,12 @@ class DebugEngine : public RNG { /** * Used by tests to ensure consistent behavior. */ -RNG& get_debug_randomness(bool reset) +RNG& get_debug_randomness(bool reset, std::uint_fast64_t seed) { // static std::seed_seq seed({ 1, 2, 3, 4, 5 }); - static DebugEngine debug_engine; + static DebugEngine debug_engine = DebugEngine(); if (reset) { - debug_engine = DebugEngine(); + debug_engine = DebugEngine(seed); } return debug_engine; } diff --git a/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp b/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp index aad7932bbbf..0e54341ea91 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp +++ b/barretenberg/cpp/src/barretenberg/numeric/random/engine.hpp @@ -4,6 +4,7 @@ #include "../uintx/uintx.hpp" #include "unistd.h" #include +#include namespace bb::numeric { @@ -45,7 +46,7 @@ class RNG { } }; -RNG& get_debug_randomness(bool reset = false); +RNG& get_debug_randomness(bool reset = false, std::uint_fast64_t seed = 12345); RNG& get_randomness(); } // namespace bb::numeric diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp index ae6731c06a7..a40ba91f45d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp @@ -7,6 +7,10 @@ namespace bb::stdlib { +namespace { +auto& engine = numeric::get_debug_randomness(); +} + /** * @brief Verify ECDSA signature. Produces unsatisfiable constraints if signature fails * @@ -241,7 +245,7 @@ template void generate_ecdsa_verification_test_circuit(Builde crypto::ecdsa_key_pair account; for (size_t i = 0; i < num_iterations; i++) { // Generate unique signature for each iteration - account.private_key = curve::fr::random_element(); + account.private_key = curve::fr::random_element(&engine); account.public_key = curve::g1::one * account.private_key; crypto::ecdsa_signature signature = diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp index 58542f3e151..dd12ae51109 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/goblin_ultra_circuit_builder.cpp @@ -92,7 +92,7 @@ template void GoblinUltraCircuitBuilder_::add_goblin_gates_to_ this->blocks.poseidon_internal, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); // add dummy mul accum op and an equality op - this->queue_ecc_mul_accum(bb::g1::affine_element::one() * FF::random_element(), FF::random_element()); + this->queue_ecc_mul_accum(bb::g1::affine_element::one(), 2); this->queue_ecc_eq(); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp index 36937d8c347..a7d72d7e53e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mock_circuits.hpp @@ -3,6 +3,9 @@ namespace bb { +namespace { +auto& engine = numeric::get_debug_randomness(); +} class MockCircuits { public: using Curve = curve::BN254; @@ -20,9 +23,9 @@ class MockCircuits { { // For good measure, include a gate with some public inputs for (size_t i = 0; i < num_gates; ++i) { - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); + FF a = FF::random_element(&engine); + FF b = FF::random_element(&engine); + FF c = FF::random_element(&engine); FF d = a + b + c; uint32_t a_idx = builder.add_public_variable(a); uint32_t b_idx = builder.add_variable(b); @@ -43,9 +46,9 @@ class MockCircuits { { // For good measure, include a gate with some public inputs for (size_t i = 0; i < num_gates; ++i) { - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); + FF a = FF::random_element(&engine); + FF b = FF::random_element(&engine); + FF c = FF::random_element(&engine); FF d = a + b + c; uint32_t a_idx = builder.add_variable(a); uint32_t b_idx = builder.add_variable(b); @@ -98,8 +101,8 @@ class MockCircuits { static void construct_goblin_ecc_op_circuit(GoblinUltraCircuitBuilder& builder) { // Add a mul accum op, an add accum op and an equality op - builder.queue_ecc_add_accum(Point::one() * FF::random_element()); - builder.queue_ecc_mul_accum(Point::one() * FF::random_element(), FF::random_element()); + builder.queue_ecc_add_accum(Point::one() * FF::random_element(&engine)); + builder.queue_ecc_mul_accum(Point::one() * FF::random_element(&engine), FF::random_element(&engine)); builder.queue_ecc_eq(); } }; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index 564afd23c4a..330a2ab8c14 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -16,10 +16,6 @@ using namespace bb; -namespace { -auto& engine = numeric::get_debug_randomness(); -} - using ProverInstance = ProverInstance_; using VerificationKey = UltraFlavor::VerificationKey;