diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index e4b65f266ec..cf6f7fefba1 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -228,10 +228,10 @@ void prove_tube(const std::string& output_path) // circuit // TODO(https://github.com/AztecProtocol/barretenberg/issues/1048): INSECURE - make this tube proof actually use // these public inputs by turning proof into witnesses and calling set_public on each witness - auto num_public_inputs = static_cast(static_cast(proof.mega_proof[1])); - num_public_inputs -= bb::PAIRING_POINT_ACCUMULATOR_SIZE; // don't add the agg object + auto num_inner_public_inputs = static_cast(static_cast(proof.mega_proof[1])); + num_inner_public_inputs -= bb::PAIRING_POINT_ACCUMULATOR_SIZE; // don't add the agg object - for (size_t i = 0; i < num_public_inputs; i++) { + for (size_t i = 0; i < num_inner_public_inputs; i++) { auto offset = bb::HONK_PROOF_PUBLIC_INPUT_OFFSET; builder->add_public_variable(proof.mega_proof[i + offset]); } @@ -278,13 +278,13 @@ void prove_tube(const std::string& output_path) Verifier tube_verifier(tube_verification_key, ipa_verification_key); // Break up the tube proof into the honk portion and the ipa portion - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1168): Add formula to flavor - const size_t HONK_PROOF_LENGTH = 469; + const size_t HONK_PROOF_LENGTH_WITHOUT_INNER_PUB_INPUTS = + UltraRollupFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + PAIRING_POINT_ACCUMULATOR_SIZE + IPA_CLAIM_SIZE; // The extra calculation is for the IPA proof length. - ASSERT(tube_proof.size() == HONK_PROOF_LENGTH + 1 + 4 * (CONST_ECCVM_LOG_N) + 2 + 2 + num_public_inputs); + ASSERT(tube_proof.size() == HONK_PROOF_LENGTH_WITHOUT_INNER_PUB_INPUTS + num_inner_public_inputs); // split out the ipa proof - const std::ptrdiff_t honk_proof_with_pub_inputs_length = - static_cast(HONK_PROOF_LENGTH + num_public_inputs); + const std::ptrdiff_t honk_proof_with_pub_inputs_length = static_cast( + HONK_PROOF_LENGTH_WITHOUT_INNER_PUB_INPUTS - IPA_PROOF_LENGTH + num_inner_public_inputs); auto ipa_proof = HonkProof(tube_proof.begin() + honk_proof_with_pub_inputs_length, tube_proof.end()); auto tube_honk_proof = HonkProof(tube_proof.begin(), tube_proof.end() + honk_proof_with_pub_inputs_length); bool verified = tube_verifier.verify_proof(tube_honk_proof, ipa_proof); @@ -895,15 +895,13 @@ template bool verify_honk(const std::string& proof_path, bool verified; if constexpr (HasIPAAccumulator) { // Break up the tube proof into the honk portion and the ipa portion - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1168): Add formula to flavor - const size_t HONK_PROOF_LENGTH = 469; - const size_t num_public_inputs = - static_cast(uint64_t(proof[1])) - PAIRING_POINT_ACCUMULATOR_SIZE - IPA_CLAIM_SIZE; + const size_t HONK_PROOF_LENGTH = Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS - IPA_PROOF_LENGTH; + const size_t num_public_inputs = static_cast(uint64_t(proof[1])); // The extra calculation is for the IPA proof length. debug("proof size: ", proof.size()); debug("num public inputs: ", num_public_inputs); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1182): Move to ProofSurgeon. - ASSERT(proof.size() == HONK_PROOF_LENGTH + 1 + 4 * (CONST_ECCVM_LOG_N) + 2 + 2 + num_public_inputs); + ASSERT(proof.size() == HONK_PROOF_LENGTH + IPA_PROOF_LENGTH + num_public_inputs); // split out the ipa proof const std::ptrdiff_t honk_proof_with_pub_inputs_length = static_cast(HONK_PROOF_LENGTH + num_public_inputs); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp index 68d5958a2b8..7e83b477ef7 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp @@ -6,9 +6,11 @@ #include "barretenberg/common/container.hpp" #include "barretenberg/common/thread.hpp" #include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/constants.hpp" #include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/stdlib/hash/poseidon2/poseidon2.hpp" #include "barretenberg/stdlib/honk_verifier/ipa_accumulator.hpp" +#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp" #include "barretenberg/stdlib/transcript/transcript.hpp" #include "barretenberg/transcript/transcript.hpp" #include @@ -20,6 +22,8 @@ namespace bb { // clang-format off +constexpr size_t IPA_PROOF_LENGTH = 1 + 4 * CONST_ECCVM_LOG_N + 2 + 2; + /** * @brief IPA (inner product argument) commitment scheme class. * @@ -949,6 +953,32 @@ template class IPA { output_claim.opening_pair.evaluation.self_reduce(); return {output_claim, prover_transcript->proof_data}; } + + static std::pair, HonkProof> create_fake_ipa_claim_and_proof(UltraCircuitBuilder& builder) + requires Curve::is_stdlib_type { + using NativeCurve = curve::Grumpkin; + using Builder = typename Curve::Builder; + using Curve = stdlib::grumpkin; + auto ipa_transcript = std::make_shared(); + auto ipa_commitment_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); + size_t n = 4; + auto poly = Polynomial(n); + for (size_t i = 0; i < n; i++) { + poly.at(i) = fq::random_element(); + } + fq x = fq::random_element(); + fq eval = poly.evaluate(x); + auto commitment = ipa_commitment_key->commit(poly); + const OpeningPair opening_pair = { x, eval }; + IPA::compute_opening_proof(ipa_commitment_key, { poly, opening_pair }, ipa_transcript); + + auto stdlib_comm = Curve::Group::from_witness(&builder, commitment); + auto stdlib_x = Curve::ScalarField::from_witness(&builder, x); + auto stdlib_eval = Curve::ScalarField::from_witness(&builder, eval); + OpeningClaim stdlib_opening_claim{ { stdlib_x, stdlib_eval }, stdlib_comm }; + + return {stdlib_opening_claim, ipa_transcript->export_proof()}; + } }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 077ffd9de8c..1789562498d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -439,31 +439,13 @@ HonkRecursionConstraintsOutput process_honk_recursion_constraints( } else if (nested_ipa_claims.size() > 2) { throw_or_abort("Too many nested IPA claims to accumulate"); } else { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1184): Move to IPA class. if (honk_recursion == 2) { info("Proving with UltraRollupHonk but no IPA claims exist."); - // just create some fake IPA claim and proof - using NativeCurve = curve::Grumpkin; - using Curve = stdlib::grumpkin; - auto ipa_transcript = std::make_shared(); - auto ipa_commitment_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); - size_t n = 4; - auto poly = Polynomial(n); - for (size_t i = 0; i < n; i++) { - poly.at(i) = fq::random_element(); - } - fq x = fq::random_element(); - fq eval = poly.evaluate(x); - auto commitment = ipa_commitment_key->commit(poly); - const OpeningPair opening_pair = { x, eval }; - IPA::compute_opening_proof(ipa_commitment_key, { poly, opening_pair }, ipa_transcript); - - auto stdlib_comm = Curve::Group::from_witness(&builder, commitment); - auto stdlib_x = Curve::ScalarField::from_witness(&builder, x); - auto stdlib_eval = Curve::ScalarField::from_witness(&builder, eval); - OpeningClaim stdlib_opening_claim{ { stdlib_x, stdlib_eval }, stdlib_comm }; + auto [stdlib_opening_claim, ipa_proof] = + IPA>::create_fake_ipa_claim_and_proof(builder); + output.ipa_claim = stdlib_opening_claim; - output.ipa_proof = ipa_transcript->export_proof(); + output.ipa_proof = ipa_proof; } } output.agg_obj_indices = current_aggregation_object; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp index e44428be1a4..310f2a57531 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp @@ -42,18 +42,9 @@ void create_dummy_vkey_and_proof(Builder& builder, const std::vector& proof_fields) { // Set vkey->circuit_size correctly based on the proof size - size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs(); - size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs(); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1168): Add formula to flavor - assert((proof_size - bb::HONK_PROOF_PUBLIC_INPUT_OFFSET - Flavor::NUM_WITNESS_ENTITIES * num_frs_comm - - Flavor::NUM_ALL_ENTITIES * num_frs_fr - num_frs_comm) % - (num_frs_comm + num_frs_fr * (Flavor::BATCHED_RELATION_PARTIAL_LENGTH + 1)) == - 0); + ASSERT(proof_size == Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS); // Note: this computation should always result in log_circuit_size = CONST_PROOF_SIZE_LOG_N - auto log_circuit_size = - (proof_size - bb::HONK_PROOF_PUBLIC_INPUT_OFFSET - Flavor::NUM_WITNESS_ENTITIES * num_frs_comm - - Flavor::NUM_ALL_ENTITIES * num_frs_fr - num_frs_comm) / - (num_frs_comm + num_frs_fr * (Flavor::BATCHED_RELATION_PARTIAL_LENGTH + 1)); + auto log_circuit_size = CONST_PROOF_SIZE_LOG_N; // First key field is circuit size builder.assert_equal(builder.add_variable(1 << log_circuit_size), key_fields[0].witness_index); // Second key field is number of public inputs diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp index 3caa326d5dc..937ca0a48ec 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp @@ -49,16 +49,14 @@ UltraRecursiveVerifier_::Output UltraRecursiveVerifier_::verify_ Output output; StdlibProof honk_proof; if constexpr (HasIPAAccumulator) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1168): Add formula to flavor - const size_t HONK_PROOF_LENGTH = 469; + const size_t HONK_PROOF_LENGTH = Flavor::NativeFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS - IPA_PROOF_LENGTH; const size_t num_public_inputs = static_cast(proof[1].get_value()); // The extra calculation is for the IPA proof length. // TODO(https://github.com/AztecProtocol/barretenberg/issues/1182): Handle in ProofSurgeon. - ASSERT(proof.size() == HONK_PROOF_LENGTH + (1 + 4 * (CONST_ECCVM_LOG_N) + 2 + 2) + num_public_inputs - - (PAIRING_POINT_ACCUMULATOR_SIZE + IPA_CLAIM_SIZE)); + ASSERT(proof.size() == HONK_PROOF_LENGTH + IPA_PROOF_LENGTH + num_public_inputs); // split out the ipa proof - const std::ptrdiff_t honk_proof_with_pub_inputs_length = static_cast( - HONK_PROOF_LENGTH + num_public_inputs - (PAIRING_POINT_ACCUMULATOR_SIZE + IPA_CLAIM_SIZE)); + const std::ptrdiff_t honk_proof_with_pub_inputs_length = + static_cast(HONK_PROOF_LENGTH + num_public_inputs); output.ipa_proof = StdlibProof(proof.begin() + honk_proof_with_pub_inputs_length, proof.end()); honk_proof = StdlibProof(proof.begin(), proof.end() + honk_proof_with_pub_inputs_length); } else { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp index bb7c633f120..5e854a677a1 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.test.cpp @@ -77,29 +77,11 @@ template class RecursiveVerifierTest : public testing PairingPointAccumulatorIndices agg_obj_indices = stdlib::recursion::init_default_agg_obj_indices(builder); builder.add_pairing_point_accumulator(agg_obj_indices); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1184): Move to IPA class. if constexpr (HasIPAAccumulator) { - using NativeCurve = curve::Grumpkin; - using Curve = stdlib::grumpkin; - auto ipa_transcript = std::make_shared(); - auto ipa_commitment_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); - size_t n = 4; - auto poly = Polynomial(n); - for (size_t i = 0; i < n; i++) { - poly.at(i) = fq::random_element(); - } - fq x = fq::random_element(); - fq eval = poly.evaluate(x); - auto commitment = ipa_commitment_key->commit(poly); - const OpeningPair opening_pair = { x, eval }; - IPA::compute_opening_proof(ipa_commitment_key, { poly, opening_pair }, ipa_transcript); - - auto stdlib_comm = Curve::Group::from_witness(&builder, commitment); - auto stdlib_x = Curve::ScalarField::from_witness(&builder, x); - auto stdlib_eval = Curve::ScalarField::from_witness(&builder, eval); - OpeningClaim stdlib_opening_claim{ { stdlib_x, stdlib_eval }, stdlib_comm }; + auto [stdlib_opening_claim, ipa_proof] = + IPA>::create_fake_ipa_claim_and_proof(builder); builder.add_ipa_claim(stdlib_opening_claim.get_witness_indices()); - builder.ipa_proof = ipa_transcript->export_proof(); + builder.ipa_proof = ipa_proof; } return builder; }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp index 62bc329ba6d..1155e1b5d8e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp @@ -67,9 +67,9 @@ class UltraFlavor { // Note: made generic for use in MegaRecursive. template - // List of relations reflecting the Ultra arithmetisation. WARNING: As UltraKeccak flavor inherits from Ultra flavor - // any change of ordering in this tuple needs to be reflected in the smart contract, otherwise relation accumulation - // will not match. + // List of relations reflecting the Ultra arithmetisation. WARNING: As UltraKeccak flavor inherits from + // Ultra flavor any change of ordering in this tuple needs to be reflected in the smart contract, otherwise + // relation accumulation will not match. using Relations_ = std::tuple, bb::UltraPermutationRelation, bb::LogDerivLookupRelation, @@ -97,6 +97,22 @@ class UltraFlavor { static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; static constexpr size_t NUM_RELATIONS = std::tuple_size_v; + // Proof length formula: + // 1. HONK_PROOF_PUBLIC_INPUT_OFFSET are the circuit_size, num_public_inputs, pub_inputs_offset + // 2. PAIRING_POINT_ACCUMULATOR_SIZE public inputs for pairing point accumulator + // 3. NUM_WITNESS_ENTITIES commitments + // 4. CONST_PROOF_SIZE_LOG_N sumcheck univariates + // 5. NUM_ALL_ENTITIES sumcheck evaluations + // 6. CONST_PROOF_SIZE_LOG_N Gemini Fold commitments + // 7. CONST_PROOF_SIZE_LOG_N Gemini a evaluations + // 8. KZG W commitment + static constexpr size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs(); + static constexpr size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs(); + static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS = + HONK_PROOF_PUBLIC_INPUT_OFFSET + NUM_WITNESS_ENTITIES * num_frs_comm + + CONST_PROOF_SIZE_LOG_N * BATCHED_RELATION_PARTIAL_LENGTH * num_frs_fr + NUM_ALL_ENTITIES * num_frs_fr + + CONST_PROOF_SIZE_LOG_N * num_frs_comm + CONST_PROOF_SIZE_LOG_N * num_frs_fr + num_frs_comm; + template using ProtogalaxyTupleOfTuplesOfUnivariatesNoOptimisticSkipping = decltype(create_protogalaxy_tuple_of_tuples_of_univariates()); @@ -537,7 +553,6 @@ class UltraFlavor { * @brief A container for storing the partially evaluated multivariates produced by sumcheck. */ class PartiallyEvaluatedMultivariates : public AllEntities { - public: PartiallyEvaluatedMultivariates() = default; PartiallyEvaluatedMultivariates(const size_t circuit_size) @@ -675,7 +690,7 @@ class UltraFlavor { this->z_perm = commitments.z_perm; } } - }; + }; // namespace bb // Specialize for Ultra (general case used in UltraRecursive). using VerifierCommitments = VerifierCommitments_; diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_rollup_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_rollup_flavor.hpp index ff3d495236b..6376f1d3f68 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_rollup_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_rollup_flavor.hpp @@ -1,10 +1,26 @@ #pragma once +#include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_flavor.hpp" namespace bb { class UltraRollupFlavor : public bb::UltraFlavor { public: + // Proof length formula: + // 1. HONK_PROOF_PUBLIC_INPUT_OFFSET are the circuit_size, num_public_inputs, pub_inputs_offset + // 2. PAIRING_POINT_ACCUMULATOR_SIZE public inputs for pairing point accumulator + // 3. IPA_CLAIM_SIZE public inputs for IPA claim + // 4. NUM_WITNESS_ENTITIES commitments + // 5. CONST_PROOF_SIZE_LOG_N sumcheck univariates + // 6. NUM_ALL_ENTITIES sumcheck evaluations + // 7. CONST_PROOF_SIZE_LOG_N Gemini Fold commitments + // 8. CONST_PROOF_SIZE_LOG_N Gemini a evaluations + // 9. KZG W commitment + static constexpr size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs(); + static constexpr size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs(); + static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS = + UltraFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + IPA_PROOF_LENGTH; + using UltraFlavor::UltraFlavor; class ProvingKey : public UltraFlavor::ProvingKey { public: diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt index 7c55050a138..0ae823699ce 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(ultra_honk sumcheck) \ No newline at end of file +barretenberg_module(ultra_honk sumcheck stdlib_primitives) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index a211564ae5d..68b9fe85363 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -47,7 +47,7 @@ template HonkProof UltraProver_::export_proof() // Add the IPA proof if constexpr (HasIPAAccumulator) { // The extra calculation is for the IPA proof length. - ASSERT(proving_key->proving_key.ipa_proof.size() == 1 + 4 * (CONST_ECCVM_LOG_N) + 2 + 2); + ASSERT(proving_key->proving_key.ipa_proof.size() == IPA_PROOF_LENGTH); proof.insert(proof.end(), proving_key->proving_key.ipa_proof.begin(), proving_key->proving_key.ipa_proof.end()); } return proof; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index 43a8e0cbb41..6428b92bf0a 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -1,24 +1,31 @@ +#include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_flavor.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_rollup_flavor.hpp" #include "barretenberg/transcript/transcript.hpp" #include "barretenberg/ultra_honk/decider_proving_key.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" -#include +#include "gtest/gtest.h" using namespace bb; -class UltraTranscriptTests : public ::testing::Test { +template class UltraTranscriptTests : public ::testing::Test { public: - static void SetUpTestSuite() { bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); } + static void SetUpTestSuite() + { + bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); + bb::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } - using Flavor = UltraFlavor; - using VerificationKey = Flavor::VerificationKey; - using FF = Flavor::FF; + using Prover = UltraProver_; + using Verifier = UltraVerifier_; + using VerificationKey = typename Flavor::VerificationKey; + using FF = typename Flavor::FF; using DeciderProvingKey = DeciderProvingKey_; /** @@ -40,7 +47,7 @@ class UltraTranscriptTests : public ::testing::Test { size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; // Size of types is number of bb::frs needed to represent the types size_t frs_per_Fr = bb::field_conversion::calc_num_bn254_frs(); - size_t frs_per_G = bb::field_conversion::calc_num_bn254_frs(); + size_t frs_per_G = bb::field_conversion::calc_num_bn254_frs(); size_t frs_per_uni = MAX_PARTIAL_RELATION_LENGTH * frs_per_Fr; size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*frs_per_Fr; size_t frs_per_uint32 = bb::field_conversion::calc_num_bn254_frs(); @@ -50,6 +57,11 @@ class UltraTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "public_input_size", frs_per_uint32); manifest_expected.add_entry(round, "pub_inputs_offset", frs_per_uint32); manifest_expected.add_entry(round, "public_input_0", frs_per_Fr); + if constexpr (HasIPAAccumulator) { + for (size_t i = 0; i < IPA_CLAIM_SIZE; i++) { + manifest_expected.add_entry(round, "public_input_" + std::to_string(i + 1), frs_per_Fr); + } + } manifest_expected.add_entry(round, "W_L", frs_per_G); manifest_expected.add_entry(round, "W_R", frs_per_G); manifest_expected.add_entry(round, "W_O", frs_per_G); @@ -115,42 +127,61 @@ class UltraTranscriptTests : public ::testing::Test { return manifest_expected; } - void generate_test_circuit(auto& builder) + void generate_test_circuit(typename Flavor::CircuitBuilder& builder) { FF a = 1; builder.add_variable(a); builder.add_public_variable(a); + + if constexpr (HasIPAAccumulator) { + auto [stdlib_opening_claim, ipa_proof] = + IPA>::create_fake_ipa_claim_and_proof(builder); + builder.add_ipa_claim(stdlib_opening_claim.get_witness_indices()); + builder.ipa_proof = ipa_proof; + } } - void generate_random_test_circuit(auto& builder) + void generate_random_test_circuit(typename Flavor::CircuitBuilder& 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); + + if constexpr (HasIPAAccumulator) { + auto [stdlib_opening_claim, ipa_proof] = + IPA>::create_fake_ipa_claim_and_proof(builder); + builder.add_ipa_claim(stdlib_opening_claim.get_witness_indices()); + builder.ipa_proof = ipa_proof; + } } }; +using FlavorTypes = testing::Types; +TYPED_TEST_SUITE(UltraTranscriptTests, 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. */ -TEST_F(UltraTranscriptTests, ProverManifestConsistency) +TYPED_TEST(UltraTranscriptTests, ProverManifestConsistency) { // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); - generate_test_circuit(builder); + auto builder = typename TypeParam::CircuitBuilder(); + TestFixture::generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof - auto proving_key = std::make_shared(builder); - UltraProver prover(proving_key); + auto proving_key = std::make_shared(builder); + typename TestFixture::Prover prover(proving_key); auto proof = prover.construct_proof(); // Check that the prover generated manifest agrees with the manifest hard coded in this suite - auto manifest_expected = construct_ultra_honk_manifest(); + auto manifest_expected = TestFixture::construct_ultra_honk_manifest(); auto prover_manifest = prover.transcript->get_manifest(); // Note: a manifest can be printed using manifest.print() + manifest_expected.print(); + prover_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; } @@ -161,22 +192,40 @@ TEST_F(UltraTranscriptTests, ProverManifestConsistency) * construction and the one generated by the verifier over the course of proof verification. * */ -TEST_F(UltraTranscriptTests, VerifierManifestConsistency) +TYPED_TEST(UltraTranscriptTests, VerifierManifestConsistency) { // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = Flavor::CircuitBuilder(); - generate_test_circuit(builder); + auto builder = typename TypeParam::CircuitBuilder(); + TestFixture::generate_test_circuit(builder); // Automatically generate a transcript manifest in the prover by constructing a proof - auto proving_key = std::make_shared(builder); - UltraProver prover(proving_key); + auto proving_key = std::make_shared(builder); + typename TestFixture::Prover prover(proving_key); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verification_key = std::make_shared(proving_key->proving_key); - UltraVerifier verifier(verification_key); - verifier.verify_proof(proof); + auto verification_key = std::make_shared(proving_key->proving_key); + typename TestFixture::Verifier verifier(verification_key); + HonkProof honk_proof; + HonkProof ipa_proof; + if constexpr (HasIPAAccumulator) { + verifier.ipa_verification_key = + std::make_shared>(1 << CONST_ECCVM_LOG_N); + const size_t HONK_PROOF_LENGTH = TypeParam::PROOF_LENGTH_WITHOUT_PUB_INPUTS - IPA_PROOF_LENGTH; + const size_t num_public_inputs = static_cast(proof[1]); + // The extra calculation is for the IPA proof length. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1182): Handle in ProofSurgeon. + ASSERT(proof.size() == HONK_PROOF_LENGTH + IPA_PROOF_LENGTH + num_public_inputs); + // split out the ipa proof + const std::ptrdiff_t honk_proof_with_pub_inputs_length = + static_cast(HONK_PROOF_LENGTH + num_public_inputs); + ipa_proof = HonkProof(proof.begin() + honk_proof_with_pub_inputs_length, proof.end()); + honk_proof = HonkProof(proof.begin(), proof.end() + honk_proof_with_pub_inputs_length); + } else { + honk_proof = proof; + } + verifier.verify_proof(honk_proof, ipa_proof); // Check consistency between the manifests generated by the prover and verifier auto prover_manifest = prover.transcript->get_manifest(); @@ -194,12 +243,12 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) * @details We generate 6 challenges that are each 128 bits, and check that they are not 0. * */ -TEST_F(UltraTranscriptTests, ChallengeGenerationTest) +TYPED_TEST(UltraTranscriptTests, ChallengeGenerationTest) { // initialized with random value sent to verifier - auto transcript = Flavor::Transcript::prover_init_empty(); + auto transcript = TypeParam::Transcript::prover_init_empty(); // test a bunch of challenges - auto challenges = transcript->template get_challenges("a", "b", "c", "d", "e", "f"); + auto challenges = transcript->template 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"; @@ -207,24 +256,27 @@ TEST_F(UltraTranscriptTests, ChallengeGenerationTest) constexpr uint32_t random_val{ 17 }; // arbitrary transcript->send_to_verifier("random val", random_val); // test more challenges - auto [a, b, c] = transcript->template get_challenges("a", "b", "c"); + auto [a, b, c] = transcript->template get_challenges("a", "b", "c"); ASSERT_NE(a, 0) << "Challenge a is 0"; ASSERT_NE(b, 0) << "Challenge b is 0"; ASSERT_NE(c, 0) << "Challenge c is 0"; } -TEST_F(UltraTranscriptTests, StructureTest) +TYPED_TEST(UltraTranscriptTests, StructureTest) { + if constexpr (IsAnyOf) { + GTEST_SKIP() << "Not built for this parameter"; + } // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); - generate_test_circuit(builder); + auto builder = typename TypeParam::CircuitBuilder(); + TestFixture::generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof - auto proving_key = std::make_shared(builder); - UltraProver prover(proving_key); + auto proving_key = std::make_shared(builder); + typename TestFixture::Prover prover(proving_key); auto proof = prover.construct_proof(); - auto verification_key = std::make_shared(proving_key->proving_key); - UltraVerifier verifier(verification_key); + auto verification_key = std::make_shared(proving_key->proving_key); + typename TestFixture::Verifier verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid @@ -232,8 +284,8 @@ TEST_F(UltraTranscriptTests, StructureTest) 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(); + auto one_group_val = TypeParam::Commitment::one(); + auto rand_val = TestFixture::FF::random_element(); prover.transcript->z_perm_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 @@ -242,5 +294,18 @@ TEST_F(UltraTranscriptTests, StructureTest) 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->z_perm_comm), one_group_val * rand_val); + EXPECT_EQ(static_cast(prover.transcript->z_perm_comm), one_group_val * rand_val); +} + +TYPED_TEST(UltraTranscriptTests, ProofLengthTest) +{ + // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) + auto builder = typename TypeParam::CircuitBuilder(); + TestFixture::generate_test_circuit(builder); + + // Automatically generate a transcript manifest by constructing a proof + auto proving_key = std::make_shared(builder); + typename TestFixture::Prover prover(proving_key); + auto proof = prover.construct_proof(); + EXPECT_EQ(proof.size(), TypeParam::PROOF_LENGTH_WITHOUT_PUB_INPUTS + builder.public_inputs.size()); }