From db67aa1eb6ae9669d98301efbbb146d6265d58f4 Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Mon, 30 Oct 2023 23:43:34 -0400 Subject: [PATCH] feat: adding structure to Transcript (#2937) Adding structuring feature to transcript based on the flavor and resolves https://github.com/AztecProtocol/barretenberg/issues/656. The main two functions added are `deserialize_full_transcript()` and `serialize_full_transcript()`, which are defined for each flavored transcript derived class. These classes are defined in the flavor classes, and primarily declare all of the transcript objects as member variables. `deserialize_full_transcript()` will take a full proof generated by the flavored prover, and put all those bytes into the member variables. Then, one can now view and modify the objects by just using the member variables. In order to actually push the modification, one has to call `serialize_full_transcript()` in order to regenerate the proof from the (modified) member variables. The tests in `(flavor)_transcript.test.cpp` illustrate how to use these functions in more depth. I also modified the tests in `stdlib/recursion/honk/verifier/goblin_verifier.test.cpp` and in `stdlib/recursion/honk/verifier/verifier.test.cpp`. Got rid of the ProverTranscript and VerifierTranscript and merging them into the BaseTranscript. This was done to avoid having to create these for every flavor derived class and because they did not provide much on top of the BaseTranscript. Created transcript tests for flavors besides Ultra. Transcript breakdown for all flavors: https://docs.google.com/spreadsheets/d/1TpkkPj9o5ZXr_kWT7WsquXSEZY10C1Lt3BWeCA7Qe9U/edit#gid=0. Some design considerations: https://hackmd.io/o8HbTiujTGa4sLccAHQaxw?both. --- .../src/barretenberg/honk/flavor/ecc_vm.hpp | 420 +++++++++++++++++- .../honk/flavor/goblin_translator.hpp | 4 +- .../barretenberg/honk/flavor/goblin_ultra.hpp | 108 ++++- .../honk/flavor/goblin_ultra_recursive.hpp | 135 ++++++ .../src/barretenberg/honk/flavor/ultra.hpp | 124 +++++- .../honk/flavor/ultra_recursive.hpp | 122 +++++ .../honk/pcs/gemini/gemini.test.cpp | 4 +- .../cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp | 6 +- .../barretenberg/honk/pcs/ipa/ipa.test.cpp | 8 +- .../cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp | 4 +- .../barretenberg/honk/pcs/kzg/kzg.test.cpp | 8 +- .../honk/pcs/shplonk/shplonk.test.cpp | 4 +- .../honk/pcs/zeromorph/zeromorph.test.cpp | 12 +- .../honk/proof_system/eccvm_prover.cpp | 2 +- .../honk/proof_system/eccvm_prover.hpp | 3 +- .../honk/proof_system/eccvm_verifier.cpp | 5 +- .../honk/proof_system/eccvm_verifier.hpp | 5 +- .../goblin_merge/merge_prover.hpp | 2 +- .../goblin_merge/merge_verifier.cpp | 2 +- .../goblin_merge/merge_verifier.hpp | 2 +- .../honk/proof_system/protogalaxy_prover.hpp | 2 +- .../proof_system/protogalaxy_verifier.cpp | 2 +- .../proof_system/protogalaxy_verifier.hpp | 2 +- .../honk/proof_system/ultra_prover.hpp | 3 +- .../honk/proof_system/ultra_verifier.cpp | 2 +- .../honk/proof_system/ultra_verifier.hpp | 2 +- .../honk/sumcheck/partial_evaluation.test.cpp | 20 +- .../barretenberg/honk/sumcheck/sumcheck.hpp | 5 +- .../honk/sumcheck/sumcheck.test.cpp | 12 +- .../honk/transcript/eccvm_transcript.test.cpp | 341 ++++++++++++++ .../goblin_ultra_transcript.test.cpp | 233 ++++++++++ .../honk/transcript/transcript.hpp | 150 ++++--- ...ipt.test.cpp => ultra_transcript.test.cpp} | 90 ++-- .../relations/ecc_vm/ecc_set_relation.cpp | 2 +- .../recursion/honk/transcript/transcript.hpp | 6 +- .../honk/transcript/transcript.test.cpp | 11 +- .../honk/verifier/goblin_verifier.test.cpp | 5 +- .../recursion/honk/verifier/verifier.test.cpp | 5 +- 38 files changed, 1710 insertions(+), 163 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp rename barretenberg/cpp/src/barretenberg/honk/transcript/{transcript.test.cpp => ultra_transcript.test.cpp} (80%) diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/ecc_vm.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/ecc_vm.hpp index 3e966d8c833..3bb83245049 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/ecc_vm.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/ecc_vm.hpp @@ -848,7 +848,7 @@ template class ECCVMBa public: VerifierCommitments(const std::shared_ptr& verification_key, - const VerifierTranscript& transcript) + [[maybe_unused]] const BaseTranscript& transcript) { static_cast(transcript); Base::lagrange_first = verification_key->lagrange_first; @@ -856,6 +856,424 @@ template class ECCVMBa Base::lagrange_last = verification_key->lagrange_last; } }; + + /** + * @brief Derived class that defines proof structure for ECCVM proofs, as well as supporting functions. + * + */ + class Transcript : public BaseTranscript { + public: + uint32_t circuit_size; + Commitment transcript_add_comm; + Commitment transcript_mul_comm; + Commitment transcript_eq_comm; + Commitment transcript_collision_check_comm; + Commitment transcript_msm_transition_comm; + Commitment transcript_pc_comm; + Commitment transcript_msm_count_comm; + Commitment transcript_x_comm; + Commitment transcript_y_comm; + Commitment transcript_z1_comm; + Commitment transcript_z2_comm; + Commitment transcript_z1zero_comm; + Commitment transcript_z2zero_comm; + Commitment transcript_op_comm; + Commitment transcript_accumulator_x_comm; + Commitment transcript_accumulator_y_comm; + Commitment transcript_msm_x_comm; + Commitment transcript_msm_y_comm; + Commitment precompute_pc_comm; + Commitment precompute_point_transition_comm; + Commitment precompute_round_comm; + Commitment precompute_scalar_sum_comm; + Commitment precompute_s1hi_comm; + Commitment precompute_s1lo_comm; + Commitment precompute_s2hi_comm; + Commitment precompute_s2lo_comm; + Commitment precompute_s3hi_comm; + Commitment precompute_s3lo_comm; + Commitment precompute_s4hi_comm; + Commitment precompute_s4lo_comm; + Commitment precompute_skew_comm; + Commitment precompute_dx_comm; + Commitment precompute_dy_comm; + Commitment precompute_tx_comm; + Commitment precompute_ty_comm; + Commitment msm_transition_comm; + Commitment msm_add_comm; + Commitment msm_double_comm; + Commitment msm_skew_comm; + Commitment msm_accumulator_x_comm; + Commitment msm_accumulator_y_comm; + Commitment msm_pc_comm; + Commitment msm_size_of_msm_comm; + Commitment msm_count_comm; + Commitment msm_round_comm; + Commitment msm_add1_comm; + Commitment msm_add2_comm; + Commitment msm_add3_comm; + Commitment msm_add4_comm; + Commitment msm_x1_comm; + Commitment msm_y1_comm; + Commitment msm_x2_comm; + Commitment msm_y2_comm; + Commitment msm_x3_comm; + Commitment msm_y3_comm; + Commitment msm_x4_comm; + Commitment msm_y4_comm; + Commitment msm_collision_x1_comm; + Commitment msm_collision_x2_comm; + Commitment msm_collision_x3_comm; + Commitment msm_collision_x4_comm; + Commitment msm_lambda1_comm; + Commitment msm_lambda2_comm; + Commitment msm_lambda3_comm; + Commitment msm_lambda4_comm; + Commitment msm_slice1_comm; + Commitment msm_slice2_comm; + Commitment msm_slice3_comm; + Commitment msm_slice4_comm; + Commitment transcript_accumulator_empty_comm; + Commitment transcript_reset_accumulator_comm; + Commitment precompute_select_comm; + Commitment lookup_read_counts_0_comm; + Commitment lookup_read_counts_1_comm; + Commitment z_perm_comm; + Commitment lookup_inverses_comm; + std::vector> sumcheck_univariates; + std::array sumcheck_evaluations; + std::vector gemini_univariate_comms; + std::vector gemini_a_evals; + Commitment shplonk_q_comm; + Commitment kzg_w_comm; + // the rest are only for Grumpkin + uint64_t ipa_poly_degree; + std::vector ipa_l_comms; + std::vector ipa_r_comms; + FF ipa_a_0_eval; + + Transcript() = default; + + Transcript(const std::vector& proof) + : BaseTranscript(proof) + {} + + void deserialize_full_transcript() override + { + // take current proof and put them into the struct + size_t num_bytes_read = 0; + circuit_size = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + size_t log_n = numeric::get_msb(circuit_size); + transcript_add_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_mul_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_eq_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_collision_check_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_msm_transition_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_pc_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_msm_count_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_x_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_y_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_z1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_z2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_z1zero_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_z2zero_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_op_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_accumulator_x_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_accumulator_y_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_msm_x_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_msm_y_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_pc_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_point_transition_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_round_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_scalar_sum_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s1hi_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s1lo_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s2hi_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s2lo_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s3hi_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s3lo_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s4hi_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_s4lo_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_skew_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_dx_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_dy_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_tx_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_ty_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_transition_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_add_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_double_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_skew_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_accumulator_x_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_accumulator_y_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_pc_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_size_of_msm_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_count_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_round_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_add1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_add2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_add3_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_add4_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_x1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_y1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_x2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_y2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_x3_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_y3_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_x4_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_y4_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_collision_x1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_collision_x2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_collision_x3_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_collision_x4_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_lambda1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_lambda2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_lambda3_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_lambda4_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_slice1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_slice2_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_slice3_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + msm_slice4_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_accumulator_empty_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + transcript_reset_accumulator_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + precompute_select_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + lookup_read_counts_0_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + lookup_read_counts_1_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + lookup_inverses_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + z_perm_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + sumcheck_univariates.emplace_back(BaseTranscript::template deserialize_from_buffer< + barretenberg::Univariate>( + BaseTranscript::proof_data, num_bytes_read)); + } + sumcheck_evaluations = + BaseTranscript::template deserialize_from_buffer>( + BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n - 1; ++i) { + gemini_univariate_comms.emplace_back(BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read)); + } + for (size_t i = 0; i < log_n; ++i) { + gemini_a_evals.emplace_back(BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read)); + } + shplonk_q_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + if (std::is_same>::value) { + kzg_w_comm = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + } else if (std::is_same>::value) { + ipa_poly_degree = BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read); + auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + ipa_l_comms.emplace_back(BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read)); + ipa_r_comms.emplace_back(BaseTranscript::template deserialize_from_buffer( + BaseTranscript::proof_data, num_bytes_read)); + } + ipa_a_0_eval = BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, + num_bytes_read); + } else { + throw_or_abort("Unsupported PCS"); + } + } + + void serialize_full_transcript() override + { + size_t old_proof_length = BaseTranscript::proof_data.size(); + BaseTranscript::proof_data.clear(); + size_t log_n = numeric::get_msb(circuit_size); + + BaseTranscript::template serialize_to_buffer(circuit_size, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_add_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_mul_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_eq_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_collision_check_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_msm_transition_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_pc_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_msm_count_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_x_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_y_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_z1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_z2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_z1zero_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_z2zero_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_op_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_accumulator_x_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_accumulator_y_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_msm_x_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_msm_y_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_pc_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_point_transition_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_round_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_scalar_sum_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s1hi_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s1lo_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s2hi_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s2lo_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s3hi_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s3lo_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s4hi_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_s4lo_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_skew_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_dx_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_dy_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_tx_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_ty_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_transition_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_add_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_double_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_skew_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_accumulator_x_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_accumulator_y_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_pc_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_size_of_msm_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_count_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_round_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_add1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_add2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_add3_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_add4_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_x1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_y1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_x2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_y2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_x3_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_y3_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_x4_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_y4_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_collision_x1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_collision_x2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_collision_x3_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_collision_x4_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_lambda1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_lambda2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_lambda3_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_lambda4_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_slice1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_slice2_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_slice3_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(msm_slice4_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_accumulator_empty_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(transcript_reset_accumulator_comm, + BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(precompute_select_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(lookup_read_counts_0_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(lookup_read_counts_1_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(lookup_inverses_comm, BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(z_perm_comm, BaseTranscript::proof_data); + for (size_t i = 0; i < log_n; ++i) { + BaseTranscript::template serialize_to_buffer(sumcheck_univariates[i], + BaseTranscript::proof_data); + } + BaseTranscript::template serialize_to_buffer(sumcheck_evaluations, BaseTranscript::proof_data); + for (size_t i = 0; i < log_n - 1; ++i) { + BaseTranscript::template serialize_to_buffer(gemini_univariate_comms[i], + BaseTranscript::proof_data); + } + for (size_t i = 0; i < log_n; ++i) { + BaseTranscript::template serialize_to_buffer(gemini_a_evals[i], BaseTranscript::proof_data); + } + BaseTranscript::template serialize_to_buffer(shplonk_q_comm, BaseTranscript::proof_data); + if (std::is_same>::value) { + BaseTranscript::template serialize_to_buffer(kzg_w_comm, BaseTranscript::proof_data); + } else if (std::is_same>::value) { + BaseTranscript::template serialize_to_buffer(ipa_poly_degree, BaseTranscript::proof_data); + auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + BaseTranscript::template serialize_to_buffer(ipa_l_comms[i], BaseTranscript::proof_data); + BaseTranscript::template serialize_to_buffer(ipa_r_comms[i], BaseTranscript::proof_data); + } + + BaseTranscript::template serialize_to_buffer(ipa_a_0_eval, BaseTranscript::proof_data); + } + ASSERT(BaseTranscript::proof_data.size() == old_proof_length); + } + }; }; class ECCVM : public ECCVMBase> {}; diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp index f68a3ff54eb..6de0d85fe03 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_translator.hpp @@ -1618,10 +1618,10 @@ template class GoblinTranslator_ { class VerifierCommitments : public AllEntities { public: - VerifierCommitments(std::shared_ptr verification_key, VerifierTranscript transcript) + VerifierCommitments(std::shared_ptr verification_key, + [[maybe_unused]] const BaseTranscript& transcript) { static_cast(transcript); - static_cast(verification_key); this->lagrange_first = verification_key->lagrange_first; this->lagrange_last = verification_key->lagrange_last; this->lagrange_odd_in_minicircuit = verification_key->lagrange_odd_in_minicircuit; diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp index faf55851306..628a910b21b 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp @@ -417,7 +417,8 @@ class GoblinUltra { class VerifierCommitments : public AllEntities { public: - VerifierCommitments(std::shared_ptr verification_key, VerifierTranscript transcript) + VerifierCommitments(std::shared_ptr verification_key, + [[maybe_unused]] const BaseTranscript& transcript) { static_cast(transcript); q_m = verification_key->q_m; @@ -454,6 +455,111 @@ class GoblinUltra { std::vector gate_separation_challenges; FF target_sum; }; + + /** + * @brief Derived class that defines proof structure for GoblinUltra proofs, as well as supporting functions. + * + */ + class Transcript : public BaseTranscript { + public: + uint32_t circuit_size; + uint32_t public_input_size; + uint32_t pub_inputs_offset; + std::vector public_inputs; + Commitment w_l_comm; + Commitment w_r_comm; + Commitment w_o_comm; + Commitment ecc_op_wire_1_comm; + Commitment ecc_op_wire_2_comm; + Commitment ecc_op_wire_3_comm; + Commitment ecc_op_wire_4_comm; + Commitment sorted_accum_comm; + Commitment w_4_comm; + Commitment z_perm_comm; + Commitment z_lookup_comm; + std::vector> sumcheck_univariates; + std::array sumcheck_evaluations; + std::vector zm_cq_comms; + Commitment zm_cq_comm; + Commitment zm_pi_comm; + + Transcript() = default; + + Transcript(const std::vector& proof) + : BaseTranscript(proof) + {} + void deserialize_full_transcript() override + { + // take current proof and put them into the struct + size_t num_bytes_read = 0; + circuit_size = deserialize_from_buffer(proof_data, num_bytes_read); + size_t log_n = numeric::get_msb(circuit_size); + + public_input_size = deserialize_from_buffer(proof_data, num_bytes_read); + pub_inputs_offset = deserialize_from_buffer(proof_data, num_bytes_read); + for (size_t i = 0; i < public_input_size; ++i) { + public_inputs.push_back(deserialize_from_buffer(proof_data, num_bytes_read)); + } + w_l_comm = deserialize_from_buffer(proof_data, num_bytes_read); + w_r_comm = deserialize_from_buffer(proof_data, num_bytes_read); + w_o_comm = deserialize_from_buffer(proof_data, num_bytes_read); + ecc_op_wire_1_comm = deserialize_from_buffer(proof_data, num_bytes_read); + ecc_op_wire_2_comm = deserialize_from_buffer(proof_data, num_bytes_read); + ecc_op_wire_3_comm = deserialize_from_buffer(proof_data, num_bytes_read); + ecc_op_wire_4_comm = deserialize_from_buffer(proof_data, num_bytes_read); + sorted_accum_comm = deserialize_from_buffer(proof_data, num_bytes_read); + w_4_comm = deserialize_from_buffer(proof_data, num_bytes_read); + z_perm_comm = deserialize_from_buffer(proof_data, num_bytes_read); + z_lookup_comm = deserialize_from_buffer(proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + sumcheck_univariates.push_back( + deserialize_from_buffer>( + proof_data, num_bytes_read)); + } + sumcheck_evaluations = + deserialize_from_buffer>(proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_bytes_read)); + } + zm_cq_comm = deserialize_from_buffer(proof_data, num_bytes_read); + zm_pi_comm = deserialize_from_buffer(proof_data, num_bytes_read); + } + + void serialize_full_transcript() override + { + size_t old_proof_length = proof_data.size(); + proof_data.clear(); + size_t log_n = numeric::get_msb(circuit_size); + serialize_to_buffer(circuit_size, proof_data); + serialize_to_buffer(public_input_size, proof_data); + serialize_to_buffer(pub_inputs_offset, proof_data); + for (size_t i = 0; i < public_input_size; ++i) { + serialize_to_buffer(public_inputs[i], proof_data); + } + serialize_to_buffer(w_l_comm, proof_data); + serialize_to_buffer(w_r_comm, proof_data); + serialize_to_buffer(w_o_comm, proof_data); + serialize_to_buffer(ecc_op_wire_1_comm, proof_data); + serialize_to_buffer(ecc_op_wire_2_comm, proof_data); + serialize_to_buffer(ecc_op_wire_3_comm, proof_data); + serialize_to_buffer(ecc_op_wire_4_comm, proof_data); + serialize_to_buffer(sorted_accum_comm, proof_data); + serialize_to_buffer(w_4_comm, proof_data); + serialize_to_buffer(z_perm_comm, proof_data); + serialize_to_buffer(z_lookup_comm, proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(sumcheck_univariates[i], proof_data); + } + serialize_to_buffer(sumcheck_evaluations, proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(zm_cq_comms[i], proof_data); + } + serialize_to_buffer(zm_cq_comm, proof_data); + serialize_to_buffer(zm_pi_comm, proof_data); + + ASSERT(proof_data.size() == old_proof_length); + } + }; }; } // 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 e4affda825a..ee4479fe7d1 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra_recursive.hpp @@ -438,6 +438,141 @@ template class GoblinUltraRecursive_ { this->lagrange_ecc_op = verification_key->lagrange_ecc_op; } }; + + /** + * @brief Derived class that defines proof structure for GoblinUltraRecursive proofs, as well as supporting + * functions. + * + */ + class Transcript : public BaseTranscript { + public: + // Transcript objects defined as public member variables for easy access and modification + uint32_t circuit_size; + uint32_t public_input_size; + uint32_t pub_inputs_offset; + std::vector public_inputs; + Commitment w_l_comm; + Commitment w_r_comm; + Commitment w_o_comm; + Commitment ecc_op_wire_1_comm; + Commitment ecc_op_wire_2_comm; + Commitment ecc_op_wire_3_comm; + Commitment ecc_op_wire_4_comm; + Commitment sorted_accum_comm; + Commitment w_4_comm; + Commitment z_perm_comm; + Commitment z_lookup_comm; + std::vector> sumcheck_univariates; + std::array sumcheck_evaluations; + std::vector zm_cq_comms; + Commitment zm_cq_comm; + Commitment zm_pi_comm; + + Transcript() = default; + + // Used by verifier to initialize the transcript + Transcript(const std::vector& proof) + : BaseTranscript(proof) + {} + + static Transcript prover_init_empty() + { + Transcript transcript; + constexpr uint32_t init{ 42 }; // arbitrary + transcript.send_to_verifier("Init", init); + return transcript; + }; + + static Transcript verifier_init_empty(const Transcript& transcript) + { + Transcript verifier_transcript{ transcript.proof_data }; + [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); + return verifier_transcript; + }; + + /** + * @brief Takes a FULL GoblinUltraRecursive proof and deserializes it into the public member variables that + * compose the structure. Must be called in order to access the structure of the proof. + * + */ + void deserialize_full_transcript() override + { + // take current proof and put them into the struct + size_t num_bytes_read = 0; + circuit_size = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + size_t log_n = numeric::get_msb(circuit_size); + + public_input_size = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + pub_inputs_offset = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < public_input_size; ++i) { + public_inputs.push_back(deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read)); + } + w_l_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + w_r_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + w_o_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + ecc_op_wire_1_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + ecc_op_wire_2_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + ecc_op_wire_3_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + ecc_op_wire_4_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + sorted_accum_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + w_4_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + z_perm_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + z_lookup_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + sumcheck_univariates.push_back( + deserialize_from_buffer>( + BaseTranscript::proof_data, num_bytes_read)); + } + sumcheck_evaluations = deserialize_from_buffer>( + BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + zm_cq_comms.push_back( + deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read)); + } + zm_cq_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + zm_pi_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + } + /** + * @brief Serializes the structure variables into a FULL GoblinUltraRecursive proof. Should be called only if + * deserialize_full_transcript() was called and some transcript variable was modified. + * + */ + void serialize_full_transcript() override + { + size_t old_proof_length = BaseTranscript::proof_data.size(); + BaseTranscript::proof_data.clear(); // clear proof_data so the rest of the function can replace it + size_t log_n = numeric::get_msb(circuit_size); + serialize_to_buffer(circuit_size, BaseTranscript::proof_data); + serialize_to_buffer(public_input_size, BaseTranscript::proof_data); + serialize_to_buffer(pub_inputs_offset, BaseTranscript::proof_data); + for (size_t i = 0; i < public_input_size; ++i) { + serialize_to_buffer(public_inputs[i], BaseTranscript::proof_data); + } + serialize_to_buffer(w_l_comm, BaseTranscript::proof_data); + serialize_to_buffer(w_r_comm, BaseTranscript::proof_data); + serialize_to_buffer(w_o_comm, BaseTranscript::proof_data); + serialize_to_buffer(ecc_op_wire_1_comm, BaseTranscript::proof_data); + serialize_to_buffer(ecc_op_wire_2_comm, BaseTranscript::proof_data); + serialize_to_buffer(ecc_op_wire_3_comm, BaseTranscript::proof_data); + serialize_to_buffer(ecc_op_wire_4_comm, BaseTranscript::proof_data); + serialize_to_buffer(sorted_accum_comm, BaseTranscript::proof_data); + serialize_to_buffer(w_4_comm, BaseTranscript::proof_data); + serialize_to_buffer(z_perm_comm, BaseTranscript::proof_data); + serialize_to_buffer(z_lookup_comm, BaseTranscript::proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(sumcheck_univariates[i], BaseTranscript::proof_data); + } + serialize_to_buffer(sumcheck_evaluations, BaseTranscript::proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(zm_cq_comms[i], BaseTranscript::proof_data); + } + serialize_to_buffer(zm_cq_comm, BaseTranscript::proof_data); + serialize_to_buffer(zm_pi_comm, BaseTranscript::proof_data); + + // sanity check to make sure we generate the same length of proof as before. + ASSERT(BaseTranscript::proof_data.size() == old_proof_length); + } + }; }; } // namespace proof_system::honk::flavor diff --git a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp index 13540b04056..36c7aff3301 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra.hpp @@ -382,7 +382,8 @@ class Ultra { class VerifierCommitments : public AllEntities { public: - VerifierCommitments(std::shared_ptr verification_key, VerifierTranscript transcript) + VerifierCommitments(std::shared_ptr verification_key, + [[maybe_unused]] const BaseTranscript& transcript) { static_cast(transcript); q_m = verification_key->q_m; @@ -418,6 +419,127 @@ class Ultra { std::vector gate_separation_challenges; FF target_sum; }; + + /** + * @brief Derived class that defines proof structure for Ultra proofs, as well as supporting functions. + * + */ + class Transcript : public BaseTranscript { + public: + // Transcript objects defined as public member variables for easy access and modification + uint32_t circuit_size; + uint32_t public_input_size; + uint32_t pub_inputs_offset; + std::vector public_inputs; + Commitment w_l_comm; + Commitment w_r_comm; + Commitment w_o_comm; + Commitment sorted_accum_comm; + Commitment w_4_comm; + Commitment z_perm_comm; + Commitment z_lookup_comm; + std::vector> sumcheck_univariates; + std::array sumcheck_evaluations; + std::vector zm_cq_comms; + Commitment zm_cq_comm; + Commitment zm_pi_comm; + + Transcript() = default; + + // Used by verifier to initialize the transcript + Transcript(const std::vector& proof) + : BaseTranscript(proof) + {} + + static Transcript prover_init_empty() + { + Transcript transcript; + constexpr uint32_t init{ 42 }; // arbitrary + transcript.send_to_verifier("Init", init); + return transcript; + }; + + static Transcript verifier_init_empty(const Transcript& transcript) + { + Transcript verifier_transcript{ transcript.proof_data }; + [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); + return verifier_transcript; + }; + + /** + * @brief Takes a FULL Ultra proof and deserializes it into the public member variables that compose the + * structure. Must be called in order to access the structure of the proof. + * + */ + void deserialize_full_transcript() override + { + // take current proof and put them into the struct + size_t num_bytes_read = 0; + circuit_size = deserialize_from_buffer(proof_data, num_bytes_read); + size_t log_n = numeric::get_msb(circuit_size); + + public_input_size = deserialize_from_buffer(proof_data, num_bytes_read); + pub_inputs_offset = deserialize_from_buffer(proof_data, num_bytes_read); + for (size_t i = 0; i < public_input_size; ++i) { + public_inputs.push_back(deserialize_from_buffer(proof_data, num_bytes_read)); + } + w_l_comm = deserialize_from_buffer(proof_data, num_bytes_read); + w_r_comm = deserialize_from_buffer(proof_data, num_bytes_read); + w_o_comm = deserialize_from_buffer(proof_data, num_bytes_read); + sorted_accum_comm = deserialize_from_buffer(proof_data, num_bytes_read); + w_4_comm = deserialize_from_buffer(proof_data, num_bytes_read); + z_perm_comm = deserialize_from_buffer(proof_data, num_bytes_read); + z_lookup_comm = deserialize_from_buffer(proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + sumcheck_univariates.push_back( + deserialize_from_buffer>( + proof_data, num_bytes_read)); + } + sumcheck_evaluations = + deserialize_from_buffer>(proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_bytes_read)); + } + zm_cq_comm = deserialize_from_buffer(proof_data, num_bytes_read); + zm_pi_comm = deserialize_from_buffer(proof_data, num_bytes_read); + } + /** + * @brief Serializes the structure variables into a FULL Ultra proof. Should be called only if + * deserialize_full_transcript() was called and some transcript variable was modified. + * + */ + void serialize_full_transcript() override + { + size_t old_proof_length = proof_data.size(); + proof_data.clear(); // clear proof_data so the rest of the function can replace it + size_t log_n = numeric::get_msb(circuit_size); + serialize_to_buffer(circuit_size, proof_data); + serialize_to_buffer(public_input_size, proof_data); + serialize_to_buffer(pub_inputs_offset, proof_data); + for (size_t i = 0; i < public_input_size; ++i) { + serialize_to_buffer(public_inputs[i], proof_data); + } + serialize_to_buffer(w_l_comm, proof_data); + serialize_to_buffer(w_r_comm, proof_data); + serialize_to_buffer(w_o_comm, proof_data); + serialize_to_buffer(sorted_accum_comm, proof_data); + serialize_to_buffer(w_4_comm, proof_data); + serialize_to_buffer(z_perm_comm, proof_data); + serialize_to_buffer(z_lookup_comm, proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(sumcheck_univariates[i], proof_data); + } + serialize_to_buffer(sumcheck_evaluations, proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(zm_cq_comms[i], proof_data); + } + serialize_to_buffer(zm_cq_comm, proof_data); + serialize_to_buffer(zm_pi_comm, proof_data); + + // sanity check to make sure we generate the same length of proof as before. + ASSERT(proof_data.size() == old_proof_length); + } + }; }; } // 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 316dff3c1ba..077d5a49c9c 100644 --- a/barretenberg/cpp/src/barretenberg/honk/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/flavor/ultra_recursive.hpp @@ -397,6 +397,128 @@ template class UltraRecursive_ { this->lagrange_last = verification_key->lagrange_last; } }; + + /** + * @brief Derived class that defines proof structure for UltraRecursive proofs, as well as supporting functions. + * + */ + class Transcript : public BaseTranscript { + public: + // Transcript objects defined as public member variables for easy access and modification + uint32_t circuit_size; + uint32_t public_input_size; + uint32_t pub_inputs_offset; + std::vector public_inputs; + Commitment w_l_comm; + Commitment w_r_comm; + Commitment w_o_comm; + Commitment sorted_accum_comm; + Commitment w_4_comm; + Commitment z_perm_comm; + Commitment z_lookup_comm; + std::vector> sumcheck_univariates; + std::array sumcheck_evaluations; + std::vector zm_cq_comms; + Commitment zm_cq_comm; + Commitment zm_pi_comm; + + Transcript() = default; + + // Used by verifier to initialize the transcript + Transcript(const std::vector& proof) + : BaseTranscript(proof) + {} + + static Transcript prover_init_empty() + { + Transcript transcript; + constexpr uint32_t init{ 42 }; // arbitrary + transcript.send_to_verifier("Init", init); + return transcript; + }; + + static Transcript verifier_init_empty(const Transcript& transcript) + { + Transcript verifier_transcript{ transcript.proof_data }; + [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); + return verifier_transcript; + }; + + /** + * @brief Takes a FULL UltraRecursive proof and deserializes it into the public member variables that compose + * the structure. Must be called in order to access the structure of the proof. + * + */ + void deserialize_full_transcript() override + { + // take current proof and put them into the struct + size_t num_bytes_read = 0; + circuit_size = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + size_t log_n = numeric::get_msb(circuit_size); + + public_input_size = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + pub_inputs_offset = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < public_input_size; ++i) { + public_inputs.push_back(deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read)); + } + w_l_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + w_r_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + w_o_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + sorted_accum_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + w_4_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + z_perm_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + z_lookup_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + sumcheck_univariates.push_back( + deserialize_from_buffer>( + BaseTranscript::proof_data, num_bytes_read)); + } + sumcheck_evaluations = deserialize_from_buffer>( + BaseTranscript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + zm_cq_comms.push_back( + deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read)); + } + zm_cq_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + zm_pi_comm = deserialize_from_buffer(BaseTranscript::proof_data, num_bytes_read); + } + /** + * @brief Serializes the structure variables into a FULL UltraRecursive proof. Should be called only if + * deserialize_full_transcript() was called and some transcript variable was modified. + * + */ + void serialize_full_transcript() override + { + size_t old_proof_length = BaseTranscript::proof_data.size(); + BaseTranscript::proof_data.clear(); // clear proof_data so the rest of the function can replace it + size_t log_n = numeric::get_msb(circuit_size); + serialize_to_buffer(circuit_size, BaseTranscript::proof_data); + serialize_to_buffer(public_input_size, BaseTranscript::proof_data); + serialize_to_buffer(pub_inputs_offset, BaseTranscript::proof_data); + for (size_t i = 0; i < public_input_size; ++i) { + serialize_to_buffer(public_inputs[i], BaseTranscript::proof_data); + } + serialize_to_buffer(w_l_comm, BaseTranscript::proof_data); + serialize_to_buffer(w_r_comm, BaseTranscript::proof_data); + serialize_to_buffer(w_o_comm, BaseTranscript::proof_data); + serialize_to_buffer(sorted_accum_comm, BaseTranscript::proof_data); + serialize_to_buffer(w_4_comm, BaseTranscript::proof_data); + serialize_to_buffer(z_perm_comm, BaseTranscript::proof_data); + serialize_to_buffer(z_lookup_comm, BaseTranscript::proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(sumcheck_univariates[i], BaseTranscript::proof_data); + } + serialize_to_buffer(sumcheck_evaluations, BaseTranscript::proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(zm_cq_comms[i], BaseTranscript::proof_data); + } + serialize_to_buffer(zm_cq_comm, BaseTranscript::proof_data); + serialize_to_buffer(zm_pi_comm, BaseTranscript::proof_data); + + // sanity check to make sure we generate the same length of proof as before. + ASSERT(BaseTranscript::proof_data.size() == old_proof_length); + } + }; }; } // namespace proof_system::honk::flavor 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 117b35d3cc4..d5c6fa7e2a1 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp @@ -25,7 +25,7 @@ template class GeminiTest : public CommitmentTest { std::vector multilinear_commitments, std::vector multilinear_commitments_to_be_shifted) { - auto prover_transcript = ProverTranscript::init_empty(); + auto prover_transcript = BaseTranscript::prover_init_empty(); const Fr rho = Fr::random_element(); @@ -79,7 +79,7 @@ template class GeminiTest : public CommitmentTest { // Check that the Fold polynomials have been evaluated correctly in the prover this->verify_batch_opening_pair(prover_output.opening_pairs, prover_output.witnesses); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); // Compute: // - Single opening pair: {r, \hat{a}_0} diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp index ae5b2fcfb24..aeafa456ec7 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.hpp @@ -35,7 +35,7 @@ template class IPA { static void compute_opening_proof(std::shared_ptr ck, const OpeningPair& opening_pair, const Polynomial& polynomial, - ProverTranscript& transcript) + BaseTranscript& transcript) { ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero"); auto poly_degree = static_cast(polynomial.size()); @@ -134,9 +134,7 @@ template class IPA { * * @return true/false depending on if the proof verifies */ - static bool verify(std::shared_ptr vk, - const OpeningClaim& opening_claim, - VerifierTranscript& transcript) + static bool verify(std::shared_ptr vk, const OpeningClaim& opening_claim, BaseTranscript& transcript) { auto poly_degree = static_cast(transcript.template receive_from_prover("IPA:poly_degree")); Fr generator_challenge = transcript.get_challenge("IPA:generator_challenge"); diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp index d015bfa6d21..e6d0333a8ab 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/ipa/ipa.test.cpp @@ -70,11 +70,11 @@ TEST_F(IPATest, Open) const OpeningClaim opening_claim{ opening_pair, commitment }; // initialize empty prover transcript - ProverTranscript prover_transcript; + BaseTranscript prover_transcript; IPA::compute_opening_proof(this->ck(), opening_pair, poly, prover_transcript); // initialize verifier transcript from proof data - VerifierTranscript verifier_transcript{ prover_transcript.proof_data }; + BaseTranscript verifier_transcript{ prover_transcript.proof_data }; auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); @@ -129,7 +129,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) batched_commitment_unshifted = commitment1 * rhos[0] + commitment2 * rhos[1]; batched_commitment_to_be_shifted = commitment2 * rhos[2]; - auto prover_transcript = ProverTranscript::init_empty(); + auto prover_transcript = BaseTranscript::prover_init_empty(); auto gemini_polynomials = GeminiProver::compute_gemini_polynomials( mle_opening_point, std::move(batched_unshifted), std::move(batched_to_be_shifted)); @@ -162,7 +162,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) IPA::compute_opening_proof(this->ck(), shplonk_opening_pair, shplonk_witness, prover_transcript); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); auto gemini_verifier_claim = GeminiVerifier::reduce_verification(mle_opening_point, batched_evaluation, diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp index 6bd41ac7bef..5fe179482e3 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp @@ -31,7 +31,7 @@ template class KZG { static void compute_opening_proof(std::shared_ptr ck, const OpeningPair& opening_pair, const Polynomial& polynomial, - ProverTranscript& prover_trancript) + BaseTranscript& prover_trancript) { Polynomial quotient(polynomial); quotient[0] -= opening_pair.evaluation; @@ -55,7 +55,7 @@ template class KZG { */ static bool verify(std::shared_ptr vk, const OpeningClaim& claim, - VerifierTranscript& verifier_transcript) + BaseTranscript& verifier_transcript) { auto quotient_commitment = verifier_transcript.template receive_from_prover("KZG:W"); auto lhs = claim.commitment - (GroupElement::one() * claim.opening_pair.evaluation) + diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp index 6fe4d1b2641..673ccddd7f7 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp @@ -39,11 +39,11 @@ TYPED_TEST(KZGTest, single) auto opening_pair = OpeningPair{ challenge, evaluation }; auto opening_claim = OpeningClaim{ opening_pair, commitment }; - auto prover_transcript = ProverTranscript::init_empty(); + auto prover_transcript = BaseTranscript::prover_init_empty(); KZG::compute_opening_proof(this->ck(), opening_pair, witness, prover_transcript); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); bool verified = KZG::verify(this->vk(), opening_claim, verifier_transcript); EXPECT_EQ(verified, true); @@ -109,7 +109,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) batched_commitment_unshifted = commitment1 * rhos[0] + commitment2 * rhos[1]; batched_commitment_to_be_shifted = commitment2 * rhos[2]; - auto prover_transcript = ProverTranscript::init_empty(); + auto prover_transcript = BaseTranscript::prover_init_empty(); // Run the full prover PCS protocol: @@ -154,7 +154,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation) - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); // Gemini verifier output: // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1 diff --git a/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp b/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp index a700b3b594c..5e607d2f038 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp @@ -28,7 +28,7 @@ TYPED_TEST(ShplonkTest, ShplonkSimple) const size_t n = 16; - auto prover_transcript = ProverTranscript::init_empty(); + auto prover_transcript = BaseTranscript::prover_init_empty(); // Generate two random (unrelated) polynomials of two different sizes, as well as their evaluations at a (single but // different) random point and their commitments. @@ -64,7 +64,7 @@ TYPED_TEST(ShplonkTest, ShplonkSimple) opening_claims.emplace_back(OpeningClaim{ opening_pairs[0], commitment1 }); opening_claims.emplace_back(OpeningClaim{ opening_pairs[1], commitment2 }); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); // Execute the shplonk verifier functionality const auto verifier_claim = ShplonkVerifier::reduce_verification(this->vk(), opening_claims, verifier_transcript); 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 c4c4dd95984..2af0af8c2ed 100644 --- a/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/pcs/zeromorph/zeromorph.test.cpp @@ -76,8 +76,8 @@ template class ZeroMorphTest : public CommitmentTest { g_commitments.emplace_back(f_commitments[i]); } - // Initialize an empty ProverTranscript - auto prover_transcript = ProverTranscript::init_empty(); + // Initialize an empty BaseTranscript + auto prover_transcript = BaseTranscript::prover_init_empty(); // Execute Prover protocol { @@ -147,7 +147,7 @@ template class ZeroMorphTest : public CommitmentTest { prover_transcript.send_to_verifier("ZM:PI", pi_commitment); } - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); // Execute Verifier protocol { @@ -332,8 +332,8 @@ template class ZeroMorphWithConcatenationTest : public CommitmentT concatenation_groups_commitments.emplace_back(concatenation_group_commitment); } - // Initialize an empty ProverTranscript - auto prover_transcript = ProverTranscript::init_empty(); + // Initialize an empty BaseTranscript + auto prover_transcript = BaseTranscript::prover_init_empty(); // Execute Prover protocol { @@ -417,7 +417,7 @@ template class ZeroMorphWithConcatenationTest : public CommitmentT prover_transcript.send_to_verifier("ZM:PI", pi_commitment); } - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); // Execute Verifier protocol { 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 9f5143ba028..b2561b7fdca 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.cpp @@ -329,7 +329,7 @@ template plonk::proof& ECCVMProver_::construct_proo // Compute sorted list accumulator and commitment execute_log_derivative_commitments_round(); - // Fiat-Shamir: bbeta & gamma + // Fiat-Shamir: beta & gamma // Compute grand product(s) and commitments. execute_grand_product_computation_round(); 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 d781fcb86c2..b0e63b907d2 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_prover.hpp @@ -21,6 +21,7 @@ template class ECCVMProver_ { using ProverPolynomials = typename Flavor::ProverPolynomials; using CommitmentLabels = typename Flavor::CommitmentLabels; using Curve = typename Flavor::Curve; + using Transcript = typename Flavor::Transcript; public: explicit ECCVMProver_(std::shared_ptr input_key, std::shared_ptr commitment_key); @@ -39,7 +40,7 @@ template class ECCVMProver_ { plonk::proof& export_proof(); plonk::proof& construct_proof(); - ProverTranscript transcript; + Transcript transcript; std::vector public_inputs; 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 80ff34bd587..76d17e59e54 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.cpp @@ -44,10 +44,11 @@ template bool ECCVMVerifier_::verify_proof(const plonk using Shplonk = pcs::shplonk::ShplonkVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; + using Transcript = typename Flavor::Transcript; RelationParameters relation_parameters; - transcript = VerifierTranscript{ proof.proof_data }; + transcript = Transcript{ proof.proof_data }; auto commitments = VerifierCommitments(key, transcript); auto commitment_labels = CommitmentLabels(); @@ -168,7 +169,7 @@ template bool ECCVMVerifier_::verify_proof(const plonk transcript.template receive_from_prover(commitment_labels.lookup_read_counts_1); // Get challenge for sorted list batching and wire four memory records - auto [beta, gamma] = transcript.get_challenges("bbeta", "gamma"); + auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); relation_parameters.gamma = gamma; auto beta_sqr = beta * beta; relation_parameters.beta = beta; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.hpp index c44ae39589c..b24fb024313 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/eccvm_verifier.hpp @@ -9,6 +9,7 @@ template class ECCVMVerifier_ { using Commitment = typename Flavor::Commitment; using VerificationKey = typename Flavor::VerificationKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; + using Transcript = typename Flavor::Transcript; public: explicit ECCVMVerifier_(std::shared_ptr verifier_key = nullptr); @@ -16,7 +17,7 @@ template class ECCVMVerifier_ { std::map commitments, std::map pcs_fr_elements, std::shared_ptr pcs_verification_key, - VerifierTranscript transcript) + Transcript& transcript) : key(std::move(key)) , commitments(std::move(commitments)) , pcs_fr_elements(std::move(pcs_fr_elements)) @@ -35,7 +36,7 @@ template class ECCVMVerifier_ { std::map commitments; std::map pcs_fr_elements; std::shared_ptr pcs_verification_key; - VerifierTranscript transcript; + Transcript transcript; }; extern template class ECCVMVerifier_; 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 7462018ec51..7d0d2cc05fd 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 @@ -25,7 +25,7 @@ template class MergeProver_ { using OpeningPair = typename pcs::OpeningPair; public: - ProverTranscript transcript; + BaseTranscript transcript; std::shared_ptr op_queue; std::shared_ptr pcs_commitment_key; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.cpp index ca477c49eb6..bfac4182d6d 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/goblin_merge/merge_verifier.cpp @@ -19,7 +19,7 @@ MergeVerifier_::MergeVerifier_(std::unique_ptr ve */ template bool MergeVerifier_::verify_proof(const plonk::proof& proof) { - transcript = VerifierTranscript{ proof.proof_data }; + transcript = BaseTranscript{ proof.proof_data }; // Receive commitments [t_i^{shift}], [T_{i-1}], and [T_i] std::array C_T_prev; 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 b195cd92a1e..c0ff00b2cab 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 @@ -26,7 +26,7 @@ template class MergeVerifier_ { using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; public: - VerifierTranscript transcript; + BaseTranscript transcript; std::shared_ptr op_queue; std::shared_ptr pcs_verification_key; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_prover.hpp index c4a87be54b7..abc4bc0059b 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_prover.hpp @@ -36,7 +36,7 @@ template class ProtoGalaxyProver_ { using RelationEvaluations = typename Flavor::TupleOfArraysOfValues; ProverInstances instances; - ProverTranscript transcript; + BaseTranscript transcript; ProtoGalaxyProver_() = default; ProtoGalaxyProver_(ProverInstances insts) diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.cpp index 57397318541..707855ee58d 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.cpp @@ -5,7 +5,7 @@ template VerifierFoldingResult ProtoGalaxyVerifier_< VerifierInstances>::fold_public_parameters(std::vector fold_data) { - transcript = VerifierTranscript{ fold_data }; + transcript = BaseTranscript{ fold_data }; auto index = 0; for (auto it = verifier_instances.begin(); it != verifier_instances.end(); it++, index++) { auto inst = *it; 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 309fcadcdd5..faa6993cec7 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/protogalaxy_verifier.hpp @@ -14,7 +14,7 @@ template class ProtoGalaxyVerifier_ { using Instance = typename VerifierInstances::Instance; using VerificationKey = typename Flavor::VerificationKey; VerifierInstances verifier_instances; - VerifierTranscript transcript; + BaseTranscript transcript; // should the PG verifier be given the VerifierInstances, nah this makes sense yo me ProtoGalaxyVerifier_(VerifierInstances insts) 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 a592fde4755..1bb0f391e11 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -20,6 +20,7 @@ template class UltraProver_ { using CommitmentLabels = typename Flavor::CommitmentLabels; using Curve = typename Flavor::Curve; using Instance = ProverInstance_; + using Transcript = typename Flavor::Transcript; public: explicit UltraProver_(std::shared_ptr); @@ -33,7 +34,7 @@ template class UltraProver_ { plonk::proof& export_proof(); plonk::proof& construct_proof(); - ProverTranscript transcript; + Transcript transcript; std::vector public_inputs; size_t pub_inputs_offset; 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 b876b31947b..ab2fb367b91 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -42,7 +42,7 @@ template bool UltraVerifier_::verify_proof(const plonk proof_system::RelationParameters relation_parameters; - transcript = VerifierTranscript{ proof.proof_data }; + transcript = BaseTranscript{ proof.proof_data }; auto commitments = VerifierCommitments(key, transcript); auto commitment_labels = CommitmentLabels(); diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp index 34c524672d5..51d0066ab07 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp @@ -23,7 +23,7 @@ template class UltraVerifier_ { std::shared_ptr key; std::map commitments; std::shared_ptr pcs_verification_key; - VerifierTranscript transcript; + BaseTranscript transcript; }; extern template class UltraVerifier_; diff --git a/barretenberg/cpp/src/barretenberg/honk/sumcheck/partial_evaluation.test.cpp b/barretenberg/cpp/src/barretenberg/honk/sumcheck/partial_evaluation.test.cpp index 49560829db9..2a5e49c4cf7 100644 --- a/barretenberg/cpp/src/barretenberg/honk/sumcheck/partial_evaluation.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/sumcheck/partial_evaluation.test.cpp @@ -41,7 +41,7 @@ TYPED_TEST(PartialEvaluationTests, TwoRoundsSpecial) { using Flavor = TypeParam; using FF = typename Flavor::FF; - using Transcript = proof_system::honk::ProverTranscript; + using Transcript = typename Flavor::Transcript; // values here are chosen to check another test const size_t multivariate_d(2); @@ -55,7 +55,7 @@ TYPED_TEST(PartialEvaluationTests, TwoRoundsSpecial) std::array f0 = { v00, v10, v01, v11 }; auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); + Transcript transcript = Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); FF round_challenge_0 = { 0x6c7301b49d85a46c, 0x44311531e39c64f6, 0xb13d66d8d6c1a24c, 0x04410c360230a295 }; @@ -79,7 +79,7 @@ TYPED_TEST(PartialEvaluationTests, TwoRoundsGeneric) { using Flavor = TypeParam; using FF = typename Flavor::FF; - using Transcript = proof_system::honk::ProverTranscript; + using Transcript = typename Flavor::Transcript; const size_t multivariate_d(2); const size_t multivariate_n(1 << multivariate_d); @@ -92,7 +92,7 @@ TYPED_TEST(PartialEvaluationTests, TwoRoundsGeneric) std::array f0 = { v00, v10, v01, v11 }; auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); + Transcript transcript = Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); FF round_challenge_0 = FF::random_element(); @@ -136,7 +136,7 @@ TYPED_TEST(PartialEvaluationTests, ThreeRoundsSpecial) { using Flavor = TypeParam; using FF = typename Flavor::FF; - using Transcript = proof_system::honk::ProverTranscript; + using Transcript = typename Flavor::Transcript; const size_t multivariate_d(3); const size_t multivariate_n(1 << multivariate_d); @@ -153,7 +153,7 @@ TYPED_TEST(PartialEvaluationTests, ThreeRoundsSpecial) std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); + Transcript transcript = Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); FF round_challenge_0 = 1; @@ -187,7 +187,7 @@ TYPED_TEST(PartialEvaluationTests, ThreeRoundsGeneric) { using Flavor = TypeParam; using FF = typename Flavor::FF; - using Transcript = proof_system::honk::ProverTranscript; + using Transcript = typename Flavor::Transcript; const size_t multivariate_d(3); const size_t multivariate_n(1 << multivariate_d); @@ -204,7 +204,7 @@ TYPED_TEST(PartialEvaluationTests, ThreeRoundsGeneric) std::array f0 = { v000, v100, v010, v110, v001, v101, v011, v111 }; auto full_polynomials = std::array, 1>({ f0 }); - auto transcript = Transcript::init_empty(); + Transcript transcript = Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); FF round_challenge_0 = FF::random_element(); @@ -238,7 +238,7 @@ TYPED_TEST(PartialEvaluationTests, ThreeRoundsGenericMultiplePolys) { using Flavor = TypeParam; using FF = typename Flavor::FF; - using Transcript = proof_system::honk::ProverTranscript; + using Transcript = typename Flavor::Transcript; const size_t multivariate_d(3); const size_t multivariate_n(1 << multivariate_d); @@ -266,7 +266,7 @@ TYPED_TEST(PartialEvaluationTests, ThreeRoundsGenericMultiplePolys) std::array f2 = { v000[2], v100[2], v010[2], v110[2], v001[2], v101[2], v011[2], v111[2] }; auto full_polynomials = std::array, 3>{ f0, f1, f2 }; - auto transcript = Transcript::init_empty(); + Transcript transcript = Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); std::array expected_q1; diff --git a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp index 033401f6361..4282bce0a30 100644 --- a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.hpp @@ -18,9 +18,10 @@ template class SumcheckProver { using ProverPolynomials = typename Flavor::ProverPolynomials; using PartiallyEvaluatedMultivariates = typename Flavor::PartiallyEvaluatedMultivariates; using ClaimedEvaluations = typename Flavor::AllValues; + using Transcript = typename Flavor::Transcript; using Instance = ProverInstance_; - ProverTranscript& transcript; + Transcript& transcript; const size_t multivariate_n; const size_t multivariate_d; SumcheckProverRound round; @@ -59,7 +60,7 @@ template class SumcheckProver { PartiallyEvaluatedMultivariates partially_evaluated_polynomials; // prover instantiates sumcheck with circuit size and a prover transcript - SumcheckProver(size_t multivariate_n, ProverTranscript& transcript) + SumcheckProver(size_t multivariate_n, Transcript& transcript) : transcript(transcript) , multivariate_n(multivariate_n) , multivariate_d(numeric::get_msb(multivariate_n)) diff --git a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp index dace121aa68..dd3867664ce 100644 --- a/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/sumcheck/sumcheck.test.cpp @@ -104,7 +104,7 @@ TEST_F(SumcheckTests, PolynomialNormalization) info(full_polynomials.w_l[2]); info(full_polynomials.w_l[3]); - auto transcript = ProverTranscript::init_empty(); + Flavor::Transcript transcript = Flavor::Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); @@ -169,7 +169,7 @@ TEST_F(SumcheckTests, Prover) } auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); - auto transcript = ProverTranscript::init_empty(); + Flavor::Transcript transcript = Flavor::Transcript::prover_init_empty(); auto sumcheck = SumcheckProver(multivariate_n, transcript); @@ -243,13 +243,13 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) .public_input_delta = FF::one(), }; - auto prover_transcript = ProverTranscript::init_empty(); + Flavor::Transcript prover_transcript = Flavor::Transcript::prover_init_empty(); auto sumcheck_prover = SumcheckProver(multivariate_n, prover_transcript); auto prover_output = sumcheck_prover.prove(full_polynomials, relation_parameters); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + Flavor::Transcript verifier_transcript = Flavor::Transcript::verifier_init_empty(prover_transcript); auto sumcheck_verifier = SumcheckVerifier(multivariate_n); @@ -396,14 +396,14 @@ TEST_F(SumcheckTests, RealCircuitUltra) instance->compute_sorted_accumulator_polynomials(eta); instance->compute_grand_product_polynomials(beta, gamma); - auto prover_transcript = ProverTranscript::init_empty(); + Flavor::Transcript prover_transcript = Flavor::Transcript::prover_init_empty(); auto circuit_size = instance->proving_key->circuit_size; auto sumcheck_prover = SumcheckProver(circuit_size, prover_transcript); auto prover_output = sumcheck_prover.prove(instance->prover_polynomials, instance->relation_parameters); - auto verifier_transcript = VerifierTranscript::init_empty(prover_transcript); + Flavor::Transcript verifier_transcript = Flavor::Transcript::verifier_init_empty(prover_transcript); auto sumcheck_verifier = SumcheckVerifier(circuit_size); diff --git a/barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp new file mode 100644 index 00000000000..bd4b88b8df3 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/transcript/eccvm_transcript.test.cpp @@ -0,0 +1,341 @@ +#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 new file mode 100644 index 00000000000..c1d07a642f5 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/honk/transcript/goblin_ultra_transcript.test.cpp @@ -0,0 +1,233 @@ +#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 index d6189d6268c..c7d4123a332 100644 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.hpp @@ -58,7 +58,7 @@ class TranscriptManifest { }; /** - * @brief Common transcript functionality for both parties. Stores the data for the current round, as well as the + * @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. @@ -66,11 +66,22 @@ class TranscriptManifest { 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 @@ -143,7 +154,44 @@ template class BaseTranscript { 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. @@ -186,23 +234,11 @@ template class BaseTranscript { return challenges; } - FF get_challenge(const std::string& label) { return get_challenges(label)[0]; } - - [[nodiscard]] TranscriptManifest get_manifest() const { return manifest; }; - - void print() { manifest.print(); } -}; - -template class ProverTranscript : public BaseTranscript { - - public: - /// Contains the raw data sent by the prover. - std::vector proof_data; - /** - * @brief Adds a prover message to the transcript. + * @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. + * @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 @@ -223,67 +259,73 @@ template class ProverTranscript : public BaseTranscript { 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 + * initialization. Only intended to be used by Prover. * - * @return ProverTranscript + * @return BaseTranscript */ - static ProverTranscript init_empty() + static BaseTranscript prover_init_empty() { - ProverTranscript transcript; + BaseTranscript transcript; constexpr uint32_t init{ 42 }; // arbitrary transcript.send_to_verifier("Init", init); return transcript; }; -}; - -template class VerifierTranscript : public BaseTranscript { - - /// Contains the raw data sent by the prover. - std::vector proof_data_; - size_t num_bytes_read_ = 0; - - public: - VerifierTranscript() = default; - - explicit VerifierTranscript(const std::vector& proof_data) - : proof_data_(proof_data.begin(), proof_data.end()) - {} /** * @brief For testing: initializes transcript based on proof data then receives junk data produced by - * ProverTranscript::init_empty() + * BaseTranscript::prover_init_empty(). Only intended to be used by Verifier. * * @param transcript - * @return VerifierTranscript + * @return BaseTranscript */ - static VerifierTranscript init_empty(const ProverTranscript& transcript) + static BaseTranscript verifier_init_empty(const BaseTranscript& transcript) { - VerifierTranscript verifier_transcript{ transcript.proof_data }; + BaseTranscript verifier_transcript{ transcript.proof_data }; [[maybe_unused]] auto _ = verifier_transcript.template receive_from_prover("Init"); return verifier_transcript; }; - /** - * @brief Reads the next element of type `T` from the transcript, with a predefined label. - * - * @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()); + FF get_challenge(const std::string& label) { return get_challenges(label)[0]; } - auto element_bytes = std::span{ proof_data_ }.subspan(num_bytes_read_, element_size); - num_bytes_read_ += element_size; + [[nodiscard]] TranscriptManifest get_manifest() const { return manifest; }; - BaseTranscript::consume_prover_element_bytes(label, element_bytes); + void print() { manifest.print(); } - T element = from_buffer(element_bytes); + /** + * @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"); } - return element; - } + /** + * @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/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/honk/transcript/ultra_transcript.test.cpp similarity index 80% rename from barretenberg/cpp/src/barretenberg/honk/transcript/transcript.test.cpp rename to barretenberg/cpp/src/barretenberg/honk/transcript/ultra_transcript.test.cpp index 246e11e92e1..331418d4746 100644 --- a/barretenberg/cpp/src/barretenberg/honk/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/honk/transcript/ultra_transcript.test.cpp @@ -1,9 +1,9 @@ -#include "transcript.hpp" #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; @@ -38,7 +38,6 @@ class UltraTranscriptTests : public ::testing::Test { 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); @@ -85,29 +84,27 @@ class UltraTranscriptTests : public ::testing::Test { round++; // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors - if constexpr (proof_system::IsGrumpkinFlavor) { - manifest_expected.add_entry(round, "IPA:poly_degree", size_uint64); - manifest_expected.add_challenge(round, "IPA:generator_challenge"); - - for (size_t i = 0; i < log_n; 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 { - manifest_expected.add_entry(round, "ZM:PI", size_G); - } - + 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); + } }; /** @@ -117,10 +114,8 @@ class UltraTranscriptTests : public ::testing::Test { TEST_F(UltraTranscriptTests, ProverManifestConsistency) { // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - typename Flavor::FF a = 1; auto builder = typename Flavor::CircuitBuilder(); - builder.add_variable(a); - builder.add_public_variable(a); + generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof auto composer = UltraComposer(); @@ -146,11 +141,8 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) { // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = proof_system::UltraCircuitBuilder(); - - auto a = 2; - builder.add_variable(a); - builder.add_public_variable(a); + auto builder = Flavor::CircuitBuilder(); + generate_test_circuit(builder); // Automatically generate a transcript manifest in the prover by constructing a proof auto composer = UltraComposer(); @@ -181,7 +173,7 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) TEST_F(UltraTranscriptTests, ChallengeGenerationTest) { // initialized with random value sent to verifier - auto transcript = ProverTranscript::init_empty(); + 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 @@ -197,6 +189,38 @@ TEST_F(UltraTranscriptTests, ChallengeGenerationTest) 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; @@ -205,11 +229,7 @@ TEST_F(UltraTranscriptTests, FoldingManifestTest) std::vector>> insts(2); std::generate(insts.begin(), insts.end(), [&]() { auto builder = proof_system::UltraCircuitBuilder(); - auto a = FF::random_element(); - auto b = FF::random_element(); - builder.add_variable(a); - builder.add_public_variable(a); - builder.add_public_variable(b); + generate_random_test_circuit(builder); return composer.create_instance(builder); }); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/relations/ecc_vm/ecc_set_relation.cpp b/barretenberg/cpp/src/barretenberg/proof_system/relations/ecc_vm/ecc_set_relation.cpp index 3663c61087f..40fff3619b5 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/relations/ecc_vm/ecc_set_relation.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/relations/ecc_vm/ecc_set_relation.cpp @@ -359,7 +359,7 @@ Accumulator ECCVMSetRelationBase::compute_permutation_denominator(const AllE * * @param evals transformed to `evals + C(in(X)...)*scaling_factor` * @param in an std::array containing the fully extended Accumulator edges. - * @param parameters contains bbeta, gamma, and public_input_delta, .... + * @param parameters contains beta, gamma, and public_input_delta, .... * @param scaling_factor optional term to scale the evaluation before adding to evals. */ template 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 3b25af820c1..7393b5e5112 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp @@ -18,12 +18,12 @@ template class Transcript { public: using field_ct = field_t; using FF = barretenberg::fr; - using VerifierTranscript = proof_system::honk::VerifierTranscript; + using BaseTranscript = proof_system::honk::BaseTranscript; using StdlibTypes = utility::StdlibTypesUtility; - static constexpr size_t HASH_OUTPUT_SIZE = VerifierTranscript::HASH_OUTPUT_SIZE; + static constexpr size_t HASH_OUTPUT_SIZE = BaseTranscript::HASH_OUTPUT_SIZE; - VerifierTranscript native_transcript; + BaseTranscript native_transcript; Builder* builder; Transcript() = default; 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 b91139f7fbf..159b34e31e1 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 @@ -14,8 +14,7 @@ using Builder = UltraCircuitBuilder; using UltraFlavor = ::proof_system::honk::flavor::Ultra; using UltraRecursiveFlavor = ::proof_system::honk::flavor::UltraRecursive_; using FF = barretenberg::fr; -using ProverTranscript = ::proof_system::honk::ProverTranscript; -using VerifierTranscript = ::proof_system::honk::VerifierTranscript; +using BaseTranscript = ::proof_system::honk::BaseTranscript; /** * @brief Create some mock data; add it to the provided prover transcript in various mock rounds @@ -97,11 +96,11 @@ TEST(RecursiveHonkTranscript, InterfacesMatch) constexpr size_t LENGTH = 8; // arbitrary length of Univariate to be serialized // Instantiate a Prover Transcript and use it to generate some mock proof data - ProverTranscript prover_transcript; + BaseTranscript prover_transcript; auto proof_data = generate_mock_proof_data(prover_transcript); // Instantiate a (native) Verifier Transcript with the proof data and perform some mock transcript operations - VerifierTranscript native_transcript(proof_data); + BaseTranscript native_transcript(proof_data); perform_mock_verifier_transcript_operations(native_transcript); // Confirm that Prover and Verifier transcripts have generated the same manifest via the operations performed @@ -145,7 +144,7 @@ TEST(RecursiveHonkTranscript, ReturnValuesMatch) } // Construct a mock proof via the prover transcript - ProverTranscript prover_transcript; + BaseTranscript prover_transcript; prover_transcript.send_to_verifier("scalar", scalar); prover_transcript.send_to_verifier("commitment", commitment); prover_transcript.send_to_verifier("evaluations", evaluations); @@ -153,7 +152,7 @@ TEST(RecursiveHonkTranscript, ReturnValuesMatch) auto proof_data = prover_transcript.proof_data; // Perform the corresponding operations with the native verifier transcript - VerifierTranscript native_transcript(proof_data); + BaseTranscript native_transcript(proof_data); auto native_scalar = native_transcript.template receive_from_prover("scalar"); auto native_commitment = native_transcript.template receive_from_prover("commitment"); auto native_evaluations = native_transcript.template receive_from_prover>("evaluations"); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index df9afcf9e4e..00a59673563 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -216,7 +216,10 @@ template class GoblinRecursiveVerifierTest : public testi const auto native_verification_key = instance->compute_verification_key(); // Arbitrarily tamper with the proof to be verified - inner_proof.proof_data[10] = 25; + inner_prover.transcript.deserialize_full_transcript(); + inner_prover.transcript.sorted_accum_comm = Flavor::Commitment::one() * Flavor::FF::random_element(); + inner_prover.transcript.serialize_full_transcript(); + inner_proof = inner_prover.export_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 1c0a69ca3a7..83c7230544a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -201,7 +201,10 @@ template class RecursiveVerifierTest : public testing::Te const auto native_verification_key = instance->compute_verification_key(); // Arbitrarily tamper with the proof to be verified - inner_proof.proof_data[10] = 25; + inner_prover.transcript.deserialize_full_transcript(); + inner_prover.transcript.sorted_accum_comm = Flavor::Commitment::one() * Flavor::FF::random_element(); + inner_prover.transcript.serialize_full_transcript(); + inner_proof = inner_prover.export_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit;