From a204d1b60514d6321c2db5063375cc2bbd507fe8 Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Mon, 9 Dec 2024 16:41:58 -0500 Subject: [PATCH] feat: modify HonkRecursionConstraint to handle IPA claims (#10469) This PR was split out of the IPA-in-rollup integration work. It modifies the recursion constraint to be able to recursively verify UltraRollupFlavor properly by either forwarding or accumulating IPA claims. --- .../dsl/acir_format/acir_format.cpp | 36 +++- .../acir_format/acir_to_constraint_buf.cpp | 5 +- .../acir_format/honk_recursion_constraint.cpp | 96 +++++++++-- .../acir_format/honk_recursion_constraint.hpp | 19 ++- .../honk_recursion_constraint.test.cpp | 155 ++++++++++++------ .../dsl/acir_format/recursion_constraint.hpp | 2 +- .../ultra_circuit_builder.hpp | 4 +- .../ultra_rollup_flavor.hpp | 32 ++++ .../barretenberg/ultra_honk/ultra_prover.cpp | 9 +- 9 files changed, 285 insertions(+), 73 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index dd48e644a22..a4a864625ca 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -3,6 +3,7 @@ #include "barretenberg/common/throw_or_abort.hpp" #include "barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp" #include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" #include "barretenberg/stdlib/primitives/field/field_conversion.hpp" #include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" @@ -350,13 +351,44 @@ PairingPointAccumulatorIndices process_honk_recursion_constraints( { // Add recursion constraints size_t idx = 0; + std::vector>> nested_ipa_claims; + std::vector> nested_ipa_proofs; for (auto& constraint : constraint_system.honk_recursion_constraints) { - current_aggregation_object = create_honk_recursion_constraints( - builder, constraint, current_aggregation_object, has_valid_witness_assignments); + if (constraint.proof_type == HONK) { + auto [next_aggregation_object, _ipa_claim, _ipa_proof] = + create_honk_recursion_constraints>( + builder, constraint, current_aggregation_object, has_valid_witness_assignments); + current_aggregation_object = next_aggregation_object; + } else if (constraint.proof_type == ROLLUP_HONK || constraint.proof_type == ROLLUP_ROOT_HONK) { + auto [next_aggregation_object, ipa_claim, ipa_proof] = + create_honk_recursion_constraints>( + builder, constraint, current_aggregation_object, has_valid_witness_assignments); + current_aggregation_object = next_aggregation_object; + + nested_ipa_claims.push_back(ipa_claim); + nested_ipa_proofs.push_back(ipa_proof); + } else { + throw_or_abort("Invalid Honk proof type"); + } gate_counter.track_diff(constraint_system.gates_per_opcode, constraint_system.original_opcode_indices.honk_recursion_constraints.at(idx++)); } + // Accumulate the claims + if (nested_ipa_claims.size() == 2) { + auto commitment_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); + using StdlibTranscript = bb::stdlib::recursion::honk::UltraStdlibTranscript; + + auto ipa_transcript_1 = std::make_shared(nested_ipa_proofs[0]); + auto ipa_transcript_2 = std::make_shared(nested_ipa_proofs[1]); + IPA>::accumulate( + commitment_key, ipa_transcript_1, nested_ipa_claims[0], ipa_transcript_2, nested_ipa_claims[1]); + } else if (nested_ipa_claims.size() == 1) { + builder.add_ipa_claim(nested_ipa_claims[0].get_witness_indices()); + // This conversion looks suspicious but there's no need to make this an output of the circuit since its a proof + // that will be checked anyway. + builder.ipa_proof = convert_stdlib_proof_to_native(nested_ipa_proofs[0]); + } return current_aggregation_object; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp index cae59733e3b..251ca8236e7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp @@ -634,7 +634,8 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, // TODO(https://github.com/AztecProtocol/barretenberg/issues/1074): Eventually arg.proof_type will // be the only means for setting the proof type. use of honk_recursion flag in this context can go // away once all noir programs (e.g. protocol circuits) are updated to use the new pattern. - if (honk_recursion && proof_type_in != HONK && proof_type_in != AVM) { + if (honk_recursion && proof_type_in != HONK && proof_type_in != AVM && proof_type_in != ROLLUP_HONK && + proof_type_in != ROLLUP_ROOT_HONK) { proof_type_in = HONK; } @@ -653,6 +654,8 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, af.original_opcode_indices.recursion_constraints.push_back(opcode_index); break; case HONK: + case ROLLUP_HONK: + case ROLLUP_ROOT_HONK: af.honk_recursion_constraints.push_back(c); af.original_opcode_indices.honk_recursion_constraints.push_back(opcode_index); break; 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 45da4234f6f..c79535ad7d4 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 @@ -31,17 +31,18 @@ namespace { * @param key_fields * @param proof_fields */ +template void create_dummy_vkey_and_proof(Builder& builder, size_t proof_size, size_t public_inputs_size, const std::vector& key_fields, - const std::vector& proof_fields) + const std::vector& proof_fields, + bool is_rollup_honk_recursion_constraint) { - using Flavor = UltraFlavor; - // 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(); + 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)) == @@ -61,13 +62,26 @@ void create_dummy_vkey_and_proof(Builder& builder, builder.assert_equal(builder.add_variable(1), key_fields[3].witness_index); uint32_t offset = 4; size_t num_inner_public_inputs = public_inputs_size - bb::PAIRING_POINT_ACCUMULATOR_SIZE; + if (is_rollup_honk_recursion_constraint) { + num_inner_public_inputs -= bb::IPA_CLAIM_SIZE; + } - // We are making the assumption that the aggregation object are behind all the inner public inputs + // We are making the assumption that the pairing point object is behind all the inner public inputs for (size_t i = 0; i < bb::PAIRING_POINT_ACCUMULATOR_SIZE; i++) { builder.assert_equal(builder.add_variable(num_inner_public_inputs + i), key_fields[offset].witness_index); offset++; } + if (is_rollup_honk_recursion_constraint) { + // Key field is the whether the proof contains an aggregation object. + builder.assert_equal(builder.add_variable(1), key_fields[offset++].witness_index); + // We are making the assumption that the IPA claim is behind the inner public inputs and pairing point object + for (size_t i = 0; i < bb::IPA_CLAIM_SIZE; i++) { + builder.assert_equal(builder.add_variable(num_inner_public_inputs + i), key_fields[offset].witness_index); + offset++; + } + } + for (size_t i = 0; i < Flavor::NUM_PRECOMPUTED_ENTITIES; ++i) { auto comm = curve::BN254::AffineElement::one() * fr::random_element(); auto frs = field_conversion::convert_to_bn254_frs(comm); @@ -96,6 +110,14 @@ void create_dummy_vkey_and_proof(Builder& builder, offset++; } + if (is_rollup_honk_recursion_constraint) { + IPAClaimIndices ipa_claim; // WORKTODO: initialize this to something? + for (auto idx : ipa_claim) { + builder.assert_equal(idx, proof_fields[offset].witness_index); + offset++; + } + } + // first 8 witness commitments for (size_t i = 0; i < Flavor::NUM_WITNESS_ENTITIES; i++) { auto comm = curve::BN254::AffineElement::one() * fr::random_element(); @@ -107,7 +129,8 @@ void create_dummy_vkey_and_proof(Builder& builder, offset += 4; } - // now the univariates, which can just be 0s (8*CONST_PROOF_SIZE_LOG_N Frs, where 8 is the maximum relation degree) + // now the univariates, which can just be 0s (8*CONST_PROOF_SIZE_LOG_N Frs, where 8 is the maximum relation + // degree) for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N * Flavor::BATCHED_RELATION_PARTIAL_LENGTH; i++) { builder.assert_equal(builder.add_variable(fr::random_element()), proof_fields[offset].witness_index); offset++; @@ -162,17 +185,20 @@ void create_dummy_vkey_and_proof(Builder& builder, * We would either need a separate ACIR opcode where inner_proof_contains_pairing_point_accumulator = true, * or we need non-witness data to be provided as metadata in the ACIR opcode */ -PairingPointAccumulatorIndices create_honk_recursion_constraints( + +template +HonkRecursionConstraintOutput create_honk_recursion_constraints( Builder& builder, const RecursionConstraint& input, PairingPointAccumulatorIndices input_aggregation_object_indices, bool has_valid_witness_assignments) { - using Flavor = UltraRecursiveFlavor_; using RecursiveVerificationKey = Flavor::VerificationKey; using RecursiveVerifier = bb::stdlib::recursion::honk::UltraRecursiveVerifier_; - ASSERT(input.proof_type == HONK); + bool is_rollup_honk_recursion_constraint = + (input.proof_type == ROLLUP_HONK || input.proof_type == ROLLUP_ROOT_HONK); + ASSERT(input.proof_type == HONK || is_rollup_honk_recursion_constraint); // Construct an in-circuit representation of the verification key. // For now, the v-key is a circuit constant and is fixed for the circuit. @@ -200,9 +226,19 @@ PairingPointAccumulatorIndices create_honk_recursion_constraints( // In the constraint, the agg object public inputs are still contained in the proof. To get the 'raw' size of // the proof and public_inputs we subtract and add the corresponding amount from the respective sizes. size_t size_of_proof_with_no_pub_inputs = input.proof.size() - bb::PAIRING_POINT_ACCUMULATOR_SIZE; + if (is_rollup_honk_recursion_constraint) { + size_of_proof_with_no_pub_inputs -= bb::IPA_CLAIM_SIZE; + } size_t total_num_public_inputs = input.public_inputs.size() + bb::PAIRING_POINT_ACCUMULATOR_SIZE; - create_dummy_vkey_and_proof( - builder, size_of_proof_with_no_pub_inputs, total_num_public_inputs, key_fields, proof_fields); + if (is_rollup_honk_recursion_constraint) { + total_num_public_inputs += bb::IPA_CLAIM_SIZE; + } + create_dummy_vkey_and_proof(builder, + size_of_proof_with_no_pub_inputs, + total_num_public_inputs, + key_fields, + proof_fields, + is_rollup_honk_recursion_constraint); } // Recursively verify the proof @@ -210,11 +246,43 @@ PairingPointAccumulatorIndices create_honk_recursion_constraints( RecursiveVerifier verifier(&builder, vkey); aggregation_state_ct input_agg_obj = bb::stdlib::recursion::convert_witness_indices_to_agg_obj( builder, input_aggregation_object_indices); - UltraRecursiveVerifierOutput output = verifier.verify_proof(proof_fields, input_agg_obj); + std::vector honk_proof = proof_fields; + HonkRecursionConstraintOutput output; + if (is_rollup_honk_recursion_constraint) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1168): Add formula to flavor + const size_t HONK_PROOF_LENGTH = 473; + // The extra calculation is for the IPA proof length. + ASSERT(input.proof.size() == HONK_PROOF_LENGTH + 1 + 4 * (CONST_ECCVM_LOG_N) + 2 + 2); + ASSERT(proof_fields.size() == HONK_PROOF_LENGTH + 65 + input.public_inputs.size()); + // split out the ipa proof + const std::ptrdiff_t honk_proof_with_pub_inputs_length = + static_cast(HONK_PROOF_LENGTH + input.public_inputs.size()); + output.ipa_proof = + StdlibProof(honk_proof.begin() + honk_proof_with_pub_inputs_length, honk_proof.end()); + honk_proof = StdlibProof(honk_proof.begin(), honk_proof.end() + honk_proof_with_pub_inputs_length); + } + UltraRecursiveVerifierOutput verifier_output = verifier.verify_proof(honk_proof, input_agg_obj); // TODO(https://github.com/AztecProtocol/barretenberg/issues/996): investigate whether assert_equal on public inputs // is important, like what the plonk recursion constraint does. - return output.agg_obj.get_witness_indices(); + output.agg_obj_indices = verifier_output.agg_obj.get_witness_indices(); + if (is_rollup_honk_recursion_constraint) { + ASSERT(HasIPAAccumulator); + output.ipa_claim = verifier_output.ipa_opening_claim; + } + return output; } +template HonkRecursionConstraintOutput create_honk_recursion_constraints>( + Builder& builder, + const RecursionConstraint& input, + PairingPointAccumulatorIndices input_aggregation_object_indices, + bool has_valid_witness_assignments); + +template HonkRecursionConstraintOutput create_honk_recursion_constraints>( + Builder& builder, + const RecursionConstraint& input, + PairingPointAccumulatorIndices input_aggregation_object_indices, + bool has_valid_witness_assignments); + } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp index 71a4a26e9cb..a850c8b4f0c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp @@ -1,6 +1,9 @@ #pragma once +#include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/dsl/acir_format/recursion_constraint.hpp" +#include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" +#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" #include namespace acir_format { @@ -8,10 +11,16 @@ using Builder = bb::UltraCircuitBuilder; using namespace bb; -PairingPointAccumulatorIndices create_honk_recursion_constraints( - Builder& builder, - const RecursionConstraint& input, - PairingPointAccumulatorIndices input_aggregation_object, - bool has_valid_witness_assignments = false); +struct HonkRecursionConstraintOutput { + PairingPointAccumulatorIndices agg_obj_indices; + OpeningClaim> ipa_claim; + StdlibProof ipa_proof; +}; + +template +HonkRecursionConstraintOutput create_honk_recursion_constraints(Builder& builder, + const RecursionConstraint& input, + PairingPointAccumulatorIndices input_aggregation_object, + bool has_valid_witness_assignments = false); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp index 50b92017818..7f1dbd8f6cb 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp @@ -12,13 +12,13 @@ using namespace acir_format; using namespace bb; -class AcirHonkRecursionConstraint : public ::testing::Test { +template class AcirHonkRecursionConstraint : public ::testing::Test { public: - using DeciderProvingKey = DeciderProvingKey_; - using Prover = bb::UltraProver; - using VerificationKey = UltraFlavor::VerificationKey; - using Verifier = bb::UltraVerifier; + using DeciderProvingKey = DeciderProvingKey_; + using Prover = bb::UltraProver_; + using VerificationKey = typename Flavor::VerificationKey; + using Verifier = bb::UltraVerifier_; Builder create_inner_circuit() { @@ -127,7 +127,29 @@ class AcirHonkRecursionConstraint : public ::testing::Test { }; auto builder = create_circuit(constraint_system, /*recursive*/ true, /*size_hint*/ 0, witness, /*honk recursion*/ true); - + 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 }; + builder.add_ipa_claim(stdlib_opening_claim.get_witness_indices()); + builder.ipa_proof = ipa_transcript->export_proof(); + } return builder; } @@ -153,8 +175,13 @@ class AcirHonkRecursionConstraint : public ::testing::Test { std::vector key_witnesses = verification_key->to_field_elements(); std::vector proof_witnesses = inner_proof; - const size_t num_public_inputs_to_extract = + size_t num_public_inputs_to_extract = inner_circuit.get_public_inputs().size() - bb::PAIRING_POINT_ACCUMULATOR_SIZE; + acir_format::PROOF_TYPE proof_type = acir_format::HONK; + if constexpr (HasIPAAccumulator) { + num_public_inputs_to_extract -= IPA_CLAIM_SIZE; + proof_type = ROLLUP_HONK; + } auto [key_indices, proof_indices, inner_public_inputs] = ProofSurgeon::populate_recursion_witness_data( witness, proof_witnesses, key_witnesses, num_public_inputs_to_extract); @@ -164,7 +191,7 @@ class AcirHonkRecursionConstraint : public ::testing::Test { .proof = proof_indices, .public_inputs = inner_public_inputs, .key_hash = 0, // not used - .proof_type = HONK, + .proof_type = proof_type, }; honk_recursion_constraints.push_back(honk_recursion_constraint); } @@ -183,48 +210,68 @@ class AcirHonkRecursionConstraint : public ::testing::Test { } protected: - static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } + static void SetUpTestSuite() + { + bb::srs::init_crs_factory("../srs_db/ignition"); + srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } }; -TEST_F(AcirHonkRecursionConstraint, TestBasicSingleHonkRecursionConstraint) +using Flavors = testing::Types; + +TYPED_TEST_SUITE(AcirHonkRecursionConstraint, Flavors); + +TYPED_TEST(AcirHonkRecursionConstraint, TestBasicSingleHonkRecursionConstraint) { std::vector layer_1_circuits; - layer_1_circuits.push_back(create_inner_circuit()); + layer_1_circuits.push_back(TestFixture::create_inner_circuit()); - auto layer_2_circuit = create_outer_circuit(layer_1_circuits); + auto layer_2_circuit = TestFixture::create_outer_circuit(layer_1_circuits); - info("circuit gates = ", layer_2_circuit.get_estimated_num_finalized_gates()); + info("estimate finalized circuit gates = ", layer_2_circuit.get_estimated_num_finalized_gates()); - auto proving_key = std::make_shared(layer_2_circuit); - Prover prover(proving_key); + auto proving_key = std::make_shared(layer_2_circuit); + typename TestFixture::Prover prover(proving_key); info("prover gates = ", proving_key->proving_key.circuit_size); auto proof = prover.construct_proof(); - auto verification_key = std::make_shared(proving_key->proving_key); - Verifier verifier(verification_key); - EXPECT_EQ(verifier.verify_proof(proof), true); + auto verification_key = std::make_shared(proving_key->proving_key); + if constexpr (HasIPAAccumulator) { + auto ipa_verification_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); + typename TestFixture::Verifier verifier(verification_key, ipa_verification_key); + EXPECT_EQ(verifier.verify_proof(proof, proving_key->proving_key.ipa_proof), true); + } else { + typename TestFixture::Verifier verifier(verification_key); + EXPECT_EQ(verifier.verify_proof(proof), true); + } } -TEST_F(AcirHonkRecursionConstraint, TestBasicDoubleHonkRecursionConstraints) +TYPED_TEST(AcirHonkRecursionConstraint, TestBasicDoubleHonkRecursionConstraints) { std::vector layer_1_circuits; - layer_1_circuits.push_back(create_inner_circuit()); + layer_1_circuits.push_back(TestFixture::create_inner_circuit()); - layer_1_circuits.push_back(create_inner_circuit()); + layer_1_circuits.push_back(TestFixture::create_inner_circuit()); - auto layer_2_circuit = create_outer_circuit(layer_1_circuits); + auto layer_2_circuit = TestFixture::create_outer_circuit(layer_1_circuits); info("circuit gates = ", layer_2_circuit.get_estimated_num_finalized_gates()); - auto proving_key = std::make_shared(layer_2_circuit); - Prover prover(proving_key); + auto proving_key = std::make_shared(layer_2_circuit); + typename TestFixture::Prover prover(proving_key); info("prover gates = ", proving_key->proving_key.circuit_size); auto proof = prover.construct_proof(); - auto verification_key = std::make_shared(proving_key->proving_key); - Verifier verifier(verification_key); - EXPECT_EQ(verifier.verify_proof(proof), true); + auto verification_key = std::make_shared(proving_key->proving_key); + if constexpr (HasIPAAccumulator) { + auto ipa_verification_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); + typename TestFixture::Verifier verifier(verification_key, ipa_verification_key); + EXPECT_EQ(verifier.verify_proof(proof, proving_key->proving_key.ipa_proof), true); + } else { + typename TestFixture::Verifier verifier(verification_key); + EXPECT_EQ(verifier.verify_proof(proof), true); + } } -TEST_F(AcirHonkRecursionConstraint, TestOneOuterRecursiveCircuit) +TYPED_TEST(AcirHonkRecursionConstraint, TestOneOuterRecursiveCircuit) { /** * We want to test the following: @@ -259,55 +306,67 @@ TEST_F(AcirHonkRecursionConstraint, TestOneOuterRecursiveCircuit) * Final aggregation object contains aggregated proofs for 2 instances of A and 1 instance of B */ std::vector layer_1_circuits; - layer_1_circuits.push_back(create_inner_circuit()); + layer_1_circuits.push_back(TestFixture::create_inner_circuit()); info("created first inner circuit"); std::vector layer_2_circuits; - layer_2_circuits.push_back(create_inner_circuit()); + layer_2_circuits.push_back(TestFixture::create_inner_circuit()); info("created second inner circuit"); - layer_2_circuits.push_back(create_outer_circuit(layer_1_circuits)); + layer_2_circuits.push_back(TestFixture::create_outer_circuit(layer_1_circuits)); info("created first outer circuit"); - auto layer_3_circuit = create_outer_circuit(layer_2_circuits); + auto layer_3_circuit = TestFixture::create_outer_circuit(layer_2_circuits); info("created second outer circuit"); info("number of gates in layer 3 = ", layer_3_circuit.get_estimated_num_finalized_gates()); - auto proving_key = std::make_shared(layer_3_circuit); - Prover prover(proving_key); + auto proving_key = std::make_shared(layer_3_circuit); + typename TestFixture::Prover prover(proving_key); info("prover gates = ", proving_key->proving_key.circuit_size); auto proof = prover.construct_proof(); - auto verification_key = std::make_shared(proving_key->proving_key); - Verifier verifier(verification_key); - EXPECT_EQ(verifier.verify_proof(proof), true); + auto verification_key = std::make_shared(proving_key->proving_key); + if constexpr (HasIPAAccumulator) { + auto ipa_verification_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); + typename TestFixture::Verifier verifier(verification_key, ipa_verification_key); + EXPECT_EQ(verifier.verify_proof(proof, proving_key->proving_key.ipa_proof), true); + } else { + typename TestFixture::Verifier verifier(verification_key); + EXPECT_EQ(verifier.verify_proof(proof), true); + } } -TEST_F(AcirHonkRecursionConstraint, TestFullRecursiveComposition) +TYPED_TEST(AcirHonkRecursionConstraint, TestFullRecursiveComposition) { std::vector layer_b_1_circuits; - layer_b_1_circuits.push_back(create_inner_circuit()); + layer_b_1_circuits.push_back(TestFixture::create_inner_circuit()); info("created first inner circuit"); std::vector layer_b_2_circuits; - layer_b_2_circuits.push_back(create_inner_circuit()); + layer_b_2_circuits.push_back(TestFixture::create_inner_circuit()); info("created second inner circuit"); std::vector layer_2_circuits; - layer_2_circuits.push_back(create_outer_circuit(layer_b_1_circuits)); + layer_2_circuits.push_back(TestFixture::create_outer_circuit(layer_b_1_circuits)); info("created first outer circuit"); - layer_2_circuits.push_back(create_outer_circuit(layer_b_2_circuits)); + layer_2_circuits.push_back(TestFixture::create_outer_circuit(layer_b_2_circuits)); info("created second outer circuit"); - auto layer_3_circuit = create_outer_circuit(layer_2_circuits); + auto layer_3_circuit = TestFixture::create_outer_circuit(layer_2_circuits); info("created third outer circuit"); info("number of gates in layer 3 circuit = ", layer_3_circuit.get_estimated_num_finalized_gates()); - auto proving_key = std::make_shared(layer_3_circuit); - Prover prover(proving_key); + auto proving_key = std::make_shared(layer_3_circuit); + typename TestFixture::Prover prover(proving_key); info("prover gates = ", proving_key->proving_key.circuit_size); auto proof = prover.construct_proof(); - auto verification_key = std::make_shared(proving_key->proving_key); - Verifier verifier(verification_key); - EXPECT_EQ(verifier.verify_proof(proof), true); + auto verification_key = std::make_shared(proving_key->proving_key); + if constexpr (HasIPAAccumulator) { + auto ipa_verification_key = std::make_shared>(1 << CONST_ECCVM_LOG_N); + typename TestFixture::Verifier verifier(verification_key, ipa_verification_key); + EXPECT_EQ(verifier.verify_proof(proof, proving_key->proving_key.ipa_proof), true); + } else { + typename TestFixture::Verifier verifier(verification_key); + EXPECT_EQ(verifier.verify_proof(proof), true); + } } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp index 6fa308df92c..c7ae3ab1d07 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp @@ -10,7 +10,7 @@ namespace acir_format { // ACIR // Keep this enum values in sync with their noir counterpart constants defined in // noir-protocol-circuits/crates/types/src/constants.nr -enum PROOF_TYPE { PLONK, HONK, OINK, PG, AVM }; +enum PROOF_TYPE { PLONK, HONK, OINK, PG, AVM, ROLLUP_HONK, ROLLUP_ROOT_HONK }; using namespace bb::plonk; using Builder = bb::UltraCircuitBuilder; diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp index 499dc9df159..c70c8d062e0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp @@ -392,7 +392,8 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase + */ + std::vector to_field_elements() const + { + using namespace bb::field_conversion; + + auto serialize_to_field_buffer = [](const auto& input, std::vector& buffer) { + std::vector input_fields = convert_to_bn254_frs(input); + buffer.insert(buffer.end(), input_fields.begin(), input_fields.end()); + }; + + std::vector elements; + + serialize_to_field_buffer(this->circuit_size, elements); + serialize_to_field_buffer(this->num_public_inputs, elements); + serialize_to_field_buffer(this->pub_inputs_offset, elements); + serialize_to_field_buffer(this->contains_pairing_point_accumulator, elements); + serialize_to_field_buffer(this->pairing_point_accumulator_public_input_indices, elements); + serialize_to_field_buffer(contains_ipa_claim, elements); + serialize_to_field_buffer(ipa_claim_public_input_indices, elements); + + for (const Commitment& commitment : this->get_all()) { + serialize_to_field_buffer(commitment, elements); + } + + return elements; + } + VerificationKey(ProvingKey& proving_key) : contains_ipa_claim(proving_key.contains_ipa_claim) , ipa_claim_public_input_indices(proving_key.ipa_claim_public_input_indices) diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index 152605af4b6..c07c75b34a3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -36,6 +36,12 @@ UltraProver_::UltraProver_(Builder& circuit) template HonkProof UltraProver_::export_proof() { proof = transcript->proof_data; + // 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); + proof.insert(proof.end(), proving_key->proving_key.ipa_proof.begin(), proving_key->proving_key.ipa_proof.end()); + } return proof; } template void UltraProver_::generate_gate_challenges() @@ -58,7 +64,8 @@ template HonkProof UltraProver_::construct_proof( DeciderProver_ decider_prover(proving_key, transcript); vinfo("created decider prover"); - return decider_prover.construct_proof(); + decider_prover.construct_proof(); + return export_proof(); } template class UltraProver_;