diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index 62f2100fa74..fe5ec34f176 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -48,26 +48,26 @@ else() message(STATUS "Using optimized assembly for field arithmetic.") endif() -add_subdirectory(barretenberg/env) +add_subdirectory(barretenberg/bb) add_subdirectory(barretenberg/common) -add_subdirectory(barretenberg/numeric) -add_subdirectory(barretenberg/srs) -add_subdirectory(barretenberg/ecc) add_subdirectory(barretenberg/crypto) -add_subdirectory(barretenberg/polynomials) -add_subdirectory(barretenberg/proof_system) -add_subdirectory(barretenberg/transcript) -add_subdirectory(barretenberg/honk) -add_subdirectory(barretenberg/plonk) -add_subdirectory(barretenberg/stdlib) -add_subdirectory(barretenberg/join_split_example) add_subdirectory(barretenberg/dsl) +add_subdirectory(barretenberg/ecc) +add_subdirectory(barretenberg/env) add_subdirectory(barretenberg/examples) +add_subdirectory(barretenberg/grumpkin_srs_gen) +add_subdirectory(barretenberg/honk) +add_subdirectory(barretenberg/join_split_example) +add_subdirectory(barretenberg/numeric) +add_subdirectory(barretenberg/plonk) +add_subdirectory(barretenberg/polynomials) +add_subdirectory(barretenberg/proof_system) add_subdirectory(barretenberg/serialize) add_subdirectory(barretenberg/solidity_helpers) +add_subdirectory(barretenberg/srs) +add_subdirectory(barretenberg/stdlib) +add_subdirectory(barretenberg/transcript) add_subdirectory(barretenberg/wasi) -add_subdirectory(barretenberg/grumpkin_srs_gen) -add_subdirectory(barretenberg/bb) if(SMT) @@ -89,7 +89,6 @@ message(STATUS "Compiling all-in-one barretenberg archive") add_library( barretenberg STATIC - $ $ $ $ @@ -100,6 +99,7 @@ add_library( $ $ $ + $ $ $ $ @@ -134,8 +134,6 @@ if(WASM) # to implement the functions in env. add_executable( barretenberg.wasm - $ - $ $ $ $ @@ -146,6 +144,7 @@ if(WASM) $ $ $ + $ $ $ $ @@ -165,6 +164,7 @@ if(WASM) $ $ $ + $ ) add_executable( diff --git a/barretenberg/cpp/src/barretenberg/barretenberg.hpp b/barretenberg/cpp/src/barretenberg/barretenberg.hpp index 24c79da90c0..30c143a6af6 100644 --- a/barretenberg/cpp/src/barretenberg/barretenberg.hpp +++ b/barretenberg/cpp/src/barretenberg/barretenberg.hpp @@ -47,6 +47,7 @@ #include "stdlib/merkle_tree/merkle_tree.hpp" // TODO(https://github.com/AztecProtocol/aztec-packages/issues/728): // Consider moving nullifier tree logic out of barretenberg into aztec repo +#include "barretenberg/plonk/transcript/manifest.hpp" #include "stdlib/merkle_tree/nullifier_tree/nullifier_leaf.hpp" #include "stdlib/merkle_tree/nullifier_tree/nullifier_memory_tree.hpp" #include "stdlib/merkle_tree/nullifier_tree/nullifier_tree.hpp" @@ -68,4 +69,3 @@ #include "stdlib/recursion/verification_key/verification_key.hpp" #include "stdlib/recursion/verifier/program_settings.hpp" #include "stdlib/recursion/verifier/verifier.hpp" -#include "transcript/manifest.hpp" diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp index fbe589bc528..0e69aab847e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -1,8 +1,8 @@ #include "recursion_constraint.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/plonk/transcript/transcript_wrappers.hpp" #include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" #include "barretenberg/stdlib/recursion/verifier/verifier.hpp" -#include "barretenberg/transcript/transcript_wrappers.hpp" namespace acir_format { diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_composer.cpp b/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_composer.cpp index 6b388cd7183..6ceb44ec11b 100644 --- a/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_composer.cpp @@ -118,4 +118,4 @@ std::shared_ptr ECCVMComposer_::comput template class ECCVMComposer_; template class ECCVMComposer_; -} // namespace proof_system::honk +} // namespace proof_system::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_transcript.test.cpp new file mode 100644 index 00000000000..27948af8c92 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/composer/eccvm_transcript.test.cpp @@ -0,0 +1,343 @@ +// #include "barretenberg/ecc/curves/bn254/g1.hpp" +// #include "barretenberg/honk/composer/eccvm_composer.hpp" +// #include "barretenberg/numeric/bitop/get_msb.hpp" +// #include "barretenberg/polynomials/univariate.hpp" +// #include "barretenberg/proof_system/flavor/flavor.hpp" +// #include "barretenberg/transcript/transcript.hpp" +// #include + +// using namespace proof_system::honk; + +// template class ECCVMTranscriptTests : public ::testing::Test { +// public: +// void SetUp() override +// { +// if constexpr (std::is_same::value) { +// barretenberg::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); +// } else { +// barretenberg::srs::init_crs_factory("../srs_db/ignition"); +// } +// }; +// using FF = typename Flavor::FF; + +// /** +// * @brief Construct a manifest for a ECCVM Honk proof +// * +// * @details This is where we define the "Manifest" for a ECCVM Honk proof. The tests in this suite are +// * intented to warn the developer if the Prover/Verifier has deviated from this manifest, however, the +// * Transcript class is not otherwise contrained to follow the manifest. +// * +// * @note Entries in the manifest consist of a name string and a size (bytes), NOT actual data. +// * +// * @return TranscriptManifest +// */ +// TranscriptManifest construct_eccvm_honk_manifest(size_t circuit_size, size_t ipa_poly_degree) +// { +// TranscriptManifest manifest_expected; + +// auto log_n = numeric::get_msb(circuit_size); + +// size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; +// size_t size_FF = sizeof(FF); +// size_t size_G = 2 * size_FF; +// size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; +// size_t size_evals = (Flavor::NUM_ALL_ENTITIES)*size_FF; +// size_t size_uint32 = 4; +// size_t size_uint64 = 8; + +// size_t round = 0; +// manifest_expected.add_entry(round, "circuit_size", size_uint32); +// manifest_expected.add_entry(round, "TRANSCRIPT_ADD", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_MUL", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_EQ", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_COLLISION_CHECK", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_MSM_TRANSITION", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_PC", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_X", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_Y", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_Z1", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_Z2", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_Z1ZERO", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_Z2ZERO", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_OP", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_X", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_Y", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_MSM_X", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_MSM_Y", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_PC", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_POINT_TRANSITION", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_ROUND", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_SCALAR_SUM", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S1HI", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S1LO", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S2HI", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S2LO", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S3HI", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S3LO", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S4HI", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_S4LO", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_SKEW", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_DX", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_DY", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_TX", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_TY", size_G); +// manifest_expected.add_entry(round, "MSM_TRANSITION", size_G); +// manifest_expected.add_entry(round, "MSM_ADD", size_G); +// manifest_expected.add_entry(round, "MSM_DOUBLE", size_G); +// manifest_expected.add_entry(round, "MSM_SKEW", size_G); +// manifest_expected.add_entry(round, "MSM_ACCUMULATOR_X", size_G); +// manifest_expected.add_entry(round, "MSM_ACCUMULATOR_Y", size_G); +// manifest_expected.add_entry(round, "MSM_PC", size_G); +// manifest_expected.add_entry(round, "MSM_SIZE_OF_MSM", size_G); +// manifest_expected.add_entry(round, "MSM_COUNT", size_G); +// manifest_expected.add_entry(round, "MSM_ROUND", size_G); +// manifest_expected.add_entry(round, "MSM_ADD1", size_G); +// manifest_expected.add_entry(round, "MSM_ADD2", size_G); +// manifest_expected.add_entry(round, "MSM_ADD3", size_G); +// manifest_expected.add_entry(round, "MSM_ADD4", size_G); +// manifest_expected.add_entry(round, "MSM_X1", size_G); +// manifest_expected.add_entry(round, "MSM_Y1", size_G); +// manifest_expected.add_entry(round, "MSM_X2", size_G); +// manifest_expected.add_entry(round, "MSM_Y2", size_G); +// manifest_expected.add_entry(round, "MSM_X3", size_G); +// manifest_expected.add_entry(round, "MSM_Y3", size_G); +// manifest_expected.add_entry(round, "MSM_X4", size_G); +// manifest_expected.add_entry(round, "MSM_Y4", size_G); +// manifest_expected.add_entry(round, "MSM_COLLISION_X1", size_G); +// manifest_expected.add_entry(round, "MSM_COLLISION_X2", size_G); +// manifest_expected.add_entry(round, "MSM_COLLISION_X3", size_G); +// manifest_expected.add_entry(round, "MSM_COLLISION_X4", size_G); +// manifest_expected.add_entry(round, "MSM_LAMBDA1", size_G); +// manifest_expected.add_entry(round, "MSM_LAMBDA2", size_G); +// manifest_expected.add_entry(round, "MSM_LAMBDA3", size_G); +// manifest_expected.add_entry(round, "MSM_LAMBDA4", size_G); +// manifest_expected.add_entry(round, "MSM_SLICE1", size_G); +// manifest_expected.add_entry(round, "MSM_SLICE2", size_G); +// manifest_expected.add_entry(round, "MSM_SLICE3", size_G); +// manifest_expected.add_entry(round, "MSM_SLICE4", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_EMPTY", size_G); +// manifest_expected.add_entry(round, "TRANSCRIPT_RESET_ACCUMULATOR", size_G); +// manifest_expected.add_entry(round, "PRECOMPUTE_SELECT", size_G); +// manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS_0", size_G); +// manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS_1", size_G); +// manifest_expected.add_challenge(round, "beta", "gamma"); + +// round++; +// manifest_expected.add_entry(round, "LOOKUP_INVERSES", size_G); +// manifest_expected.add_entry(round, "Z_PERM", size_G); +// manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); + +// for (size_t i = 0; i < log_n; ++i) { +// round++; +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); +// std::string label = "Sumcheck:u_" + idx; +// manifest_expected.add_challenge(round, label); +// } + +// round++; +// manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); +// manifest_expected.add_challenge(round, "rho"); + +// round++; +// for (size_t i = 1; i < log_n; ++i) { +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, size_G); +// } +// manifest_expected.add_challenge(round, "Gemini:r"); + +// round++; +// for (size_t i = 0; i < log_n; ++i) { +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "Gemini:a_" + idx, size_FF); +// } +// manifest_expected.add_challenge(round, "Shplonk:nu"); + +// round++; +// manifest_expected.add_entry(round, "Shplonk:Q", size_G); +// manifest_expected.add_challenge(round, "Shplonk:z"); + +// // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors +// if constexpr (proof_system::IsGrumpkinFlavor) { +// round++; +// manifest_expected.add_entry(round, "IPA:poly_degree", size_uint64); +// manifest_expected.add_challenge(round, "IPA:generator_challenge"); + +// auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); +// for (size_t i = 0; i < log_poly_degree; ++i) { +// round++; +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "IPA:L_" + idx, size_G); +// manifest_expected.add_entry(round, "IPA:R_" + idx, size_G); +// std::string label = "IPA:round_challenge_" + idx; +// manifest_expected.add_challenge(round, label); +// } + +// round++; +// manifest_expected.add_entry(round, "IPA:a_0", size_FF); +// } else { +// round++; +// manifest_expected.add_entry(round, "KZG:W", size_G); +// } + +// return manifest_expected; +// } +// proof_system::ECCVMCircuitBuilder generate_trace(numeric::random::Engine* engine = nullptr) +// { +// proof_system::ECCVMCircuitBuilder result; +// using G1 = typename Flavor::CycleGroup; +// using Fr = typename G1::Fr; + +// auto generators = G1::derive_generators("test generators", 3); + +// typename G1::element a = generators[0]; +// typename G1::element b = generators[1]; +// typename G1::element c = generators[2]; +// Fr x = Fr::random_element(engine); +// Fr y = Fr::random_element(engine); + +// typename G1::element expected_1 = (a * x) + a + a + (b * y) + (b * x) + (b * x); +// typename G1::element expected_2 = (a * x) + c + (b * x); + +// result.add_accumulate(a); +// result.mul_accumulate(a, x); +// result.mul_accumulate(b, x); +// result.mul_accumulate(b, y); +// result.add_accumulate(a); +// result.mul_accumulate(b, x); +// result.eq_and_reset(expected_1); +// result.add_accumulate(c); +// result.mul_accumulate(a, x); +// result.mul_accumulate(b, x); +// result.eq_and_reset(expected_2); +// result.mul_accumulate(a, x); +// result.mul_accumulate(b, x); +// result.mul_accumulate(c, x); + +// return result; +// } +// }; + +// numeric::random::Engine& engine = numeric::random::get_debug_engine(); + +// using FlavorTypes = testing::Types; + +// TYPED_TEST_SUITE(ECCVMTranscriptTests, FlavorTypes); +// /** +// * @brief Ensure consistency between the manifest hard coded in this testing suite and the one generated by the +// * standard honk prover over the course of proof construction. +// */ +// TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) +// { +// using Flavor = TypeParam; + +// // Construct a simple circuit +// auto builder = this->generate_trace(&engine); + +// // Automatically generate a transcript manifest by constructing a proof +// auto composer = ECCVMComposer_(); +// auto prover = composer.create_prover(builder); +// auto proof = prover.construct_proof(); + +// // Check that the prover generated manifest agrees with the manifest hard coded in this suite +// auto manifest_expected = +// this->construct_eccvm_honk_manifest(prover.key->circuit_size, prover.shplonk_output.witness.size()); +// auto prover_manifest = prover.transcript.get_manifest(); + +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < manifest_expected.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << +// round; +// } +// } + +// /** +// * @brief Ensure consistency between the manifest generated by the ECCVM honk prover over the course of proof +// * construction and the one generated by the verifier over the course of proof verification. +// * +// */ +// TYPED_TEST(ECCVMTranscriptTests, VerifierManifestConsistency) +// { +// using Flavor = TypeParam; + +// // Construct a simple circuit +// auto builder = this->generate_trace(&engine); + +// // Automatically generate a transcript manifest in the prover by constructing a proof +// auto composer = ECCVMComposer_(); +// auto prover = composer.create_prover(builder); +// auto proof = prover.construct_proof(); + +// // Automatically generate a transcript manifest in the verifier by verifying a proof +// auto verifier = composer.create_verifier(builder); +// verifier.verify_proof(proof); + +// // Check consistency between the manifests generated by the prover and verifier +// auto prover_manifest = prover.transcript.get_manifest(); +// auto verifier_manifest = verifier.transcript.get_manifest(); + +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < prover_manifest.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) +// << "Prover/Verifier manifest discrepency in round " << round; +// } +// } + +// /** +// * @brief Check that multiple challenges can be generated and sanity check +// * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. +// * +// */ +// TYPED_TEST(ECCVMTranscriptTests, ChallengeGenerationTest) +// { +// using Flavor = TypeParam; +// // initialized with random value sent to verifier +// auto transcript = Flavor::Transcript::prover_init_empty(); +// // test a bunch of challenges +// auto challenges = transcript.get_challenges("a", "b", "c", "d", "e", "f"); +// // check they are not 0 +// for (size_t i = 0; i < challenges.size(); ++i) { +// ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; +// } +// constexpr uint32_t random_val{ 17 }; // arbitrary +// transcript.send_to_verifier("random val", random_val); +// // test more challenges +// auto [a, b, c] = transcript.get_challenges("a", "b", "c"); +// ASSERT_NE(a, 0) << "Challenge a is 0"; +// ASSERT_NE(b, 0) << "Challenge a is 0"; +// ASSERT_NE(b, 0) << "Challenge a is 0"; +// } + +// TYPED_TEST(ECCVMTranscriptTests, StructureTest) +// { +// using Flavor = TypeParam; + +// // Construct a simple circuit +// auto builder = this->generate_trace(&engine); + +// // Automatically generate a transcript manifest by constructing a proof +// auto composer = ECCVMComposer_(); +// auto prover = composer.create_prover(builder); +// auto proof = prover.construct_proof(); +// auto verifier = composer.create_verifier(builder); +// EXPECT_TRUE(verifier.verify_proof(proof)); + +// // try deserializing and serializing with no changes and check proof is still valid +// prover.transcript.deserialize_full_transcript(); +// prover.transcript.serialize_full_transcript(); +// EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid + +// typename Flavor::Commitment one_group_val = Flavor::Commitment::one(); +// typename Flavor::FF rand_val = Flavor::FF::random_element(); +// prover.transcript.transcript_x_comm = one_group_val * rand_val; // choose random object to modify +// EXPECT_TRUE(verifier.verify_proof( +// prover.export_proof())); // we have not serialized it back to the proof so it should still be fine + +// prover.transcript.serialize_full_transcript(); +// EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it + +// prover.transcript.deserialize_full_transcript(); +// EXPECT_EQ(static_cast(prover.transcript.transcript_x_comm), one_group_val * +// rand_val); +// } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_transcript.test.cpp new file mode 100644 index 00000000000..f2b45872d9d --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_transcript.test.cpp @@ -0,0 +1,234 @@ +// #include "barretenberg/ecc/curves/bn254/g1.hpp" +// #include "barretenberg/honk/composer/ultra_composer.hpp" +// #include "barretenberg/numeric/bitop/get_msb.hpp" +// #include "barretenberg/polynomials/univariate.hpp" +// #include "barretenberg/proof_system/flavor/flavor.hpp" +// #include "barretenberg/transcript/transcript.hpp" +// #include + +// using namespace proof_system::honk; + +// class GoblinUltraTranscriptTests : public ::testing::Test { +// public: +// // static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } + +// using Flavor = proof_system::honk::flavor::GoblinUltra; +// using FF = Flavor::FF; + +// /** +// * @brief Construct a manifest for a GoblinUltra Honk proof +// * +// * @details This is where we define the "Manifest" for a GoblinUltra Honk proof. The tests in this suite are +// * intented to warn the developer if the Prover/Verifier has deviated from this manifest, however, the +// * Transcript class is not otherwise contrained to follow the manifest. +// * +// * @note Entries in the manifest consist of a name string and a size (bytes), NOT actual data. +// * +// * @return TranscriptManifest +// */ +// TranscriptManifest construct_goblin_ultra_honk_manifest(size_t circuit_size) +// { +// TranscriptManifest manifest_expected; + +// auto log_n = numeric::get_msb(circuit_size); + +// size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; +// size_t size_FF = sizeof(FF); +// size_t size_G = 2 * size_FF; +// size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; +// size_t size_evals = (Flavor::NUM_ALL_ENTITIES)*size_FF; +// size_t size_uint32 = 4; + +// size_t round = 0; +// manifest_expected.add_entry(round, "circuit_size", size_uint32); +// manifest_expected.add_entry(round, "public_input_size", size_uint32); +// manifest_expected.add_entry(round, "pub_inputs_offset", size_uint32); +// manifest_expected.add_entry(round, "public_input_0", size_FF); +// manifest_expected.add_entry(round, "W_L", size_G); +// manifest_expected.add_entry(round, "W_R", size_G); +// manifest_expected.add_entry(round, "W_O", size_G); +// manifest_expected.add_entry(round, "ECC_OP_WIRE_1", size_G); +// manifest_expected.add_entry(round, "ECC_OP_WIRE_2", size_G); +// manifest_expected.add_entry(round, "ECC_OP_WIRE_3", size_G); +// manifest_expected.add_entry(round, "ECC_OP_WIRE_4", size_G); +// manifest_expected.add_challenge(round, "eta"); + +// round++; +// manifest_expected.add_entry(round, "SORTED_ACCUM", size_G); +// manifest_expected.add_entry(round, "W_4", size_G); +// manifest_expected.add_challenge(round, "beta", "gamma"); + +// round++; +// manifest_expected.add_entry(round, "Z_PERM", size_G); +// manifest_expected.add_entry(round, "Z_LOOKUP", size_G); +// manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); + +// for (size_t i = 0; i < log_n; ++i) { +// round++; +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); +// std::string label = "Sumcheck:u_" + idx; +// manifest_expected.add_challenge(round, label); +// } + +// round++; +// manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); +// manifest_expected.add_challenge(round, "rho"); + +// round++; +// for (size_t i = 0; i < log_n; ++i) { +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "ZM:C_q_" + idx, size_G); +// } +// manifest_expected.add_challenge(round, "ZM:y"); + +// round++; +// manifest_expected.add_entry(round, "ZM:C_q", size_G); +// manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); + +// round++; +// // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors +// manifest_expected.add_entry(round, "ZM:PI", size_G); +// manifest_expected.add_challenge(round); // no challenge + +// return manifest_expected; +// } + +// void generate_test_circuit(auto& builder) +// { +// // Add some ecc op gates +// for (size_t i = 0; i < 3; ++i) { +// auto point = Flavor::Curve::AffineElement::one() * FF::random_element(); +// auto scalar = FF::random_element(); +// builder.queue_ecc_mul_accum(point, scalar); +// } +// builder.queue_ecc_eq(); + +// // Add one conventional gates that utilize public inputs +// FF a = FF::random_element(); +// FF b = FF::random_element(); +// FF c = FF::random_element(); +// FF d = a + b + c; +// uint32_t a_idx = builder.add_public_variable(a); +// uint32_t b_idx = builder.add_variable(b); +// uint32_t c_idx = builder.add_variable(c); +// uint32_t d_idx = builder.add_variable(d); + +// builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); +// } +// }; + +// /** +// * @brief Ensure consistency between the manifest hard coded in this testing suite and the one generated by the +// * standard honk prover over the course of proof construction. +// */ +// TEST_F(GoblinUltraTranscriptTests, ProverManifestConsistency) +// { +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto builder = typename Flavor::CircuitBuilder(); +// generate_test_circuit(builder); + +// // Automatically generate a transcript manifest by constructing a proof +// auto composer = GoblinUltraComposer(); +// auto instance = composer.create_instance(builder); +// auto prover = composer.create_prover(instance); +// auto proof = prover.construct_proof(); + +// // Check that the prover generated manifest agrees with the manifest hard coded in this suite +// auto manifest_expected = construct_goblin_ultra_honk_manifest(instance->proving_key->circuit_size); +// auto prover_manifest = prover.transcript.get_manifest(); +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < manifest_expected.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << +// round; +// } +// } + +// /** +// * @brief Ensure consistency between the manifest generated by the goblin ultra honk prover over the course of proof +// * construction and the one generated by the verifier over the course of proof verification. +// * +// */ +// TEST_F(GoblinUltraTranscriptTests, VerifierManifestConsistency) +// { + +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto builder = Flavor::CircuitBuilder(); +// generate_test_circuit(builder); + +// // Automatically generate a transcript manifest in the prover by constructing a proof +// auto composer = GoblinUltraComposer(); +// auto instance = composer.create_instance(builder); +// auto prover = composer.create_prover(instance); +// auto proof = prover.construct_proof(); + +// // Automatically generate a transcript manifest in the verifier by verifying a proof +// auto verifier = composer.create_verifier(instance); +// verifier.verify_proof(proof); + +// // Check consistency between the manifests generated by the prover and verifier +// auto prover_manifest = prover.transcript.get_manifest(); +// auto verifier_manifest = verifier.transcript.get_manifest(); + +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < prover_manifest.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) +// << "Prover/Verifier manifest discrepency in round " << round; +// } +// } + +// /** +// * @brief Check that multiple challenges can be generated and sanity check +// * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. +// * +// */ +// TEST_F(GoblinUltraTranscriptTests, ChallengeGenerationTest) +// { +// // initialized with random value sent to verifier +// auto transcript = Flavor::Transcript::prover_init_empty(); +// // test a bunch of challenges +// auto challenges = transcript.get_challenges("a", "b", "c", "d", "e", "f"); +// // check they are not 0 +// for (size_t i = 0; i < challenges.size(); ++i) { +// ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; +// } +// constexpr uint32_t random_val{ 17 }; // arbitrary +// transcript.send_to_verifier("random val", random_val); +// // test more challenges +// auto [a, b, c] = transcript.get_challenges("a", "b", "c"); +// ASSERT_NE(a, 0) << "Challenge a is 0"; +// ASSERT_NE(b, 0) << "Challenge a is 0"; +// ASSERT_NE(b, 0) << "Challenge a is 0"; +// } + +// TEST_F(GoblinUltraTranscriptTests, StructureTest) +// { +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto builder = typename Flavor::CircuitBuilder(); +// generate_test_circuit(builder); + +// // Automatically generate a transcript manifest by constructing a proof +// auto composer = GoblinUltraComposer(); +// auto instance = composer.create_instance(builder); +// auto prover = composer.create_prover(instance); +// auto proof = prover.construct_proof(); +// auto verifier = composer.create_verifier(instance); +// EXPECT_TRUE(verifier.verify_proof(proof)); + +// // try deserializing and serializing with no changes and check proof is still valid +// prover.transcript.deserialize_full_transcript(); +// prover.transcript.serialize_full_transcript(); +// EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid + +// Flavor::Commitment one_group_val = Flavor::Commitment::one(); +// FF rand_val = FF::random_element(); +// prover.transcript.sorted_accum_comm = one_group_val * rand_val; // choose random object to modify +// EXPECT_TRUE(verifier.verify_proof( +// prover.export_proof())); // we have not serialized it back to the proof so it should still be fine + +// prover.transcript.serialize_full_transcript(); +// EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it + +// prover.transcript.deserialize_full_transcript(); +// EXPECT_EQ(static_cast(prover.transcript.sorted_accum_comm), one_group_val * rand_val); +// } diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp index 24835a00b32..d43b3d0d5f9 100644 --- a/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp @@ -8,12 +8,7 @@ #include "barretenberg/honk/proof_system/ultra_verifier.hpp" #include "barretenberg/proof_system/composer/composer_lib.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" -#include "barretenberg/srs/factories/file_crs_factory.hpp" - -#include -#include -#include -#include +#include "barretenberg/srs/global_crs.hpp" namespace proof_system::honk { template class UltraComposer_ { diff --git a/barretenberg/cpp/src/barretenberg/honk/composer/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/composer/ultra_transcript.test.cpp new file mode 100644 index 00000000000..89e522d31ed --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/composer/ultra_transcript.test.cpp @@ -0,0 +1,258 @@ +// #include "barretenberg/ecc/curves/bn254/g1.hpp" +// #include "barretenberg/honk/composer/ultra_composer.hpp" +// #include "barretenberg/numeric/bitop/get_msb.hpp" +// #include "barretenberg/polynomials/univariate.hpp" +// #include "barretenberg/proof_system/flavor/flavor.hpp" +// #include "barretenberg/transcript/transcript.hpp" +// #include + +// using namespace proof_system::honk; + +// class UltraTranscriptTests : public ::testing::Test { +// public: +// static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } + +// using Flavor = proof_system::honk::flavor::Ultra; +// using FF = Flavor::FF; + +// /** +// * @brief Construct a manifest for a Ultra Honk proof +// * +// * @details This is where we define the "Manifest" for a Ultra Honk proof. The tests in this suite are +// * intented to warn the developer if the Prover/Verifier has deviated from this manifest, however, the +// * Transcript class is not otherwise contrained to follow the manifest. +// * +// * @note Entries in the manifest consist of a name string and a size (bytes), NOT actual data. +// * +// * @return TranscriptManifest +// */ +// TranscriptManifest construct_ultra_honk_manifest(size_t circuit_size) +// { +// TranscriptManifest manifest_expected; + +// auto log_n = numeric::get_msb(circuit_size); + +// size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; +// size_t size_FF = sizeof(FF); +// size_t size_G = 2 * size_FF; +// size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; +// size_t size_evals = (Flavor::NUM_ALL_ENTITIES)*size_FF; +// size_t size_uint32 = 4; + +// size_t round = 0; +// manifest_expected.add_entry(round, "circuit_size", size_uint32); +// manifest_expected.add_entry(round, "public_input_size", size_uint32); +// manifest_expected.add_entry(round, "pub_inputs_offset", size_uint32); +// manifest_expected.add_entry(round, "public_input_0", size_FF); +// manifest_expected.add_entry(round, "W_L", size_G); +// manifest_expected.add_entry(round, "W_R", size_G); +// manifest_expected.add_entry(round, "W_O", size_G); +// manifest_expected.add_challenge(round, "eta"); + +// round++; +// manifest_expected.add_entry(round, "SORTED_ACCUM", size_G); +// manifest_expected.add_entry(round, "W_4", size_G); +// manifest_expected.add_challenge(round, "beta", "gamma"); + +// round++; +// manifest_expected.add_entry(round, "Z_PERM", size_G); +// manifest_expected.add_entry(round, "Z_LOOKUP", size_G); +// manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); + +// for (size_t i = 0; i < log_n; ++i) { +// round++; +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); +// std::string label = "Sumcheck:u_" + idx; +// manifest_expected.add_challenge(round, label); +// } + +// round++; +// manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); +// manifest_expected.add_challenge(round, "rho"); + +// round++; +// for (size_t i = 0; i < log_n; ++i) { +// std::string idx = std::to_string(i); +// manifest_expected.add_entry(round, "ZM:C_q_" + idx, size_G); +// } +// manifest_expected.add_challenge(round, "ZM:y"); + +// round++; +// manifest_expected.add_entry(round, "ZM:C_q", size_G); +// manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); + +// round++; +// // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors +// manifest_expected.add_entry(round, "ZM:PI", size_G); +// manifest_expected.add_challenge(round); // no challenge + +// return manifest_expected; +// } + +// void generate_test_circuit(auto& builder) +// { +// FF a = 1; +// builder.add_variable(a); +// builder.add_public_variable(a); +// } + +// void generate_random_test_circuit(auto& builder) +// { +// auto a = FF::random_element(); +// auto b = FF::random_element(); +// builder.add_variable(a); +// builder.add_public_variable(a); +// builder.add_public_variable(b); +// } +// }; + +// /** +// * @brief Ensure consistency between the manifest hard coded in this testing suite and the one generated by the +// * standard honk prover over the course of proof construction. +// */ +// TEST_F(UltraTranscriptTests, ProverManifestConsistency) +// { +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto builder = typename Flavor::CircuitBuilder(); +// generate_test_circuit(builder); + +// // Automatically generate a transcript manifest by constructing a proof +// auto composer = UltraComposer(); +// auto instance = composer.create_instance(builder); +// auto prover = composer.create_prover(instance); +// auto proof = prover.construct_proof(); + +// // Check that the prover generated manifest agrees with the manifest hard coded in this suite +// auto manifest_expected = construct_ultra_honk_manifest(instance->proving_key->circuit_size); +// auto prover_manifest = prover.transcript.get_manifest(); +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < manifest_expected.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << +// round; +// } +// } + +// /** +// * @brief Ensure consistency between the manifest generated by the ultra honk prover over the course of proof +// * construction and the one generated by the verifier over the course of proof verification. +// * +// */ +// TEST_F(UltraTranscriptTests, VerifierManifestConsistency) +// { + +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto builder = Flavor::CircuitBuilder(); +// generate_test_circuit(builder); + +// // Automatically generate a transcript manifest in the prover by constructing a proof +// auto composer = UltraComposer(); +// auto instance = composer.create_instance(builder); +// auto prover = composer.create_prover(instance); +// auto proof = prover.construct_proof(); + +// // Automatically generate a transcript manifest in the verifier by verifying a proof +// auto verifier = composer.create_verifier(instance); +// verifier.verify_proof(proof); + +// // Check consistency between the manifests generated by the prover and verifier +// auto prover_manifest = prover.transcript.get_manifest(); +// auto verifier_manifest = verifier.transcript.get_manifest(); + +// // Note: a manifest can be printed using manifest.print() +// for (size_t round = 0; round < prover_manifest.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) +// << "Prover/Verifier manifest discrepency in round " << round; +// } +// } + +// /** +// * @brief Check that multiple challenges can be generated and sanity check +// * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. +// * +// */ +// TEST_F(UltraTranscriptTests, ChallengeGenerationTest) +// { +// // initialized with random value sent to verifier +// auto transcript = Flavor::Transcript::prover_init_empty(); +// // test a bunch of challenges +// auto challenges = transcript.get_challenges("a", "b", "c", "d", "e", "f"); +// // check they are not 0 +// for (size_t i = 0; i < challenges.size(); ++i) { +// ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; +// } +// constexpr uint32_t random_val{ 17 }; // arbitrary +// transcript.send_to_verifier("random val", random_val); +// // test more challenges +// auto [a, b, c] = transcript.get_challenges("a", "b", "c"); +// ASSERT_NE(a, 0) << "Challenge a is 0"; +// ASSERT_NE(b, 0) << "Challenge a is 0"; +// ASSERT_NE(b, 0) << "Challenge a is 0"; +// } + +// TEST_F(UltraTranscriptTests, StructureTest) +// { +// // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) +// auto builder = typename Flavor::CircuitBuilder(); +// generate_test_circuit(builder); + +// // Automatically generate a transcript manifest by constructing a proof +// auto composer = UltraComposer(); +// auto instance = composer.create_instance(builder); +// auto prover = composer.create_prover(instance); +// auto proof = prover.construct_proof(); +// auto verifier = composer.create_verifier(instance); +// EXPECT_TRUE(verifier.verify_proof(proof)); + +// // try deserializing and serializing with no changes and check proof is still valid +// prover.transcript.deserialize_full_transcript(); +// prover.transcript.serialize_full_transcript(); +// EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid + +// Flavor::Commitment one_group_val = Flavor::Commitment::one(); +// FF rand_val = FF::random_element(); +// prover.transcript.sorted_accum_comm = one_group_val * rand_val; // choose random object to modify +// EXPECT_TRUE(verifier.verify_proof( +// prover.export_proof())); // we have not serialized it back to the proof so it should still be fine + +// prover.transcript.serialize_full_transcript(); +// EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it + +// prover.transcript.deserialize_full_transcript(); +// EXPECT_EQ(static_cast(prover.transcript.sorted_accum_comm), one_group_val * rand_val); +// } + +// TEST_F(UltraTranscriptTests, FoldingManifestTest) +// { +// using Flavor = flavor::Ultra; +// auto composer = UltraComposer(); + +// std::vector>> insts(2); +// std::generate(insts.begin(), insts.end(), [&]() { +// auto builder = proof_system::UltraCircuitBuilder(); +// generate_random_test_circuit(builder); +// return composer.create_instance(builder); +// }); + +// // artificially make first instance relaxed +// auto log_instance_size = static_cast(numeric::get_msb(insts[0]->proving_key->circuit_size)); +// std::vector betas(log_instance_size); +// for (size_t idx = 0; idx < log_instance_size; idx++) { +// betas[idx] = FF::random_element(); +// } +// insts[0]->folding_parameters = { betas, FF(1) }; + +// auto prover = composer.create_folding_prover(insts); +// auto verifier = composer.create_folding_verifier(insts); + +// auto prover_res = prover.fold_instances(); +// verifier.fold_public_parameters(prover_res.folding_data); + +// // Check consistency between the manifests generated by the prover and verifier +// auto prover_manifest = prover.transcript.get_manifest(); +// auto verifier_manifest = verifier.transcript.get_manifest(); +// for (size_t round = 0; round < prover_manifest.size(); ++round) { +// ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) +// << "Prover/Verifier manifest discrepency in round " << round; +// } +// } diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp index 628a910b21b..968f5812a77 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp @@ -1,6 +1,5 @@ #pragma once #include "barretenberg/honk/pcs/kzg/kzg.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" @@ -11,6 +10,7 @@ #include "barretenberg/proof_system/relations/lookup_relation.hpp" #include "barretenberg/proof_system/relations/permutation_relation.hpp" #include "barretenberg/proof_system/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk::flavor { diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp index ee4479fe7d1..3598048811d 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp @@ -6,7 +6,6 @@ #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/honk/flavor/goblin_ultra.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" @@ -19,6 +18,7 @@ #include "barretenberg/proof_system/relations/permutation_relation.hpp" #include "barretenberg/proof_system/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/srs/factories/crs_factory.hpp" +#include "barretenberg/transcript/transcript.hpp" #include #include #include diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp index 36c7aff3301..e647fbe520e 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp @@ -1,7 +1,6 @@ #pragma once #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/pcs/kzg/kzg.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/barycentric.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" @@ -14,6 +13,7 @@ #include "barretenberg/proof_system/relations/lookup_relation.hpp" #include "barretenberg/proof_system/relations/permutation_relation.hpp" #include "barretenberg/proof_system/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk::flavor { diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra_recursive.hpp index 077d5a49c9c..191730c98c1 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra_recursive.hpp @@ -6,7 +6,6 @@ #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/honk/flavor/ultra.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" @@ -18,6 +17,7 @@ #include "barretenberg/proof_system/relations/permutation_relation.hpp" #include "barretenberg/proof_system/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/srs/factories/crs_factory.hpp" +#include "barretenberg/transcript/transcript.hpp" #include #include diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp index 3f70e9d4789..a32356b36c3 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/commitment_key.test.hpp @@ -1,22 +1,17 @@ #pragma once -#include -#include - -#include -#include -#include -#include - #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/pcs/verification_key.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" - -#include "../../transcript/transcript_wrappers.hpp" - #include "claim.hpp" +#include +#include +#include +#include + +#include namespace proof_system::honk::pcs { diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp index 526c7bd84d2..f9c370bf3e7 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp @@ -1,8 +1,8 @@ #pragma once #include "../claim.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/transcript/transcript.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp index d5c6fa7e2a1..203ebb523e2 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp @@ -1,8 +1,8 @@ #include "gemini.hpp" #include "../commitment_key.test.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/transcript/transcript.hpp" #include #include #include diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp index aeafa456ec7..700bfa7269d 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp @@ -3,7 +3,7 @@ #include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/honk/pcs/claim.hpp" #include "barretenberg/honk/pcs/verification_key.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/transcript/transcript.hpp" #include #include #include diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp index 5fe179482e3..d818e798f8b 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp @@ -3,8 +3,8 @@ #include "../claim.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/pcs/verification_key.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/transcript/transcript.hpp" #include #include diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp index 784641012e1..9e4ccf701aa 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp @@ -2,7 +2,7 @@ #include "barretenberg/honk/pcs/claim.hpp" #include "barretenberg/honk/pcs/commitment_key.hpp" #include "barretenberg/honk/pcs/verification_key.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/transcript/transcript.hpp" /** * @brief Reduces multiple claims about commitments, each opened at a single point diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp index 2af0af8c2ed..82b6191eca2 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp @@ -1,6 +1,6 @@ #include "zeromorph.hpp" #include "../commitment_key.test.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/transcript/transcript.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.cpp index b2561b7fdca..649f8a9e078 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.cpp @@ -9,7 +9,6 @@ #include "barretenberg/polynomials/univariate.hpp" // will go away #include "barretenberg/proof_system/relations/lookup_relation.hpp" #include "barretenberg/proof_system/relations/permutation_relation.hpp" -#include "barretenberg/transcript/transcript_wrappers.hpp" #include #include #include diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.hpp index b0e63b907d2..01bf9330310 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.hpp @@ -3,9 +3,9 @@ #include "barretenberg/honk/pcs/gemini/gemini.hpp" #include "barretenberg/honk/pcs/shplonk/shplonk.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/proof_system/relations/relation_parameters.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk { diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.cpp index 76d17e59e54..0446a8758f1 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.cpp @@ -1,9 +1,9 @@ #include "./eccvm_verifier.hpp" #include "barretenberg/honk/pcs/gemini/gemini.hpp" #include "barretenberg/honk/pcs/shplonk/shplonk.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/transcript/transcript.hpp" using namespace barretenberg; using namespace proof_system::honk::sumcheck; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_prover.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_prover.hpp index 7d0d2cc05fd..aef88482292 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_prover.hpp @@ -3,9 +3,9 @@ #include "barretenberg/honk/flavor/goblin_ultra.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/pcs/claim.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk { diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.hpp index c0ff00b2cab..548e41c77f0 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.hpp @@ -3,9 +3,9 @@ #include "barretenberg/honk/flavor/goblin_ultra.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/pcs/claim.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk { diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.hpp index faa6993cec7..145f44dc87e 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.hpp @@ -3,8 +3,8 @@ #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/instance/instances.hpp" #include "barretenberg/honk/proof_system/folding_result.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk { template class ProtoGalaxyVerifier_ { diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index 1bb0f391e11..c1e5aacf245 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -4,9 +4,9 @@ #include "barretenberg/honk/instance/prover_instance.hpp" #include "barretenberg/honk/pcs/zeromorph/zeromorph.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/proof_system/relations/relation_parameters.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::honk { diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index ab2fb367b91..1062e1af86f 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -1,8 +1,8 @@ #include "./ultra_verifier.hpp" #include "barretenberg/honk/pcs/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/transcript/transcript.hpp" using namespace barretenberg; using namespace proof_system::honk::sumcheck; diff --git a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp index 4282bce0a30..40e0d09b664 100644 --- a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp @@ -3,10 +3,10 @@ #include "barretenberg/common/throw_or_abort.hpp" #include "barretenberg/honk/instance/prover_instance.hpp" #include "barretenberg/honk/sumcheck/sumcheck_output.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/grand_product_delta.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/relations/relation_parameters.hpp" +#include "barretenberg/transcript/transcript.hpp" #include "sumcheck_round.hpp" namespace proof_system::honk::sumcheck { diff --git a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp index dd3867664ce..35ced6e72ef 100644 --- a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp @@ -2,7 +2,6 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/honk/composer/ultra_composer.hpp" #include "barretenberg/honk/proof_system/grand_product_library.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/proof_system/plookup_tables/fixed_base/fixed_base.hpp" #include "barretenberg/proof_system/relations/auxiliary_relation.hpp" #include "barretenberg/proof_system/relations/elliptic_relation.hpp" @@ -10,6 +9,7 @@ #include "barretenberg/proof_system/relations/lookup_relation.hpp" #include "barretenberg/proof_system/relations/permutation_relation.hpp" #include "barretenberg/proof_system/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/transcript/transcript.hpp" #include using namespace proof_system::honk; diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp deleted file mode 100644 index bd4b88b8df3..00000000000 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/honk/composer/eccvm_composer.hpp" -#include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/proof_system/flavor/flavor.hpp" -#include "transcript.hpp" -#include - -using namespace proof_system::honk; - -template class ECCVMTranscriptTests : public ::testing::Test { - public: - void SetUp() override - { - if constexpr (std::is_same::value) { - barretenberg::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); - } else { - barretenberg::srs::init_crs_factory("../srs_db/ignition"); - } - }; - using FF = typename Flavor::FF; - - /** - * @brief Construct a manifest for a ECCVM Honk proof - * - * @details This is where we define the "Manifest" for a ECCVM Honk proof. The tests in this suite are - * intented to warn the developer if the Prover/Verifier has deviated from this manifest, however, the - * Transcript class is not otherwise contrained to follow the manifest. - * - * @note Entries in the manifest consist of a name string and a size (bytes), NOT actual data. - * - * @return TranscriptManifest - */ - TranscriptManifest construct_eccvm_honk_manifest(size_t circuit_size, size_t ipa_poly_degree) - { - TranscriptManifest manifest_expected; - - auto log_n = numeric::get_msb(circuit_size); - - size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; - size_t size_FF = sizeof(FF); - size_t size_G = 2 * size_FF; - size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; - size_t size_evals = (Flavor::NUM_ALL_ENTITIES)*size_FF; - size_t size_uint32 = 4; - size_t size_uint64 = 8; - - size_t round = 0; - manifest_expected.add_entry(round, "circuit_size", size_uint32); - manifest_expected.add_entry(round, "TRANSCRIPT_ADD", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_MUL", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_EQ", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_COLLISION_CHECK", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_MSM_TRANSITION", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_PC", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_X", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_Y", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_Z1", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_Z2", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_Z1ZERO", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_Z2ZERO", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_OP", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_X", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_Y", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_MSM_X", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_MSM_Y", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_PC", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_POINT_TRANSITION", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_ROUND", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_SCALAR_SUM", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S1HI", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S1LO", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S2HI", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S2LO", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S3HI", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S3LO", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S4HI", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_S4LO", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_SKEW", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_DX", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_DY", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_TX", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_TY", size_G); - manifest_expected.add_entry(round, "MSM_TRANSITION", size_G); - manifest_expected.add_entry(round, "MSM_ADD", size_G); - manifest_expected.add_entry(round, "MSM_DOUBLE", size_G); - manifest_expected.add_entry(round, "MSM_SKEW", size_G); - manifest_expected.add_entry(round, "MSM_ACCUMULATOR_X", size_G); - manifest_expected.add_entry(round, "MSM_ACCUMULATOR_Y", size_G); - manifest_expected.add_entry(round, "MSM_PC", size_G); - manifest_expected.add_entry(round, "MSM_SIZE_OF_MSM", size_G); - manifest_expected.add_entry(round, "MSM_COUNT", size_G); - manifest_expected.add_entry(round, "MSM_ROUND", size_G); - manifest_expected.add_entry(round, "MSM_ADD1", size_G); - manifest_expected.add_entry(round, "MSM_ADD2", size_G); - manifest_expected.add_entry(round, "MSM_ADD3", size_G); - manifest_expected.add_entry(round, "MSM_ADD4", size_G); - manifest_expected.add_entry(round, "MSM_X1", size_G); - manifest_expected.add_entry(round, "MSM_Y1", size_G); - manifest_expected.add_entry(round, "MSM_X2", size_G); - manifest_expected.add_entry(round, "MSM_Y2", size_G); - manifest_expected.add_entry(round, "MSM_X3", size_G); - manifest_expected.add_entry(round, "MSM_Y3", size_G); - manifest_expected.add_entry(round, "MSM_X4", size_G); - manifest_expected.add_entry(round, "MSM_Y4", size_G); - manifest_expected.add_entry(round, "MSM_COLLISION_X1", size_G); - manifest_expected.add_entry(round, "MSM_COLLISION_X2", size_G); - manifest_expected.add_entry(round, "MSM_COLLISION_X3", size_G); - manifest_expected.add_entry(round, "MSM_COLLISION_X4", size_G); - manifest_expected.add_entry(round, "MSM_LAMBDA1", size_G); - manifest_expected.add_entry(round, "MSM_LAMBDA2", size_G); - manifest_expected.add_entry(round, "MSM_LAMBDA3", size_G); - manifest_expected.add_entry(round, "MSM_LAMBDA4", size_G); - manifest_expected.add_entry(round, "MSM_SLICE1", size_G); - manifest_expected.add_entry(round, "MSM_SLICE2", size_G); - manifest_expected.add_entry(round, "MSM_SLICE3", size_G); - manifest_expected.add_entry(round, "MSM_SLICE4", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_EMPTY", size_G); - manifest_expected.add_entry(round, "TRANSCRIPT_RESET_ACCUMULATOR", size_G); - manifest_expected.add_entry(round, "PRECOMPUTE_SELECT", size_G); - manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS_0", size_G); - manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS_1", size_G); - manifest_expected.add_challenge(round, "beta", "gamma"); - - round++; - manifest_expected.add_entry(round, "LOOKUP_INVERSES", size_G); - manifest_expected.add_entry(round, "Z_PERM", size_G); - manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); - - for (size_t i = 0; i < log_n; ++i) { - round++; - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); - std::string label = "Sumcheck:u_" + idx; - manifest_expected.add_challenge(round, label); - } - - round++; - manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); - manifest_expected.add_challenge(round, "rho"); - - round++; - for (size_t i = 1; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, size_G); - } - manifest_expected.add_challenge(round, "Gemini:r"); - - round++; - for (size_t i = 0; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:a_" + idx, size_FF); - } - manifest_expected.add_challenge(round, "Shplonk:nu"); - - round++; - manifest_expected.add_entry(round, "Shplonk:Q", size_G); - manifest_expected.add_challenge(round, "Shplonk:z"); - - // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors - if constexpr (proof_system::IsGrumpkinFlavor) { - round++; - manifest_expected.add_entry(round, "IPA:poly_degree", size_uint64); - manifest_expected.add_challenge(round, "IPA:generator_challenge"); - - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { - round++; - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "IPA:L_" + idx, size_G); - manifest_expected.add_entry(round, "IPA:R_" + idx, size_G); - std::string label = "IPA:round_challenge_" + idx; - manifest_expected.add_challenge(round, label); - } - - round++; - manifest_expected.add_entry(round, "IPA:a_0", size_FF); - } else { - round++; - manifest_expected.add_entry(round, "KZG:W", size_G); - } - - return manifest_expected; - } - proof_system::ECCVMCircuitBuilder generate_trace(numeric::random::Engine* engine = nullptr) - { - proof_system::ECCVMCircuitBuilder result; - using G1 = typename Flavor::CycleGroup; - using Fr = typename G1::Fr; - - auto generators = G1::derive_generators("test generators", 3); - - typename G1::element a = generators[0]; - typename G1::element b = generators[1]; - typename G1::element c = generators[2]; - Fr x = Fr::random_element(engine); - Fr y = Fr::random_element(engine); - - typename G1::element expected_1 = (a * x) + a + a + (b * y) + (b * x) + (b * x); - typename G1::element expected_2 = (a * x) + c + (b * x); - - result.add_accumulate(a); - result.mul_accumulate(a, x); - result.mul_accumulate(b, x); - result.mul_accumulate(b, y); - result.add_accumulate(a); - result.mul_accumulate(b, x); - result.eq_and_reset(expected_1); - result.add_accumulate(c); - result.mul_accumulate(a, x); - result.mul_accumulate(b, x); - result.eq_and_reset(expected_2); - result.mul_accumulate(a, x); - result.mul_accumulate(b, x); - result.mul_accumulate(c, x); - - return result; - } -}; - -numeric::random::Engine& engine = numeric::random::get_debug_engine(); - -using FlavorTypes = testing::Types; - -TYPED_TEST_SUITE(ECCVMTranscriptTests, FlavorTypes); -/** - * @brief Ensure consistency between the manifest hard coded in this testing suite and the one generated by the - * standard honk prover over the course of proof construction. - */ -TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) -{ - using Flavor = TypeParam; - - // Construct a simple circuit - auto builder = this->generate_trace(&engine); - - // Automatically generate a transcript manifest by constructing a proof - auto composer = ECCVMComposer_(); - auto prover = composer.create_prover(builder); - auto proof = prover.construct_proof(); - - // Check that the prover generated manifest agrees with the manifest hard coded in this suite - auto manifest_expected = - this->construct_eccvm_honk_manifest(prover.key->circuit_size, prover.shplonk_output.witness.size()); - auto prover_manifest = prover.transcript.get_manifest(); - - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < manifest_expected.size(); ++round) { - ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; - } -} - -/** - * @brief Ensure consistency between the manifest generated by the ECCVM honk prover over the course of proof - * construction and the one generated by the verifier over the course of proof verification. - * - */ -TYPED_TEST(ECCVMTranscriptTests, VerifierManifestConsistency) -{ - using Flavor = TypeParam; - - // Construct a simple circuit - auto builder = this->generate_trace(&engine); - - // Automatically generate a transcript manifest in the prover by constructing a proof - auto composer = ECCVMComposer_(); - auto prover = composer.create_prover(builder); - auto proof = prover.construct_proof(); - - // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(builder); - verifier.verify_proof(proof); - - // Check consistency between the manifests generated by the prover and verifier - auto prover_manifest = prover.transcript.get_manifest(); - auto verifier_manifest = verifier.transcript.get_manifest(); - - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < prover_manifest.size(); ++round) { - ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) - << "Prover/Verifier manifest discrepency in round " << round; - } -} - -/** - * @brief Check that multiple challenges can be generated and sanity check - * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. - * - */ -TYPED_TEST(ECCVMTranscriptTests, ChallengeGenerationTest) -{ - using Flavor = TypeParam; - // initialized with random value sent to verifier - auto transcript = Flavor::Transcript::prover_init_empty(); - // test a bunch of challenges - auto challenges = transcript.get_challenges("a", "b", "c", "d", "e", "f"); - // check they are not 0 - for (size_t i = 0; i < challenges.size(); ++i) { - ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; - } - constexpr uint32_t random_val{ 17 }; // arbitrary - transcript.send_to_verifier("random val", random_val); - // test more challenges - auto [a, b, c] = transcript.get_challenges("a", "b", "c"); - ASSERT_NE(a, 0) << "Challenge a is 0"; - ASSERT_NE(b, 0) << "Challenge a is 0"; - ASSERT_NE(b, 0) << "Challenge a is 0"; -} - -TYPED_TEST(ECCVMTranscriptTests, StructureTest) -{ - using Flavor = TypeParam; - - // Construct a simple circuit - auto builder = this->generate_trace(&engine); - - // Automatically generate a transcript manifest by constructing a proof - auto composer = ECCVMComposer_(); - auto prover = composer.create_prover(builder); - auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(builder); - EXPECT_TRUE(verifier.verify_proof(proof)); - - // try deserializing and serializing with no changes and check proof is still valid - prover.transcript.deserialize_full_transcript(); - prover.transcript.serialize_full_transcript(); - EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid - - typename Flavor::Commitment one_group_val = Flavor::Commitment::one(); - typename Flavor::FF rand_val = Flavor::FF::random_element(); - prover.transcript.transcript_x_comm = one_group_val * rand_val; // choose random object to modify - EXPECT_TRUE(verifier.verify_proof( - prover.export_proof())); // we have not serialized it back to the proof so it should still be fine - - prover.transcript.serialize_full_transcript(); - EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it - - prover.transcript.deserialize_full_transcript(); - EXPECT_EQ(static_cast(prover.transcript.transcript_x_comm), one_group_val * rand_val); -} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp deleted file mode 100644 index c1d07a642f5..00000000000 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp +++ /dev/null @@ -1,233 +0,0 @@ -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/honk/composer/ultra_composer.hpp" -#include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/proof_system/flavor/flavor.hpp" -#include "transcript.hpp" -#include - -using namespace proof_system::honk; - -class GoblinUltraTranscriptTests : public ::testing::Test { - public: - static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } - - using Flavor = proof_system::honk::flavor::GoblinUltra; - using FF = Flavor::FF; - - /** - * @brief Construct a manifest for a GoblinUltra Honk proof - * - * @details This is where we define the "Manifest" for a GoblinUltra Honk proof. The tests in this suite are - * intented to warn the developer if the Prover/Verifier has deviated from this manifest, however, the - * Transcript class is not otherwise contrained to follow the manifest. - * - * @note Entries in the manifest consist of a name string and a size (bytes), NOT actual data. - * - * @return TranscriptManifest - */ - TranscriptManifest construct_goblin_ultra_honk_manifest(size_t circuit_size) - { - TranscriptManifest manifest_expected; - - auto log_n = numeric::get_msb(circuit_size); - - size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; - size_t size_FF = sizeof(FF); - size_t size_G = 2 * size_FF; - size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; - size_t size_evals = (Flavor::NUM_ALL_ENTITIES)*size_FF; - size_t size_uint32 = 4; - - size_t round = 0; - manifest_expected.add_entry(round, "circuit_size", size_uint32); - manifest_expected.add_entry(round, "public_input_size", size_uint32); - manifest_expected.add_entry(round, "pub_inputs_offset", size_uint32); - manifest_expected.add_entry(round, "public_input_0", size_FF); - manifest_expected.add_entry(round, "W_L", size_G); - manifest_expected.add_entry(round, "W_R", size_G); - manifest_expected.add_entry(round, "W_O", size_G); - manifest_expected.add_entry(round, "ECC_OP_WIRE_1", size_G); - manifest_expected.add_entry(round, "ECC_OP_WIRE_2", size_G); - manifest_expected.add_entry(round, "ECC_OP_WIRE_3", size_G); - manifest_expected.add_entry(round, "ECC_OP_WIRE_4", size_G); - manifest_expected.add_challenge(round, "eta"); - - round++; - manifest_expected.add_entry(round, "SORTED_ACCUM", size_G); - manifest_expected.add_entry(round, "W_4", size_G); - manifest_expected.add_challenge(round, "beta", "gamma"); - - round++; - manifest_expected.add_entry(round, "Z_PERM", size_G); - manifest_expected.add_entry(round, "Z_LOOKUP", size_G); - manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); - - for (size_t i = 0; i < log_n; ++i) { - round++; - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); - std::string label = "Sumcheck:u_" + idx; - manifest_expected.add_challenge(round, label); - } - - round++; - manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); - manifest_expected.add_challenge(round, "rho"); - - round++; - for (size_t i = 0; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "ZM:C_q_" + idx, size_G); - } - manifest_expected.add_challenge(round, "ZM:y"); - - round++; - manifest_expected.add_entry(round, "ZM:C_q", size_G); - manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); - - round++; - // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors - manifest_expected.add_entry(round, "ZM:PI", size_G); - manifest_expected.add_challenge(round); // no challenge - - return manifest_expected; - } - - void generate_test_circuit(auto& builder) - { - // Add some ecc op gates - for (size_t i = 0; i < 3; ++i) { - auto point = Flavor::Curve::AffineElement::one() * FF::random_element(); - auto scalar = FF::random_element(); - builder.queue_ecc_mul_accum(point, scalar); - } - builder.queue_ecc_eq(); - - // Add one conventional gates that utilize public inputs - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); - FF d = a + b + c; - uint32_t a_idx = builder.add_public_variable(a); - uint32_t b_idx = builder.add_variable(b); - uint32_t c_idx = builder.add_variable(c); - uint32_t d_idx = builder.add_variable(d); - - builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); - } -}; - -/** - * @brief Ensure consistency between the manifest hard coded in this testing suite and the one generated by the - * standard honk prover over the course of proof construction. - */ -TEST_F(GoblinUltraTranscriptTests, ProverManifestConsistency) -{ - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); - generate_test_circuit(builder); - - // Automatically generate a transcript manifest by constructing a proof - auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); - auto proof = prover.construct_proof(); - - // Check that the prover generated manifest agrees with the manifest hard coded in this suite - auto manifest_expected = construct_goblin_ultra_honk_manifest(instance->proving_key->circuit_size); - auto prover_manifest = prover.transcript.get_manifest(); - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < manifest_expected.size(); ++round) { - ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; - } -} - -/** - * @brief Ensure consistency between the manifest generated by the goblin ultra honk prover over the course of proof - * construction and the one generated by the verifier over the course of proof verification. - * - */ -TEST_F(GoblinUltraTranscriptTests, VerifierManifestConsistency) -{ - - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = Flavor::CircuitBuilder(); - generate_test_circuit(builder); - - // Automatically generate a transcript manifest in the prover by constructing a proof - auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); - auto proof = prover.construct_proof(); - - // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance); - verifier.verify_proof(proof); - - // Check consistency between the manifests generated by the prover and verifier - auto prover_manifest = prover.transcript.get_manifest(); - auto verifier_manifest = verifier.transcript.get_manifest(); - - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < prover_manifest.size(); ++round) { - ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) - << "Prover/Verifier manifest discrepency in round " << round; - } -} - -/** - * @brief Check that multiple challenges can be generated and sanity check - * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. - * - */ -TEST_F(GoblinUltraTranscriptTests, ChallengeGenerationTest) -{ - // initialized with random value sent to verifier - auto transcript = Flavor::Transcript::prover_init_empty(); - // test a bunch of challenges - auto challenges = transcript.get_challenges("a", "b", "c", "d", "e", "f"); - // check they are not 0 - for (size_t i = 0; i < challenges.size(); ++i) { - ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; - } - constexpr uint32_t random_val{ 17 }; // arbitrary - transcript.send_to_verifier("random val", random_val); - // test more challenges - auto [a, b, c] = transcript.get_challenges("a", "b", "c"); - ASSERT_NE(a, 0) << "Challenge a is 0"; - ASSERT_NE(b, 0) << "Challenge a is 0"; - ASSERT_NE(b, 0) << "Challenge a is 0"; -} - -TEST_F(GoblinUltraTranscriptTests, StructureTest) -{ - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); - generate_test_circuit(builder); - - // Automatically generate a transcript manifest by constructing a proof - auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); - auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); - EXPECT_TRUE(verifier.verify_proof(proof)); - - // try deserializing and serializing with no changes and check proof is still valid - prover.transcript.deserialize_full_transcript(); - prover.transcript.serialize_full_transcript(); - EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid - - Flavor::Commitment one_group_val = Flavor::Commitment::one(); - FF rand_val = FF::random_element(); - prover.transcript.sorted_accum_comm = one_group_val * rand_val; // choose random object to modify - EXPECT_TRUE(verifier.verify_proof( - prover.export_proof())); // we have not serialized it back to the proof so it should still be fine - - prover.transcript.serialize_full_transcript(); - EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it - - prover.transcript.deserialize_full_transcript(); - EXPECT_EQ(static_cast(prover.transcript.sorted_accum_comm), one_group_val * rand_val); -} diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.hpp deleted file mode 100644 index c7d4123a332..00000000000 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.hpp +++ /dev/null @@ -1,331 +0,0 @@ -#pragma once - -#include "barretenberg/common/serialize.hpp" -#include "barretenberg/crypto/blake3s/blake3s.hpp" -#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace proof_system::honk { - -class TranscriptManifest { - struct RoundData { - std::vector challenge_label; - std::vector> entries; - - bool operator==(const RoundData& other) const = default; - }; - - std::map manifest; - - public: - void print() - { - for (auto& round : manifest) { - info("Round: ", round.first); - for (auto& label : round.second.challenge_label) { - info("\tchallenge: ", label); - } - for (auto& entry : round.second.entries) { - info("\telement (", entry.second, "): ", entry.first); - } - } - } - - template void add_challenge(size_t round, Strings&... labels) - { - manifest[round].challenge_label = { labels... }; - } - void add_entry(size_t round, std::string element_label, size_t element_size) - { - manifest[round].entries.emplace_back(element_label, element_size); - } - - [[nodiscard]] size_t size() const { return manifest.size(); } - - RoundData operator[](const size_t& round) { return manifest[round]; }; - - bool operator==(const TranscriptManifest& other) const = default; -}; - -/** - * @brief Common transcript class for both parties. Stores the data for the current round, as well as the - * manifest. - * - * @tparam FF Field from which we sample challenges. - */ -template class BaseTranscript { - // TODO(Adrian): Make these tweakable - public: - BaseTranscript() = default; - - /** - * @brief Construct a new Base Transcript object for Verifier using proof_data - * - * @param proof_data - */ - explicit BaseTranscript(const std::vector& proof_data) - : proof_data(proof_data.begin(), proof_data.end()) - {} - static constexpr size_t HASH_OUTPUT_SIZE = 32; - - private: - static constexpr size_t MIN_BYTES_PER_CHALLENGE = 128 / 8; // 128 bit challenges - - size_t num_bytes_read = 0; // keeps track of number of bytes read from proof_data by the verifier - size_t round_number = 0; // current round for manifest - bool is_first_challenge = true; // indicates if this is the first challenge this transcript is generating - std::array previous_challenge_buffer{}; // default-initialized to zeros - std::vector current_round_data; - - // "Manifest" object that records a summary of the transcript interactions - TranscriptManifest manifest; - - /** - * @brief Compute next challenge c_next = H( Compress(c_prev || round_buffer) ) - * @details This function computes a new challenge for the current round using the previous challenge - * and the current round data, if they are exist. It clears the current_round_data if nonempty after - * computing the challenge to minimize how much we compress. It also sets previous_challenge_buffer - * to the current challenge buffer to set up next function call. - * @return std::array - */ - [[nodiscard]] std::array get_next_challenge_buffer() - { - // Prevent challenge generation if this is the first challenge we're generating, - // AND nothing was sent by the prover. - if (is_first_challenge) { - ASSERT(!current_round_data.empty()); - } - - // concatenate the previous challenge (if this is not the first challenge) with the current round data. - // TODO(Adrian): Do we want to use a domain separator as the initial challenge buffer? - // We could be cheeky and use the hash of the manifest as domain separator, which would prevent us from having - // to domain separate all the data. (See https://safe-hash.dev) - std::vector full_buffer; - if (!is_first_challenge) { - // if not the first challenge, we can use the previous_challenge_buffer - full_buffer.insert(full_buffer.end(), previous_challenge_buffer.begin(), previous_challenge_buffer.end()); - } else { - // Update is_first_challenge for the future - is_first_challenge = false; - } - if (!current_round_data.empty()) { - full_buffer.insert(full_buffer.end(), current_round_data.begin(), current_round_data.end()); - current_round_data.clear(); // clear the round data buffer since it has been used - } - - // Pre-hash the full buffer to minimize the amount of data passed to the cryptographic hash function. - // Only a collision-resistant hash-function like Pedersen is required for this step. - // Note: this pre-hashing is an efficiency trick that may be discareded if using a SNARK-friendly or in contexts - // (eg smart contract verification) where the cost of elliptic curve operations is high. - std::vector compressed_buffer = to_buffer(crypto::pedersen_hash::hash_buffer(full_buffer)); - - // Use a strong hash function to derive the new challenge_buffer. - auto base_hash = blake3::blake3s(compressed_buffer); - - std::array new_challenge_buffer; - std::copy_n(base_hash.begin(), HASH_OUTPUT_SIZE, new_challenge_buffer.begin()); - // update previous challenge buffer for next time we call this function - previous_challenge_buffer = new_challenge_buffer; - return new_challenge_buffer; - }; - - protected: - /** - * @brief Adds challenge elements to the current_round_buffer and updates the manifest. - * - * @param label of the element sent - * @param element_bytes serialized - */ - void consume_prover_element_bytes(const std::string& label, std::span element_bytes) - { - // Add an entry to the current round of the manifest - manifest.add_entry(round_number, label, element_bytes.size()); - - current_round_data.insert(current_round_data.end(), element_bytes.begin(), element_bytes.end()); - } - - /** - * @brief Serializes object and appends it to proof_data - * @details Calls to_buffer on element to serialize, and modifies proof_data object by appending the serialized - * bytes to it. - * @tparam T - * @param element - * @param proof_data - */ - template void serialize_to_buffer(const T& element, std::vector& proof_data) - { - auto element_bytes = to_buffer(element); - proof_data.insert(proof_data.end(), element_bytes.begin(), element_bytes.end()); - } - /** - * @brief Deserializes the bytes starting at offset into the typed element and returns that element. - * @details Using the template parameter and the offset argument, this function deserializes the bytes with - * from_buffer and then increments the offset appropriately based on the number of bytes that were deserialized. - * @tparam T - * @param proof_data - * @param offset - * @return T - */ - template T deserialize_from_buffer(const std::vector& proof_data, size_t& offset) const - { - constexpr size_t element_size = sizeof(T); - ASSERT(offset + element_size <= proof_data.size()); - - auto element_bytes = std::span{ proof_data }.subspan(offset, element_size); - offset += element_size; - - T element = from_buffer(element_bytes); - - return element; - } - - public: - // Contains the raw data sent by the prover. - std::vector proof_data; - /** - * @brief After all the prover messages have been sent, finalize the round by hashing all the data and then create - * the number of requested challenges. - * @details Challenges are generated by iteratively hashing over the previous challenge, using - * get_next_challenge_buffer(). - * TODO(#741): Optimizations for this function include generalizing type of hash, splitting hashes into - * multiple challenges. - * - * @param labels human-readable names for the challenges for the manifest - * @return std::array challenges for this round. - */ - template std::array get_challenges(const Strings&... labels) - { - constexpr size_t num_challenges = sizeof...(Strings); - - // Add challenge labels for current round to the manifest - manifest.add_challenge(round_number, labels...); - - // Compute the new challenge buffer from which we derive the challenges. - - // Create challenges from bytes. - std::array challenges{}; - - // Generate the challenges by iteratively hashing over the previous challenge. - for (size_t i = 0; i < num_challenges; i++) { - auto next_challenge_buffer = get_next_challenge_buffer(); // get next challenge buffer - std::array field_element_buffer{}; - // copy half of the hash to lower 128 bits of challenge - // Note: because of how read() from buffers to fields works (in field_declarations.hpp), - // we use the later half of the buffer - std::copy_n(next_challenge_buffer.begin(), - HASH_OUTPUT_SIZE / 2, - field_element_buffer.begin() + HASH_OUTPUT_SIZE / 2); - challenges[i] = from_buffer(field_element_buffer); - } - - // Prepare for next round. - ++round_number; - - return challenges; - } - - /** - * @brief Adds a prover message to the transcript, only intended to be used by the prover. - * - * @details Serializes the provided object into `proof_data`, and updates the current round state in - * consume_prover_element_bytes. - * - * @param label Description/name of the object being added. - * @param element Serializable object that will be added to the transcript - * - * @todo Use a concept to only allow certain types to be passed. Requirements are that the object should be - * serializable. - * - */ - template void send_to_verifier(const std::string& label, const T& element) - { - using serialize::write; - // TODO(Adrian): Ensure that serialization of affine elements (including point at infinity) is consistent. - // TODO(Adrian): Consider restricting serialization (via concepts) to types T for which sizeof(T) reliably - // returns the size of T in bytes. (E.g. this is true for std::array but not for std::vector). - auto element_bytes = to_buffer(element); - proof_data.insert(proof_data.end(), element_bytes.begin(), element_bytes.end()); - - BaseTranscript::consume_prover_element_bytes(label, element_bytes); - } - - /** - * @brief Reads the next element of type `T` from the transcript, with a predefined label, only used by verifier. - * - * @param label Human readable name for the challenge. - * @return deserialized element of type T - */ - template T receive_from_prover(const std::string& label) - { - constexpr size_t element_size = sizeof(T); - ASSERT(num_bytes_read + element_size <= proof_data.size()); - - auto element_bytes = std::span{ proof_data }.subspan(num_bytes_read, element_size); - num_bytes_read += element_size; - - BaseTranscript::consume_prover_element_bytes(label, element_bytes); - - T element = from_buffer(element_bytes); - - return element; - } - - /** - * @brief For testing: initializes transcript with some arbitrary data so that a challenge can be generated after - * initialization. Only intended to be used by Prover. - * - * @return BaseTranscript - */ - static BaseTranscript prover_init_empty() - { - BaseTranscript transcript; - constexpr uint32_t init{ 42 }; // arbitrary - transcript.send_to_verifier("Init", init); - return transcript; - }; - - /** - * @brief For testing: initializes transcript based on proof data then receives junk data produced by - * BaseTranscript::prover_init_empty(). Only intended to be used by Verifier. - * - * @param transcript - * @return BaseTranscript - */ - static BaseTranscript verifier_init_empty(const BaseTranscript& transcript) - { - BaseTranscript verifier_transcript{ transcript.proof_data }; - [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); - return verifier_transcript; - }; - - FF get_challenge(const std::string& label) { return get_challenges(label)[0]; } - - [[nodiscard]] TranscriptManifest get_manifest() const { return manifest; }; - - void print() { manifest.print(); } - - /** - * @brief Deserializes the FULL transcript into the struct defined by each flavor derivedclass. - * @details Not supported for base transcript class because it does not have a defined structure. The current - * proof_data object must represent the whole proof and not a partial proof or it will throw an error. - */ - virtual void deserialize_full_transcript() { throw_or_abort("Cannot deserialize transcript"); } - - /** - * @brief Serializes the FULL transcript from the defined derived class back into proof_data. - * @details Only works if the struct is populated (usually from a call to deserialize_full_transcript). Allows for - * modified transcript objects to be updated in the actual proof for testing purposes. - */ - virtual void serialize_full_transcript() { throw_or_abort("Cannot serialize transcript"); } -}; -} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/ultra_transcript.test.cpp deleted file mode 100644 index 331418d4746..00000000000 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/ultra_transcript.test.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/honk/composer/ultra_composer.hpp" -#include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/proof_system/flavor/flavor.hpp" -#include "transcript.hpp" -#include - -using namespace proof_system::honk; - -class UltraTranscriptTests : public ::testing::Test { - public: - static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } - - using Flavor = proof_system::honk::flavor::Ultra; - using FF = Flavor::FF; - - /** - * @brief Construct a manifest for a Ultra Honk proof - * - * @details This is where we define the "Manifest" for a Ultra Honk proof. The tests in this suite are - * intented to warn the developer if the Prover/Verifier has deviated from this manifest, however, the - * Transcript class is not otherwise contrained to follow the manifest. - * - * @note Entries in the manifest consist of a name string and a size (bytes), NOT actual data. - * - * @return TranscriptManifest - */ - TranscriptManifest construct_ultra_honk_manifest(size_t circuit_size) - { - TranscriptManifest manifest_expected; - - auto log_n = numeric::get_msb(circuit_size); - - size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; - size_t size_FF = sizeof(FF); - size_t size_G = 2 * size_FF; - size_t size_uni = MAX_PARTIAL_RELATION_LENGTH * size_FF; - size_t size_evals = (Flavor::NUM_ALL_ENTITIES)*size_FF; - size_t size_uint32 = 4; - - size_t round = 0; - manifest_expected.add_entry(round, "circuit_size", size_uint32); - manifest_expected.add_entry(round, "public_input_size", size_uint32); - manifest_expected.add_entry(round, "pub_inputs_offset", size_uint32); - manifest_expected.add_entry(round, "public_input_0", size_FF); - manifest_expected.add_entry(round, "W_L", size_G); - manifest_expected.add_entry(round, "W_R", size_G); - manifest_expected.add_entry(round, "W_O", size_G); - manifest_expected.add_challenge(round, "eta"); - - round++; - manifest_expected.add_entry(round, "SORTED_ACCUM", size_G); - manifest_expected.add_entry(round, "W_4", size_G); - manifest_expected.add_challenge(round, "beta", "gamma"); - - round++; - manifest_expected.add_entry(round, "Z_PERM", size_G); - manifest_expected.add_entry(round, "Z_LOOKUP", size_G); - manifest_expected.add_challenge(round, "Sumcheck:alpha", "Sumcheck:zeta"); - - for (size_t i = 0; i < log_n; ++i) { - round++; - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, size_uni); - std::string label = "Sumcheck:u_" + idx; - manifest_expected.add_challenge(round, label); - } - - round++; - manifest_expected.add_entry(round, "Sumcheck:evaluations", size_evals); - manifest_expected.add_challenge(round, "rho"); - - round++; - for (size_t i = 0; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "ZM:C_q_" + idx, size_G); - } - manifest_expected.add_challenge(round, "ZM:y"); - - round++; - manifest_expected.add_entry(round, "ZM:C_q", size_G); - manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); - - round++; - // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors - manifest_expected.add_entry(round, "ZM:PI", size_G); - manifest_expected.add_challenge(round); // no challenge - - return manifest_expected; - } - - void generate_test_circuit(auto& builder) - { - FF a = 1; - builder.add_variable(a); - builder.add_public_variable(a); - } - - void generate_random_test_circuit(auto& builder) - { - auto a = FF::random_element(); - auto b = FF::random_element(); - builder.add_variable(a); - builder.add_public_variable(a); - builder.add_public_variable(b); - } -}; - -/** - * @brief Ensure consistency between the manifest hard coded in this testing suite and the one generated by the - * standard honk prover over the course of proof construction. - */ -TEST_F(UltraTranscriptTests, ProverManifestConsistency) -{ - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); - generate_test_circuit(builder); - - // Automatically generate a transcript manifest by constructing a proof - auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); - auto proof = prover.construct_proof(); - - // Check that the prover generated manifest agrees with the manifest hard coded in this suite - auto manifest_expected = construct_ultra_honk_manifest(instance->proving_key->circuit_size); - auto prover_manifest = prover.transcript.get_manifest(); - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < manifest_expected.size(); ++round) { - ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; - } -} - -/** - * @brief Ensure consistency between the manifest generated by the ultra honk prover over the course of proof - * construction and the one generated by the verifier over the course of proof verification. - * - */ -TEST_F(UltraTranscriptTests, VerifierManifestConsistency) -{ - - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = Flavor::CircuitBuilder(); - generate_test_circuit(builder); - - // Automatically generate a transcript manifest in the prover by constructing a proof - auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); - auto proof = prover.construct_proof(); - - // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance); - verifier.verify_proof(proof); - - // Check consistency between the manifests generated by the prover and verifier - auto prover_manifest = prover.transcript.get_manifest(); - auto verifier_manifest = verifier.transcript.get_manifest(); - - // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < prover_manifest.size(); ++round) { - ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) - << "Prover/Verifier manifest discrepency in round " << round; - } -} - -/** - * @brief Check that multiple challenges can be generated and sanity check - * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. - * - */ -TEST_F(UltraTranscriptTests, ChallengeGenerationTest) -{ - // initialized with random value sent to verifier - auto transcript = Flavor::Transcript::prover_init_empty(); - // test a bunch of challenges - auto challenges = transcript.get_challenges("a", "b", "c", "d", "e", "f"); - // check they are not 0 - for (size_t i = 0; i < challenges.size(); ++i) { - ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; - } - constexpr uint32_t random_val{ 17 }; // arbitrary - transcript.send_to_verifier("random val", random_val); - // test more challenges - auto [a, b, c] = transcript.get_challenges("a", "b", "c"); - ASSERT_NE(a, 0) << "Challenge a is 0"; - ASSERT_NE(b, 0) << "Challenge a is 0"; - ASSERT_NE(b, 0) << "Challenge a is 0"; -} - -TEST_F(UltraTranscriptTests, StructureTest) -{ - // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); - generate_test_circuit(builder); - - // Automatically generate a transcript manifest by constructing a proof - auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); - auto prover = composer.create_prover(instance); - auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); - EXPECT_TRUE(verifier.verify_proof(proof)); - - // try deserializing and serializing with no changes and check proof is still valid - prover.transcript.deserialize_full_transcript(); - prover.transcript.serialize_full_transcript(); - EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid - - Flavor::Commitment one_group_val = Flavor::Commitment::one(); - FF rand_val = FF::random_element(); - prover.transcript.sorted_accum_comm = one_group_val * rand_val; // choose random object to modify - EXPECT_TRUE(verifier.verify_proof( - prover.export_proof())); // we have not serialized it back to the proof so it should still be fine - - prover.transcript.serialize_full_transcript(); - EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it - - prover.transcript.deserialize_full_transcript(); - EXPECT_EQ(static_cast(prover.transcript.sorted_accum_comm), one_group_val * rand_val); -} - -TEST_F(UltraTranscriptTests, FoldingManifestTest) -{ - using Flavor = flavor::Ultra; - auto composer = UltraComposer(); - - std::vector>> insts(2); - std::generate(insts.begin(), insts.end(), [&]() { - auto builder = proof_system::UltraCircuitBuilder(); - generate_random_test_circuit(builder); - return composer.create_instance(builder); - }); - - // artificially make first instance relaxed - auto log_instance_size = static_cast(numeric::get_msb(insts[0]->proving_key->circuit_size)); - std::vector betas(log_instance_size); - for (size_t idx = 0; idx < log_instance_size; idx++) { - betas[idx] = FF::random_element(); - } - insts[0]->folding_parameters = { betas, FF(1) }; - - auto prover = composer.create_folding_prover(insts); - auto verifier = composer.create_folding_verifier(insts); - - auto prover_res = prover.fold_instances(); - verifier.fold_public_parameters(prover_res.folding_data); - - // Check consistency between the manifests generated by the prover and verifier - auto prover_manifest = prover.transcript.get_manifest(); - auto verifier_manifest = verifier.transcript.get_manifest(); - for (size_t round = 0; round < prover_manifest.size(); ++round) { - ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) - << "Prover/Verifier manifest discrepency in round " << round; - } -} diff --git a/barretenberg/cpp/src/barretenberg/plonk/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/plonk/flavor/flavor.hpp index 967b0c1539a..0cf96a7e8a5 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/flavor/flavor.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/plonk/transcript/transcript.hpp" #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/proof_system/flavor/flavor.hpp" diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.hpp index 32102304fc0..1d76401514e 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.hpp @@ -1,9 +1,9 @@ #pragma once #include "../../../polynomials/polynomial.hpp" #include "../../../polynomials/polynomial_arithmetic.hpp" -#include "../../../proof_system/work_queue/work_queue.hpp" #include "../types/commitment_open_proof.hpp" #include "../types/program_settings.hpp" +#include "barretenberg/plonk/work_queue/work_queue.hpp" namespace proof_system::plonk { diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp index cfc63adf8cd..453fc6c5678 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.test.cpp @@ -2,9 +2,9 @@ #include "commitment_scheme.hpp" #include "kate_commitment_scheme.hpp" -#include "../../../proof_system/work_queue/work_queue.hpp" #include "../types/program_settings.hpp" #include "barretenberg/common/mem.hpp" +#include "barretenberg/plonk/work_queue/work_queue.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp index 408b9ea3363..935bc15d61c 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp @@ -1,11 +1,11 @@ #pragma once -#include "../../../proof_system/work_queue/work_queue.hpp" #include "../commitment_scheme/commitment_scheme.hpp" #include "../types/program_settings.hpp" #include "../types/proof.hpp" #include "../widgets/random_widgets/random_widget.hpp" #include "../widgets/transition_widgets/transition_widget.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/plonk/work_queue/work_queue.hpp" namespace proof_system::plonk { diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/program_settings.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/program_settings.hpp index df56091e5ac..2b5d6b899bf 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/program_settings.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/program_settings.hpp @@ -2,7 +2,6 @@ #include -#include "../../../transcript/transcript.hpp" #include "../widgets/random_widgets/permutation_widget.hpp" #include "../widgets/random_widgets/plookup_widget.hpp" #include "../widgets/random_widgets/random_widget.hpp" @@ -14,6 +13,7 @@ #include "../widgets/transition_widgets/plookup_arithmetic_widget.hpp" #include "../widgets/transition_widgets/plookup_auxiliary_widget.hpp" #include "./prover_settings.hpp" +#include "barretenberg/plonk/transcript/transcript.hpp" namespace proof_system::plonk { diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.hpp index b39f1a97c4d..3d88c1290b7 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.hpp @@ -3,7 +3,7 @@ #include "../types/proof.hpp" #include "../widgets/random_widgets/random_widget.hpp" #include "barretenberg/plonk/proof_system/commitment_scheme/commitment_scheme.hpp" -#include "barretenberg/transcript/manifest.hpp" +#include "barretenberg/plonk/transcript/manifest.hpp" namespace proof_system::plonk { template class VerifierBase { diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp index 660a685bda1..4885e7f8788 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.test.cpp @@ -1,4 +1,3 @@ -#include "../../../transcript/transcript.hpp" #include "../prover/prover.hpp" #include "../utils/permutation.hpp" #include "../widgets/transition_widgets/arithmetic_widget.hpp" @@ -7,6 +6,7 @@ #include "barretenberg/plonk/composer/standard_composer.hpp" #include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/plonk/transcript/transcript.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/random_widget.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/random_widget.hpp index d19e9aa6aba..b055ed23023 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/random_widget.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/random_widget.hpp @@ -1,14 +1,12 @@ #pragma once -#include "../../../../proof_system/work_queue/work_queue.hpp" -#include "../../../../transcript/transcript.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/plonk/transcript/transcript.hpp" +#include "barretenberg/plonk/work_queue/work_queue.hpp" #include namespace transcript { class Transcript; } - -// TODO(Cody) Fix this namespace. namespace proof_system::plonk { struct proving_key; diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/transition_widgets/transition_widget.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/transition_widgets/transition_widget.hpp index 6b4d3105bda..727d92e796d 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/transition_widgets/transition_widget.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/transition_widgets/transition_widget.hpp @@ -8,8 +8,8 @@ #include "../../types/prover_settings.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/plonk/work_queue/work_queue.hpp" #include "barretenberg/polynomials/iterate_over_domain.hpp" -#include "barretenberg/proof_system/work_queue/work_queue.hpp" using namespace proof_system; namespace proof_system::plonk { diff --git a/barretenberg/cpp/src/barretenberg/transcript/manifest.hpp b/barretenberg/cpp/src/barretenberg/plonk/transcript/manifest.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/transcript/manifest.hpp rename to barretenberg/cpp/src/barretenberg/plonk/transcript/manifest.hpp diff --git a/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.cpp b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.cpp new file mode 100644 index 00000000000..5447a0480a6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.cpp @@ -0,0 +1,447 @@ +#include "transcript.hpp" +#include "barretenberg/common/assert.hpp" +#include "barretenberg/common/net.hpp" +#include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/crypto/blake3s/blake3s.hpp" +#include "barretenberg/crypto/keccak/keccak.hpp" +#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" +#include "manifest.hpp" +#include +#include +#include +#include +#include + +namespace transcript { + +// Set to 1 to enable some logging. +#if 0 +template inline void info_togglable(Args... args) +{ + info("Transcript: ", args...); +} +#else +template inline void info_togglable(Args...) {} +#endif + +std::array Keccak256Hasher::hash(std::vector const& buffer) +{ + keccak256 hash_result = ethash_keccak256(&buffer[0], buffer.size()); + for (auto& word : hash_result.word64s) { + if (is_little_endian()) { + word = __builtin_bswap64(word); + } + } + std::array result; + + for (size_t i = 0; i < 4; ++i) { + for (size_t j = 0; j < 8; ++j) { + uint8_t byte = static_cast(hash_result.word64s[i] >> (56 - (j * 8))); + result[i * 8 + j] = byte; + } + } + return result; +} + +std::array Blake3sHasher::hash(std::vector const& buffer) +{ + grumpkin::fq input = grumpkin::fq::serialize_from_buffer(&buffer[0]); + grumpkin::fq hashed = crypto::pedersen_hash::hash({ input }); + std::vector res = to_buffer(hashed); + std::array result; + for (size_t i = 0; i < PRNG_OUTPUT_SIZE; ++i) { + result[i] = res[i]; + } + return result; +} + +Transcript::Transcript(const std::vector& input_transcript, + const Manifest input_manifest, + const HashType hash_type, + const size_t challenge_bytes) + : num_challenge_bytes(challenge_bytes) + , hasher(hash_type) + , manifest(input_manifest) +{ + current_challenge.data = {}; + const size_t num_rounds = input_manifest.get_num_rounds(); + const uint8_t* buffer = &input_transcript[0]; + size_t count = 0; + // Compute how much data we need according to the manifest + size_t totalRequiredSize = 0; + for (size_t i = 0; i < num_rounds; ++i) { + for (auto manifest_element : input_manifest.get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + totalRequiredSize += manifest_element.num_bytes; + } + } + } + // Check that the total required size is equal to the size of the input_transcript + if (totalRequiredSize != input_transcript.size()) + throw_or_abort(format("Serialized transcript does not contain the required number of bytes: ", + totalRequiredSize, + " != ", + input_transcript.size())); + + for (size_t i = 0; i < num_rounds; ++i) { + for (auto manifest_element : input_manifest.get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + // printf("reading element %s ", manifest_element.name.c_str()); + // for (size_t j = 0; j < manifest_element.num_bytes; ++j) { + // printf("%x", buffer[count + j]); + // } + // printf("\n"); + + // This can once again become a buffer overread if + // someone removes the above checks. + elements.insert({ manifest_element.name, + std::vector(buffer + count, buffer + count + manifest_element.num_bytes) }); + count += manifest_element.num_bytes; + } + } + } + compute_challenge_map(); + // printf("input buffer size = %lu \n", count); +} + +/** + * Insert element names from all rounds of the manifest + * into the challenge_map. + * */ +void Transcript::compute_challenge_map() +{ + challenge_map = std::map(); + for (const auto& manifest : manifest.get_round_manifests()) { + if (manifest.map_challenges) { + for (const auto& element : manifest.elements) { + challenge_map.insert({ element.name, element.challenge_map_index }); + } + } + } +} + +/** + * @brief Mock prover transcript interactions up to fiat-shamir of a given challenge. + * + * @details This is useful for testing individual parts of the prover since all + * transcript interactions must occur sequentially according to the manifest. + * Function allows for optional input of circuit_size since this is needed in some + * test cases, e.g. instantiating a Sumcheck from a mocked transcript. + * + * @param challenge_in + */ +void Transcript::mock_inputs_prior_to_challenge(const std::string& challenge_in, size_t circuit_size) +{ + // Perform operations only up to fiat-shamir of challenge_in + for (auto& manifest : manifest.get_round_manifests()) // loop over RoundManifests + { + for (auto& entry : manifest.elements) // loop over ManifestEntrys + { + if (entry.name == "circuit_size") { + add_element("circuit_size", + { static_cast(circuit_size >> 24), + static_cast(circuit_size >> 16), + static_cast(circuit_size >> 8), + static_cast(circuit_size) }); + } else { + std::vector buffer(entry.num_bytes, 1); // arbitrary buffer of 1's + add_element(entry.name, buffer); + } + } + if (challenge_in == manifest.challenge) { + break; + } else { + apply_fiat_shamir(manifest.challenge); + } + } +} + +void Transcript::add_element(const std::string& element_name, const std::vector& buffer) +{ + info_togglable("add_element(): ", element_name, "\n"); + elements.insert({ element_name, buffer }); +} + +/** + * Apply Fiat-Shamir transform to create challenges for the current round. + * The challenges are saved to transcript. Round number is increased. + * + * @param challenge_name Challenge name (needed to check if the challenge fits the current round). + * */ +void Transcript::apply_fiat_shamir(const std::string& challenge_name /*, const bool info_togglable*/) +{ + // For reference, see the relevant manifest, which is defined in + // plonk/composer/[standard/ultra]_composer.hpp + ASSERT(current_round <= manifest.get_num_rounds()); + // TODO(Cody): Coupling: this line insists that the challenges in the manifest + // are encountered in the order that matches the order of the proof construction functions. + // Future architecture should specify this data in a single place (?). + info_togglable("apply_fiat_shamir(): challenge name match:"); + info_togglable("\t challenge_name in: ", challenge_name); + info_togglable("\t challenge_name expected: ", manifest.get_round_manifest(current_round).challenge, "\n"); + ASSERT(challenge_name == manifest.get_round_manifest(current_round).challenge); + + const size_t num_challenges = manifest.get_round_manifest(current_round).num_challenges; + if (num_challenges == 0) { + ++current_round; + return; + } + + // Combine the very last challenge from the previous fiat-shamir round (which is, inductively, a hash containing the + // manifest data of all previous rounds), plus the manifest data for this round, into a buffer. This buffer will + // ultimately be hashed, to form this round's fiat-shamir challenge(s). + std::vector buffer; + if (current_round > 0) { + buffer.insert(buffer.end(), current_challenge.data.begin(), current_challenge.data.end()); + } + for (const auto& manifest_element : manifest.get_round_manifest(current_round).elements) { + info_togglable("apply_fiat_shamir(): manifest element name match:"); + info_togglable("\t element name: ", manifest_element.name); + info_togglable( + "\t element exists and is unique: ", (elements.count(manifest_element.name) == 1) ? "true" : "false", "\n"); + ASSERT(elements.count(manifest_element.name) == 1); + + std::vector& element_data = elements.at(manifest_element.name); + if (!manifest_element.derived_by_verifier) { + ASSERT(manifest_element.num_bytes == element_data.size()); + } + buffer.insert(buffer.end(), element_data.begin(), element_data.end()); + } + + std::vector round_challenges; + std::array base_hash{}; + + switch (hasher) { + case HashType::Keccak256: { + base_hash = Keccak256Hasher::hash(buffer); + break; + } + case HashType::PedersenBlake3s: { + std::vector hashed_buffer = to_buffer(crypto::pedersen_hash::hash_buffer(buffer)); + base_hash = Blake3sHasher::hash(hashed_buffer); + break; + } + default: { + throw_or_abort("no hasher was selected for the transcript"); + } + } + + // Depending on the settings, we might be able to chunk the bytes of a single hash across multiple challenges: + const size_t challenges_per_hash = PRNG_OUTPUT_SIZE / num_challenge_bytes; + + for (size_t j = 0; j < challenges_per_hash; ++j) { + if (j < num_challenges) { + // Each challenge still occupies PRNG_OUTPUT_SIZE number of bytes, but only num_challenge_bytes rhs bytes + // are nonzero. + std::array challenge{}; + std::copy(base_hash.begin() + (j * num_challenge_bytes), + base_hash.begin() + (j + 1) * num_challenge_bytes, + challenge.begin() + + (PRNG_OUTPUT_SIZE - + num_challenge_bytes)); // Left-pad the challenge with zeros, and then copy the next + // num_challange_bytes slice of the hash to the rhs of the challenge. + round_challenges.push_back({ challenge }); + } + } + + std::vector rolling_buffer(base_hash.begin(), base_hash.end()); + if (hasher == HashType::Keccak256) { + rolling_buffer.push_back(0); + } else { + rolling_buffer[31] = (0); + } + + // Compute how many hashes we need so that we have enough distinct chunks of 'random' bytes to distribute + // across the num_challenges. + size_t num_hashes = (num_challenges / challenges_per_hash); + if (num_hashes * challenges_per_hash != num_challenges) { + ++num_hashes; + } + + for (size_t i = 1; i < num_hashes; ++i) { + // Compute hash_output = hash(base_hash, i); + rolling_buffer[rolling_buffer.size() - 1] = static_cast(i); + std::array hash_output{}; + switch (hasher) { + case HashType::Keccak256: { + hash_output = Keccak256Hasher::hash(rolling_buffer); + break; + } + case HashType::PedersenBlake3s: { + hash_output = Blake3sHasher::hash(rolling_buffer); + break; + } + default: { + throw_or_abort("no hasher was selected for the transcript"); + } + } + for (size_t j = 0; j < challenges_per_hash; ++j) { + // Only produce as many challenges as we need. + if (challenges_per_hash * i + j < num_challenges) { + std::array challenge{}; + std::copy(hash_output.begin() + (j * num_challenge_bytes), + hash_output.begin() + (j + 1) * num_challenge_bytes, + challenge.begin() + (PRNG_OUTPUT_SIZE - num_challenge_bytes)); + round_challenges.push_back({ challenge }); + } + } + } + + // Remember the very last challenge, as it will be included in the buffer of the next fiat-shamir round (since this + // challenge is effectively a hash of _all_ previous rounds' manifest data). + current_challenge = round_challenges[round_challenges.size() - 1]; + + challenges.insert({ challenge_name, round_challenges }); + ++current_round; +} + +/** + * Get the challenge with the given name at index. + * Will fail if there is no challenge with such name + * or there are not enough subchallenges in the vector. + * + * @param challenge_name The name of the challenge. + * @param idx The idx of subchallenge + * + * @return The challenge value + * */ +std::array Transcript::get_challenge(const std::string& challenge_name, + const size_t idx) const +{ + info_togglable("get_challenge(): ", challenge_name, "\n"); + ASSERT(challenges.count(challenge_name) == 1); + return challenges.at(challenge_name)[idx].data; +} + +/** + * Get the challenge index from map (needed when we name subchallenges). + * + * @param challenge_map_name The name of the subchallenge + * + * @return The index of the subchallenge in the vector + * corresponding to the challenge. + * */ +int Transcript::get_challenge_index_from_map(const std::string& challenge_map_name) const +{ + const auto key = challenge_map.at(challenge_map_name); + return key; +} + +/** + * Check if a challenge exists. + * + * @param challenge_name The name of the challenge + * + * @return true if exists, false if not + * **/ +bool Transcript::has_challenge(const std::string& challenge_name) const +{ + return (challenges.count(challenge_name) > 0); +} + +/** + * Get a particular subchallenge value by the name of the subchallenge. + * For example, we use it with (nu, r). + * + * @param challenge_name The name of the challenge. + * @param challenge_map_name The name of the subchallenge. + * + * @return The value of the subchallenge. + * */ +std::array Transcript::get_challenge_from_map( + const std::string& challenge_name, const std::string& challenge_map_name) const +{ + const auto key = challenge_map.at(challenge_map_name); + if (key == -1) { + std::array result; + for (size_t i = 0; i < Transcript::PRNG_OUTPUT_SIZE - 1; ++i) { + result[i] = 0; + } + result[Transcript::PRNG_OUTPUT_SIZE - 1] = 1; + return result; + } + const auto value = challenges.at(challenge_name)[static_cast(key)]; + return value.data; +} + +/** + * Get the number of subchallenges for a given challenge. + * Fails if no such challenge exists. + * We use it with beta/gamma which need to be created in one + * Fiat-Shamir transform. + * + * @param challenge_name The name of the challenge. + * + * @return The number of subchallenges. + * */ +size_t Transcript::get_num_challenges(const std::string& challenge_name) const +{ + ASSERT(challenges.count(challenge_name) == 1); + + return challenges.at(challenge_name).size(); +} + +/** + * Get the value of an element. + * Fails if there is no such element. + * + * @param element_name The name of the element. + * + * @return The value of the element. + * */ +std::vector Transcript::get_element(const std::string& element_name) const +{ + ASSERT(elements.count(element_name) == 1); + return elements.at(element_name); +} + +/** + * Get the size of an element from the manifest. + * + * @param element_name The name of the element + * + * @return The size of the element if found, otherwise -1. + * */ +size_t Transcript::get_element_size(const std::string& element_name) const +{ + for (size_t i = 0; i < manifest.get_num_rounds(); ++i) { + for (auto manifest_element : manifest.get_round_manifest(i).elements) { + if (manifest_element.name == element_name) { + return manifest_element.num_bytes; + } + } + } + return static_cast(-1); +} + +/** + * Serialize transcript to a vector of bytes. + * + * @return Serialized transcript + * */ +std::vector Transcript::export_transcript() const +{ + std::vector buffer; + + for (size_t i = 0; i < manifest.get_num_rounds(); ++i) { + for (auto manifest_element : manifest.get_round_manifest(i).elements) { + ASSERT(elements.count(manifest_element.name) == 1); + const std::vector& element_data = elements.at(manifest_element.name); + if (!manifest_element.derived_by_verifier) { + ASSERT(manifest_element.num_bytes == element_data.size()); + } + if (!manifest_element.derived_by_verifier) { + // printf("writing element %s ", manifest_element.name.c_str()); + // for (size_t j = 0; j < element_data.size(); ++j) { + // printf("%x", element_data[j]); + // } + // printf("\n"); + buffer.insert(buffer.end(), element_data.begin(), element_data.end()); + } + } + } + // printf("output buffer size = %lu \n", buffer.size()); + return buffer; +} + +} // namespace transcript diff --git a/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.hpp new file mode 100644 index 00000000000..6a892ad411b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.hpp @@ -0,0 +1,122 @@ +#pragma once +#include "manifest.hpp" +#include +#include +#include +#include +#include + +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +namespace transcript { + +struct Keccak256Hasher { + static constexpr size_t SECURITY_PARAMETER_SIZE = 32; + static constexpr size_t PRNG_OUTPUT_SIZE = 32; + + static std::array hash(std::vector const& buffer); +}; + +struct Blake3sHasher { + static constexpr size_t SECURITY_PARAMETER_SIZE = 16; + static constexpr size_t PRNG_OUTPUT_SIZE = 32; + + static std::array hash(std::vector const& input); +}; + +enum HashType { Keccak256, PedersenBlake3s }; + +/** + * Transcript is used by the Prover to store round values + * and derive challenges. The verifier uses it to parse serialized + * values and get the data and challenges back. + * + */ +class Transcript { + static constexpr size_t PRNG_OUTPUT_SIZE = 32; + struct challenge { + std::array data; + }; + + public: + typedef proof_system::plonk::verification_key Key; + + /** + * Create a new transcript for Prover based on the manifest. + * + * @param input_manifes The manifest with round descriptions. + * @param hash_type The hash to use for Fiat-Shamir. + * @param challenge_bytes The number of bytes per challenge to generate. + * + */ + Transcript(const Manifest input_manifest, + const HashType hash_type = HashType::Keccak256, + const size_t challenge_bytes = 32) + : num_challenge_bytes(challenge_bytes) + , hasher(hash_type) + , manifest(input_manifest) + { + // Just to be safe, because compilers can be weird. + current_challenge.data = {}; + compute_challenge_map(); + } + + /** + * Parse a serialized version of an input_transcript into a deserialized + * one based on the manifest. + * + * @param input_transcript Serialized transcript. + * @param input_manifest The manifest which governs the parsing. + * @param hash_type The hash used for Fiat-Shamir + * @param challenge_bytes The number of bytes per challenge to generate. + * + */ + Transcript(const std::vector& input_transcript, + const Manifest input_manifest, + const HashType hash_type = HashType::Keccak256, + const size_t challenge_bytes = 32); + + Manifest get_manifest() const { return manifest; } + + void add_element(const std::string& element_name, const std::vector& buffer); + + void apply_fiat_shamir(const std::string& challenge_name /*, const bool debug = false*/); + + bool has_challenge(const std::string& challenge_name) const; + + std::array get_challenge(const std::string& challenge_name, const size_t idx = 0) const; + + int get_challenge_index_from_map(const std::string& challenge_map_name) const; + + std::array get_challenge_from_map(const std::string& challenge_name, + const std::string& challenge_map_name) const; + + size_t get_num_challenges(const std::string& challenge_name) const; + + std::vector get_element(const std::string& element_name) const; + + size_t get_element_size(const std::string& element_name) const; + + std::vector export_transcript() const; + + void compute_challenge_map(); + + void mock_inputs_prior_to_challenge(const std::string& challenge_name, size_t circuit_size = 1); + + void print(); + + private: + // The round of the protocol + size_t current_round = 0; + size_t num_challenge_bytes; + HashType hasher; + std::map> elements; + + std::map> challenges; + + challenge current_challenge; + + Manifest manifest; + std::map challenge_map; +}; + +} // namespace transcript diff --git a/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.test.cpp new file mode 100644 index 00000000000..6489f90d014 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript.test.cpp @@ -0,0 +1,191 @@ +#include "barretenberg/polynomials/univariate.hpp" +#include "transcript_wrappers.hpp" +#include +#include +#include +#include + +namespace { +transcript::Manifest create_manifest(const size_t num_public_inputs) +{ + // add public inputs.... + constexpr size_t g1_size = 64; + constexpr size_t fr_size = 32; + const size_t public_input_size = fr_size * num_public_inputs; + const transcript::Manifest output = transcript::Manifest( + { transcript::Manifest::RoundManifest( + { { "circuit_size", 4, true }, { "public_input_size", 4, true } }, "init", 1), + transcript::Manifest::RoundManifest({ { "public_inputs", public_input_size, false }, + { "W_1", g1_size, false }, + { "W_2", g1_size, false }, + { "W_3", g1_size, false } }, + "beta", + 2), + transcript::Manifest::RoundManifest({ { "Z_PERM", g1_size, false } }, "alpha", 1), + transcript::Manifest::RoundManifest( + { { "T_1", g1_size, false }, { "T_2", g1_size, false }, { "T_3", g1_size, false } }, "z", 1), + transcript::Manifest::RoundManifest({ { "w_1", fr_size, false }, + { "w_2", fr_size, false }, + { "w_3", fr_size, false }, + { "w_3_omega", fr_size, false }, + { "z_perm_omega", fr_size, false }, + { "sigma_1", fr_size, false }, + { "sigma_2", fr_size, false }, + { "r", fr_size, false }, + { "t", fr_size, true } }, + "nu", + 10), + transcript::Manifest::RoundManifest( + { { "PI_Z", g1_size, false }, { "PI_Z_OMEGA", g1_size, false } }, "separator", 1) }); + return output; +} +} // namespace + +TEST(transcript, validate_transcript) +{ + std::vector g1_vector(64); + std::vector g2_vector(128); + std::vector fr_vector(32); + + for (size_t i = 0; i < g1_vector.size(); ++i) { + g1_vector[i] = 1; + } + for (size_t i = 0; i < g2_vector.size(); ++i) { + g2_vector[i] = 1; + } + for (size_t i = 0; i < fr_vector.size(); ++i) { + fr_vector[i] = 1; + } + transcript::Transcript transcript = transcript::Transcript(create_manifest(0)); + transcript.add_element("circuit_size", { 1, 2, 3, 4 }); + transcript.add_element("public_input_size", { 1, 2, 3, 4 }); + transcript.apply_fiat_shamir("init"); + + transcript.add_element("public_inputs", {}); + + transcript.add_element("W_1", g1_vector); + transcript.add_element("W_2", g1_vector); + transcript.add_element("W_3", g1_vector); + + transcript.apply_fiat_shamir("beta"); + + transcript.add_element("Z_PERM", g1_vector); + + transcript.apply_fiat_shamir("alpha"); + + transcript.add_element("T_1", g1_vector); + transcript.add_element("T_2", g1_vector); + transcript.add_element("T_3", g1_vector); + + transcript.apply_fiat_shamir("z"); + + transcript.add_element("w_1", fr_vector); + transcript.add_element("w_2", fr_vector); + transcript.add_element("w_3", fr_vector); + transcript.add_element("w_3_omega", fr_vector); + transcript.add_element("z_perm_omega", fr_vector); + transcript.add_element("sigma_1", fr_vector); + transcript.add_element("sigma_2", fr_vector); + transcript.add_element("r", fr_vector); + transcript.add_element("t", fr_vector); + + transcript.apply_fiat_shamir("nu"); + + transcript.add_element("PI_Z", g1_vector); + transcript.add_element("PI_Z_OMEGA", g1_vector); + + transcript.apply_fiat_shamir("separator"); + + std::vector result = transcript.get_element("PI_Z_OMEGA"); + EXPECT_EQ(result.size(), g1_vector.size()); + for (size_t i = 0; i < result.size(); ++i) { + EXPECT_EQ(result[i], g1_vector[i]); + } +} + +namespace { +transcript::Manifest create_toy_honk_manifest(const size_t num_public_inputs, const size_t SUMCHECK_RELATION_LENGTH) +{ + // Create a toy honk manifest that includes a univariate like the ones constructed by the prover in each round of + // sumcheck + constexpr size_t g1_size = 64; + constexpr size_t fr_size = 32; + const size_t public_input_size = fr_size * num_public_inputs; + const transcript::Manifest output = transcript::Manifest( + { transcript::Manifest::RoundManifest( + { { "circuit_size", 4, true }, { "public_input_size", 4, true } }, "init", 1), + transcript::Manifest::RoundManifest({ { "public_inputs", public_input_size, false }, + { "W_1", g1_size, false }, + { "W_2", g1_size, false }, + { "W_3", g1_size, false } }, + "beta", + 2), + transcript::Manifest::RoundManifest( + { { "round_univariate_i", fr_size * SUMCHECK_RELATION_LENGTH, false } }, "omicron", 1) }); + return output; +} +} // namespace + +/** + * @brief Test transcript serialization/deserialization of a Univariate object, which is needed for Sumcheck + * + */ +TEST(transcript, univariate_serialization) +{ + constexpr size_t num_public_inputs = 0; + constexpr size_t LENGTH = 8; + + using Fr = barretenberg::fr; + using Univariate = barretenberg::Univariate; + using Transcript = transcript::StandardTranscript; + + std::vector g1_vector(64); + std::vector fr_vector(32); + std::array evaluations; + + for (size_t i = 0; i < g1_vector.size(); ++i) { + g1_vector[i] = 1; + } + for (size_t i = 0; i < fr_vector.size(); ++i) { + fr_vector[i] = 1; + } + for (size_t i = 0; i < LENGTH; ++i) { + evaluations[i] = Fr::random_element(); + } + + // Instantiate a StandardTranscript + auto transcript = Transcript(create_toy_honk_manifest(num_public_inputs, LENGTH)); + + // Add some junk to the transcript and compute challenges + transcript.add_element("circuit_size", { 1, 2, 3, 4 }); + transcript.add_element("public_input_size", { 1, 2, 3, 4 }); + + transcript.apply_fiat_shamir("init"); + + transcript.add_element("public_inputs", {}); + transcript.add_element("W_1", g1_vector); + transcript.add_element("W_2", g1_vector); + transcript.add_element("W_3", g1_vector); + + transcript.apply_fiat_shamir("beta"); + + // Instantiate a Univariate from the evaluations + auto univariate = Univariate(evaluations); + + // Add the univariate to the transcript using the to_buffer() member function + // NOTE: the element being added here does not actually have to exist in the manifest for the + // serialization/deserialization to work. + transcript.add_element("round_univariate_i", univariate.to_buffer()); + + // Example of challenge generation; not used in test + transcript.apply_fiat_shamir("omicron"); + Fr omicron = Fr::serialize_from_buffer(transcript.get_challenge("omicron").begin()); + static_cast(omicron); + + // Deserialize into a univariate from the transcript + auto deserialized_univariate = Univariate::serialize_from_buffer(&transcript.get_element("round_univariate_i")[0]); + + for (size_t i = 0; i < LENGTH; ++i) { + EXPECT_EQ(univariate.value_at(i), deserialized_univariate.value_at(i)); + } +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript_wrappers.cpp b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript_wrappers.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/transcript/transcript_wrappers.cpp rename to barretenberg/cpp/src/barretenberg/plonk/transcript/transcript_wrappers.cpp diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript_wrappers.hpp b/barretenberg/cpp/src/barretenberg/plonk/transcript/transcript_wrappers.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/transcript/transcript_wrappers.hpp rename to barretenberg/cpp/src/barretenberg/plonk/transcript/transcript_wrappers.hpp diff --git a/barretenberg/cpp/src/barretenberg/proof_system/work_queue/work_queue.cpp b/barretenberg/cpp/src/barretenberg/plonk/work_queue/work_queue.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/proof_system/work_queue/work_queue.cpp rename to barretenberg/cpp/src/barretenberg/plonk/work_queue/work_queue.cpp diff --git a/barretenberg/cpp/src/barretenberg/proof_system/work_queue/work_queue.hpp b/barretenberg/cpp/src/barretenberg/plonk/work_queue/work_queue.hpp similarity index 96% rename from barretenberg/cpp/src/barretenberg/proof_system/work_queue/work_queue.hpp rename to barretenberg/cpp/src/barretenberg/plonk/work_queue/work_queue.hpp index c38576e46e3..707f5ba3376 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/work_queue/work_queue.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/work_queue/work_queue.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../../transcript/transcript_wrappers.hpp" #include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp" +#include "barretenberg/plonk/transcript/transcript_wrappers.hpp" namespace proof_system::plonk { diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp index cb226fc5255..fc7c833e025 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp @@ -12,14 +12,15 @@ namespace proof_system { static constexpr uint32_t DUMMY_TAG = 0; -template class CircuitBuilderBase { +template class CircuitBuilderBase { public: + using Arithmetization = Arithmetization_; using FF = typename Arithmetization::FF; using EmbeddedCurve = std::conditional_t, curve::BN254, curve::Grumpkin>; static constexpr size_t NUM_WIRES = Arithmetization::NUM_WIRES; - // Keeping NUM_WIRES, at least temporarily, for backward compatibility + // Keeping program_width, at least temporarily, for backward compatibility static constexpr size_t program_width = Arithmetization::NUM_WIRES; static constexpr size_t num_selectors = Arithmetization::num_selectors; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp index 7982af217e5..74df538a15a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp @@ -1,7 +1,4 @@ #pragma once -#include "barretenberg/plonk/proof_system/constants.hpp" -#include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" -#include "barretenberg/plonk/proof_system/types/prover_settings.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/arithmetization/arithmetization.hpp" #include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp" diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp index e6c83a20fd8..772fd411699 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp @@ -852,7 +852,7 @@ template void UltraCircuitBuilder_::process_range_list(RangeLi std::sort(std::execution::par_unseq, sorted_list.begin(), sorted_list.end()); #endif // list must be padded to a multipe of 4 and larger than 4 (gate_width) - constexpr size_t gate_width = plonk::ultra_settings::program_width; + constexpr size_t gate_width = NUM_WIRES; size_t padding = (gate_width - (list.variable_indices.size() % gate_width)) % gate_width; std::vector indices; @@ -895,7 +895,7 @@ template void UltraCircuitBuilder_::process_range_lists() template void UltraCircuitBuilder_::create_sort_constraint(const std::vector& variable_index) { - constexpr size_t gate_width = plonk::ultra_settings::program_width; + constexpr size_t gate_width = NUM_WIRES; ASSERT(variable_index.size() % gate_width == 0); this->assert_valid_variables(variable_index); @@ -943,7 +943,7 @@ template void UltraCircuitBuilder_::create_dummy_constraints(const std::vector& variable_index) { std::vector padded_list = variable_index; - constexpr size_t gate_width = plonk::ultra_settings::program_width; + constexpr size_t gate_width = NUM_WIRES; const uint64_t padding = (gate_width - (padded_list.size() % gate_width)) % gate_width; for (uint64_t i = 0; i < padding; ++i) { padded_list.emplace_back(this->zero_idx); @@ -978,7 +978,7 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges(const std::vect const FF& end) { // Convenient to assume size is at least 8 (gate_width = 4) for separate gates for start and end conditions - constexpr size_t gate_width = plonk::ultra_settings::program_width; + constexpr size_t gate_width = NUM_WIRES; ASSERT(variable_index.size() % gate_width == 0 && variable_index.size() > gate_width); this->assert_valid_variables(variable_index); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index 9c3f25ee609..a7d0cc1be8c 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -1,12 +1,13 @@ #pragma once -#include "barretenberg/plonk/proof_system/constants.hpp" -#include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" -#include "barretenberg/plonk/proof_system/types/prover_settings.hpp" +// #include "barretenberg/plonk/proof_system/constants.hpp" +// #include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" +// #include "barretenberg/plonk/proof_system/types/prover_settings.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/arithmetization/arithmetization.hpp" #include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp" #include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/proof_system/plookup_tables/types.hpp" +#include "barretenberg/proof_system/types/circuit_type.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" #include "circuit_builder_base.hpp" @@ -18,8 +19,10 @@ using namespace barretenberg; template class UltraCircuitBuilder_ : public CircuitBuilderBase> { public: + using Base = CircuitBuilderBase>; static constexpr std::string_view NAME_STRING = "UltraArithmetization"; static constexpr CircuitType CIRCUIT_TYPE = CircuitType::ULTRA; + static constexpr size_t NUM_WIRES = Base::NUM_WIRES; static constexpr merkle::HashType merkle_hash_type = merkle::HashType::LOOKUP_PEDERSEN; static constexpr pedersen::CommitmentType commitment_type = pedersen::CommitmentType::FIXED_BASE_PEDERSEN; static constexpr size_t UINT_LOG2_BASE = 6; // DOCTODO: explain what this is, or rename. diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp index 7393b5e5112..49fcdd6bf92 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp @@ -5,7 +5,7 @@ #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/transcript/transcript.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp index 159b34e31e1..254224a6a88 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp @@ -4,9 +4,9 @@ #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/flavor/ultra_recursive.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::plonk::stdlib::recursion::honk { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index 068a62ca1c8..4ca548f84e4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -1,9 +1,9 @@ #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/honk/pcs/zeromorph/zeromorph.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" #include "barretenberg/honk/utils/grand_product_delta.hpp" #include "barretenberg/honk/utils/power_polynomial.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/transcript/transcript.hpp" namespace proof_system::plonk::stdlib::recursion::honk { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp index b890566302f..936e93412be 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp @@ -1,10 +1,5 @@ #pragma once -#include "barretenberg/ecc/curves/bn254/fq.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/transcript/transcript.hpp" - #include "../../commitment/pedersen/pedersen.hpp" #include "../../hash/blake3s/blake3s.hpp" #include "../../primitives/bigfield/bigfield.hpp" @@ -14,6 +9,10 @@ #include "../../primitives/field/field.hpp" #include "../../primitives/witness/witness.hpp" #include "../verification_key/verification_key.hpp" +#include "barretenberg/ecc/curves/bn254/fq.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/plonk/transcript/transcript.hpp" namespace proof_system::plonk::stdlib::recursion { template class Transcript { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp index e52f966db1a..975a833037c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp @@ -1,22 +1,19 @@ #pragma once -#include "barretenberg/polynomials/evaluation_domain.hpp" -#include "barretenberg/srs/factories/crs_factory.hpp" -#include - -#include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" - -#include "barretenberg/plonk/proof_system/public_inputs/public_inputs.hpp" - -#include "barretenberg/polynomials/polynomial_arithmetic.hpp" - -#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" -#include "barretenberg/ecc/curves/bn254/fq12.hpp" -#include "barretenberg/ecc/curves/bn254/pairing.hpp" #include "../../primitives/curves/bn254.hpp" #include "../../primitives/memory/rom_table.hpp" #include "../../primitives/uint/uint.hpp" +#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" +#include "barretenberg/ecc/curves/bn254/fq12.hpp" +#include "barretenberg/ecc/curves/bn254/pairing.hpp" +#include "barretenberg/plonk/proof_system/public_inputs/public_inputs.hpp" +#include "barretenberg/plonk/proof_system/types/polynomial_manifest.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/polynomials/evaluation_domain.hpp" +#include "barretenberg/polynomials/polynomial_arithmetic.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include namespace proof_system::plonk::stdlib::recursion { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp index c1f07fd1b92..f86d7963697 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp @@ -1,8 +1,7 @@ #pragma once #include "barretenberg/plonk/proof_system/types/program_settings.hpp" - -#include "../transcript/transcript.hpp" +#include "barretenberg/stdlib/recursion/transcript/transcript.hpp" namespace proof_system::plonk { namespace stdlib { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp b/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp index 5d0fb4f43b4..451ef2c8e97 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp @@ -5,7 +5,7 @@ #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/transcript/transcript.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" diff --git a/barretenberg/cpp/src/barretenberg/transcript/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/transcript/CMakeLists.txt index ecc5f09dc24..5f44c7b2463 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/transcript/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(transcript crypto_pedersen_hash crypto_blake3s) \ No newline at end of file +barretenberg_module(transcript crypto_blake3s crypto_pedersen_hash) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript.cpp b/barretenberg/cpp/src/barretenberg/transcript/transcript.cpp index 5447a0480a6..9fd60d9b409 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/transcript.cpp +++ b/barretenberg/cpp/src/barretenberg/transcript/transcript.cpp @@ -1,447 +1,3 @@ #include "transcript.hpp" -#include "barretenberg/common/assert.hpp" -#include "barretenberg/common/net.hpp" -#include "barretenberg/common/throw_or_abort.hpp" -#include "barretenberg/crypto/blake3s/blake3s.hpp" -#include "barretenberg/crypto/keccak/keccak.hpp" -#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" -#include "manifest.hpp" -#include -#include -#include -#include -#include -namespace transcript { - -// Set to 1 to enable some logging. -#if 0 -template inline void info_togglable(Args... args) -{ - info("Transcript: ", args...); -} -#else -template inline void info_togglable(Args...) {} -#endif - -std::array Keccak256Hasher::hash(std::vector const& buffer) -{ - keccak256 hash_result = ethash_keccak256(&buffer[0], buffer.size()); - for (auto& word : hash_result.word64s) { - if (is_little_endian()) { - word = __builtin_bswap64(word); - } - } - std::array result; - - for (size_t i = 0; i < 4; ++i) { - for (size_t j = 0; j < 8; ++j) { - uint8_t byte = static_cast(hash_result.word64s[i] >> (56 - (j * 8))); - result[i * 8 + j] = byte; - } - } - return result; -} - -std::array Blake3sHasher::hash(std::vector const& buffer) -{ - grumpkin::fq input = grumpkin::fq::serialize_from_buffer(&buffer[0]); - grumpkin::fq hashed = crypto::pedersen_hash::hash({ input }); - std::vector res = to_buffer(hashed); - std::array result; - for (size_t i = 0; i < PRNG_OUTPUT_SIZE; ++i) { - result[i] = res[i]; - } - return result; -} - -Transcript::Transcript(const std::vector& input_transcript, - const Manifest input_manifest, - const HashType hash_type, - const size_t challenge_bytes) - : num_challenge_bytes(challenge_bytes) - , hasher(hash_type) - , manifest(input_manifest) -{ - current_challenge.data = {}; - const size_t num_rounds = input_manifest.get_num_rounds(); - const uint8_t* buffer = &input_transcript[0]; - size_t count = 0; - // Compute how much data we need according to the manifest - size_t totalRequiredSize = 0; - for (size_t i = 0; i < num_rounds; ++i) { - for (auto manifest_element : input_manifest.get_round_manifest(i).elements) { - if (!manifest_element.derived_by_verifier) { - totalRequiredSize += manifest_element.num_bytes; - } - } - } - // Check that the total required size is equal to the size of the input_transcript - if (totalRequiredSize != input_transcript.size()) - throw_or_abort(format("Serialized transcript does not contain the required number of bytes: ", - totalRequiredSize, - " != ", - input_transcript.size())); - - for (size_t i = 0; i < num_rounds; ++i) { - for (auto manifest_element : input_manifest.get_round_manifest(i).elements) { - if (!manifest_element.derived_by_verifier) { - // printf("reading element %s ", manifest_element.name.c_str()); - // for (size_t j = 0; j < manifest_element.num_bytes; ++j) { - // printf("%x", buffer[count + j]); - // } - // printf("\n"); - - // This can once again become a buffer overread if - // someone removes the above checks. - elements.insert({ manifest_element.name, - std::vector(buffer + count, buffer + count + manifest_element.num_bytes) }); - count += manifest_element.num_bytes; - } - } - } - compute_challenge_map(); - // printf("input buffer size = %lu \n", count); -} - -/** - * Insert element names from all rounds of the manifest - * into the challenge_map. - * */ -void Transcript::compute_challenge_map() -{ - challenge_map = std::map(); - for (const auto& manifest : manifest.get_round_manifests()) { - if (manifest.map_challenges) { - for (const auto& element : manifest.elements) { - challenge_map.insert({ element.name, element.challenge_map_index }); - } - } - } -} - -/** - * @brief Mock prover transcript interactions up to fiat-shamir of a given challenge. - * - * @details This is useful for testing individual parts of the prover since all - * transcript interactions must occur sequentially according to the manifest. - * Function allows for optional input of circuit_size since this is needed in some - * test cases, e.g. instantiating a Sumcheck from a mocked transcript. - * - * @param challenge_in - */ -void Transcript::mock_inputs_prior_to_challenge(const std::string& challenge_in, size_t circuit_size) -{ - // Perform operations only up to fiat-shamir of challenge_in - for (auto& manifest : manifest.get_round_manifests()) // loop over RoundManifests - { - for (auto& entry : manifest.elements) // loop over ManifestEntrys - { - if (entry.name == "circuit_size") { - add_element("circuit_size", - { static_cast(circuit_size >> 24), - static_cast(circuit_size >> 16), - static_cast(circuit_size >> 8), - static_cast(circuit_size) }); - } else { - std::vector buffer(entry.num_bytes, 1); // arbitrary buffer of 1's - add_element(entry.name, buffer); - } - } - if (challenge_in == manifest.challenge) { - break; - } else { - apply_fiat_shamir(manifest.challenge); - } - } -} - -void Transcript::add_element(const std::string& element_name, const std::vector& buffer) -{ - info_togglable("add_element(): ", element_name, "\n"); - elements.insert({ element_name, buffer }); -} - -/** - * Apply Fiat-Shamir transform to create challenges for the current round. - * The challenges are saved to transcript. Round number is increased. - * - * @param challenge_name Challenge name (needed to check if the challenge fits the current round). - * */ -void Transcript::apply_fiat_shamir(const std::string& challenge_name /*, const bool info_togglable*/) -{ - // For reference, see the relevant manifest, which is defined in - // plonk/composer/[standard/ultra]_composer.hpp - ASSERT(current_round <= manifest.get_num_rounds()); - // TODO(Cody): Coupling: this line insists that the challenges in the manifest - // are encountered in the order that matches the order of the proof construction functions. - // Future architecture should specify this data in a single place (?). - info_togglable("apply_fiat_shamir(): challenge name match:"); - info_togglable("\t challenge_name in: ", challenge_name); - info_togglable("\t challenge_name expected: ", manifest.get_round_manifest(current_round).challenge, "\n"); - ASSERT(challenge_name == manifest.get_round_manifest(current_round).challenge); - - const size_t num_challenges = manifest.get_round_manifest(current_round).num_challenges; - if (num_challenges == 0) { - ++current_round; - return; - } - - // Combine the very last challenge from the previous fiat-shamir round (which is, inductively, a hash containing the - // manifest data of all previous rounds), plus the manifest data for this round, into a buffer. This buffer will - // ultimately be hashed, to form this round's fiat-shamir challenge(s). - std::vector buffer; - if (current_round > 0) { - buffer.insert(buffer.end(), current_challenge.data.begin(), current_challenge.data.end()); - } - for (const auto& manifest_element : manifest.get_round_manifest(current_round).elements) { - info_togglable("apply_fiat_shamir(): manifest element name match:"); - info_togglable("\t element name: ", manifest_element.name); - info_togglable( - "\t element exists and is unique: ", (elements.count(manifest_element.name) == 1) ? "true" : "false", "\n"); - ASSERT(elements.count(manifest_element.name) == 1); - - std::vector& element_data = elements.at(manifest_element.name); - if (!manifest_element.derived_by_verifier) { - ASSERT(manifest_element.num_bytes == element_data.size()); - } - buffer.insert(buffer.end(), element_data.begin(), element_data.end()); - } - - std::vector round_challenges; - std::array base_hash{}; - - switch (hasher) { - case HashType::Keccak256: { - base_hash = Keccak256Hasher::hash(buffer); - break; - } - case HashType::PedersenBlake3s: { - std::vector hashed_buffer = to_buffer(crypto::pedersen_hash::hash_buffer(buffer)); - base_hash = Blake3sHasher::hash(hashed_buffer); - break; - } - default: { - throw_or_abort("no hasher was selected for the transcript"); - } - } - - // Depending on the settings, we might be able to chunk the bytes of a single hash across multiple challenges: - const size_t challenges_per_hash = PRNG_OUTPUT_SIZE / num_challenge_bytes; - - for (size_t j = 0; j < challenges_per_hash; ++j) { - if (j < num_challenges) { - // Each challenge still occupies PRNG_OUTPUT_SIZE number of bytes, but only num_challenge_bytes rhs bytes - // are nonzero. - std::array challenge{}; - std::copy(base_hash.begin() + (j * num_challenge_bytes), - base_hash.begin() + (j + 1) * num_challenge_bytes, - challenge.begin() + - (PRNG_OUTPUT_SIZE - - num_challenge_bytes)); // Left-pad the challenge with zeros, and then copy the next - // num_challange_bytes slice of the hash to the rhs of the challenge. - round_challenges.push_back({ challenge }); - } - } - - std::vector rolling_buffer(base_hash.begin(), base_hash.end()); - if (hasher == HashType::Keccak256) { - rolling_buffer.push_back(0); - } else { - rolling_buffer[31] = (0); - } - - // Compute how many hashes we need so that we have enough distinct chunks of 'random' bytes to distribute - // across the num_challenges. - size_t num_hashes = (num_challenges / challenges_per_hash); - if (num_hashes * challenges_per_hash != num_challenges) { - ++num_hashes; - } - - for (size_t i = 1; i < num_hashes; ++i) { - // Compute hash_output = hash(base_hash, i); - rolling_buffer[rolling_buffer.size() - 1] = static_cast(i); - std::array hash_output{}; - switch (hasher) { - case HashType::Keccak256: { - hash_output = Keccak256Hasher::hash(rolling_buffer); - break; - } - case HashType::PedersenBlake3s: { - hash_output = Blake3sHasher::hash(rolling_buffer); - break; - } - default: { - throw_or_abort("no hasher was selected for the transcript"); - } - } - for (size_t j = 0; j < challenges_per_hash; ++j) { - // Only produce as many challenges as we need. - if (challenges_per_hash * i + j < num_challenges) { - std::array challenge{}; - std::copy(hash_output.begin() + (j * num_challenge_bytes), - hash_output.begin() + (j + 1) * num_challenge_bytes, - challenge.begin() + (PRNG_OUTPUT_SIZE - num_challenge_bytes)); - round_challenges.push_back({ challenge }); - } - } - } - - // Remember the very last challenge, as it will be included in the buffer of the next fiat-shamir round (since this - // challenge is effectively a hash of _all_ previous rounds' manifest data). - current_challenge = round_challenges[round_challenges.size() - 1]; - - challenges.insert({ challenge_name, round_challenges }); - ++current_round; -} - -/** - * Get the challenge with the given name at index. - * Will fail if there is no challenge with such name - * or there are not enough subchallenges in the vector. - * - * @param challenge_name The name of the challenge. - * @param idx The idx of subchallenge - * - * @return The challenge value - * */ -std::array Transcript::get_challenge(const std::string& challenge_name, - const size_t idx) const -{ - info_togglable("get_challenge(): ", challenge_name, "\n"); - ASSERT(challenges.count(challenge_name) == 1); - return challenges.at(challenge_name)[idx].data; -} - -/** - * Get the challenge index from map (needed when we name subchallenges). - * - * @param challenge_map_name The name of the subchallenge - * - * @return The index of the subchallenge in the vector - * corresponding to the challenge. - * */ -int Transcript::get_challenge_index_from_map(const std::string& challenge_map_name) const -{ - const auto key = challenge_map.at(challenge_map_name); - return key; -} - -/** - * Check if a challenge exists. - * - * @param challenge_name The name of the challenge - * - * @return true if exists, false if not - * **/ -bool Transcript::has_challenge(const std::string& challenge_name) const -{ - return (challenges.count(challenge_name) > 0); -} - -/** - * Get a particular subchallenge value by the name of the subchallenge. - * For example, we use it with (nu, r). - * - * @param challenge_name The name of the challenge. - * @param challenge_map_name The name of the subchallenge. - * - * @return The value of the subchallenge. - * */ -std::array Transcript::get_challenge_from_map( - const std::string& challenge_name, const std::string& challenge_map_name) const -{ - const auto key = challenge_map.at(challenge_map_name); - if (key == -1) { - std::array result; - for (size_t i = 0; i < Transcript::PRNG_OUTPUT_SIZE - 1; ++i) { - result[i] = 0; - } - result[Transcript::PRNG_OUTPUT_SIZE - 1] = 1; - return result; - } - const auto value = challenges.at(challenge_name)[static_cast(key)]; - return value.data; -} - -/** - * Get the number of subchallenges for a given challenge. - * Fails if no such challenge exists. - * We use it with beta/gamma which need to be created in one - * Fiat-Shamir transform. - * - * @param challenge_name The name of the challenge. - * - * @return The number of subchallenges. - * */ -size_t Transcript::get_num_challenges(const std::string& challenge_name) const -{ - ASSERT(challenges.count(challenge_name) == 1); - - return challenges.at(challenge_name).size(); -} - -/** - * Get the value of an element. - * Fails if there is no such element. - * - * @param element_name The name of the element. - * - * @return The value of the element. - * */ -std::vector Transcript::get_element(const std::string& element_name) const -{ - ASSERT(elements.count(element_name) == 1); - return elements.at(element_name); -} - -/** - * Get the size of an element from the manifest. - * - * @param element_name The name of the element - * - * @return The size of the element if found, otherwise -1. - * */ -size_t Transcript::get_element_size(const std::string& element_name) const -{ - for (size_t i = 0; i < manifest.get_num_rounds(); ++i) { - for (auto manifest_element : manifest.get_round_manifest(i).elements) { - if (manifest_element.name == element_name) { - return manifest_element.num_bytes; - } - } - } - return static_cast(-1); -} - -/** - * Serialize transcript to a vector of bytes. - * - * @return Serialized transcript - * */ -std::vector Transcript::export_transcript() const -{ - std::vector buffer; - - for (size_t i = 0; i < manifest.get_num_rounds(); ++i) { - for (auto manifest_element : manifest.get_round_manifest(i).elements) { - ASSERT(elements.count(manifest_element.name) == 1); - const std::vector& element_data = elements.at(manifest_element.name); - if (!manifest_element.derived_by_verifier) { - ASSERT(manifest_element.num_bytes == element_data.size()); - } - if (!manifest_element.derived_by_verifier) { - // printf("writing element %s ", manifest_element.name.c_str()); - // for (size_t j = 0; j < element_data.size(); ++j) { - // printf("%x", element_data[j]); - // } - // printf("\n"); - buffer.insert(buffer.end(), element_data.begin(), element_data.end()); - } - } - } - // printf("output buffer size = %lu \n", buffer.size()); - return buffer; -} - -} // namespace transcript +// This file is here to make sure that a transcript object file is created. \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp index 2c218ede456..afdd70f3808 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp @@ -1,123 +1,320 @@ #pragma once -#include "manifest.hpp" -#include -#include -#include -#include -#include -#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/common/serialize.hpp" +#include "barretenberg/crypto/blake3s/blake3s.hpp" +#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" -namespace transcript { +namespace proof_system::honk { -struct Keccak256Hasher { - static constexpr size_t SECURITY_PARAMETER_SIZE = 32; - static constexpr size_t PRNG_OUTPUT_SIZE = 32; +// class TranscriptManifest; +class TranscriptManifest { + struct RoundData { + std::vector challenge_label; + std::vector> entries; - static std::array hash(std::vector const& buffer); -}; + bool operator==(const RoundData& other) const = default; + }; -struct Blake3sHasher { - static constexpr size_t SECURITY_PARAMETER_SIZE = 16; - static constexpr size_t PRNG_OUTPUT_SIZE = 32; + std::map manifest; - static std::array hash(std::vector const& input); -}; + public: + void print() + { + for (auto& round : manifest) { + info("Round: ", round.first); + for (auto& label : round.second.challenge_label) { + info("\tchallenge: ", label); + } + for (auto& entry : round.second.entries) { + info("\telement (", entry.second, "): ", entry.first); + } + } + } + + template void add_challenge(size_t round, Strings&... labels) + { + manifest[round].challenge_label = { labels... }; + } + void add_entry(size_t round, const std::string& element_label, size_t element_size) + { + manifest[round].entries.emplace_back(element_label, element_size); + } + + [[nodiscard]] size_t size() const { return manifest.size(); } -enum HashType { Keccak256, PedersenBlake3s }; + RoundData operator[](const size_t& round) { return manifest[round]; }; + + bool operator==(const TranscriptManifest& other) const = default; +}; /** - * Transcript is used by the Prover to store round values - * and derive challenges. The verifier uses it to parse serialized - * values and get the data and challenges back. + * @brief Common transcript class for both parties. Stores the data for the current round, as well as the + * manifest. * + * @tparam FF Field from which we sample challenges. */ -class Transcript { - static constexpr size_t PRNG_OUTPUT_SIZE = 32; - struct challenge { - std::array data; - }; - +template class BaseTranscript { public: - typedef proof_system::plonk::verification_key Key; + BaseTranscript() = default; /** - * Create a new transcript for Prover based on the manifest. + * @brief Construct a new Base Transcript object for Verifier using proof_data * - * @param input_manifes The manifest with round descriptions. - * @param hash_type The hash to use for Fiat-Shamir. - * @param challenge_bytes The number of bytes per challenge to generate. + * @param proof_data + */ + explicit BaseTranscript(const std::vector& proof_data) + : proof_data(proof_data.begin(), proof_data.end()) + {} + static constexpr size_t HASH_OUTPUT_SIZE = 32; + + private: + static constexpr size_t MIN_BYTES_PER_CHALLENGE = 128 / 8; // 128 bit challenges + + size_t num_bytes_read = 0; // keeps track of number of bytes read from proof_data by the verifier + size_t round_number = 0; // current round for manifest + bool is_first_challenge = true; // indicates if this is the first challenge this transcript is generating + std::array previous_challenge_buffer{}; // default-initialized to zeros + std::vector current_round_data; + + // "Manifest" object that records a summary of the transcript interactions + TranscriptManifest manifest; + + /** + * @brief Compute next challenge c_next = H( Compress(c_prev || round_buffer) ) + * @details This function computes a new challenge for the current round using the previous challenge + * and the current round data, if they are exist. It clears the current_round_data if nonempty after + * computing the challenge to minimize how much we compress. It also sets previous_challenge_buffer + * to the current challenge buffer to set up next function call. + * @return std::array + */ + [[nodiscard]] std::array get_next_challenge_buffer() + { + // Prevent challenge generation if this is the first challenge we're generating, + // AND nothing was sent by the prover. + if (is_first_challenge) { + ASSERT(!current_round_data.empty()); + } + + // concatenate the previous challenge (if this is not the first challenge) with the current round data. + // TODO(Adrian): Do we want to use a domain separator as the initial challenge buffer? + // We could be cheeky and use the hash of the manifest as domain separator, which would prevent us from having + // to domain separate all the data. (See https://safe-hash.dev) + std::vector full_buffer; + if (!is_first_challenge) { + // if not the first challenge, we can use the previous_challenge_buffer + full_buffer.insert(full_buffer.end(), previous_challenge_buffer.begin(), previous_challenge_buffer.end()); + } else { + // Update is_first_challenge for the future + is_first_challenge = false; + } + if (!current_round_data.empty()) { + full_buffer.insert(full_buffer.end(), current_round_data.begin(), current_round_data.end()); + current_round_data.clear(); // clear the round data buffer since it has been used + } + + // Pre-hash the full buffer to minimize the amount of data passed to the cryptographic hash function. + // Only a collision-resistant hash-function like Pedersen is required for this step. + // Note: this pre-hashing is an efficiency trick that may be discareded if using a SNARK-friendly or in contexts + // (eg smart contract verification) where the cost of elliptic curve operations is high. + std::vector compressed_buffer = to_buffer(crypto::pedersen_hash::hash_buffer(full_buffer)); + + // Use a strong hash function to derive the new challenge_buffer. + auto base_hash = blake3::blake3s(compressed_buffer); + + std::array new_challenge_buffer; + std::copy_n(base_hash.begin(), HASH_OUTPUT_SIZE, new_challenge_buffer.begin()); + // update previous challenge buffer for next time we call this function + previous_challenge_buffer = new_challenge_buffer; + return new_challenge_buffer; + }; + + protected: + /** + * @brief Adds challenge elements to the current_round_buffer and updates the manifest. * + * @param label of the element sent + * @param element_bytes serialized */ - Transcript(const Manifest input_manifest, - const HashType hash_type = HashType::Keccak256, - const size_t challenge_bytes = 32) - : num_challenge_bytes(challenge_bytes) - , hasher(hash_type) - , manifest(input_manifest) + void consume_prover_element_bytes(const std::string& label, std::span element_bytes) { - // Just to be safe, because compilers can be weird. - current_challenge.data = {}; - compute_challenge_map(); + // Add an entry to the current round of the manifest + manifest.add_entry(round_number, label, element_bytes.size()); + + current_round_data.insert(current_round_data.end(), element_bytes.begin(), element_bytes.end()); } /** - * Parse a serialized version of an input_transcript into a deserialized - * one based on the manifest. - * - * @param input_transcript Serialized transcript. - * @param input_manifest The manifest which governs the parsing. - * @param hash_type The hash used for Fiat-Shamir - * @param challenge_bytes The number of bytes per challenge to generate. + * @brief Serializes object and appends it to proof_data + * @details Calls to_buffer on element to serialize, and modifies proof_data object by appending the serialized + * bytes to it. + * @tparam T + * @param element + * @param proof_data + */ + template void serialize_to_buffer(const T& element, std::vector& proof_data) + { + auto element_bytes = to_buffer(element); + proof_data.insert(proof_data.end(), element_bytes.begin(), element_bytes.end()); + } + /** + * @brief Deserializes the bytes starting at offset into the typed element and returns that element. + * @details Using the template parameter and the offset argument, this function deserializes the bytes with + * from_buffer and then increments the offset appropriately based on the number of bytes that were deserialized. + * @tparam T + * @param proof_data + * @param offset + * @return T + */ + template T deserialize_from_buffer(const std::vector& proof_data, size_t& offset) const + { + constexpr size_t element_size = sizeof(T); + ASSERT(offset + element_size <= proof_data.size()); + + auto element_bytes = std::span{ proof_data }.subspan(offset, element_size); + offset += element_size; + + T element = from_buffer(element_bytes); + + return element; + } + + public: + // Contains the raw data sent by the prover. + std::vector proof_data; + /** + * @brief After all the prover messages have been sent, finalize the round by hashing all the data and then create + * the number of requested challenges. + * @details Challenges are generated by iteratively hashing over the previous challenge, using + * get_next_challenge_buffer(). + * TODO(#741): Optimizations for this function include generalizing type of hash, splitting hashes into + * multiple challenges. * + * @param labels human-readable names for the challenges for the manifest + * @return std::array challenges for this round. */ - Transcript(const std::vector& input_transcript, - const Manifest input_manifest, - const HashType hash_type = HashType::Keccak256, - const size_t challenge_bytes = 32); + template std::array get_challenges(const Strings&... labels) + { + constexpr size_t num_challenges = sizeof...(Strings); + + // Add challenge labels for current round to the manifest + manifest.add_challenge(round_number, labels...); + + // Compute the new challenge buffer from which we derive the challenges. - Manifest get_manifest() const { return manifest; } + // Create challenges from bytes. + std::array challenges{}; - void add_element(const std::string& element_name, const std::vector& buffer); + // Generate the challenges by iteratively hashing over the previous challenge. + for (size_t i = 0; i < num_challenges; i++) { + auto next_challenge_buffer = get_next_challenge_buffer(); // get next challenge buffer + std::array field_element_buffer{}; + // copy half of the hash to lower 128 bits of challenge + // Note: because of how read() from buffers to fields works (in field_declarations.hpp), + // we use the later half of the buffer + std::copy_n(next_challenge_buffer.begin(), + HASH_OUTPUT_SIZE / 2, + field_element_buffer.begin() + HASH_OUTPUT_SIZE / 2); + challenges[i] = from_buffer(field_element_buffer); + } - void apply_fiat_shamir(const std::string& challenge_name /*, const bool debug = false*/); + // Prepare for next round. + ++round_number; - bool has_challenge(const std::string& challenge_name) const; + return challenges; + } - std::array get_challenge(const std::string& challenge_name, const size_t idx = 0) const; + /** + * @brief Adds a prover message to the transcript, only intended to be used by the prover. + * + * @details Serializes the provided object into `proof_data`, and updates the current round state in + * consume_prover_element_bytes. + * + * @param label Description/name of the object being added. + * @param element Serializable object that will be added to the transcript + * + * @todo Use a concept to only allow certain types to be passed. Requirements are that the object should be + * serializable. + * + */ + template void send_to_verifier(const std::string& label, const T& element) + { + using serialize::write; + // TODO(Adrian): Ensure that serialization of affine elements (including point at infinity) is consistent. + // TODO(Adrian): Consider restricting serialization (via concepts) to types T for which sizeof(T) reliably + // returns the size of T in bytes. (E.g. this is true for std::array but not for std::vector). + auto element_bytes = to_buffer(element); + proof_data.insert(proof_data.end(), element_bytes.begin(), element_bytes.end()); - int get_challenge_index_from_map(const std::string& challenge_map_name) const; + BaseTranscript::consume_prover_element_bytes(label, element_bytes); + } - std::array get_challenge_from_map(const std::string& challenge_name, - const std::string& challenge_map_name) const; + /** + * @brief Reads the next element of type `T` from the transcript, with a predefined label, only used by verifier. + * + * @param label Human readable name for the challenge. + * @return deserialized element of type T + */ + template T receive_from_prover(const std::string& label) + { + constexpr size_t element_size = sizeof(T); + ASSERT(num_bytes_read + element_size <= proof_data.size()); - size_t get_num_challenges(const std::string& challenge_name) const; + auto element_bytes = std::span{ proof_data }.subspan(num_bytes_read, element_size); + num_bytes_read += element_size; - std::vector get_element(const std::string& element_name) const; + BaseTranscript::consume_prover_element_bytes(label, element_bytes); - size_t get_element_size(const std::string& element_name) const; + T element = from_buffer(element_bytes); - std::vector export_transcript() const; + return element; + } - void compute_challenge_map(); + /** + * @brief For testing: initializes transcript with some arbitrary data so that a challenge can be generated after + * initialization. Only intended to be used by Prover. + * + * @return BaseTranscript + */ + static BaseTranscript prover_init_empty() + { + BaseTranscript transcript; + constexpr uint32_t init{ 42 }; // arbitrary + transcript.send_to_verifier("Init", init); + return transcript; + }; - void mock_inputs_prior_to_challenge(const std::string& challenge_name, size_t circuit_size = 1); + /** + * @brief For testing: initializes transcript based on proof data then receives junk data produced by + * BaseTranscript::prover_init_empty(). Only intended to be used by Verifier. + * + * @param transcript + * @return BaseTranscript + */ + static BaseTranscript verifier_init_empty(const BaseTranscript& transcript) + { + BaseTranscript verifier_transcript{ transcript.proof_data }; + [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); + return verifier_transcript; + }; - void print(); + FF get_challenge(const std::string& label) { return get_challenges(label)[0]; } - private: - // The round of the protocol - size_t current_round = 0; - size_t num_challenge_bytes; - HashType hasher; - std::map> elements; + [[nodiscard]] TranscriptManifest get_manifest() const { return manifest; }; - std::map> challenges; + void print() { manifest.print(); } - challenge current_challenge; + /** + * @brief Deserializes the FULL transcript into the struct defined by each flavor derivedclass. + * @details Not supported for base transcript class because it does not have a defined structure. The current + * proof_data object must represent the whole proof and not a partial proof or it will throw an error. + */ + virtual void deserialize_full_transcript() { throw_or_abort("Cannot deserialize transcript"); } - Manifest manifest; - std::map challenge_map; + /** + * @brief Serializes the FULL transcript from the defined derived class back into proof_data. + * @details Only works if the struct is populated (usually from a call to deserialize_full_transcript). Allows for + * modified transcript objects to be updated in the actual proof for testing purposes. + */ + virtual void serialize_full_transcript() { throw_or_abort("Cannot serialize transcript"); } }; - -} // namespace transcript +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp index 6489f90d014..6016fef8c89 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp @@ -1,191 +1,18 @@ -#include "barretenberg/polynomials/univariate.hpp" -#include "transcript_wrappers.hpp" -#include -#include +#include "barretenberg/transcript/transcript.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" #include -#include -namespace { -transcript::Manifest create_manifest(const size_t num_public_inputs) -{ - // add public inputs.... - constexpr size_t g1_size = 64; - constexpr size_t fr_size = 32; - const size_t public_input_size = fr_size * num_public_inputs; - const transcript::Manifest output = transcript::Manifest( - { transcript::Manifest::RoundManifest( - { { "circuit_size", 4, true }, { "public_input_size", 4, true } }, "init", 1), - transcript::Manifest::RoundManifest({ { "public_inputs", public_input_size, false }, - { "W_1", g1_size, false }, - { "W_2", g1_size, false }, - { "W_3", g1_size, false } }, - "beta", - 2), - transcript::Manifest::RoundManifest({ { "Z_PERM", g1_size, false } }, "alpha", 1), - transcript::Manifest::RoundManifest( - { { "T_1", g1_size, false }, { "T_2", g1_size, false }, { "T_3", g1_size, false } }, "z", 1), - transcript::Manifest::RoundManifest({ { "w_1", fr_size, false }, - { "w_2", fr_size, false }, - { "w_3", fr_size, false }, - { "w_3_omega", fr_size, false }, - { "z_perm_omega", fr_size, false }, - { "sigma_1", fr_size, false }, - { "sigma_2", fr_size, false }, - { "r", fr_size, false }, - { "t", fr_size, true } }, - "nu", - 10), - transcript::Manifest::RoundManifest( - { { "PI_Z", g1_size, false }, { "PI_Z_OMEGA", g1_size, false } }, "separator", 1) }); - return output; -} -} // namespace - -TEST(transcript, validate_transcript) -{ - std::vector g1_vector(64); - std::vector g2_vector(128); - std::vector fr_vector(32); - - for (size_t i = 0; i < g1_vector.size(); ++i) { - g1_vector[i] = 1; - } - for (size_t i = 0; i < g2_vector.size(); ++i) { - g2_vector[i] = 1; - } - for (size_t i = 0; i < fr_vector.size(); ++i) { - fr_vector[i] = 1; - } - transcript::Transcript transcript = transcript::Transcript(create_manifest(0)); - transcript.add_element("circuit_size", { 1, 2, 3, 4 }); - transcript.add_element("public_input_size", { 1, 2, 3, 4 }); - transcript.apply_fiat_shamir("init"); - - transcript.add_element("public_inputs", {}); - - transcript.add_element("W_1", g1_vector); - transcript.add_element("W_2", g1_vector); - transcript.add_element("W_3", g1_vector); - - transcript.apply_fiat_shamir("beta"); - - transcript.add_element("Z_PERM", g1_vector); - - transcript.apply_fiat_shamir("alpha"); - - transcript.add_element("T_1", g1_vector); - transcript.add_element("T_2", g1_vector); - transcript.add_element("T_3", g1_vector); - - transcript.apply_fiat_shamir("z"); - - transcript.add_element("w_1", fr_vector); - transcript.add_element("w_2", fr_vector); - transcript.add_element("w_3", fr_vector); - transcript.add_element("w_3_omega", fr_vector); - transcript.add_element("z_perm_omega", fr_vector); - transcript.add_element("sigma_1", fr_vector); - transcript.add_element("sigma_2", fr_vector); - transcript.add_element("r", fr_vector); - transcript.add_element("t", fr_vector); - - transcript.apply_fiat_shamir("nu"); - - transcript.add_element("PI_Z", g1_vector); - transcript.add_element("PI_Z_OMEGA", g1_vector); - - transcript.apply_fiat_shamir("separator"); +namespace barretenberg::honk_transcript_tests { - std::vector result = transcript.get_element("PI_Z_OMEGA"); - EXPECT_EQ(result.size(), g1_vector.size()); - for (size_t i = 0; i < result.size(); ++i) { - EXPECT_EQ(result[i], g1_vector[i]); - } -} +using FF = barretenberg::fr; +using Transcript = proof_system::honk::BaseTranscript; -namespace { -transcript::Manifest create_toy_honk_manifest(const size_t num_public_inputs, const size_t SUMCHECK_RELATION_LENGTH) +TEST(BaseTranscript, Basic) { - // Create a toy honk manifest that includes a univariate like the ones constructed by the prover in each round of - // sumcheck - constexpr size_t g1_size = 64; - constexpr size_t fr_size = 32; - const size_t public_input_size = fr_size * num_public_inputs; - const transcript::Manifest output = transcript::Manifest( - { transcript::Manifest::RoundManifest( - { { "circuit_size", 4, true }, { "public_input_size", 4, true } }, "init", 1), - transcript::Manifest::RoundManifest({ { "public_inputs", public_input_size, false }, - { "W_1", g1_size, false }, - { "W_2", g1_size, false }, - { "W_3", g1_size, false } }, - "beta", - 2), - transcript::Manifest::RoundManifest( - { { "round_univariate_i", fr_size * SUMCHECK_RELATION_LENGTH, false } }, "omicron", 1) }); - return output; + Transcript transcript; + FF elt = 561; + transcript.send_to_verifier("something", elt); + auto received = transcript.template receive_from_prover("something"); + EXPECT_EQ(received, elt); } -} // namespace - -/** - * @brief Test transcript serialization/deserialization of a Univariate object, which is needed for Sumcheck - * - */ -TEST(transcript, univariate_serialization) -{ - constexpr size_t num_public_inputs = 0; - constexpr size_t LENGTH = 8; - - using Fr = barretenberg::fr; - using Univariate = barretenberg::Univariate; - using Transcript = transcript::StandardTranscript; - - std::vector g1_vector(64); - std::vector fr_vector(32); - std::array evaluations; - - for (size_t i = 0; i < g1_vector.size(); ++i) { - g1_vector[i] = 1; - } - for (size_t i = 0; i < fr_vector.size(); ++i) { - fr_vector[i] = 1; - } - for (size_t i = 0; i < LENGTH; ++i) { - evaluations[i] = Fr::random_element(); - } - - // Instantiate a StandardTranscript - auto transcript = Transcript(create_toy_honk_manifest(num_public_inputs, LENGTH)); - - // Add some junk to the transcript and compute challenges - transcript.add_element("circuit_size", { 1, 2, 3, 4 }); - transcript.add_element("public_input_size", { 1, 2, 3, 4 }); - - transcript.apply_fiat_shamir("init"); - - transcript.add_element("public_inputs", {}); - transcript.add_element("W_1", g1_vector); - transcript.add_element("W_2", g1_vector); - transcript.add_element("W_3", g1_vector); - - transcript.apply_fiat_shamir("beta"); - - // Instantiate a Univariate from the evaluations - auto univariate = Univariate(evaluations); - - // Add the univariate to the transcript using the to_buffer() member function - // NOTE: the element being added here does not actually have to exist in the manifest for the - // serialization/deserialization to work. - transcript.add_element("round_univariate_i", univariate.to_buffer()); - - // Example of challenge generation; not used in test - transcript.apply_fiat_shamir("omicron"); - Fr omicron = Fr::serialize_from_buffer(transcript.get_challenge("omicron").begin()); - static_cast(omicron); - - // Deserialize into a univariate from the transcript - auto deserialized_univariate = Univariate::serialize_from_buffer(&transcript.get_element("round_univariate_i")[0]); - - for (size_t i = 0; i < LENGTH; ++i) { - EXPECT_EQ(univariate.value_at(i), deserialized_univariate.value_at(i)); - } -} \ No newline at end of file +} // namespace barretenberg::honk_transcript_tests \ No newline at end of file