diff --git a/barretenberg/cpp/bb-civc-inputs.tar.gz b/barretenberg/cpp/bb-civc-inputs.tar.gz deleted file mode 100644 index fc159645d6e3..000000000000 Binary files a/barretenberg/cpp/bb-civc-inputs.tar.gz and /dev/null differ diff --git a/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh b/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh index ee014d97aedf..6fcaeaecf3dc 100755 --- a/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh +++ b/barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh @@ -11,7 +11,7 @@ cd .. # - Generate a hash for versioning: sha256sum bb-civc-inputs.tar.gz # - Upload the compressed results: aws s3 cp bb-civc-inputs.tar.gz s3://aztec-ci-artifacts/protocol/bb-civc-inputs-[hash(0:8)].tar.gz # Note: In case of the "Test suite failed to run ... Unexpected token 'with' " error, need to run: docker pull aztecprotocol/build:3.0 -pinned_short_hash="458fb354" +pinned_short_hash="bb7c0098" pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-${pinned_short_hash}.tar.gz" function compress_and_upload { @@ -53,7 +53,7 @@ if [[ "${1:-}" == "--update_inputs" ]]; then fi export inputs_tmp_dir=$(mktemp -d) -trap 'rm -rf "$inputs_tmp_dir"' EXIT SIGINT +trap 'rm -rf "$inputs_tmp_dir" bb-civc-inputs.tar.gz' EXIT SIGINT curl -s -f "$pinned_civc_inputs_url" | tar -xzf - -C "$inputs_tmp_dir" &>/dev/null diff --git a/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp b/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp index a537909da452..63960f3724d6 100644 --- a/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp +++ b/barretenberg/cpp/src/barretenberg/api/prove_tube.cpp @@ -32,15 +32,20 @@ void prove_tube(const std::string& output_path, const std::string& vk_path) ClientIVCRecursiveVerifier::Output client_ivc_rec_verifier_output = verifier.verify(stdlib_proof); // The public inputs in the proof are propagated to the base rollup by making them public inputs of this circuit. - // Exclude the pairing points which are handled separately. - auto num_inner_public_inputs = vk.mega->num_public_inputs - bb::PAIRING_POINTS_SIZE; + // Exclude the public inputs of the Hiding Kernel: the pairing points are handled separately, the ecc op tables are + // not needed after this point + auto num_inner_public_inputs = vk.mega->num_public_inputs - HidingKernelIO::PUBLIC_INPUTS_SIZE; for (size_t i = 0; i < num_inner_public_inputs; i++) { stdlib_proof.mega_proof[i].set_public(); } - client_ivc_rec_verifier_output.points_accumulator.set_public(); - // The tube only calls an IPA recursive verifier once, so we can just add this IPA claim and proof - client_ivc_rec_verifier_output.opening_claim.set_public(); + // IO + RollupIO inputs; + inputs.pairing_inputs = client_ivc_rec_verifier_output.points_accumulator; + inputs.ipa_claim = client_ivc_rec_verifier_output.opening_claim; + inputs.set_public(); + + // The tube only calls an IPA recursive verifier once, so we can just add this IPA proof builder->ipa_proof = client_ivc_rec_verifier_output.ipa_proof.get_value(); BB_ASSERT_EQ(builder->ipa_proof.size(), IPA_PROOF_LENGTH, "IPA proof should be set."); @@ -92,7 +97,7 @@ void prove_tube(const std::string& output_path, const std::string& vk_path) // Break up the tube proof into the honk portion and the ipa portion const size_t HONK_PROOF_LENGTH_WITHOUT_INNER_PUB_INPUTS = - UltraRollupFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + PAIRING_POINTS_SIZE + IPA_CLAIM_SIZE; + UltraRollupFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + RollupIO::PUBLIC_INPUTS_SIZE; // The extra calculation is for the IPA proof length. BB_ASSERT_EQ(tube_proof.size(), HONK_PROOF_LENGTH_WITHOUT_INNER_PUB_INPUTS + num_inner_public_inputs, diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp index 5dcab081551b..f9e7ddf4f9a7 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph.cpp @@ -317,10 +317,9 @@ inline std::vector StaticAnalyzer_::get_memory_gate_connected_comp gate_variables.reserve(8); auto q_1 = block.q_1()[index]; auto q_2 = block.q_2()[index]; - [[maybe_unused]] auto q_3 = block.q_3()[index]; + auto q_3 = block.q_3()[index]; auto q_4 = block.q_4()[index]; [[maybe_unused]] auto q_m = block.q_m()[index]; - auto q_arith = block.q_arith()[index]; [[maybe_unused]] auto q_c = block.q_c()[index]; [[maybe_unused]] auto w_l = block.w_l()[index]; @@ -329,7 +328,7 @@ inline std::vector StaticAnalyzer_::get_memory_gate_connected_comp [[maybe_unused]] auto w_4 = block.w_4()[index]; if (q_1 == FF::one() && q_4 == FF::one()) { - ASSERT(q_arith.is_zero()); + ASSERT(q_3.is_zero()); // ram timestamp check if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), @@ -340,7 +339,7 @@ inline std::vector StaticAnalyzer_::get_memory_gate_connected_comp block.w_o()[index] }); } } else if (q_1 == FF::one() && q_2 == FF::one()) { - ASSERT(q_arith.is_zero()); + ASSERT(q_3.is_zero()); // rom constitency check if (index < block.size() - 1) { gate_variables.insert( @@ -349,7 +348,7 @@ inline std::vector StaticAnalyzer_::get_memory_gate_connected_comp } } else { // ram constitency check - if (!q_arith.is_zero()) { + if (!q_3.is_zero()) { if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), { block.w_o()[index], @@ -388,7 +387,6 @@ inline std::vector StaticAnalyzer_::get_non_native_field_gate_conn auto q_3 = block.q_3()[index]; auto q_4 = block.q_4()[index]; auto q_m = block.q_m()[index]; - auto q_arith = block.q_arith()[index]; [[maybe_unused]] auto q_c = block.q_c()[index]; auto w_l = block.w_l()[index]; @@ -397,13 +395,11 @@ inline std::vector StaticAnalyzer_::get_non_native_field_gate_conn auto w_4 = block.w_4()[index]; if (q_3 == FF::one() && q_4 == FF::one()) { // bigfield limb accumulation 1 - ASSERT(q_arith.is_zero()); if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), { w_l, w_r, w_o, w_4, block.w_l()[index + 1], block.w_r()[index + 1] }); // 6 } } else if (q_3 == FF::one() && q_m == FF::one()) { - ASSERT(q_arith.is_zero()); // bigfield limb accumulation 2 if (index < block.size() - 1) { gate_variables.insert(gate_variables.end(), @@ -415,7 +411,6 @@ inline std::vector StaticAnalyzer_::get_non_native_field_gate_conn block.w_4()[index + 1] }); } } else if (q_2 == FF::one() && (q_3 == FF::one() || q_4 == FF::one() || q_m == FF::one())) { - ASSERT(q_arith.is_zero()); // bigfield product cases if (index < block.size() - 1) { std::vector limb_subproduct_vars = { @@ -483,7 +478,6 @@ inline std::vector StaticAnalyzer_::get_rom_table_connected_compon auto q_3 = ultra_builder.blocks.memory.q_3()[gate_index]; auto q_4 = ultra_builder.blocks.memory.q_4()[gate_index]; auto q_m = ultra_builder.blocks.memory.q_m()[gate_index]; - auto q_arith = ultra_builder.blocks.memory.q_arith()[gate_index]; auto q_c = ultra_builder.blocks.memory.q_c()[gate_index]; auto index_witness = record.index_witness; @@ -491,8 +485,7 @@ inline std::vector StaticAnalyzer_::get_rom_table_connected_compon auto vc2_witness = record.value_column2_witness; // state[1] from RomTranscript auto record_witness = record.record_witness; - if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && q_c.is_zero() && - q_arith.is_zero()) { + if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && q_c.is_zero()) { // By default ROM read gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, vc1_witness, vc2_witness, // record_witness) So we can update all of them gate_variables.emplace_back(index_witness); @@ -538,7 +531,6 @@ inline std::vector StaticAnalyzer_::get_ram_table_connected_compon auto q_3 = ultra_builder.blocks.memory.q_3()[gate_index]; auto q_4 = ultra_builder.blocks.memory.q_4()[gate_index]; auto q_m = ultra_builder.blocks.memory.q_m()[gate_index]; - auto q_arith = ultra_builder.blocks.memory.q_arith()[gate_index]; auto q_c = ultra_builder.blocks.memory.q_c()[gate_index]; auto index_witness = record.index_witness; @@ -547,7 +539,7 @@ inline std::vector StaticAnalyzer_::get_ram_table_connected_compon auto record_witness = record.record_witness; if (q_1 == FF::one() && q_m == FF::one() && q_2.is_zero() && q_3.is_zero() && q_4.is_zero() && - q_arith.is_zero() && (q_c.is_zero() || q_c == FF::one())) { + (q_c.is_zero() || q_c == FF::one())) { // By default RAM read/write gate uses variables (w_1, w_2, w_3, w_4) = (index_witness, timestamp_witness, // value_witness, record_witness) So we can update all of them gate_variables.emplace_back(index_witness); diff --git a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp index de48c31a598d..0519337ebe81 100644 --- a/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp +++ b/barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp @@ -23,15 +23,16 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { using OuterDeciderProvingKey = DeciderProvingKey_; using Commitment = MergeVerifier::Commitment; + using MergeCommitments = MergeVerifier::InputCommitments; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; - using MergeCommitments = GoblinRecursiveVerifier::MergeVerifier::WitnessCommitments; + using RecursiveMergeCommitments = GoblinRecursiveVerifier::MergeVerifier::InputCommitments; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } struct ProverOutput { GoblinProof proof; Goblin::VerificationKey verifier_input; - std::array t_commitments; + MergeCommitments merge_commitments; }; /** @@ -58,17 +59,19 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { GoblinMockCircuits::construct_simple_circuit(builder); goblin_final.op_queue->merge(); // Subtable values and commitments - needed for (Recursive)MergeVerifier - std::array t_commitments; + MergeCommitments merge_commitments; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); + auto T_prev = goblin_final.op_queue->construct_previous_ultra_ops_table_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { - t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); + merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); + merge_commitments.T_prev_commitments[idx] = pcs_commitment_key.commit(T_prev[idx]); } // Output is a goblin proof plus ECCVM/Translator verification keys return { goblin_final.prove(), { std::make_shared(), std::make_shared() }, - t_commitments }; + merge_commitments }; } }; @@ -78,20 +81,21 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test { */ TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic) { - auto [proof, verifier_input, t_commitments] = create_goblin_prover_output(); + auto [proof, verifier_input, merge_commitments] = create_goblin_prover_output(); Builder builder; // Merge commitments - MergeCommitments recursive_merge_commitments; + RecursiveMergeCommitments recursive_merge_commitments; for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { recursive_merge_commitments.t_commitments[idx] = - RecursiveCommitment::from_witness(&builder, t_commitments[idx]); + RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]); + recursive_merge_commitments.T_prev_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_commitments.T_prev_commitments[idx]); } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = - verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_commitments); output.points_accumulator.set_public(); // Construct and verify a proof for the Goblin Recursive Verifier circuit { diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index f721140193f4..e8b45b3515b0 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -9,6 +9,7 @@ #include "barretenberg/common/streams.hpp" #include "barretenberg/honk/proving_key_inspector.hpp" #include "barretenberg/serialize/msgpack_impl.hpp" +#include "barretenberg/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/ultra_honk/oink_prover.hpp" namespace bb { @@ -86,17 +87,27 @@ void ClientIVC::instantiate_stdlib_verification_queue( * @param merge_commitments Container for the commitments for the Merge recursive verification to be performed * @param accumulation_recursive_transcript Transcript shared across recursive verification of the folding of * K_{i-1} (kernel), A_{i,1} (app), .., A_{i, n} (app) + * + * @return Pair of PairingPoints for final verification and commitments to the merged tables as read from the proof by + * the Merge verifier */ -ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_consistency_checks( - ClientCircuit& circuit, - const StdlibVerifierInputs& verifier_inputs, - MergeCommitments& merge_commitments, - const std::shared_ptr& accumulation_recursive_transcript) +std::pair ClientIVC:: + perform_recursive_verification_and_databus_consistency_checks( + ClientCircuit& circuit, + const StdlibVerifierInputs& verifier_inputs, + const TableCommitments& T_prev_commitments, + const std::shared_ptr& accumulation_recursive_transcript) { + using MergeCommitments = Goblin::MergeRecursiveVerifier::InputCommitments; + // Witness commitments and public inputs corresponding to the incoming instance WitnessCommitments witness_commitments; std::vector public_inputs; + // Input commitments to be passed to the merge recursive verification + MergeCommitments merge_commitments; + merge_commitments.T_prev_commitments = T_prev_commitments; + switch (verifier_inputs.type) { case QUEUE_TYPE::PG: { // Construct stdlib verifier accumulator from the native counterpart computed on a previous round @@ -134,34 +145,35 @@ ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_c witness_commitments = std::move(verifier_accum->witness_commitments); public_inputs = std::move(verifier.public_inputs); + // T_prev = 0 in the first recursive verification + merge_commitments.T_prev_commitments = HidingKernelIO::empty_ecc_op_tables(circuit); + break; } case QUEUE_TYPE::PG_FINAL: { // Constuct the hiding circuit - PairingPoints pairing_points = + auto [pairing_points, merged_table_commitments] = complete_hiding_circuit_logic(verifier_inputs.proof, verifier_inputs.honk_vk_and_hash, circuit); // Return early since the hiding circuit method performs merge and public inputs handling (fix this!) - return pairing_points; + return { pairing_points, merged_table_commitments }; } default: { throw_or_abort("Invalid queue type! Only OINK, PG and PG_FINAL are supported"); } } - // Extract the commitments to the subtable corresponding to the incoming circuit - merge_commitments.set_t_commitments(witness_commitments.get_ecc_op_wires()); - - // Recursively verify the corresponding merge proof - PairingPoints pairing_points = goblin.recursively_verify_merge( - circuit, merge_commitments, merge_commitments.T_commitments, accumulation_recursive_transcript); - PairingPoints nested_pairing_points; // to be extracted from public inputs of app or kernel proof just verified if (verifier_inputs.is_kernel) { // Reconstruct the input from the previous kernel from its public inputs KernelIO kernel_input; // pairing points, databus return data commitments kernel_input.reconstruct_from_public(public_inputs); + nested_pairing_points = kernel_input.pairing_inputs; + // T_prev is read by the public input of the previous kernel K_{i-1} at the beginning of the recursive + // verification of of the folding of K_{i-1} (kernel), A_{i,1} (app), .., A_{i, n} (app). This verification + // happens in K_{i} + merge_commitments.T_prev_commitments = kernel_input.ecc_op_tables; // Perform databus consistency checks kernel_input.kernel_return_data.assert_equal(witness_commitments.calldata); @@ -179,9 +191,16 @@ ClientIVC::PairingPoints ClientIVC::perform_recursive_verification_and_databus_c bus_depot.set_app_return_data_commitment(witness_commitments.return_data); } + // Extract the commitments to the subtable corresponding to the incoming circuit + merge_commitments.t_commitments = witness_commitments.get_ecc_op_wires().get_copy(); + + // Recursively verify the corresponding merge proof + auto [pairing_points, merged_table_commitments] = + goblin.recursively_verify_merge(circuit, merge_commitments, accumulation_recursive_transcript); + pairing_points.aggregate(nested_pairing_points); - return pairing_points; + return { pairing_points, merged_table_commitments }; } /** @@ -199,8 +218,8 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) // .., A_{i, n} (app) auto accumulation_recursive_transcript = std::make_shared(); - // Merge commitments to be used in the recursive verifications - MergeCommitments merge_commitments; + // Commitment to the previous state of the op_queue in the recursive verification + TableCommitments T_prev_commitments; // Instantiate stdlib verifier inputs from their native counterparts if (stdlib_verification_queue.empty()) { @@ -212,13 +231,16 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) PairingPoints points_accumulator; while (!stdlib_verification_queue.empty()) { const StdlibVerifierInputs& verifier_input = stdlib_verification_queue.front(); - PairingPoints pairing_points = perform_recursive_verification_and_databus_consistency_checks( - circuit, verifier_input, merge_commitments, accumulation_recursive_transcript); + auto [pairing_points, merged_table_commitments] = perform_recursive_verification_and_databus_consistency_checks( + circuit, verifier_input, T_prev_commitments, accumulation_recursive_transcript); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1376): Optimize recursion aggregation - seems // we can use `batch_mul` here to decrease the size of the `ECCOpQueue`, but must be cautious with FS security. points_accumulator.aggregate(pairing_points); + // Update commitment to the status of the op_queue + T_prev_commitments = merged_table_commitments; + stdlib_verification_queue.pop_front(); is_hiding_kernel = (verifier_input.type == QUEUE_TYPE::PG_FINAL); @@ -226,13 +248,14 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) // Set the kernel output data to be propagated via the public inputs if (is_hiding_kernel) { - HidingKernelIO hiding_output{ points_accumulator }; + HidingKernelIO hiding_output{ points_accumulator, T_prev_commitments }; hiding_output.set_public(); } else { KernelIO kernel_output; kernel_output.pairing_inputs = points_accumulator; kernel_output.kernel_return_data = bus_depot.get_kernel_return_data_commitment(circuit); kernel_output.app_return_data = bus_depot.get_app_return_data_commitment(circuit); + kernel_output.ecc_op_tables = T_prev_commitments; kernel_output.set_public(); } @@ -353,11 +376,13 @@ void ClientIVC::hide_op_queue_accumulation_result(ClientCircuit& circuit) circuit.queue_ecc_eq(); } -ClientIVC::PairingPoints ClientIVC::complete_hiding_circuit_logic( +std::pair ClientIVC::complete_hiding_circuit_logic( const StdlibProof& stdlib_proof, const std::shared_ptr& stdlib_vk_and_hash, ClientCircuit& circuit) { + using MergeCommitments = Goblin::MergeRecursiveVerifier::InputCommitments; + // Shared transcript between PG and Merge // TODO(https://github.com/AztecProtocol/barretenberg/issues/1453): Investigate whether Decider/PG/Merge need to // share a transcript @@ -399,10 +424,12 @@ ClientIVC::PairingPoints ClientIVC::complete_hiding_circuit_logic( // Extract the commitments to the subtable corresponding to the incoming circuit MergeCommitments merge_commitments; - merge_commitments.set_t_commitments(witness_commitments.get_ecc_op_wires()); + merge_commitments.t_commitments = witness_commitments.get_ecc_op_wires().get_copy(); + merge_commitments.T_prev_commitments = std::move( + kernel_input.ecc_op_tables); // Commitment to the status of the op_queue before folding the tail kernel // Perform recursive verification of the last merge proof - PairingPoints points_accumulator = goblin.recursively_verify_merge( - circuit, merge_commitments, merge_commitments.T_commitments, pg_merge_transcript); + auto [points_accumulator, merged_table_commitments] = + goblin.recursively_verify_merge(circuit, merge_commitments, pg_merge_transcript); points_accumulator.aggregate(kernel_input.pairing_inputs); @@ -411,7 +438,7 @@ ClientIVC::PairingPoints ClientIVC::complete_hiding_circuit_logic( BB_ASSERT_EQ(!decider_proof.empty(), true, "Decider proof is empty!"); PairingPoints decider_pairing_points = decider.verify_proof(decider_proof); points_accumulator.aggregate(decider_pairing_points); - return points_accumulator; + return { points_accumulator, merged_table_commitments }; } /** @@ -434,10 +461,11 @@ std::shared_ptr ClientIVC::construct_hiding_circ std::make_shared(&builder, verification_queue[0].honk_vk), ClientIVC::RecursiveFlavor::FF::from_witness(&builder, verification_queue[0].honk_vk->hash())); - PairingPoints pairing_points = complete_hiding_circuit_logic(stdlib_proof, stdlib_vk_and_hash, builder); + auto [pairing_points, merged_table_commitments] = + complete_hiding_circuit_logic(stdlib_proof, stdlib_vk_and_hash, builder); fold_output.accumulator = nullptr; - HidingKernelIO hiding_output{ pairing_points }; + HidingKernelIO hiding_output{ pairing_points, merged_table_commitments }; hiding_output.set_public(); auto decider_pk = std::make_shared(builder, TraceSettings(), bn254_commitment_key); @@ -483,20 +511,20 @@ ClientIVC::Proof ClientIVC::prove() bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk) { + using TableCommitments = Goblin::TableCommitments; // Create a transcript to be shared by MegaZK-, Merge-, ECCVM-, and Translator- Verifiers. std::shared_ptr civc_verifier_transcript = std::make_shared(); // Verify the hiding circuit proof MegaZKVerifier verifier{ vk.mega, /*ipa_verification_key=*/{}, civc_verifier_transcript }; - auto [mega_verified, _] = verifier.verify_proof(proof.mega_proof); + auto [mega_verified, T_prev_commitments] = verifier.verify_proof(proof.mega_proof); vinfo("Mega verified: ", mega_verified); // Extract the commitments to the subtable corresponding to the incoming circuit - MergeVerifier::WitnessCommitments merge_commitments; - merge_commitments.set_t_commitments(verifier.verification_key->witness_commitments.get_ecc_op_wires()); + TableCommitments t_commitments = verifier.verification_key->witness_commitments.get_ecc_op_wires().get_copy(); // Goblin verification (final merge, eccvm, translator) - bool goblin_verified = Goblin::verify( - proof.goblin_proof, merge_commitments, merge_commitments.T_commitments, civc_verifier_transcript); + bool goblin_verified = + Goblin::verify(proof.goblin_proof, { t_commitments, T_prev_commitments }, civc_verifier_transcript); vinfo("Goblin verified: ", goblin_verified); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers. diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 6c1707c06d9d..bb3d445b70f3 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -75,14 +75,14 @@ class ClientIVC { using PairingPoints = stdlib::recursion::PairingPoints; using PublicPairingPoints = stdlib::PublicInputComponent; using KernelIO = bb::stdlib::recursion::honk::KernelIO; - using HidingKernelIO = bb::stdlib::recursion::honk::HidingKernelIO; + using HidingKernelIO = bb::stdlib::recursion::honk::HidingKernelIO; using AppIO = bb::stdlib::recursion::honk::AppIO; using StdlibProof = stdlib::Proof; using StdlibFF = RecursiveFlavor::FF; using WitnessCommitments = RecursiveFlavor::WitnessCommitments; // Merge commitments - using MergeCommitments = stdlib::recursion::goblin::MergeRecursiveVerifier_::WitnessCommitments; + using TableCommitments = std::array; /** * @brief A full proof for the IVC scheme containing a Mega proof showing correctness of the hiding circuit (which @@ -201,18 +201,18 @@ class ClientIVC { void instantiate_stdlib_verification_queue(ClientCircuit& circuit, const std::vector>& input_keys = {}); - [[nodiscard("Pairing points should be accumulated")]] PairingPoints + [[nodiscard("Pairing points should be accumulated")]] std::pair perform_recursive_verification_and_databus_consistency_checks( ClientCircuit& circuit, const StdlibVerifierInputs& verifier_inputs, - MergeCommitments& merge_commitments, + const TableCommitments& T_prev_commitments, const std::shared_ptr& accumulation_recursive_transcript); // Complete the logic of a kernel circuit (e.g. PG/merge recursive verification, databus consistency checks) void complete_kernel_circuit_logic(ClientCircuit& circuit); // Complete the logic of the hiding circuit, which includes PG, decider and merge recursive verification - ClientIVC::PairingPoints complete_hiding_circuit_logic( + std::pair complete_hiding_circuit_logic( const StdlibProof& stdlib_proof, const std::shared_ptr& stdlib_vk_and_hash, ClientCircuit& circuit); diff --git a/barretenberg/cpp/src/barretenberg/common/ref_array.hpp b/barretenberg/cpp/src/barretenberg/common/ref_array.hpp index 7f6dc5ebc065..e2860c25ae28 100644 --- a/barretenberg/cpp/src/barretenberg/common/ref_array.hpp +++ b/barretenberg/cpp/src/barretenberg/common/ref_array.hpp @@ -55,6 +55,21 @@ template class RefArray { #endif } + /** + * @brief Get a copy of the underlying data. Use carefully, as it allocates new data for the data pointed to by the + * elements in the RefArray + * + */ + std::array get_copy() + { + std::array data; + for (size_t idx = 0; idx < N; idx++) { + data[idx] = *storage[idx]; + } + + return data; + } + /** * @brief Nested iterator class for RefArray, based on indexing into the pointer array. * Provides semantics similar to what would be expected if std::array was possible. diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 389e2d2e30fd..229ba0de2a90 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -37,7 +37,7 @@ static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; // extra evaluations static constexpr uint32_t NUM_SMALL_IPA_EVALUATIONS = 4; -static constexpr uint32_t MERGE_PROOF_SIZE = 65; // used to ensure mock proofs are generated correctly +static constexpr uint32_t MERGE_PROOF_SIZE = 49; // used to ensure mock proofs are generated correctly // There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between // ECCVM and Translator 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 95392f8640e1..5ca330ecc3c3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -271,7 +271,7 @@ void build_constraints(Builder& builder, AcirProgram& program, const ProgramMeta // If its an app circuit that has no recursion constraints, add default pairing points to public inputs. if (constraint_system.honk_recursion_constraints.empty() && constraint_system.ivc_recursion_constraints.empty()) { - PairingPoints::add_default_to_public_inputs(builder); + stdlib::recursion::honk::AppIO::add_default(builder); } } else { HonkRecursionConstraintsOutput honk_output = 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 8fcc98eacc7d..72654ad1c685 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 @@ -18,6 +18,7 @@ #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/proof/proof.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "proof_surgeon.hpp" #include "recursion_constraint.hpp" @@ -215,7 +216,7 @@ void create_dummy_vkey_and_proof(typename Flavor::CircuitBuilder& builder, template HonkRecursionConstraintOutput create_honk_recursion_constraints( typename Flavor::CircuitBuilder& builder, const RecursionConstraint& input, bool has_valid_witness_assignments) - requires IsRecursiveFlavor + requires(IsRecursiveFlavor && IsUltraHonk) { using Builder = typename Flavor::CircuitBuilder; using RecursiveVerificationKey = Flavor::VerificationKey; @@ -253,13 +254,14 @@ HonkRecursionConstraintOutput create_honk_recur if (!has_valid_witness_assignments) { // 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_POINTS_SIZE; - if constexpr (HasIPAAccumulator) { - size_of_proof_with_no_pub_inputs -= bb::IPA_CLAIM_SIZE; - } - size_t total_num_public_inputs = input.public_inputs.size() + bb::PAIRING_POINTS_SIZE; + size_t size_of_proof_with_no_pub_inputs = input.proof.size(); + size_t total_num_public_inputs = input.public_inputs.size(); if constexpr (HasIPAAccumulator) { - total_num_public_inputs += bb::IPA_CLAIM_SIZE; + size_of_proof_with_no_pub_inputs -= RollupIO::PUBLIC_INPUTS_SIZE; + total_num_public_inputs += RollupIO::PUBLIC_INPUTS_SIZE; + } else { + size_of_proof_with_no_pub_inputs -= DefaultIO::PUBLIC_INPUTS_SIZE; + total_num_public_inputs += DefaultIO::PUBLIC_INPUTS_SIZE; } create_dummy_vkey_and_proof( 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 8d172b524132..f71b6fa8d3d1 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 @@ -27,6 +27,6 @@ template create_honk_recursion_constraints(typename Flavor::CircuitBuilder& builder, const RecursionConstraint& input, bool has_valid_witness_assignments = false) - requires IsRecursiveFlavor; + requires(IsRecursiveFlavor && IsUltraHonk); } // 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 93d40afdee5d..3ff63081ce98 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 @@ -1,6 +1,7 @@ #include "honk_recursion_constraint.hpp" #include "acir_format.hpp" #include "acir_format_mocks.hpp" +#include "barretenberg/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/ultra_honk/decider_proving_key.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -173,14 +174,19 @@ template class AcirHonkRecursionConstraint : public : std::vector key_witnesses = verification_key->to_field_elements(); fr key_hash_witness = verification_key->hash(); std::vector proof_witnesses = inner_proof; - size_t num_public_inputs_to_extract = inner_circuit.num_public_inputs() - bb::PAIRING_POINTS_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; - } else if constexpr (InnerFlavor::HasZK) { - proof_type = HONK_ZK; - } + + // Compute the number of public inputs to extract (the ones from the circuit) and the proof type based on + // the Flavor + auto [num_public_inputs_to_extract, proof_type] = [&]() -> std::pair { + size_t num_public_inputs_to_extract = inner_circuit.num_public_inputs(); + if constexpr (HasIPAAccumulator) { + return { num_public_inputs_to_extract - RollupIO::PUBLIC_INPUTS_SIZE, ROLLUP_HONK }; + } else if constexpr (InnerFlavor::HasZK) { + return { num_public_inputs_to_extract - DefaultIO::PUBLIC_INPUTS_SIZE, HONK_ZK }; + } else { + return { num_public_inputs_to_extract - DefaultIO::PUBLIC_INPUTS_SIZE, HONK }; + } + }(); auto [key_indices, key_hash_index, proof_indices, inner_public_inputs] = ProofSurgeon::populate_recursion_witness_data( @@ -216,6 +222,16 @@ template class AcirHonkRecursionConstraint : public : AcirProgram program{ constraint_system, witness }; BuilderType outer_circuit = create_circuit(program, metadata); + // If BuilderType = Mega, then the proof of outer_circuit will be a Mega proof, and thus will be verified with + // a MegaVerifier = UltraVerifier. By design, the MegaVerifier expects the public inputs to be the + // ones of the HidingKernel, so we mock the missing part: ecc_op_tables + if constexpr (IsMegaBuilder) { + for (auto& commitment : + stdlib::recursion::honk::HidingKernelIO::default_ecc_op_tables(outer_circuit)) { + commitment.set_public(); + } + } + return outer_circuit; } @@ -223,7 +239,10 @@ template class AcirHonkRecursionConstraint : public : const std::shared_ptr& verification_key, const HonkProof& proof) { - if constexpr (IsUltraHonk) { + if constexpr (IsMegaFlavor) { + OuterVerifier verifier(verification_key); + return std::get<0>(verifier.verify_proof(proof)); + } else { if constexpr (HasIPAAccumulator) { VerifierCommitmentKey ipa_verification_key(1 << CONST_ECCVM_LOG_N); OuterVerifier verifier(verification_key, ipa_verification_key); @@ -232,9 +251,6 @@ template class AcirHonkRecursionConstraint : public : OuterVerifier verifier(verification_key); return verifier.verify_proof(proof); } - } else { - OuterVerifier verifier(verification_key); - return std::get<0>(verifier.verify_proof(proof)); } } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 24aa7fa07937..fdd63d2e5bbc 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -99,6 +99,7 @@ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC:: { using FF = ClientIVC::FF; using MegaVerificationKey = ClientIVC::MegaVerificationKey; + using Flavor = ClientIVC::Flavor; // Use the trace settings to determine the correct dyadic size and the public inputs offset MegaExecutionTraceBlocks blocks; @@ -106,26 +107,41 @@ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC:: blocks.compute_offsets(/*is_structured=*/true); size_t dyadic_size = blocks.get_structured_dyadic_size(); size_t pub_inputs_offset = blocks.pub_inputs.trace_offset(); - // All circuits have pairing point public inputs; kernels have additional public inputs for two databus commitments - size_t num_public_inputs = bb::PAIRING_POINTS_SIZE; - if (is_kernel) { - num_public_inputs += bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; - } - // Construct a mock Oink or PG proof + // Construct a mock Oink or PG proof and a mock MegaHonk verification key std::vector proof; - if (verification_type == ClientIVC::QUEUE_TYPE::OINK) { - proof = create_mock_oink_proof(num_public_inputs); - } else if (verification_type == ClientIVC::QUEUE_TYPE::PG || verification_type == ClientIVC::QUEUE_TYPE::PG_FINAL) { - proof = create_mock_pg_proof(num_public_inputs); + std::shared_ptr verification_key; + + if (is_kernel) { + using KernelIO = stdlib::recursion::honk::KernelIO; + switch (verification_type) { + case ClientIVC::QUEUE_TYPE::OINK: + proof = create_mock_oink_proof(); + break; + case ClientIVC::QUEUE_TYPE::PG: + case ClientIVC::QUEUE_TYPE::PG_FINAL: + proof = create_mock_pg_proof(); + break; + default: + throw_or_abort("Invalid verification type! Only OINK, PG and PG_FINAL are supported"); + } + verification_key = create_mock_honk_vk(dyadic_size, pub_inputs_offset); } else { - throw_or_abort("Invalid verification type! Only OINK, PG and PG_FINAL are supported"); + using AppIO = stdlib::recursion::honk::AppIO; + switch (verification_type) { + case ClientIVC::QUEUE_TYPE::OINK: + proof = create_mock_oink_proof(); + break; + case ClientIVC::QUEUE_TYPE::PG: + case ClientIVC::QUEUE_TYPE::PG_FINAL: + proof = create_mock_pg_proof(); + break; + default: + throw_or_abort("Invalid verification type! Only OINK, PG and PG_FINAL are supported"); + } + verification_key = create_mock_honk_vk(dyadic_size, pub_inputs_offset); } - // Construct a mock MegaHonk verification key - std::shared_ptr verification_key = - create_mock_honk_vk(dyadic_size, num_public_inputs, pub_inputs_offset); - return ClientIVC::VerifierInputs{ proof, verification_key, verification_type, is_kernel }; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index f28345682e7e..b4fe5f15f649 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -481,8 +481,6 @@ TEST_F(IvcRecursionConstraintTest, GenerateHidingKernelVKFromConstraints) // construct a mock tail kernel acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG_FINAL, /*is_kernel=*/true); AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - // acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG_FINAL, /*is_kernel=*/true); - // program = construct_mock_kernel_program(ivc->verification_queue); program.witness = {}; // remove the witness to mimick VK construction context kernel_vk = construct_kernel_vk_from_acir_program(program, TraceSettings()); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp index 1ece4124f736..dcabb8fd4011 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.cpp @@ -13,6 +13,7 @@ #include "barretenberg/stdlib/pairing_points.hpp" #include "barretenberg/stdlib/primitives/bigfield/constants.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/ultra_honk/decider_keys.hpp" #include "proof_surgeon.hpp" #include "recursion_constraint.hpp" @@ -42,36 +43,17 @@ void populate_field_elements_for_mock_commitments(std::vector& fields, const * @brief Create a mock oink proof that has the correct structure but is not in general valid * */ -template HonkProof create_mock_oink_proof(const size_t num_public_inputs) +template HonkProof create_mock_oink_proof() { HonkProof proof; // Populate mock public inputs - // Get some values for a valid aggregation object and use them here to avoid divide by 0 or other issues. - std::array::PUBLIC_INPUTS_SIZE> - dummy_pairing_points_values = stdlib::recursion::PairingPoints::construct_dummy(); - size_t public_input_count = 0; - for (size_t i = 0; i < stdlib::recursion::PairingPoints::PUBLIC_INPUTS_SIZE; i++) { - proof.emplace_back(dummy_pairing_points_values[i]); - public_input_count++; - } + typename Flavor::CircuitBuilder builder; + PublicInputs::add_default(builder); - if (public_input_count < num_public_inputs) { - // Databus commitments if necessary - for (size_t i = 0; i < NUM_DATABUS_COMMITMENTS; ++i) { - // We represent commitments in the public inputs as biggroup elements. - using BigGroup = stdlib::element_default::element, - stdlib::field_t, - curve::BN254::Group>; - auto pub_input_comm_vals = BigGroup::construct_dummy(); - for (const fr& comm_fr : pub_input_comm_vals) { - proof.emplace_back(comm_fr); - public_input_count++; - } - } + for (const auto& pub : builder.public_inputs()) { + proof.emplace_back(builder.get_variable(pub)); } - BB_ASSERT_EQ(public_input_count, num_public_inputs, "Mock oink proof has the wrong number of public inputs."); // Populate mock witness polynomial commitments populate_field_elements_for_mock_commitments(proof, Flavor::NUM_WITNESS_ENTITIES); @@ -122,10 +104,10 @@ template HonkProof create_mock_decider_proof() * @brief Create a mock honk proof that has the correct structure but is not in general valid * */ -template HonkProof create_mock_honk_proof(const size_t num_public_inputs) +template HonkProof create_mock_honk_proof() { // Construct a Honk proof as the concatenation of an Oink proof and a Decider proof - HonkProof oink_proof = create_mock_oink_proof(num_public_inputs); + HonkProof oink_proof = create_mock_oink_proof(); HonkProof decider_proof = create_mock_decider_proof(); HonkProof proof; proof.reserve(oink_proof.size() + decider_proof.size()); @@ -138,10 +120,10 @@ template HonkProof create_mock_honk_proof(const size_t num_pub * @brief Create a mock PG proof that has the correct structure but is not in general valid * */ -template HonkProof create_mock_pg_proof(const size_t num_public_inputs) +template HonkProof create_mock_pg_proof() { // The first part of a PG proof is an Oink proof - HonkProof proof = create_mock_oink_proof(num_public_inputs); + HonkProof proof = create_mock_oink_proof(); // Populate mock perturbator coefficients for (size_t idx = 1; idx <= CONST_PG_LOG_N; idx++) { @@ -177,9 +159,9 @@ Goblin::MergeProof create_mock_merge_proof() // Populate mock subtable size proof.emplace_back(mock_val); - // There are 12 entities in the merge protocol (4 columns x 3 components: T_{prev,j}, T_j, g_j(X) = X^{l-1} t_j(X)) + // There are 8 entities in the merge protocol (4 columns x 2 components: T_j, g_j(X) = X^{l-1} t_j(X)) // and 8 evaluations (4 columns x 2 components: g_j(kappa), t_j(1/kappa)) - const size_t NUM_TRANSCRIPT_ENTITIES = 12; + const size_t NUM_TRANSCRIPT_ENTITIES = 8; const size_t NUM_TRANSCRIPT_EVALUATIONS = 8; // Transcript poly commitments @@ -212,15 +194,14 @@ Goblin::MergeProof create_mock_merge_proof() * @brief Create a mock MegaHonk VK that has the correct structure * */ -template +template std::shared_ptr create_mock_honk_vk(const size_t dyadic_size, - const size_t num_public_inputs, const size_t pub_inputs_offset) { // Set relevant VK metadata and commitments auto honk_verification_key = std::make_shared(); honk_verification_key->log_circuit_size = bb::numeric::get_msb(dyadic_size); - honk_verification_key->num_public_inputs = num_public_inputs; + honk_verification_key->num_public_inputs = PublicInputs::PUBLIC_INPUTS_SIZE; honk_verification_key->pub_inputs_offset = pub_inputs_offset; // must be set correctly for (auto& commitment : honk_verification_key->get_all()) { @@ -241,7 +222,8 @@ template std::shared_ptr> crea // Set relevant VK metadata and commitments auto decider_verification_key = std::make_shared>(); std::shared_ptr vk = - create_mock_honk_vk(0, 0, 0); // metadata does not need to be accurate + create_mock_honk_vk>( + 0, 0); // metadata does not need to be accurate decider_verification_key->vk = vk; decider_verification_key->is_accumulator = true; decider_verification_key->gate_challenges = std::vector(static_cast(CONST_PG_LOG_N), 0); @@ -254,19 +236,33 @@ template std::shared_ptr> crea } // Explicitly instantiate template functions -template HonkProof create_mock_oink_proof(const size_t); -template HonkProof create_mock_oink_proof(const size_t); +template HonkProof create_mock_oink_proof(); +template HonkProof create_mock_oink_proof(); +template HonkProof create_mock_oink_proof>(); + +template HonkProof create_mock_oink_proof>(); template HonkProof create_mock_decider_proof(); template HonkProof create_mock_decider_proof(); -template HonkProof create_mock_honk_proof(const size_t); -template HonkProof create_mock_honk_proof(const size_t); +template HonkProof create_mock_honk_proof(); +template HonkProof create_mock_honk_proof(); +template HonkProof create_mock_honk_proof>(); + +template HonkProof create_mock_honk_proof>(); + +template HonkProof create_mock_pg_proof(); +template HonkProof create_mock_pg_proof(); +template HonkProof create_mock_pg_proof>(); -template HonkProof create_mock_pg_proof(const size_t); -template std::shared_ptr create_mock_honk_vk(const size_t, - const size_t, - const size_t); +template std::shared_ptr create_mock_honk_vk( + const size_t, const size_t); +template std::shared_ptr create_mock_honk_vk( + const size_t, const size_t); +template std::shared_ptr create_mock_honk_vk< + MegaFlavor, + stdlib::recursion::honk::HidingKernelIO>(const size_t, const size_t); template std::shared_ptr> create_mock_decider_vk(); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.hpp index b9f611a049d7..eef92550e588 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.hpp @@ -14,15 +14,14 @@ namespace acir_format { -template bb::HonkProof create_mock_oink_proof(const size_t num_public_inputs); +template bb::HonkProof create_mock_oink_proof(); template bb::HonkProof create_mock_decider_proof(); -template bb::HonkProof create_mock_honk_proof(const size_t num_public_inputs); -template bb::HonkProof create_mock_pg_proof(const size_t num_public_inputs); +template bb::HonkProof create_mock_honk_proof(); +template bb::HonkProof create_mock_pg_proof(); bb::Goblin::MergeProof create_mock_merge_proof(); -template +template std::shared_ptr create_mock_honk_vk(const size_t dyadic_size, - const size_t num_public_inputs, const size_t pub_inputs_offset); template std::shared_ptr> create_mock_decider_vk(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.test.cpp index 59fd8a58aa0f..b91f44252af9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/mock_verifier_inputs.test.cpp @@ -3,6 +3,7 @@ #include "acir_format_mocks.hpp" #include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/ultra_honk/decider_proving_key.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -31,15 +32,48 @@ TEST(MockVerifierInputsTest, MockMergeProofSize) } /** - * @brief Check that the size of a mock Oink proof matches expectation based on Flavor + * @brief Check that the size of a mock Oink proof matches expectation for MegaFlavor * */ -TYPED_TEST(MockVerifierInputsTest, MockOinkProofSize) +TEST(MockVerifierInputsTest, MockMegaOinkProofSize) { - using Flavor = TypeParam; + using Flavor = MegaFlavor; + using Builder = MegaCircuitBuilder; + + { + // AppIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::AppIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_oink_proof(); + EXPECT_EQ(honk_proof.size(), Flavor::OINK_PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); + } + + { + // KernelIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::KernelIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_oink_proof(); + EXPECT_EQ(honk_proof.size(), Flavor::OINK_PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); + } + + { + // HidingKernelIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::HidingKernelIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_oink_proof>(); + EXPECT_EQ(honk_proof.size(), Flavor::OINK_PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); + } +} + +/** + * @brief Check that the size of a mock Oink proof matches expectation for UltraFlavor + * + */ +TEST(MockVerifierInputsTest, MockUltraOinkProofSize) +{ + using Flavor = UltraFlavor; + using Builder = UltraCircuitBuilder; - const size_t NUM_PUBLIC_INPUTS = PAIRING_POINTS_SIZE; - HonkProof honk_proof = create_mock_oink_proof(NUM_PUBLIC_INPUTS); + // DefaultIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::DefaultIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_oink_proof>(); EXPECT_EQ(honk_proof.size(), Flavor::OINK_PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); } @@ -56,14 +90,47 @@ TYPED_TEST(MockVerifierInputsTest, MockDeciderProofSize) } /** - * @brief Check that the size of a mock Honk proof matches expectation based on Flavor + * @brief Check that the size of a mock Honk proof matches expectation based for MegaFlavor * */ -TYPED_TEST(MockVerifierInputsTest, MockHonkProofSize) +TEST(MockVerifierInputsTest, MockMegaHonkProofSize) { - using Flavor = TypeParam; + using Flavor = MegaFlavor; + using Builder = MegaCircuitBuilder; + + { + // AppIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::AppIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_honk_proof(); + EXPECT_EQ(honk_proof.size(), Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); + } + + { + // KernelIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::KernelIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_honk_proof(); + EXPECT_EQ(honk_proof.size(), Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); + } + + { + // HidingKernelIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::HidingKernelIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_honk_proof>(); + EXPECT_EQ(honk_proof.size(), Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); + } +} + +/** + * @brief Check that the size of a mock Honk proof matches expectation for UltraFlavor + * + */ +TEST(MockVerifierInputsTest, MockHonkProofSize) +{ + using Flavor = UltraFlavor; + using Builder = UltraCircuitBuilder; - const size_t NUM_PUBLIC_INPUTS = PAIRING_POINTS_SIZE; - HonkProof honk_proof = create_mock_honk_proof(NUM_PUBLIC_INPUTS); + // DefaultIO + const size_t NUM_PUBLIC_INPUTS = stdlib::recursion::honk::DefaultIO::PUBLIC_INPUTS_SIZE; + HonkProof honk_proof = create_mock_honk_proof>(); EXPECT_EQ(honk_proof.size(), Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS + NUM_PUBLIC_INPUTS); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index eebeff8cd9d7..071d24fd4a6d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -1132,12 +1132,11 @@ library RelationsLib { // Putting it all together... evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = - ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 + evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_ARITH)); // deg 3 or 9 + ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 /** * RAM Timestamp Consistency Check diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index e6f633b8e1fc..68883159fd71 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1194,12 +1194,11 @@ library RelationsLib { // Putting it all together... evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = - ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 + evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_ARITH)); // deg 3 or 9 + ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 /** * RAM Timestamp Consistency Check diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp index 45fdf9a46672..cdd28a5d90db 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp @@ -16,6 +16,8 @@ // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) namespace bb { +// TODO(https://github.com/AztecProtocol/barretenberg/issues/1478): Can we define this constant as part of the +// parameters and make it avaiable via the interface of field? // A point in Fq is represented with 4 public inputs static constexpr size_t FQ_PUBLIC_INPUT_SIZE = 4; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp index c42ad1bffa23..01b3d713ec9d 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.cpp @@ -74,10 +74,9 @@ GoblinProof Goblin::prove() return goblin_proof; } -Goblin::PairingPoints Goblin::recursively_verify_merge( +std::pair Goblin::recursively_verify_merge( MegaBuilder& builder, - const RecursiveSubtableCommitments& subtable_commitments, - std::array& merged_table_commitment, + const RecursiveMergeCommitments& merge_commitments, const std::shared_ptr& transcript) { ASSERT(!merge_verification_queue.empty()); @@ -86,21 +85,20 @@ Goblin::PairingPoints Goblin::recursively_verify_merge( const stdlib::Proof stdlib_merge_proof(builder, merge_proof); MergeRecursiveVerifier merge_verifier{ &builder, MergeSettings::PREPEND, transcript }; - PairingPoints pairing_points = - merge_verifier.verify_proof(stdlib_merge_proof, subtable_commitments, merged_table_commitment); + auto [pairing_points, merged_table_commitments] = + merge_verifier.verify_proof(stdlib_merge_proof, merge_commitments); merge_verification_queue.pop_front(); // remove the processed proof from the queue - return pairing_points; + return { pairing_points, merged_table_commitments }; } bool Goblin::verify(const GoblinProof& proof, - const SubtableCommitments& subtable_commitments, - std::array& merged_table_commitment, + const MergeCommitments& merge_commitments, const std::shared_ptr& transcript) { MergeVerifier merge_verifier(MergeSettings::PREPEND, transcript); - bool merge_verified = merge_verifier.verify_proof(proof.merge_proof, subtable_commitments, merged_table_commitment); + auto [merge_verified, merged_table_commitments] = merge_verifier.verify_proof(proof.merge_proof, merge_commitments); ECCVMVerifier eccvm_verifier(transcript); bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); @@ -116,7 +114,7 @@ bool Goblin::verify(const GoblinProof& proof, // Verify the consistency between the commitments to polynomials representing the op queue received by translator // and final merge verifier bool op_queue_consistency_verified = - translator_verifier.verify_consistency_with_final_merge(merged_table_commitment); + translator_verifier.verify_consistency_with_final_merge(merged_table_commitments); vinfo("merge verified?: ", merge_verified); vinfo("eccvm verified?: ", eccvm_verified); diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index e9af2a069b00..46cbf6fdf18f 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -38,8 +38,10 @@ class Goblin { using TranslatorVerificationKey = TranslatorFlavor::VerificationKey; using MergeRecursiveVerifier = stdlib::recursion::goblin::MergeRecursiveVerifier_; using PairingPoints = MergeRecursiveVerifier::PairingPoints; - using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments; - using RecursiveSubtableCommitments = MergeRecursiveVerifier::SubtableWitnessCommitments; + using TableCommitments = MergeVerifier::TableCommitments; + using RecursiveTableCommitments = MergeRecursiveVerifier::TableCommitments; + using MergeCommitments = MergeVerifier::InputCommitments; + using RecursiveMergeCommitments = MergeRecursiveVerifier::InputCommitments; using RecursiveCommitment = MergeRecursiveVerifier::Commitment; using RecursiveTranscript = bb::BaseTranscript>; @@ -94,33 +96,28 @@ class Goblin { * @details Proofs are verified in a FIFO manner * * @param builder The circuit in which the recursive verification will be performed. - * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the - * transcript by the PG verifier with which the Merge verifier shares a transcript - * @param merged_table_commitment The commitment to the merged table as read from the proof + * @param inputs_commitments The commitment used by the Merge verifier * @param transcript The transcript to be passed to the MergeRecursiveVerifier. - * @return PairingPoints + * @return Pair of PairingPoints and commitments to the merged tables as read from the proof by the Merge verifier */ - PairingPoints recursively_verify_merge( + std::pair recursively_verify_merge( MegaBuilder& builder, - const RecursiveSubtableCommitments& subtable_commitments, - std::array& merged_table_commitment, + const RecursiveMergeCommitments& merge_commitments, const std::shared_ptr& transcript); /** * @brief Verify a full Goblin proof (ECCVM, Translator, merge) * * @param proof - * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the - * transcript by the PG verifier with which the Merge verifier shares a transcript + * @param inputs_commitments The commitments used by the Merge verifier * @param merged_table_commitment The commitment to the merged table as read from the proof * @param transcript * - * @return true - * @return false + * @return Pair of verification result and commitments to the merged tables as read from the proof by the Merge + * verifier */ static bool verify(const GoblinProof& proof, - const SubtableCommitments& subtable_commitments, - std::array& merged_table_commitment, + const MergeCommitments& merge_commitments, const std::shared_ptr& transcript); }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index db7ca5372f0f..d24fd0ca2924 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -19,6 +19,7 @@ #include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/stdlib_circuit_builders/mock_circuits.hpp" namespace bb { @@ -69,7 +70,6 @@ class GoblinMockCircuits { using RecursiveVerifierAccumulator = std::shared_ptr; using VerificationKey = Flavor::VerificationKey; - using PairingPoints = stdlib::recursion::PairingPoints; static constexpr size_t NUM_WIRES = Flavor::NUM_WIRES; struct KernelInput { @@ -104,7 +104,7 @@ class GoblinMockCircuits { // MegaHonk circuits (where we don't explicitly need to add goblin ops), in IVC merge proving happens prior to // folding where the absense of goblin ecc ops will result in zero commitments. MockCircuits::construct_goblin_ecc_op_circuit(builder); - PairingPoints::add_default_to_public_inputs(builder); + bb::stdlib::recursion::honk::AppIO::add_default(builder); } /** @@ -142,7 +142,9 @@ class GoblinMockCircuits { add_some_ecc_op_gates(builder); MockCircuits::construct_arithmetic_circuit(builder); - PairingPoints::add_default_to_public_inputs(builder); + // Flavor = bb::MegaFlavor, so the public inputs should be that of the HidingKernelIO (UltraVerifier + // expects the public inputs to be that of the HidingKernel) + bb::stdlib::recursion::honk::HidingKernelIO::add_default(builder); } /** diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp index 01db50a6faca..72036b8a5d0f 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -42,7 +42,7 @@ TEST_F(MegaMockCircuitsPinning, SmallTestStructuredCircuitSize) { Goblin goblin; MegaCircuitBuilder app_circuit{ goblin.op_queue }; - GoblinMockCircuits::PairingPoints::add_default_to_public_inputs(app_circuit); + stdlib::recursion::honk::DefaultIO::add_default(app_circuit); TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; auto proving_key = std::make_shared(app_circuit, trace_settings); EXPECT_EQ(proving_key->log_dyadic_size(), 18); @@ -52,7 +52,7 @@ TEST_F(MegaMockCircuitsPinning, AztecStructuredCircuitSize) { Goblin goblin; MegaCircuitBuilder app_circuit{ goblin.op_queue }; - GoblinMockCircuits::PairingPoints::add_default_to_public_inputs(app_circuit); + stdlib::recursion::honk::DefaultIO::add_default(app_circuit); TraceSettings trace_settings{ AZTEC_TRACE_STRUCTURE }; auto proving_key = std::make_shared(app_circuit, trace_settings); EXPECT_EQ(proving_key->log_dyadic_size(), 18); diff --git a/barretenberg/cpp/src/barretenberg/honk/execution_trace/mega_execution_trace.hpp b/barretenberg/cpp/src/barretenberg/honk/execution_trace/mega_execution_trace.hpp index 1b7ff4cf2631..22eb29106845 100644 --- a/barretenberg/cpp/src/barretenberg/honk/execution_trace/mega_execution_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/execution_trace/mega_execution_trace.hpp @@ -255,7 +255,7 @@ class MegaExecutionTraceBlocks : public MegaTraceBlockData { static constexpr TraceStructure TINY_TEST_STRUCTURE{ .ecc_op = 18, .busread = 3, .lookup = 2, - .pub_inputs = 20, + .pub_inputs = 52, // Accomodate 4 + HidingKernelIO = 4 + 48 .arithmetic = 1 << 14, .delta_range = 5, .elliptic = 2, diff --git a/barretenberg/cpp/src/barretenberg/relations/memory_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/memory_relation.hpp index 789692b8291d..7fb6074a6522 100644 --- a/barretenberg/cpp/src/barretenberg/relations/memory_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/memory_relation.hpp @@ -47,15 +47,6 @@ template class MemoryRelationImpl { * * Multiple selectors are used to 'switch' memory gates on/off according to the following pattern: * - * | gate type | q_mem | q_1 | q_2 | q_4 | q_m | q_c | q_arith | - * | ---------------------------- | ----- | --- | --- | --- | --- | --- | ------ | - * | RAM/ROM access gate | 1 | 1 | 0 | 0 | 1 | --- | 0 | - * | RAM timestamp check | 1 | 1 | 0 | 1 | 0 | --- | 0 | - * | ROM consistency check | 1 | 1 | 1 | 0 | 0 | --- | 0 | - * | RAM consistency check | 1 | 0 | 0 | 0 | 0 | 0 | 1 | - * - * NOTE: Proposed updated selector pattern (i.e. replace q_arith with q_3): - * * | gate type | q_mem | q_1 | q_2 | q_3 | q_4 | q_m | q_c | * | ---------------------------- | ----- | --- | --- | --- | --- | --- | --- | * | RAM/ROM access gate | 1 | 1 | 0 | 0 | 0 | 1 | --- | @@ -105,10 +96,10 @@ template class MemoryRelationImpl { auto q_1_m = CoefficientAccumulator(in.q_l); auto q_2_m = CoefficientAccumulator(in.q_r); + auto q_3_m = CoefficientAccumulator(in.q_o); auto q_4_m = CoefficientAccumulator(in.q_4); auto q_m_m = CoefficientAccumulator(in.q_m); auto q_c_m = CoefficientAccumulator(in.q_c); - auto q_arith_m = CoefficientAccumulator(in.q_arith); auto q_memory_m = CoefficientAccumulator(in.q_memory); @@ -245,15 +236,15 @@ template class MemoryRelationImpl { // deg 2 or 4 auto next_gate_access_type_is_boolean = neg_next_gate_access_type.sqr() + neg_next_gate_access_type; - auto q_arith_by_memory_and_scaling = Accumulator(q_arith_m * q_memory_by_scaling_m); + auto q_3_by_memory_and_scaling = Accumulator(q_3_m * q_memory_by_scaling_m); // Putting it all together... std::get<3>(accumulators) += adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * - q_arith_by_memory_and_scaling; // deg 5 or 6 - std::get<4>(accumulators) += index_is_monotonically_increasing * q_arith_by_memory_and_scaling; // deg 4 - std::get<5>(accumulators) += next_gate_access_type_is_boolean * q_arith_by_memory_and_scaling; // deg 4 or 6 + q_3_by_memory_and_scaling; // deg 5 or 6 + std::get<4>(accumulators) += index_is_monotonically_increasing * q_3_by_memory_and_scaling; // deg 4 + std::get<5>(accumulators) += next_gate_access_type_is_boolean * q_3_by_memory_and_scaling; // deg 4 or 6 - auto RAM_consistency_check_identity = access_check * q_arith_by_memory_and_scaling; // deg 3 or 5 + auto RAM_consistency_check_identity = access_check * q_3_by_memory_and_scaling; // deg 3 or 5 /** * RAM Timestamp Consistency Check diff --git a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp index c6b35eac2d4e..c0e325b96fd1 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp @@ -394,10 +394,10 @@ TEST_F(UltraRelationConsistency, MemoryRelation) const auto& q_1 = input_elements.q_l; const auto& q_2 = input_elements.q_r; + const auto& q_3 = input_elements.q_o; const auto& q_4 = input_elements.q_4; const auto& q_m = input_elements.q_m; const auto& q_c = input_elements.q_c; - const auto& q_arith = input_elements.q_arith; const auto& q_memory = input_elements.q_memory; const auto parameters = RelationParameters::get_random(); @@ -455,10 +455,10 @@ TEST_F(UltraRelationConsistency, MemoryRelation) // Putting it all together... expected_values[3] = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_arith); - expected_values[4] = index_is_monotonically_increasing * (q_arith); - expected_values[5] = next_gate_access_type_is_boolean * (q_arith); - auto RAM_consistency_check_identity = access_check * (q_arith); + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (q_3); + expected_values[4] = index_is_monotonically_increasing * (q_3); + expected_values[5] = next_gate_access_type_is_boolean * (q_3); + auto RAM_consistency_check_identity = access_check * (q_3); /** * RAM/ROM access check gate diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/ultra_circuit.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/ultra_circuit.cpp index 627080030ed5..28f76200fb04 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/ultra_circuit.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/ultra_circuit.cpp @@ -490,8 +490,6 @@ size_t UltraCircuit::handle_memory_relation(size_t cursor) bb::fr q_2 = this->selectors[BlockType::MEMORY][cursor][2]; bb::fr q_3 = this->selectors[BlockType::MEMORY][cursor][3]; bb::fr q_4 = this->selectors[BlockType::MEMORY][cursor][4]; - // bb::fr q_c = this->selectors[BlockType::MEMORY][cursor][5]; - bb::fr q_arith = this->selectors[BlockType::MEMORY][cursor][6]; // reassure that only one entry size_t entry_flag = 0; @@ -512,7 +510,7 @@ size_t UltraCircuit::handle_memory_relation(size_t cursor) // ROM consistency check } - if (q_arith) { + if (q_3) { entry_flag += 1; // RAM consistency check } @@ -560,8 +558,6 @@ size_t UltraCircuit::handle_nnf_relation(size_t cursor) bb::fr q_2 = this->selectors[BlockType::NNF][cursor][2]; bb::fr q_3 = this->selectors[BlockType::NNF][cursor][3]; bb::fr q_4 = this->selectors[BlockType::NNF][cursor][4]; - // bb::fr q_c = this->selectors[BlockType::NNF][cursor][5]; - bb::fr q_arith = this->selectors[BlockType::NNF][cursor][6]; bb::fr LIMB_SIZE(uint256_t(1) << 68); bb::fr SUBLIMB_SHIFT(uint256_t(1) << 14); diff --git a/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp b/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp index 5b75269402f4..c5a8dd4a8394 100644 --- a/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp +++ b/barretenberg/cpp/src/barretenberg/special_public_inputs/special_public_inputs.hpp @@ -41,6 +41,50 @@ class DefaultIO { } }; +/** + * @brief Manages the data that is propagated on the public inputs of of a hiding kernel circuit + */ +class HidingKernelIO { + public: + using FF = curve::BN254::ScalarField; + using G1 = curve::BN254::AffineElement; + + // Number of columns that jointly constitute the op_queue, should be the same as the number of wires in the + // MegaCircuitBuilder + static constexpr size_t NUM_WIRES = 4; + + // Number of bb::fr field elements used to represent a goblin element in the public inputs + // The element is of goblin type because the HidingKernel is always employed with a MegaBuilder + static constexpr size_t G1_PUBLIC_INPUTS_SIZE = FQ_PUBLIC_INPUT_SIZE * 2; + static constexpr size_t PUBLIC_INPUTS_SIZE = NUM_WIRES * G1_PUBLIC_INPUTS_SIZE + PAIRING_POINTS_SIZE; + + PairingPoints pairing_inputs; + std::array ecc_op_tables; + + /** + * @brief Reconstructs the IO components from a public inputs array. + * + * @param public_inputs Public inputs array containing the serialized kernel public inputs. + */ + void reconstruct_from_public(const std::vector& public_inputs) + { + // Assumes that the hiding-kernel-io public inputs are at the end of the public_inputs vector + uint32_t index = static_cast(public_inputs.size() - PUBLIC_INPUTS_SIZE); + + const std::span pairing_inputs_limbs(public_inputs.data() + index, + PAIRING_POINTS_SIZE); + index += PAIRING_POINTS_SIZE; + pairing_inputs = PairingPoints::reconstruct_from_public(pairing_inputs_limbs); + + for (auto& commitment : ecc_op_tables) { + const std::span ecc_op_table_limbs(public_inputs.data() + index, + G1_PUBLIC_INPUTS_SIZE); + commitment = G1::reconstruct_from_public(ecc_op_table_limbs); + index += G1_PUBLIC_INPUTS_SIZE; + } + } +}; + /** * @brief The data that is propagated on the public inputs of a rollup circuit */ diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp index 74346ea090d8..bdda5fbecb33 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.cpp @@ -16,7 +16,7 @@ namespace bb::stdlib::recursion::honk { */ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const StdlibProof& proof) { - using MergeCommitments = ClientIVCRecursiveVerifier::GoblinVerifier::MergeVerifier::WitnessCommitments; + using MergeCommitments = GoblinVerifier::MergeVerifier::InputCommitments; std::shared_ptr civc_rec_verifier_transcript(std::make_shared()); // Construct stdlib Mega verification key auto stdlib_mega_vk_and_hash = std::make_shared(*builder, ivc_verification_key.mega); @@ -27,11 +27,14 @@ ClientIVCRecursiveVerifier::Output ClientIVCRecursiveVerifier::verify(const Stdl // Perform Goblin recursive verification GoblinVerificationKey goblin_verification_key{}; - MergeCommitments merge_commitments; - merge_commitments.set_t_commitments(verifier.key->witness_commitments.get_ecc_op_wires()); + MergeCommitments merge_commitments{ + .t_commitments = verifier.key->witness_commitments.get_ecc_op_wires() + .get_copy(), // Commitments to subtables added by the hiding kernel + .T_prev_commitments = std::move(mega_output.ecc_op_tables) // Commitments to the state of the ecc op_queue as + // computed insided the hiding kernel + }; GoblinVerifier goblin_verifier{ builder.get(), goblin_verification_key, civc_rec_verifier_transcript }; - GoblinRecursiveVerifierOutput output = - goblin_verifier.verify(proof.goblin_proof, merge_commitments, merge_commitments.T_commitments); + GoblinRecursiveVerifierOutput output = goblin_verifier.verify(proof.goblin_proof, merge_commitments); output.points_accumulator.aggregate(mega_output.points_accumulator); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers return { output }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp index bff875d06ccd..ebbf7b48ce34 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/client_ivc_verifier/client_ivc_recursive_verifier.test.cpp @@ -108,9 +108,15 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) StdlibProof stdlib_proof(*tube_builder, proof); CIVCRecVerifierOutput client_ivc_rec_verifier_output = verifier.verify(stdlib_proof); - client_ivc_rec_verifier_output.points_accumulator.set_public(); - // The tube only calls an IPA recursive verifier once, so we can just add this IPA claim and proof - client_ivc_rec_verifier_output.opening_claim.set_public(); + { + // IO + RollupIO inputs; + inputs.pairing_inputs = client_ivc_rec_verifier_output.points_accumulator; + inputs.ipa_claim = client_ivc_rec_verifier_output.opening_claim; + inputs.set_public(); + } + + // The tube only calls an IPA recursive verifier once, so we can just add this IPA proof tube_builder->ipa_proof = client_ivc_rec_verifier_output.ipa_proof.get_value(); info("ClientIVC Recursive Verifier: num prefinalized gates = ", tube_builder->num_gates); @@ -139,8 +145,15 @@ TEST_F(ClientIVCRecursionTests, ClientTubeBase) UltraRecursiveVerifier base_verifier{ &base_builder, stdlib_tube_vk_and_hash }; UltraRecursiveVerifierOutput output = base_verifier.verify_proof(base_tube_proof); info("Tube UH Recursive Verifier: num prefinalized gates = ", base_builder.num_gates); - output.points_accumulator.set_public(); - output.ipa_claim.set_public(); + + { + // IO + RollupIO inputs; + inputs.pairing_inputs = output.points_accumulator; + inputs.ipa_claim = output.ipa_claim; + inputs.set_public(); + } + base_builder.ipa_proof = tube_prover.proving_key->ipa_proof; EXPECT_EQ(base_builder.failed(), false) << base_builder.err(); EXPECT_TRUE(CircuitChecker::check(base_builder)); @@ -169,9 +182,13 @@ TEST_F(ClientIVCRecursionTests, TubeVKIndependentOfInputCircuits) StdlibProof stdlib_proof(*tube_builder, proof); auto client_ivc_rec_verifier_output = verifier.verify(stdlib_proof); - client_ivc_rec_verifier_output.points_accumulator.set_public(); - // The tube only calls an IPA recursive verifier once, so we can just add this IPA claim and proof - client_ivc_rec_verifier_output.opening_claim.set_public(); + // IO + RollupIO inputs; + inputs.pairing_inputs = client_ivc_rec_verifier_output.points_accumulator; + inputs.ipa_claim = client_ivc_rec_verifier_output.opening_claim; + inputs.set_public(); + + // The tube only calls an IPA recursive verifier once, so we can just add this IPA proof tube_builder->ipa_proof = client_ivc_rec_verifier_output.ipa_proof.get_value(); info("ClientIVC Recursive Verifier: num prefinalized gates = ", tube_builder->num_gates); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp index 25e18f670e8e..d21dc8cb43d6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp @@ -15,13 +15,11 @@ namespace bb::stdlib::recursion::honk { * @param t_commitments The commitments to the subtable for the merge being verified * */ -GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( - const GoblinProof& proof, - const SubtableCommitments& subtable_commitments, - std::array& merged_table_commitment) +GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof& proof, + const MergeCommitments& merge_commitments) { StdlibProof stdlib_proof(*builder, proof); - return verify(stdlib_proof, subtable_commitments, merged_table_commitment); + return verify(stdlib_proof, merge_commitments); } /** @@ -31,15 +29,13 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( * @param t_commitments The commitments to the subtable for the merge being verified * */ -GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( - const StdlibProof& proof, - const SubtableCommitments& subtable_commitments, - std::array& merged_table_commitment) +GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const StdlibProof& proof, + const MergeCommitments& merge_commitments) { // Verify the final merge step MergeVerifier merge_verifier{ builder, MergeSettings::PREPEND, transcript }; - PairingPoints merge_pairing_points = - merge_verifier.verify_proof(proof.merge_proof, subtable_commitments, merged_table_commitment); + auto [merge_pairing_points, merged_table_commitments] = + merge_verifier.verify_proof(proof.merge_proof, merge_commitments); // Run the ECCVM recursive verifier ECCVMVerifier eccvm_verifier{ builder, verification_keys.eccvm_verification_key, transcript }; @@ -58,7 +54,7 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify( // Verify the consistency between the commitments to polynomials representing the op queue received by translator // and final merge verifier - translator_verifier.verify_consistency_with_final_merge(merged_table_commitment); + translator_verifier.verify_consistency_with_final_merge(merged_table_commitments); return { translator_pairing_points, opening_claim, ipa_proof }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp index 7513c7b32e6f..e2d567681c73 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp @@ -15,7 +15,6 @@ namespace bb::stdlib::recursion::honk { struct GoblinRecursiveVerifierOutput { using Builder = UltraCircuitBuilder; using Curve = grumpkin; - using Transcript = bb::BaseTranscript>; using PairingAccumulator = PairingPoints; PairingAccumulator points_accumulator; OpeningClaim opening_claim; @@ -39,8 +38,7 @@ class GoblinRecursiveVerifier { using VerificationKey = Goblin::VerificationKey; // Merge commitments - using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments; - using Commitment = MergeVerifier::Commitment; + using MergeCommitments = MergeVerifier::InputCommitments; struct StdlibProof { using StdlibHonkProof = bb::stdlib::Proof; @@ -66,13 +64,9 @@ class GoblinRecursiveVerifier { , transcript(transcript){}; [[nodiscard("IPA claim and Pairing points should be accumulated")]] GoblinRecursiveVerifierOutput verify( - const GoblinProof&, - const SubtableCommitments& subtable_commitments, - std::array& merged_table_commitment); + const GoblinProof&, const MergeCommitments& merge_commitments); [[nodiscard("IPA claim and Pairing points should be accumulated")]] GoblinRecursiveVerifierOutput verify( - const StdlibProof&, - const SubtableCommitments& subtable_commitments, - std::array& merged_table_commitment); + const StdlibProof&, const MergeCommitments& merge_commitments); private: Builder* builder; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index 1c179c70746e..2fcca300bdb5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -23,8 +23,8 @@ class GoblinRecursiveVerifierTests : public testing::Test { using Commitment = MergeVerifier::Commitment; using RecursiveCommitment = GoblinRecursiveVerifier::MergeVerifier::Commitment; - using MergeCommitments = MergeVerifier::WitnessCommitments; - using RecursiveMergeCommitments = GoblinRecursiveVerifier::MergeVerifier::WitnessCommitments; + using MergeCommitments = MergeVerifier::InputCommitments; + using RecursiveMergeCommitments = GoblinRecursiveVerifier::MergeVerifier::InputCommitments; static void SetUpTestSuite() { bb::srs::init_file_crs_factory(bb::srs::bb_crs_path()); } @@ -63,9 +63,11 @@ class GoblinRecursiveVerifierTests : public testing::Test { // Subtable values and commitments - needed for (Recursive)MergeVerifier MergeCommitments merge_commitments; auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns(); + auto T_prev = goblin_final.op_queue->construct_previous_ultra_ops_table_columns(); CommitmentKey pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows()); for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]); + merge_commitments.T_prev_commitments[idx] = pcs_commitment_key.commit(T_prev[idx]); } RecursiveMergeCommitments recursive_merge_commitments; @@ -73,6 +75,8 @@ class GoblinRecursiveVerifierTests : public testing::Test { for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { recursive_merge_commitments.t_commitments[idx] = RecursiveCommitment::from_witness(outer_builder, merge_commitments.t_commitments[idx]); + recursive_merge_commitments.T_prev_commitments[idx] = + RecursiveCommitment::from_witness(outer_builder, merge_commitments.T_prev_commitments[idx]); } } @@ -94,7 +98,7 @@ TEST_F(GoblinRecursiveVerifierTests, NativeVerification) std::shared_ptr verifier_transcript = std::make_shared(); - EXPECT_TRUE(Goblin::verify(proof, merge_commitments, merge_commitments.T_commitments, verifier_transcript)); + EXPECT_TRUE(Goblin::verify(proof, merge_commitments, verifier_transcript)); } /** @@ -109,8 +113,7 @@ TEST_F(GoblinRecursiveVerifierTests, Basic) create_goblin_prover_output(&builder); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = - verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_commitments); output.points_accumulator.set_public(); info("Recursive Verifier: num gates = ", builder.num_gates); @@ -144,8 +147,7 @@ TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) create_goblin_prover_output(&builder, inner_size); GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput output = - verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_commitments); output.points_accumulator.set_public(); info("Recursive Verifier: num gates = ", builder.num_gates); @@ -186,8 +188,7 @@ TEST_F(GoblinRecursiveVerifierTests, ECCVMFailure) } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - GoblinRecursiveVerifierOutput goblin_rec_verifier_output = - verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + GoblinRecursiveVerifierOutput goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_commitments); srs::init_file_crs_factory(bb::srs::bb_crs_path()); auto crs_factory = srs::get_grumpkin_crs_factory(); @@ -226,11 +227,12 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { recursive_merge_commitments.t_commitments[idx] = RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]); + recursive_merge_commitments.T_prev_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_commitments.T_prev_commitments[idx]); } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = - verifier.verify(tampered_proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(tampered_proof, recursive_merge_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } // Tamper with the Translator proof non-preamble values @@ -252,11 +254,12 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorFailure) for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) { recursive_merge_commitments.t_commitments[idx] = RecursiveCommitment::from_witness(&builder, merge_commitments.t_commitments[idx]); + recursive_merge_commitments.T_prev_commitments[idx] = + RecursiveCommitment::from_witness(&builder, merge_commitments.T_prev_commitments[idx]); } GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = - verifier.verify(tampered_proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(tampered_proof, recursive_merge_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } } @@ -279,8 +282,7 @@ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) proof.eccvm_proof.pre_ipa_proof[op_limb_index] += 1; GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = - verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } @@ -305,7 +307,7 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) std::shared_ptr verifier_transcript = std::make_shared(); // Check natively that the proof is correct. - EXPECT_TRUE(Goblin::verify(proof, merge_commitments, merge_commitments.T_commitments, verifier_transcript)); + EXPECT_TRUE(Goblin::verify(proof, merge_commitments, verifier_transcript)); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1298): // Better recursion testing - create more flexible proof tampering tests. @@ -332,8 +334,7 @@ TEST_F(GoblinRecursiveVerifierTests, TranslatorMergeConsistencyFailure) // Construct and check the Goblin Recursive Verifier circuit GoblinRecursiveVerifier verifier{ &builder, verifier_input }; - [[maybe_unused]] auto goblin_rec_verifier_output = - verifier.verify(proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + [[maybe_unused]] auto goblin_rec_verifier_output = verifier.verify(proof, recursive_merge_commitments); EXPECT_FALSE(CircuitChecker::check(builder)); } 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 bb685a15dd31..a0617e73b7c3 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 @@ -90,10 +90,10 @@ UltraRecursiveVerifier_::Output UltraRecursiveVerifier_::verify_ output.points_accumulator = inputs.pairing_inputs; output.ipa_claim = inputs.ipa_claim; } else if constexpr (IsMegaFlavor) { - DefaultIO inputs; // will be HidingKernelIO + HidingKernelIO inputs; inputs.reconstruct_from_public(public_inputs); output.points_accumulator = inputs.pairing_inputs; - // output.ecc_op_tables = inputs.ecc_op_tables; + output.ecc_op_tables = inputs.ecc_op_tables; } else { DefaultIO inputs; // pairing points inputs.reconstruct_from_public(public_inputs); 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 7e23f793c4c9..0468e552938c 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 @@ -3,6 +3,7 @@ #include "barretenberg/common/test.hpp" #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/ultra_rollup_recursive_flavor.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/stdlib/test_utils/tamper_proof.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -84,14 +85,14 @@ template class RecursiveVerifierTest : public testing builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); } - PairingPoints::add_default_to_public_inputs(builder); - - if constexpr (HasIPAAccumulator) { - auto [stdlib_opening_claim, ipa_proof] = - IPA>::create_fake_ipa_claim_and_proof(builder); - stdlib_opening_claim.set_public(); - builder.ipa_proof = ipa_proof; + if constexpr (IsMegaBuilder) { + HidingKernelIO::add_default(builder); + } else if constexpr (HasIPAAccumulator) { + RollupIO::add_default(builder); + } else { + DefaultIO::add_default(builder); } + return builder; } @@ -211,10 +212,26 @@ template class RecursiveVerifierTest : public testing verifier.transcript->enable_manifest(); VerifierOutput output = verifier.verify_proof(inner_proof); - output.points_accumulator.set_public(); - if constexpr (HasIPAAccumulator) { - output.ipa_claim.set_public(); + + // IO + if constexpr (IsMegaFlavor) { + HidingKernelIO inputs; + inputs.pairing_inputs = output.points_accumulator; + inputs.ecc_op_tables = HidingKernelIO::default_ecc_op_tables(outer_circuit); + inputs.set_public(); + } else if constexpr (HasIPAAccumulator) { + // HasIPAAccumulator requires RollUpIO + RollupIO inputs; + inputs.pairing_inputs = output.points_accumulator; + inputs.ipa_claim = output.ipa_claim; + inputs.set_public(); + + // Store ipa_proof outer_circuit.ipa_proof = output.ipa_proof.get_value(); + } else { + DefaultIO inputs; + inputs.pairing_inputs = output.points_accumulator; + inputs.set_public(); } // Check for a failure flag in the recursive verifier circuit @@ -261,23 +278,21 @@ template class RecursiveVerifierTest : public testing info("Recursive Verifier: num gates = ", outer_circuit.get_num_finalized_gates()); OuterProver prover(proving_key, verification_key); auto proof = prover.construct_proof(); - if constexpr (IsUltraHonk) { - if constexpr (HasIPAAccumulator) { - VerifierCommitmentKey ipa_verification_key = (1 << CONST_ECCVM_LOG_N); - OuterVerifier verifier(verification_key, ipa_verification_key); - ASSERT_TRUE(verifier.verify_proof(proof, proving_key->ipa_proof)); - } else { - OuterVerifier verifier(verification_key); - ASSERT_TRUE(verifier.verify_proof(proof)); - } - } else { + if constexpr (IsMegaFlavor) { OuterVerifier verifier(verification_key); ASSERT_TRUE(std::get<0>(verifier.verify_proof(proof))); + } else if constexpr (HasIPAAccumulator) { + VerifierCommitmentKey ipa_verification_key = (1 << CONST_ECCVM_LOG_N); + OuterVerifier verifier(verification_key, ipa_verification_key); + ASSERT_TRUE(verifier.verify_proof(proof, proving_key->ipa_proof)); + } else { + OuterVerifier verifier(verification_key); + ASSERT_TRUE(verifier.verify_proof(proof)); } } // Check the size of the recursive verifier if constexpr (std::same_as>) { - uint32_t NUM_GATES_EXPECTED = 873673; + uint32_t NUM_GATES_EXPECTED = 874803; ASSERT_EQ(static_cast(outer_circuit.get_num_finalized_gates()), NUM_GATES_EXPECTED) << "MegaZKHonk Recursive verifier changed in Ultra gate count! Update this value if you " "are sure this is expected."; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp index e96bcc526bc5..50f3720b5449 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.cpp @@ -60,16 +60,15 @@ MergeRecursiveVerifier_::MergeRecursiveVerifier_(CircuitBuilder* * * @tparam CircuitBuilder * @param proof - * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the transcript - * by the PG verifier with which the Merge verifier shares a transcript - * @param merged_table_commitment The commitment to the merged table as read from the proof - * @return PairingPoints Inputs to final pairing + * @param inputs_commitments The commitments used by the Merge verifier + * @return std::pair Pair of the pairing inputs for final verification and the + * commitments to the merged tables as read from the proof */ template -MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_::verify_proof( - const stdlib::Proof& proof, - const SubtableWitnessCommitments& subtable_commitments, - std::array& merged_table_commitment) +std::pair::PairingPoints, + typename MergeRecursiveVerifier_::TableCommitments> +MergeRecursiveVerifier_::verify_proof(const stdlib::Proof& proof, + const InputCommitments& input_commitments) { using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; @@ -82,12 +81,10 @@ MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_ table_commitments; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove receiving commitment to T_prev - auto T_prev_commitment = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx)); - auto left_table = - settings == MergeSettings::PREPEND ? subtable_commitments.t_commitments[idx] : T_prev_commitment; - auto right_table = - settings == MergeSettings::PREPEND ? T_prev_commitment : subtable_commitments.t_commitments[idx]; + auto left_table = settings == MergeSettings::PREPEND ? input_commitments.t_commitments[idx] + : input_commitments.T_prev_commitments[idx]; + auto right_table = settings == MergeSettings::PREPEND ? input_commitments.T_prev_commitments[idx] + : input_commitments.t_commitments[idx]; table_commitments.emplace_back(left_table); table_commitments.emplace_back(right_table); @@ -98,8 +95,9 @@ MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_::PairingPoints MergeRecursiveVerifier_; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp index f40b02961552..2f951e01b9d1 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_recursive_verifier.hpp @@ -30,50 +30,25 @@ template class MergeRecursiveVerifier_ { // Number of columns that jointly constitute the op_queue, should be the same as the number of wires in the // MegaCircuitBuilder static constexpr size_t NUM_WIRES = MegaExecutionTraceBlocks::NUM_WIRES; + using TableCommitments = std::array; // Commitments to the subtables and the merged table /** - * @brief Commitments to the subtable t_j on which the Merge verifier operates - * + * Commitments used by the verifier to run the verification algorithm. They contain: + * - `t_commitments`: the subtable commitments data, containing the commitments to t_j read from the transcript by + * the PG verifier with which the Merge verifier shares a transcript + * - `T_prev_commitments`: the commitments to the full op_queue table after the previous iteration of merge */ - class SubtableWitnessCommitments { - public: - std::array t_commitments; - // std::array T_prev_commitments; - - SubtableWitnessCommitments() = default; - - /** - * @brief Set t_commitments from RefArray - * - * @param t_commitments_ref - */ - void set_t_commitments(const RefArray& t_commitments_ref) - { - for (size_t idx = 0; idx < NUM_WIRES; idx++) { - t_commitments[idx] = t_commitments_ref[idx]; - } - } - }; - - /** - * @brief Commitments used by the Merge verifier during the protocol - * - */ - class WitnessCommitments : public SubtableWitnessCommitments { - public: - std::array T_commitments; - - WitnessCommitments() = default; + struct InputCommitments { + TableCommitments t_commitments; + TableCommitments T_prev_commitments; }; explicit MergeRecursiveVerifier_(CircuitBuilder* builder, const MergeSettings settings = MergeSettings::PREPEND, const std::shared_ptr& transcript = std::make_shared()); - [[nodiscard("Pairing points should be accumulated")]] PairingPoints verify_proof( - const stdlib::Proof& proof, - const SubtableWitnessCommitments& subtable_commitments, - std::array& merged_table_commitment); + [[nodiscard("Pairing points should be accumulated")]] std::pair verify_proof( + const stdlib::Proof& proof, const InputCommitments& input_commitments); }; } // namespace bb::stdlib::recursion::goblin diff --git a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp index 9c4b2948e041..b82513b9df7e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/merge_verifier/merge_verifier.test.cpp @@ -22,8 +22,8 @@ template class RecursiveMergeVerifierTest : public test // Types for recursive verifier circuit using RecursiveMergeVerifier = MergeRecursiveVerifier_; - using RecursiveSubtableCommitments = MergeRecursiveVerifier_::SubtableWitnessCommitments; - using RecursiveMergeCommitments = MergeRecursiveVerifier_::WitnessCommitments; + using RecursiveTableCommitments = MergeRecursiveVerifier_::TableCommitments; + using RecursiveMergeCommitments = MergeRecursiveVerifier_::InputCommitments; // Define types relevant for inner circuit using InnerFlavor = MegaFlavor; @@ -35,8 +35,8 @@ template class RecursiveMergeVerifierTest : public test using FF = InnerFlavor::FF; using VerifierCommitmentKey = bb::VerifierCommitmentKey; using MergeProof = MergeProver::MergeProof; - using SubtableCommitments = MergeVerifier::SubtableWitnessCommitments; - using MergeCommitments = MergeVerifier::WitnessCommitments; + using TableCommitments = MergeVerifier::TableCommitments; + using MergeCommitments = MergeVerifier::InputCommitments; enum class TamperProofMode { None, Shift, MCommitment, LEval }; @@ -46,8 +46,8 @@ template class RecursiveMergeVerifierTest : public test static void tamper_with_proof(MergeProof& merge_proof, const TamperProofMode tampering_mode) { const size_t shift_idx = 0; // Index of shift_size in the merge proof - const size_t m_commitment_idx = 5; // Index of first commitment to merged table in merge proof - const size_t l_eval_idx = 50; // Index of first evaluation of l(1/kappa) in merge proof + const size_t m_commitment_idx = 1; // Index of first commitment to merged table in merge proof + const size_t l_eval_idx = 34; // Index of first evaluation of l(1/kappa) in merge proof switch (tampering_mode) { case TamperProofMode::Shift: @@ -91,19 +91,22 @@ template class RecursiveMergeVerifierTest : public test MergeCommitments merge_commitments; RecursiveMergeCommitments recursive_merge_commitments; auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); + auto T_prev = op_queue->construct_previous_ultra_ops_table_columns(); for (size_t idx = 0; idx < InnerFlavor::NUM_WIRES; idx++) { - auto cm = merge_prover.pcs_commitment_key.commit(t_current[idx]); - merge_commitments.t_commitments[idx] = cm; + merge_commitments.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); + merge_commitments.T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]); recursive_merge_commitments.t_commitments[idx] = - RecursiveMergeVerifier::Commitment::from_witness(&outer_circuit, cm); + RecursiveMergeVerifier::Commitment::from_witness(&outer_circuit, merge_commitments.t_commitments[idx]); + recursive_merge_commitments.T_prev_commitments[idx] = RecursiveMergeVerifier::Commitment::from_witness( + &outer_circuit, merge_commitments.T_prev_commitments[idx]); } // Create a recursive merge verification circuit for the merge proof RecursiveMergeVerifier verifier{ &outer_circuit, settings }; verifier.transcript->enable_manifest(); const stdlib::Proof stdlib_merge_proof(outer_circuit, merge_proof); - auto pairing_points = verifier.verify_proof( - stdlib_merge_proof, recursive_merge_commitments, recursive_merge_commitments.T_commitments); + auto [pairing_points, recursive_merged_table_commitments] = + verifier.verify_proof(stdlib_merge_proof, recursive_merge_commitments); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_circuit.failed(), !expected) << outer_circuit.err(); @@ -112,8 +115,7 @@ template class RecursiveMergeVerifierTest : public test // verifier and check that the result agrees. MergeVerifier native_verifier{ settings }; native_verifier.transcript->enable_manifest(); - bool verified_native = - native_verifier.verify_proof(merge_proof, merge_commitments, merge_commitments.T_commitments); + auto [verified_native, merged_table_commitments] = native_verifier.verify_proof(merge_proof, merge_commitments); VerifierCommitmentKey pcs_verification_key; bool verified_recursive = pcs_verification_key.pairing_check(pairing_points.P0.get_value(), pairing_points.P1.get_value()); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp index 9acda8a1bc9f..631e6e4842c4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp @@ -21,8 +21,9 @@ namespace bb::stdlib::element_default { // ( ͡° ͜ʖ ͡°) -template class element { +template class element { public: + using Builder = Builder_; using bool_ct = stdlib::bool_t; using biggroup_tag = element; // Facilitates a constexpr check IsBigGroup using BaseField = Fq; @@ -163,6 +164,17 @@ template class element { return element(x_fq, y_fq); } + static element point_at_infinity(Builder* ctx) + { + Fr zero = Fr::from_witness_index(ctx, ctx->zero_idx); + zero.unset_free_witness_tag(); + Fq x_fq(zero, zero); + Fq y_fq(zero, zero); + element result(x_fq, y_fq); + result.set_point_at_infinity(true); + return result; + } + element& operator=(const element& other); element& operator=(element&& other) noexcept; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp index 30047c9505b1..f295545cde9b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.cpp @@ -1290,6 +1290,54 @@ std::array, 3> field_t::slice(const uint8_t msb, const return result; } +template +std::pair, field_t> field_t::split_at(const size_t lsb_index, + const size_t num_bits) const +{ + ASSERT(lsb_index < num_bits); + ASSERT(num_bits <= grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH); + + const uint256_t value = get_value(); + const uint256_t hi = value >> lsb_index; + const uint256_t lo = value % (uint256_t(1) << lsb_index); + + if (is_constant()) { + // If `*this` is constant, we can return the split values directly + ASSERT(lo + (hi << lsb_index) == value); + return std::make_pair(field_t(lo), field_t(hi)); + } + + // Handle edge case when lsb_index == 0 + if (lsb_index == 0) { + ASSERT(hi == value); + ASSERT(lo == 0); + create_range_constraint(num_bits, "split_at: hi value too large."); + return std::make_pair(field_t(0), *this); + } + + Builder* ctx = get_context(); + ASSERT(ctx != nullptr); + + field_t lo_wit(witness_t(ctx, lo)); + field_t hi_wit(witness_t(ctx, hi)); + + // Ensure that `lo_wit` is in the range [0, 2^lsb_index - 1] + lo_wit.create_range_constraint(lsb_index, "split_at: lo value too large."); + + // Ensure that `hi_wit` is in the range [0, 2^(num_bits - lsb_index) - 1] + hi_wit.create_range_constraint(num_bits - lsb_index, "split_at: hi value too large."); + + // Check that *this = lo_wit + hi_wit * 2^{lsb_index} + const field_t reconstructed = lo_wit + (hi_wit * field_t(uint256_t(1) << lsb_index)); + assert_equal(reconstructed, "split_at: decomposition failed"); + + // Set the origin tag for both witnesses + lo_wit.set_origin_tag(tag); + hi_wit.set_origin_tag(tag); + + return std::make_pair(lo_wit, hi_wit); +} + /** * @brief Build constraints establishing the decomposition of `*this` into bits. * diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp index 295dfe6997cc..9d64a4ee228d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp @@ -339,6 +339,9 @@ template class field_t { std::array slice(uint8_t msb, uint8_t lsb) const; + std::pair, field_t> split_at( + const size_t lsb_index, const size_t num_bits = grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH) const; + bool_t is_zero() const; void create_range_constraint(size_t num_bits, std::string const& msg = "field_t::range_constraint") const; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index 4ab429965782..1605ffb21971 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -4,6 +4,7 @@ #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/streams.hpp" #include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include #include @@ -859,6 +860,56 @@ template class stdlib_field : public testing::Test { EXPECT_TRUE(builder.err() == "slice: hi value too large."); } + static void test_split_at() + { + Builder builder = Builder(); + + // Test different bit sizes + std::vector test_bit_sizes = { 8, 16, 32, 100, 252 }; + + // Lambda to check split_at functionality + auto check_split_at = [&](const field_ct& a, size_t start, size_t num_bits) { + const uint256_t a_native = a.get_value(); + auto split_data = a.split_at(start, num_bits); + EXPECT_EQ(split_data.first.get_value(), a_native & ((uint256_t(1) << start) - 1)); + EXPECT_EQ(split_data.second.get_value(), (a_native >> start) & ((uint256_t(1) << num_bits) - 1)); + + if (a.is_constant()) { + EXPECT_TRUE(split_data.first.is_constant()); + EXPECT_TRUE(split_data.second.is_constant()); + } + + if (start == 0) { + EXPECT_TRUE(split_data.first.is_constant()); + EXPECT_TRUE(split_data.first.get_value() == 0); + EXPECT_EQ(split_data.second.get_value(), a.get_value()); + } + }; + + for (size_t num_bits : test_bit_sizes) { + uint256_t a_native = engine.get_random_uint256() & ((uint256_t(1) << num_bits) - 1); + + // check split_at for a constant + field_ct a_constant(a_native); + check_split_at(a_constant, 0, num_bits); + check_split_at(a_constant, num_bits / 4, num_bits); + check_split_at(a_constant, num_bits / 3, num_bits); + check_split_at(a_constant, num_bits / 2, num_bits); + check_split_at(a_constant, num_bits - 1, num_bits); + + // check split_at for a witness + field_ct a_witness(witness_ct(&builder, a_native)); + check_split_at(a_witness, 0, num_bits); + check_split_at(a_witness, num_bits / 4, num_bits); + check_split_at(a_witness, num_bits / 3, num_bits); + check_split_at(a_witness, num_bits / 2, num_bits); + check_split_at(a_witness, num_bits - 1, num_bits); + } + + bool result = CircuitChecker::check(builder); + EXPECT_EQ(result, true); + } + static void test_three_bit_table() { Builder builder = Builder(); @@ -1258,7 +1309,10 @@ template class stdlib_field : public testing::Test { static void test_origin_tag_consistency() { Builder builder = Builder(); - auto a = field_ct(witness_ct(&builder, bb::fr::random_element())); + // Randomly generate a and b (a must ≤ 252 bits) + uint256_t a_val = + uint256_t(bb::fr::random_element()) & ((uint256_t(1) << grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH) - 1); + auto a = field_ct(witness_ct(&builder, a_val)); auto b = field_ct(witness_ct(&builder, bb::fr::random_element())); EXPECT_TRUE(a.get_origin_tag().is_empty()); EXPECT_TRUE(b.get_origin_tag().is_empty()); @@ -1362,6 +1416,12 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(element.get_origin_tag(), submitted_value_origin_tag); } + // Split preserves tags + const size_t num_bits = uint256_t(a.get_value()).get_msb() + 1; + auto split_data = a.split_at(num_bits / 2, num_bits); + EXPECT_EQ(split_data.first.get_origin_tag(), submitted_value_origin_tag); + EXPECT_EQ(split_data.second.get_origin_tag(), submitted_value_origin_tag); + // Decomposition preserves tags auto decomposed_bits = a.decompose_into_bits(); @@ -1555,6 +1615,10 @@ TYPED_TEST(stdlib_field, test_slice_random) { TestFixture::test_slice_random(); } +TYPED_TEST(stdlib_field, test_split_at) +{ + TestFixture::test_split_at(); +} TYPED_TEST(stdlib_field, test_three_bit_table) { TestFixture::test_three_bit_table(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp index dcc0329b65d8..0539ac7c9c07 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } +// internal: { status: done, auditors: [suyash], date: 2025-07-23 } // external_1: { status: not started, auditors: [], date: YYYY-MM-DD } // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== @@ -18,6 +18,7 @@ uint uint::operator+(const uint& other) const ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || (context == nullptr && other.context != nullptr)); + Builder* ctx = (context == nullptr) ? other.context : context; if (is_constant() && other.is_constant()) { @@ -25,6 +26,13 @@ uint uint::operator+(const uint& other) const } // N.B. We assume that additive_constant is nonzero ONLY if value is constant + if (!is_constant()) { + BB_ASSERT_EQ(additive_constant, 0ULL, "uint::operator+ expected additive_constant to be zero"); + } + if (!other.is_constant()) { + BB_ASSERT_EQ(other.additive_constant, 0ULL, "uint::operator+ expected other.additive_constant to be zero"); + } + const uint256_t lhs = get_value(); const uint256_t rhs = other.get_value(); const uint256_t constants = (additive_constant + other.additive_constant) & MASK; @@ -48,7 +56,7 @@ uint uint::operator+(const uint& other) const uint result(ctx); result.witness_index = gate.c; - result.witness_status = WitnessStatus::WEAK_NORMALIZED; + result.normalize(); return result; } @@ -67,12 +75,19 @@ uint uint::operator-(const uint& other) const } // N.B. We assume that additive_constant is nonzero ONLY if value is constant + if (!is_constant()) { + BB_ASSERT_EQ(additive_constant, 0ULL, "uint::operator- expected additive_constant to be zero"); + } + if (!other.is_constant()) { + BB_ASSERT_EQ(other.additive_constant, 0ULL, "uint::operator- expected other.additive_constant to be zero"); + } + const uint32_t lhs_idx = is_constant() ? ctx->zero_idx : witness_index; const uint32_t rhs_idx = other.is_constant() ? ctx->zero_idx : other.witness_index; const uint256_t lhs = get_value(); const uint256_t rhs = other.get_value(); - const uint256_t constant_term = (additive_constant - other.additive_constant); + const uint256_t constant_term = CIRCUIT_UINT_MAX_PLUS_ONE + (additive_constant - other.additive_constant); const uint256_t difference = CIRCUIT_UINT_MAX_PLUS_ONE + lhs - rhs; const uint256_t overflow = difference >> width; @@ -87,14 +102,14 @@ uint uint::operator-(const uint& other) const FF::neg_one(), FF::neg_one(), -FF(CIRCUIT_UINT_MAX_PLUS_ONE), - CIRCUIT_UINT_MAX_PLUS_ONE + constant_term, + constant_term, }; ctx->create_balanced_add_gate(gate); uint result(ctx); result.witness_index = gate.c; - result.witness_status = WitnessStatus::WEAK_NORMALIZED; + result.normalize(); return result; } @@ -102,6 +117,9 @@ uint uint::operator-(const uint& other) const template uint uint::operator*(const uint& other) const { + ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || + (context == nullptr && other.context != nullptr)); + Builder* ctx = (context == nullptr) ? other.context : context; if (is_constant() && other.is_constant()) { @@ -111,6 +129,14 @@ uint uint::operator*(const uint& other) const return other * (*this); } + // N.B. We assume that additive_constant is nonzero ONLY if value is constant + if (!is_constant()) { + BB_ASSERT_EQ(additive_constant, 0ULL, "uint::operator* expected additive_constant to be zero"); + } + if (!other.is_constant()) { + BB_ASSERT_EQ(other.additive_constant, 0ULL, "uint::operator* expected other.additive_constant to be zero"); + } + const uint32_t rhs_idx = other.is_constant() ? ctx->zero_idx : other.witness_index; const uint256_t lhs = ctx->get_variable(witness_index); @@ -139,9 +165,8 @@ uint uint::operator*(const uint& other) const ctx->decompose_into_default_range(gate.d, width); uint result(ctx); - result.accumulators = constrain_accumulators(ctx, gate.c); result.witness_index = gate.c; - result.witness_status = WitnessStatus::OK; + result.normalize(); return result; } @@ -184,20 +209,17 @@ std::pair, uint> uint::d Builder* ctx = (context == nullptr) ? other.context : context; // We want to force the divisor to be non-zero, as this is an error state - if (other.is_constant() && other.get_value() == 0) { - // TODO: should have an actual error handler! - const uint32_t one = ctx->add_variable(FF::one()); - ctx->assert_equal_constant(one, FF::zero(), "plookup_arithmetic: divide by zero!"); - } else if (!other.is_constant()) { - const bool_t is_divisor_zero = field_t(other).is_zero(); - ctx->assert_equal_constant(is_divisor_zero.witness_index, FF::zero(), "plookup_arithmetic: divide by zero!"); - } + static_cast>(other).assert_is_not_zero("uint_arithmetic: divide by zero!"); + // If both are constants, we can compute the quotient and remainder directly if (is_constant() && other.is_constant()) { const uint remainder(ctx, additive_constant % other.additive_constant); const uint quotient(ctx, additive_constant / other.additive_constant); return std::make_pair(quotient, remainder); - } else if (witness_index == other.witness_index) { + } + + // If the divisor and dividend are the same witness, we can return a quotient of 1 and a remainder of 0. + if (witness_index == other.witness_index) { const uint remainder(context, 0); const uint quotient(context, 1); return std::make_pair(quotient, remainder); @@ -248,13 +270,11 @@ std::pair, uint> uint::d ctx->decompose_into_default_range(delta_idx, width); uint quotient(ctx); quotient.witness_index = quotient_idx; - quotient.accumulators = constrain_accumulators(ctx, quotient.witness_index); - quotient.witness_status = WitnessStatus::OK; + quotient.normalize(); uint remainder(ctx); remainder.witness_index = remainder_idx; - remainder.accumulators = constrain_accumulators(ctx, remainder.witness_index); - remainder.witness_status = WitnessStatus::OK; + remainder.normalize(); return std::make_pair(quotient, remainder); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp index 294c93cb23a3..99fea541d128 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } +// internal: { status: done, auditors: [suyash], date: 2025-07-23 } // external_1: { status: not started, auditors: [], date: YYYY-MM-DD } // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp index 9d6ef527eb02..7f462949032b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } +// internal: { status: done, auditors: [suyash], date: 2025-07-23 } // external_1: { status: not started, auditors: [], date: YYYY-MM-DD } // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== @@ -47,55 +47,64 @@ uint uint::operator>>(const size_t shift) cons return uint(context, (additive_constant >> shift) & MASK); } - if (witness_status != WitnessStatus::OK) { - normalize(); - } + // Normalize before shifting. + normalize(); if (shift == 0) { return *this; } - uint64_t bits_per_hi_limb; - // last limb will not likely bit `bits_per_limb`. Need to be careful with our range check - if (shift >= ((width / bits_per_limb) * bits_per_limb)) { - bits_per_hi_limb = width % bits_per_limb; - } else { - bits_per_hi_limb = bits_per_limb; - } - const uint64_t slice_bit_position = shift % bits_per_limb; + // Example for uint32_t: + // + // |<------ acc[2] ------>||<----------- acc[1] ----------->||<------- acc[0] ------->| + // val: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] + // ↑ + // [<--------------- keep --------------->][<-------- discard -------->] + // + // out: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 ] + // |<------ acc[2] ------>||<----- acc[1].hi ----->| + // + // Suppose the shift is 15, then we must discard the 15 least significant bits of the accumulator. + // The accumulator is split into three parts, so we clearly need to split acc[1]. On splitting, we must + // discard the lower slice of acc[1] and keep the upper slice. Thus, the updated uint value will be: + // + // acc[1].hi + (acc[2] << (24 - 15)) + // + // Let us first fetch the accumlator that needs to be sliced. const size_t accumulator_index = shift / bits_per_limb; - const uint32_t slice_index = accumulators[accumulator_index]; - const uint64_t slice_value = uint256_t(context->get_variable(slice_index)).data[0]; - - const uint64_t slice_lo = slice_value % (1ULL << slice_bit_position); - const uint64_t slice_hi = slice_value >> slice_bit_position; - const uint32_t slice_lo_idx = slice_bit_position ? context->add_variable(slice_lo) : context->zero_idx; - const uint32_t slice_hi_idx = - (slice_bit_position != bits_per_limb) ? context->add_variable(slice_hi) : context->zero_idx; - - context->create_big_add_gate( - { slice_index, slice_lo_idx, context->zero_idx, slice_hi_idx, -1, 1, 0, (1 << slice_bit_position), 0 }); - - if (slice_bit_position != 0) { - context->create_new_range_constraint(slice_lo_idx, (1ULL << slice_bit_position) - 1); - } - context->create_new_range_constraint(slice_hi_idx, (1ULL << (bits_per_hi_limb - slice_bit_position)) - 1); + const uint32_t slice_witness_index = accumulators[accumulator_index]; + const field_t acc_to_be_sliced = field_t::from_witness_index(context, slice_witness_index); + + // Now, lets calculate: + // (i) bit position (from lsb) at which we need to slice. + // (ii) number of bits in the slice based on whether it is the highest slice or not. + const size_t slice_bit_position = shift % bits_per_limb; + const bool is_slice_hi = (accumulator_index == num_accumulators() - 1); + const uint8_t num_bits_per_limb = is_slice_hi ? bits_in_high_limb : bits_per_limb; + + // Finally, we can slice the accumulator. + // The slice_hi will be the upper slice of the accumulator, which we will keep. + // The slice_lo will be the lower slice of the accumulator, which we will discard. + // Its important to note that although slice_lo is not used here, it is still created and properly constrained + // in the split_at function. + field_t slice_hi = acc_to_be_sliced.split_at(slice_bit_position, num_bits_per_limb).second; + + // Now we reconstruct the shifted uint value. std::vector> sublimbs; - sublimbs.emplace_back(field_t::from_witness_index(context, slice_hi_idx)); + sublimbs.emplace_back(slice_hi); const size_t start = accumulator_index + 1; field_t coefficient(context, uint64_t(1ULL << (start * bits_per_limb - shift))); field_t shifter(context, uint64_t(1ULL << bits_per_limb)); for (size_t i = accumulator_index + 1; i < num_accumulators(); ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * - field_t(coefficient)); + sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); coefficient *= shifter; } uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); uint result(context); result.witness_index = result_index; - result.witness_status = WitnessStatus::WEAK_NORMALIZED; + result.normalize(); return result; } @@ -109,70 +118,69 @@ uint uint::operator<<(const size_t shift) cons return uint(context, (additive_constant << shift) & MASK); } - if (witness_status != WitnessStatus::OK) { - normalize(); - } + // Normalize before shifting. + normalize(); if (shift == 0) { return *this; } - uint64_t slice_bit_position; - size_t accumulator_index; - size_t bits_per_hi_limb; - // most significant limb is only 2 bits long (for u32), need to be careful about which slice we index, - // and how large the range check is on our hi limb - if (shift < (width - ((width / bits_per_limb) * bits_per_limb))) { - bits_per_hi_limb = width % bits_per_limb; - slice_bit_position = bits_per_hi_limb - (shift % bits_per_hi_limb); - accumulator_index = num_accumulators() - 1; - } else { - const size_t offset = width % bits_per_limb; - slice_bit_position = bits_per_limb - ((shift - offset) % bits_per_limb); - accumulator_index = num_accumulators() - 2 - ((shift - offset) / bits_per_limb); - bits_per_hi_limb = bits_per_limb; - } - - const uint32_t slice_index = accumulators[accumulator_index]; - const uint64_t slice_value = uint256_t(context->get_variable(slice_index)).data[0]; - - const uint64_t slice_lo = slice_value % (1ULL << slice_bit_position); - const uint64_t slice_hi = slice_value >> slice_bit_position; - const uint32_t slice_lo_idx = slice_bit_position ? context->add_variable(slice_lo) : context->zero_idx; - const uint32_t slice_hi_idx = - (slice_bit_position != bits_per_hi_limb) ? context->add_variable(slice_hi) : context->zero_idx; - - context->create_big_add_gate( - { slice_index, slice_lo_idx, context->zero_idx, slice_hi_idx, -1, 1, 0, (1 << slice_bit_position), 0 }); - - context->create_new_range_constraint(slice_lo_idx, (1ULL << slice_bit_position) - 1); - - if (slice_bit_position != bits_per_limb) { - context->create_new_range_constraint(slice_hi_idx, (1ULL << (bits_per_hi_limb - slice_bit_position)) - 1); - } - + // Example for uint32_t: + // + // |<------ acc[2] ------->||<----------- acc[1] ----------->||<------- acc[0] ------->| + // val: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] + // ↑ + // [<---- discard ---->][<---------------------- keep ----------------------->] + // + // out: [ 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] + // [<- acc[2].lo ->||<----------- acc[1] ----------->||<------- acc[0] ------->| + // + // Suppose the shift is 7, then we must discard the 7 most significant bits of the accumulator, and move + // the remaining bits to the left. The accumulator is split into three parts, so in this case we clearly + // need to split acc[2]. On splitting, we must discard the higher slice of acc[2] and keep the lower slice. + // Thus, the updated uint value will be: + // + // (acc[2].lo << (24 + 7)) + (acc[1] << (12 + 7)) + (acc[0] << 7) + // + // Let us first fetch the accumulator that needs to be sliced. + // We will do so by adjusting the shift from the most-significant bit. + size_t adjusted_shift = width - shift; + const size_t accumulator_index = adjusted_shift / bits_per_limb; + const uint32_t slice_witness_index = accumulators[accumulator_index]; + const field_t acc_to_be_sliced = field_t::from_witness_index(context, slice_witness_index); + + // Now, lets calculate: + // (i) bit position (from lsb) at which we need to slice. + // (ii) number of bits in the slice based on whether it is the highest slice or not. + const bool is_slice_hi = (accumulator_index == num_accumulators() - 1); + const size_t slice_bit_position = adjusted_shift % bits_per_limb; + const uint8_t num_bits_per_limb = is_slice_hi ? bits_in_high_limb : bits_per_limb; + + // We can now slice the accumulator. + field_t slice_lo = acc_to_be_sliced.split_at(slice_bit_position, num_bits_per_limb).first; + + // Now we reconstruct the shifted uint value. std::vector> sublimbs; - sublimbs.emplace_back(field_t::from_witness_index(context, slice_lo_idx) * - field_t(context, 1ULL << ((accumulator_index)*bits_per_limb + shift))); + sublimbs.emplace_back(slice_lo * field_t(context, 1ULL << ((accumulator_index * bits_per_limb) + shift))); field_t coefficient(context, uint64_t(1ULL << shift)); field_t shifter(context, uint64_t(1ULL << bits_per_limb)); for (size_t i = 0; i < accumulator_index; ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * - field_t(coefficient)); + sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); coefficient *= shifter; } uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); uint result(context); result.witness_index = result_index; - result.witness_status = WitnessStatus::WEAK_NORMALIZED; + result.normalize(); return result; } template uint uint::ror(const size_t target_rotation) const { + // Note: width is always a power of two, so we can use bitwise AND. const size_t rotation = target_rotation & (width - 1); const auto rotate = [](const uint256_t input, const uint64_t rot) { @@ -185,64 +193,69 @@ uint uint::ror(const size_t target_rotation) c return uint(context, rotate(additive_constant, rotation)); } - if (witness_status != WitnessStatus::OK) { - normalize(); - } + // Normalize before ror. + normalize(); if (rotation == 0) { return *this; } - const size_t shift = rotation; - uint64_t bits_per_hi_limb; - // last limb will not likely bit `bits_per_limb`. Need to be careful with our range check - if (shift >= ((width / bits_per_limb) * bits_per_limb)) { - bits_per_hi_limb = width % bits_per_limb; - } else { - bits_per_hi_limb = bits_per_limb; - } - const uint64_t slice_bit_position = shift % bits_per_limb; + // Example for uint32_t: + // + // |<------ acc[2] ------>||<----------- acc[1] ----------->||<------- acc[0] ------->| + // val: [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] + // ↑ + // [<--------------- keep --------------->][<-------- right rotate -------->] + // + // out: [ 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ] [ 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 ] + // [<- acc[1].lo ->||<------- acc[0] ------->| |<------ acc[2] ------>||<----- acc[1].hi ------>] + // + // Suppose the right-rotation is 15 (i.e., rotate = 15), then we must right-rotate the 15 least + // significant bits of the accumulator. The accumulator is split into three parts, so in this case we need to split + // acc[1]. On splitting, we must "rotate" the lower slice of acc[1] and keep the upper slice. Thus, the updated uint + // value will be: + // + // acc[1].hi + (acc[2] << (24 - 15)) + (acc[0] >> (32 - 15)) + (acc[1].lo >> (32 - 15 + 12)) + // + // Let us first fetch the accumlator that needs to be sliced. + size_t shift = rotation; const size_t accumulator_index = shift / bits_per_limb; - const uint32_t slice_index = accumulators[accumulator_index]; - const uint64_t slice_value = uint256_t(context->get_variable(slice_index)).data[0]; + const uint32_t slice_witness_index = accumulators[accumulator_index]; + const field_t acc_to_be_sliced = field_t::from_witness_index(context, slice_witness_index); - const uint64_t slice_lo = slice_value % (1ULL << slice_bit_position); - const uint64_t slice_hi = slice_value >> slice_bit_position; - const uint32_t slice_lo_idx = slice_bit_position ? context->add_variable(slice_lo) : context->zero_idx; - const uint32_t slice_hi_idx = - (slice_bit_position != bits_per_limb) ? context->add_variable(slice_hi) : context->zero_idx; + // Now, lets calculate: + // (i) bit position (from lsb) at which we need to slice. + // (ii) number of bits in the slice based on whether it is the highest slice or not. + const size_t slice_bit_position = shift % bits_per_limb; + const bool is_slice_hi = (accumulator_index == num_accumulators() - 1); + const uint8_t num_bits_per_limb = is_slice_hi ? bits_in_high_limb : bits_per_limb; - context->create_big_add_gate( - { slice_index, slice_lo_idx, context->zero_idx, slice_hi_idx, -1, 1, 0, (1 << slice_bit_position), 0 }); + // Finally, we can slice the accumulator. + auto [slice_lo, slice_hi] = acc_to_be_sliced.split_at(slice_bit_position, num_bits_per_limb); - if (slice_bit_position != 0) { - context->create_new_range_constraint(slice_lo_idx, (1ULL << slice_bit_position) - 1); - } - context->create_new_range_constraint(slice_hi_idx, (1ULL << (bits_per_hi_limb - slice_bit_position)) - 1); + // Now we reconstruct the shifted uint value. std::vector> sublimbs; - sublimbs.emplace_back(field_t::from_witness_index(context, slice_hi_idx)); + sublimbs.emplace_back(slice_hi); const size_t start = accumulator_index + 1; field_t coefficient(context, uint64_t(1ULL << (start * bits_per_limb - shift))); field_t shifter(context, uint64_t(1ULL << bits_per_limb)); for (size_t i = accumulator_index + 1; i < num_accumulators(); ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * - field_t(coefficient)); + sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); coefficient *= shifter; } coefficient = field_t(context, uint64_t(1ULL << (width - shift))); for (size_t i = 0; i < accumulator_index; ++i) { - sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * - field_t(coefficient)); + sublimbs.emplace_back(field_t::from_witness_index(context, accumulators[i]) * coefficient); coefficient *= shifter; } - sublimbs.emplace_back(field_t::from_witness_index(context, slice_lo_idx) * field_t(coefficient)); + sublimbs.emplace_back(slice_lo * field_t(coefficient)); uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); uint result(context); result.witness_index = result_index; - result.witness_status = WitnessStatus::WEAK_NORMALIZED; + result.normalize(); return result; } @@ -348,8 +361,8 @@ uint uint::logic_operator(const uint& other, c } } + // Since we reconstruct accumulators from the lookup table, we don't need to normalize them here. result.witness_index = lookup[ColumnIdx::C3][0].get_witness_index(); - result.witness_status = WitnessStatus::OK; return result; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp index 2fbd81f9d756..3cc8762c907d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } +// internal: { status: done, auditors: [suyash], date: 2025-07-23 } // external_1: { status: not started, auditors: [], date: YYYY-MM-DD } // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== @@ -13,35 +13,33 @@ template std::vector uint::constrain_accumulators(Builder* context, const uint32_t witness_index) const { - const auto res = context->decompose_into_default_range(witness_index, width, bits_per_limb); + std::vector res = context->decompose_into_default_range(witness_index, width, bits_per_limb); return res; } template -uint::uint(const witness_t& witness) - : context(witness.context) - , witness_status(WitnessStatus::OK) +uint::uint(const witness_t& other) + : context(other.context) { - if (witness.witness_index == IS_CONSTANT) { - additive_constant = witness.witness; + if (other.is_constant()) { + additive_constant = other.witness; witness_index = IS_CONSTANT; } else { - accumulators = constrain_accumulators(context, witness.witness_index); - witness_index = witness.witness_index; + accumulators = constrain_accumulators(context, other.witness_index); + witness_index = other.witness_index; } } template -uint::uint(const field_t& value) - : context(value.context) +uint::uint(const field_t& other) + : context(other.context) , additive_constant(0) - , witness_status(WitnessStatus::OK) { - if (value.witness_index == IS_CONSTANT) { - additive_constant = value.additive_constant; + if (other.is_constant()) { + additive_constant = other.additive_constant; witness_index = IS_CONSTANT; } else { - field_t norm = value.normalize(); + field_t norm = other.normalize(); accumulators = constrain_accumulators(context, norm.get_witness_index()); witness_index = norm.get_witness_index(); } @@ -51,7 +49,6 @@ template uint::uint(Builder* builder, const uint256_t& value) : context(builder) , additive_constant(value) - , witness_status(WitnessStatus::OK) , accumulators() , witness_index(IS_CONSTANT) {} @@ -60,7 +57,6 @@ template uint::uint(const uint256_t& value) : context(nullptr) , additive_constant(value) - , witness_status(WitnessStatus::OK) , accumulators() , witness_index(IS_CONSTANT) {} @@ -69,25 +65,32 @@ template uint::uint(const byte_array& other) : context(other.get_context()) , additive_constant(0) - , witness_status(WitnessStatus::WEAK_NORMALIZED) , accumulators() , witness_index(IS_CONSTANT) { - field_t accumulator(context, fr::zero()); + const auto& bytes = other.bytes(); + const size_t num_bytes = bytes.size(); field_t scaling_factor(context, fr::one()); - const auto bytes = other.bytes(); - // TODO JUMP IN STEPS OF TWO - for (size_t i = 0; i < bytes.size(); ++i) { - accumulator = accumulator + scaling_factor * bytes[bytes.size() - 1 - i]; - scaling_factor = scaling_factor * fr(256); + // Collect the bytes in reverse order and scale them appropriately. + std::vector> scaled_bytes; + scaled_bytes.reserve(num_bytes); + for (size_t i = 0; i < num_bytes; ++i) { + scaled_bytes.push_back(bytes[num_bytes - 1 - i] * scaling_factor); + scaling_factor = scaling_factor * fr(256); // Scale by 2^8. } - accumulator = accumulator.normalize(); - if (accumulator.witness_index == IS_CONSTANT) { + field_t accumulator = field_t::accumulate(scaled_bytes); + + // If the accumulator is constant, we set the additive constant. + // Otherwise, we set the witness index. + if (accumulator.is_constant()) { additive_constant = uint256_t(accumulator.additive_constant); } else { witness_index = accumulator.witness_index; } + + // We need to constrain the accumulators, so we normalize here. + normalize(); } template @@ -99,59 +102,66 @@ template uint::uint(Builder* parent_context, const std::vector>& wires) : context(parent_context) , additive_constant(0) - , witness_status(WitnessStatus::WEAK_NORMALIZED) , accumulators() , witness_index(IS_CONSTANT) { - field_t accumulator(context, fr::zero()); field_t scaling_factor(context, fr::one()); - - // TODO JUMP IN STEPS OF TWO - for (size_t i = 0; i < wires.size(); ++i) { - accumulator = accumulator + scaling_factor * field_t(wires[i]); - scaling_factor = scaling_factor + scaling_factor; + const size_t num_wires = wires.size(); + + // Collect the bits and scale them appropriately. + std::vector> scaled_bits; + scaled_bits.reserve(num_wires); + for (size_t i = 0; i < num_wires; ++i) { + scaled_bits.push_back(field_t(wires[i]) * scaling_factor); + scaling_factor = scaling_factor * fr(2); // Scale by 2^1. } - accumulator = accumulator.normalize(); - if (accumulator.witness_index == IS_CONSTANT) { + field_t accumulator = field_t::accumulate(scaled_bits); + + // If the accumulator is constant, we set the additive constant. + // Otherwise, we set the witness index. + if (accumulator.is_constant()) { additive_constant = uint256_t(accumulator.additive_constant); } else { witness_index = accumulator.witness_index; } + + // We need to constrain the accumulators, so we normalize here. + normalize(); } template uint::uint(const uint& other) : context(other.context) , additive_constant(other.additive_constant) - , witness_status(other.witness_status) , accumulators(other.accumulators) , witness_index(other.witness_index) {} template -uint::uint(uint&& other) +uint::uint(uint&& other) noexcept : context(other.context) , additive_constant(other.additive_constant) - , witness_status(other.witness_status) , accumulators(other.accumulators) , witness_index(other.witness_index) {} template uint& uint::operator=(const uint& other) { + if (this == &other) { + return *this; + } context = other.context; additive_constant = other.additive_constant; - witness_status = other.witness_status; accumulators = other.accumulators; witness_index = other.witness_index; return *this; } -template uint& uint::operator=(uint&& other) +template +uint& uint::operator=(uint&& other) noexcept { context = other.context; additive_constant = other.additive_constant; - witness_status = other.witness_status; accumulators = other.accumulators; witness_index = other.witness_index; return *this; @@ -177,10 +187,8 @@ template uint uint uint256_t uint::ge if (!context || is_constant()) { return additive_constant; } - return (uint256_t(context->get_variable(witness_index))) & MASK; -} - -template uint256_t uint::get_unbounded_value() const -{ - if (!context || is_constant()) { - return additive_constant; - } - return (uint256_t(context->get_variable(witness_index))); -} -template bool_t uint::at(const size_t bit_index) const -{ - if (is_constant()) { - return bool_t(context, get_value().get_bit(bit_index)); - } - if (witness_status != WitnessStatus::OK) { - normalize(); - } + const uint256_t witness_value = context->get_variable(witness_index); + ASSERT(witness_value.get_msb() < width, "uint::get_value(): witness value exceeds type width"); - const uint64_t slice_bit_position = bit_index % bits_per_limb; - - const uint32_t slice_index = accumulators[bit_index / bits_per_limb]; - const uint64_t slice_value = uint256_t(context->get_variable(slice_index)).data[0]; - - const uint64_t slice_lo = slice_value % (1ULL << slice_bit_position); - const uint64_t bit_value = (slice_value >> slice_bit_position) & 1ULL; - const uint64_t slice_hi = slice_value >> (slice_bit_position + 1); - - const uint32_t slice_lo_idx = slice_bit_position ? context->add_variable(slice_lo) : context->zero_idx; - const uint32_t bit_idx = context->add_variable(bit_value); - const uint32_t slice_hi_idx = - (slice_bit_position + 1 != bits_per_limb) ? context->add_variable(slice_hi) : context->zero_idx; - - context->create_big_add_gate({ slice_index, - slice_lo_idx, - bit_idx, - slice_hi_idx, - -1, - 1, - (1 << slice_bit_position), - (1 << (slice_bit_position + 1)), - 0 }); - - if (slice_bit_position != 0) { - context->create_new_range_constraint(slice_lo_idx, (1ULL << slice_bit_position) - 1); - } - if (slice_bit_position + 1 != bits_per_limb) { - context->create_new_range_constraint(slice_hi_idx, (1ULL << (bits_per_limb - (slice_bit_position + 1))) - 1); - } - bool_t result = witness_t(context, bit_value); - return result; + return witness_value & MASK; } template class uint; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp index fd3e3fbee49e..4d23091f2cee 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp @@ -69,7 +69,6 @@ template class UintFuzzBase { AND, OR, XOR, - GET_BIT, SHL, SHR, ROL, @@ -140,7 +139,6 @@ template class UintFuzzBase { out = static_cast(rng.next() & 0xff); return { .id = instruction_opcode, .arguments.threeArgs = { .in1 = in1, .in2 = in2, .out = out } }; break; - case OPCODE::GET_BIT: case OPCODE::SHL: case OPCODE::SHR: case OPCODE::ROL: @@ -204,7 +202,6 @@ template class UintFuzzBase { PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.in2) PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.threeArgs.out) break; - case OPCODE::GET_BIT: case OPCODE::SHL: case OPCODE::SHR: case OPCODE::ROL: @@ -241,7 +238,6 @@ template class UintFuzzBase { static constexpr size_t AND = 3; static constexpr size_t OR = 3; static constexpr size_t XOR = 3; - static constexpr size_t GET_BIT = 10; static constexpr size_t SHL = 10; static constexpr size_t SHR = 10; static constexpr size_t ROL = 10; @@ -276,9 +272,8 @@ template class UintFuzzBase { return { .id = static_cast(opcode), .arguments.threeArgs = { .in1 = *Data, .in2 = *(Data + 1), .out = *(Data + 2) } }; } - if constexpr (opcode == Instruction::OPCODE::GET_BIT || opcode == Instruction::OPCODE::SHL || - opcode == Instruction::OPCODE::SHR || opcode == Instruction::OPCODE::ROL || - opcode == Instruction::OPCODE::ROR) { + if constexpr (opcode == Instruction::OPCODE::SHL || opcode == Instruction::OPCODE::SHR || + opcode == Instruction::OPCODE::ROL || opcode == Instruction::OPCODE::ROR) { return Instruction{ .id = static_cast(opcode), .arguments.bitArgs = { .in = *Data, .out = *(Data + 1), .bit = *(Data + 2) } }; } @@ -320,8 +315,7 @@ template class UintFuzzBase { *(Data + 2) = instruction.arguments.threeArgs.in2; *(Data + 3) = instruction.arguments.threeArgs.out; } - if constexpr (instruction_opcode == Instruction::OPCODE::GET_BIT || - instruction_opcode == Instruction::OPCODE::SHL || + if constexpr (instruction_opcode == Instruction::OPCODE::SHL || instruction_opcode == Instruction::OPCODE::SHR || instruction_opcode == Instruction::OPCODE::ROL || instruction_opcode == Instruction::OPCODE::ROR) { @@ -365,48 +359,6 @@ template class UintFuzzBase { return static_cast(v >> bits); } } - template static T get_bit(const T v, const size_t bit) - { - if (bit >= sizeof(T) * 8) { - return 0; - } else { - return (v & (uint64_t(1) << bit)) ? 1 : 0; - } - } - /* wrapper for uint::at which ensures the context of - * the return value has been set - */ - template static bool_t at(const T& v, const size_t bit_index) - { - const auto ret = v.at(bit_index); - - if (ret.get_context() != v.get_context()) { - std::cerr << "Context of return bool_t not set" << std::endl; - abort(); - } - - return ret; - } - template static T get_bit(Builder* builder, const T& v, const size_t bit) - { - return T(builder, std::vector{ at<>(v, bit) }); - } - template static std::vector to_bit_vector(const T& v) - { - std::vector bits; - for (size_t i = 0; i < v.get_width(); i++) { - bits.push_back(at<>(v, i)); - } - return bits; - } - template static std::array to_bit_array(const T& v) - { - std::array bits; - for (size_t i = 0; i < T::width; i++) { - bits[i] = at<>(v, i); - } - return bits; - } template static uint256_t get_value(const T& v) { const auto ret = v.get_value(); @@ -761,17 +713,6 @@ template class UintFuzzBase { abort(); } } - ExecutionHandler get_bit(Builder* builder, const size_t bit) const - { - return ExecutionHandler(Reference(this->get_bit(this->ref.v8, bit), - this->get_bit(this->ref.v16, bit), - this->get_bit(this->ref.v32, bit), - this->get_bit(this->ref.v64, bit)), - Uint(this->get_bit(builder, this->uint.v8, bit), - this->get_bit(builder, this->uint.v16, bit), - this->get_bit(builder, this->uint.v32, bit), - this->get_bit(builder, this->uint.v64, bit))); - } ExecutionHandler shl(const size_t bits) const { const Reference ref_result(shl(this->ref.v8, bits), @@ -862,7 +803,7 @@ template class UintFuzzBase { /* Explicit re-instantiation using the various constructors */ ExecutionHandler set(Builder* builder) const { - switch (VarianceRNG.next() % 7) { + switch (VarianceRNG.next() % 5) { case 0: return ExecutionHandler(this->ref, Uint(uint_8_t(this->uint.v8), @@ -888,18 +829,6 @@ template class UintFuzzBase { uint_32_t(this->to_byte_array(this->uint.v32)), uint_64_t(this->to_byte_array(this->uint.v64)))); case 4: - return ExecutionHandler(this->ref, - Uint(uint_8_t(builder, this->to_bit_vector(this->uint.v8)), - uint_16_t(builder, this->to_bit_vector(this->uint.v16)), - uint_32_t(builder, this->to_bit_vector(this->uint.v32)), - uint_64_t(builder, this->to_bit_vector(this->uint.v64)))); - case 5: - return ExecutionHandler(this->ref, - Uint(uint_8_t(builder, this->to_bit_array(this->uint.v8)), - uint_16_t(builder, this->to_bit_array(this->uint.v16)), - uint_32_t(builder, this->to_bit_array(this->uint.v32)), - uint_64_t(builder, this->to_bit_array(this->uint.v64)))); - case 6: return ExecutionHandler(this->ref, Uint(uint_8_t(builder, this->ref.v8), uint_16_t(builder, this->ref.v16), @@ -1164,34 +1093,6 @@ template class UintFuzzBase { } return 0; }; - /** - * @brief Execute the GET_BIT instruction - * - * @param builder - * @param stack - * @param instruction - * @return if everything is ok, 1 if we should stop execution, since an expected error was encountered - */ - static inline size_t execute_GET_BIT(Builder* builder, - std::vector& stack, - Instruction& instruction) - { - if (stack.size() == 0) { - return 1; - } - size_t first_index = instruction.arguments.bitArgs.in % stack.size(); - size_t output_index = instruction.arguments.bitArgs.out; - const uint8_t bit = instruction.arguments.bitArgs.bit; - ExecutionHandler result; - result = stack[first_index].get_bit(builder, bit); - // If the output index is larger than the number of elements in stack, append - if (output_index >= stack.size()) { - stack.push_back(result); - } else { - stack[output_index] = result; - } - return 0; - }; /** * @brief Execute the left-shift operator instruction * diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp index 7c68f3de436a..2dcb2957737b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp @@ -1,5 +1,5 @@ // === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } +// internal: { status: done, auditors: [suyash], date: 2025-07-23 } // external_1: { status: not started, auditors: [], date: YYYY-MM-DD } // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== @@ -18,6 +18,9 @@ template class uint { using FF = typename Builder::FF; static constexpr size_t width = sizeof(Native) * 8; + static_assert(width == 8 || width == 16 || width == 32 || width == 64, + "unsupported uint width, supported uint widths are: 8, 16, 32, and 64 bits."); + uint(const witness_t& other); uint(const field_t& other); uint(const uint256_t& value = 0); @@ -30,26 +33,31 @@ template class uint { : uint(static_cast(v)) {} - std::vector constrain_accumulators(Builder* ctx, const uint32_t witness_index) const; + std::vector constrain_accumulators(Builder* context, const uint32_t witness_index) const; static constexpr size_t bits_per_limb = 12; + static constexpr size_t bits_in_high_limb = width % bits_per_limb == 0 ? bits_per_limb : width % bits_per_limb; static constexpr size_t num_accumulators() { return (width + bits_per_limb - 1) / bits_per_limb; } uint(const uint& other); - uint(uint&& other); + uint(uint&& other) noexcept; + + ~uint() = default; uint& operator=(const uint& other); - uint& operator=(uint&& other); + uint& operator=(uint&& other) noexcept; explicit operator byte_array() const; explicit operator field_t() const; + // Arithmetic operations uint operator+(const uint& other) const; uint operator-(const uint& other) const; uint operator*(const uint& other) const; uint operator/(const uint& other) const; uint operator%(const uint& other) const; + // Bitwise operations uint operator&(const uint& other) const; uint operator^(const uint& other) const; uint operator|(const uint& other) const; @@ -63,6 +71,7 @@ template class uint { uint ror(const uint256_t target_rotation) const { return ror(static_cast(target_rotation.data[0])); } uint rol(const uint256_t target_rotation) const { return rol(static_cast(target_rotation.data[0])); } + // Comparison operations bool_t operator>(const uint& other) const; bool_t operator<(const uint& other) const; bool_t operator>=(const uint& other) const; @@ -71,6 +80,7 @@ template class uint { bool_t operator!=(const uint& other) const; bool_t operator!() const; + // Assignment operators uint operator+=(const uint& other) { *this = operator+(other); @@ -124,6 +134,7 @@ template class uint { return *this; } + // Helper functions uint normalize() const; uint256_t get_value() const; @@ -131,8 +142,6 @@ template class uint { bool is_constant() const { return witness_index == IS_CONSTANT; } Builder* get_context() const { return context; } - bool_t at(const size_t bit_index) const; - size_t get_width() const { return width; } uint32_t get_witness_index() const { return witness_index; } @@ -140,17 +149,15 @@ template class uint { uint256_t get_additive_constant() const { return additive_constant; } std::vector get_accumulators() const { return accumulators; } - uint256_t get_unbounded_value() const; protected: Builder* context; - enum WitnessStatus { OK, NOT_NORMALIZED, WEAK_NORMALIZED }; - mutable uint256_t additive_constant; - mutable WitnessStatus witness_status; // N.B. Not an accumulator! Contains 6-bit slices of input + // `accumulators` are used to store 6-bit slices of the value of the uint. This is done to + // range-constrain the uint by constraining individual slices. mutable std::vector accumulators; mutable uint32_t witness_index; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp index 6b4d591035e8..903b16e4b311 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp @@ -189,8 +189,6 @@ template class stdlib_uint : public testing::Test { witness_ct(&builder, true), }); - EXPECT_EQ(a.at(0).get_value(), false); - EXPECT_EQ(a.at(7).get_value(), true); EXPECT_EQ(static_cast(a.get_value()), 128U); } @@ -1035,6 +1033,13 @@ template class stdlib_uint : public testing::Test { uint_ct b_shift = uint_ct(&builder, const_b); uint_ct c = a + a_shift; uint_ct d = b + b_shift; + + // If both dividend and divisor are constants and divisor is zero, we expect an exception to be thrown. + if (divisor_zero && (lhs_constant && rhs_constant)) { + EXPECT_THROW_OR_ABORT(c / d, "divide by zero with constant dividend and divisor"); + return; + } + uint_ct e = c / d; e = e.normalize(); @@ -1730,39 +1735,6 @@ template class stdlib_uint : public testing::Test { bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } - - /** - * @brief Test the function uint_ct::at used to extract bits. - */ - static void test_at() - { - Builder builder = Builder(); - - const auto bit_test = [&builder](const bool is_constant) { - // construct a sum of uint_ct's, where at least one is a constant, - // and validate its correctness bitwise - uint_native const_a = get_random(); - uint_native a_val = get_random(); - uint_native c_val = const_a + a_val; - uint_ct a = is_constant ? uint_ct(&builder, a_val) : witness_ct(&builder, a_val); - uint_ct a_shift = uint_ct(&builder, const_a); - uint_ct c = a + a_shift; - for (size_t i = 0; i < uint_native_width; ++i) { - bool_ct result = c.at(i); - bool expected = (((c_val >> i) & 1UL) == 1UL) ? true : false; - EXPECT_EQ(result.get_value(), expected); - EXPECT_EQ(result.get_context(), c.get_context()); - } - }; - - bit_test(false); - bit_test(true); - - printf("builder gates = %zu\n", builder.get_estimated_num_finalized_gates()); - - bool proof_result = CircuitChecker::check(builder); - EXPECT_EQ(proof_result, true); - } }; // Define the test types for all combinations @@ -1938,7 +1910,3 @@ TYPED_TEST(stdlib_uint, test_rol) { TestFixture::test_rol(); } -TYPED_TEST(stdlib_uint, test_at) -{ - TestFixture::test_at(); -} diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp index 3c42571feecd..902023130b93 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/witness/witness.hpp @@ -49,6 +49,8 @@ template class witness_t { return out; } + bool is_constant() const { return witness_index == IS_CONSTANT; } + bb::fr witness; uint32_t witness_index = IS_CONSTANT; Builder* context = nullptr; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.test.cpp index 96271917f976..f920dcaf0c4d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.test.cpp @@ -6,6 +6,7 @@ #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" #include "barretenberg/stdlib/honk_verifier/decider_recursive_verifier.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/ultra_honk/decider_prover.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -106,7 +107,8 @@ class ProtogalaxyRecursiveTests : public testing::Test { big_a* big_b; - stdlib::recursion::PairingPoints::add_default_to_public_inputs(builder); + // Must be HidingKernelIO as UltraVerifier expects the public inputs set by HidingKernelIO + stdlib::recursion::honk::HidingKernelIO::add_default(builder); }; static std::tuple, std::shared_ptr> @@ -257,7 +259,8 @@ class ProtogalaxyRecursiveTests : public testing::Test { // Check for a failure flag in the recursive verifier circuit { - stdlib::recursion::PairingPoints::add_default_to_public_inputs(folding_circuit); + // Must be HidingKernelIO as UltraVerifier expects the public inputs set by HidingKernelIO + stdlib::recursion::honk::HidingKernelIO::add_default(folding_circuit); // inefficiently check finalized size folding_circuit.finalize_circuit(/* ensure_nonzero= */ true); info("Folding Recursive Verifier: num gates finalized = ", folding_circuit.num_gates); @@ -345,7 +348,13 @@ class ProtogalaxyRecursiveTests : public testing::Test { OuterBuilder decider_circuit; DeciderRecursiveVerifier decider_verifier{ &decider_circuit, native_verifier_acc }; auto pairing_points = decider_verifier.verify_proof(decider_proof); - pairing_points.set_public(); + + // IO + HidingKernelIO inputs; + inputs.pairing_inputs = pairing_points; + inputs.ecc_op_tables = HidingKernelIO::default_ecc_op_tables(decider_circuit); + inputs.set_public(); + info("Decider Recursive Verifier: num gates = ", decider_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(decider_circuit.failed(), false) << decider_circuit.err(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp b/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp index fc23b615284e..11896150da1c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp @@ -6,13 +6,22 @@ #pragma once +#include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/commitment_schemes/pairing_points.hpp" #include "barretenberg/stdlib/pairing_points.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib/primitives/databus/databus.hpp" #include "barretenberg/stdlib/primitives/public_input_component/public_input_component.hpp" namespace bb::stdlib::recursion::honk { +// Default coordinates of commitment to an ecc op table +// These are the coordinates that come from committing to the ecc ops that are added to the op_queue by finalize_circuit +static constexpr bb::fq DEFAULT_ECC_COMMITMENT_X("0x08434fa4480433735e7aeaccecb911eb7a06165ad70e5ced6ac6848296e59279"); +static constexpr bb::fq DEFAULT_ECC_COMMITMENT_Y("0x0a13a1839ab95ef15be8d0710b2c8aa47cea0b0e62a8596e68cc0fd54a6ae73d"); +static constexpr bb::curve::BN254::AffineElement DEFAULT_ECC_COMMITMENT(DEFAULT_ECC_COMMITMENT_X, + DEFAULT_ECC_COMMITMENT_Y); + /** * @brief Manages the data that is propagated on the public inputs of a kernel circuit * @@ -24,19 +33,21 @@ class KernelIO { using G1 = Curve::Group; using FF = Curve::ScalarField; using PairingInputs = stdlib::recursion::PairingPoints; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1490): Make PublicInputComponent work with arrays + using TableCommitments = std::array; using PublicPoint = stdlib::PublicInputComponent; using PublicPairingPoints = stdlib::PublicInputComponent; - PairingInputs pairing_inputs; // Inputs {P0, P1} to an EC pairing check - G1 kernel_return_data; // Commitment to the return data of a kernel circuit - G1 app_return_data; // Commitment to the return data of an app circuit - // G1 ecc_op_table; + PairingInputs pairing_inputs; // Inputs {P0, P1} to an EC pairing check + G1 kernel_return_data; // Commitment to the return data of a kernel circuit + G1 app_return_data; // Commitment to the return data of an app circuit + TableCommitments ecc_op_tables; // commitments to merged tables obtained from recursive Merge verification // FF pg_acc_hash; // Total size of the kernel IO public inputs - static constexpr size_t PUBLIC_INPUTS_SIZE = - PairingInputs::PUBLIC_INPUTS_SIZE + G1::PUBLIC_INPUTS_SIZE + G1::PUBLIC_INPUTS_SIZE; + static constexpr size_t PUBLIC_INPUTS_SIZE = PairingInputs::PUBLIC_INPUTS_SIZE + G1::PUBLIC_INPUTS_SIZE + + G1::PUBLIC_INPUTS_SIZE + Builder::NUM_WIRES * G1::PUBLIC_INPUTS_SIZE; /** * @brief Reconstructs the IO components from a public inputs array. @@ -54,8 +65,10 @@ class KernelIO { index += G1::PUBLIC_INPUTS_SIZE; app_return_data = PublicPoint::reconstruct(public_inputs, PublicComponentKey{ index }); index += G1::PUBLIC_INPUTS_SIZE; - // ecc_op_table = PublicPoint::reconstruct(public_inputs, PublicComponentKey{ index }); - // index += G1::PUBLIC_INPUTS_SIZE; + for (auto& table_commitment : ecc_op_tables) { + table_commitment = PublicPoint::reconstruct(public_inputs, PublicComponentKey{ index }); + index += G1::PUBLIC_INPUTS_SIZE; + } // pg_acc_hash = FF::reconstruct(public_inputs, PublicComponentKey{ index }); } @@ -68,13 +81,34 @@ class KernelIO { pairing_inputs.set_public(); kernel_return_data.set_public(); app_return_data.set_public(); - // ecc_op_table.set_public(); + for (auto& table_commitment : ecc_op_tables) { + table_commitment.set_public(); + } // pg_acc_hash.set_public(); // Finalize the public inputs to ensure no more public inputs can be added hereafter. Builder* builder = pairing_inputs.P0.get_context(); builder->finalize_public_inputs(); } + + /** + * @brief Add default public inputs when they are not present + * + */ + static void add_default(Builder& builder) + { + PairingInputs::add_default_to_public_inputs(builder); + G1 kernel_return_data = DataBusDepot::construct_default_commitment(builder); + kernel_return_data.set_public(); + G1 app_return_data = DataBusDepot::construct_default_commitment(builder); + app_return_data.set_public(); + TableCommitments ecc_op_tables; + for (auto& table_commitment : ecc_op_tables) { + table_commitment = G1(DEFAULT_ECC_COMMITMENT); + table_commitment.convert_constant_to_fixed_witness(&builder); + table_commitment.set_public(); + } + }; }; /** @@ -118,6 +152,12 @@ template class DefaultIO { Builder* builder = pairing_inputs.P0.get_context(); builder->finalize_public_inputs(); } + + /** + * @brief Add default public inputs when they are not present + * + */ + static void add_default(Builder& builder) { PairingInputs::add_default_to_public_inputs(builder); }; }; /** @@ -126,9 +166,103 @@ template class DefaultIO { using AppIO = DefaultIO; // app IO is always Mega /** - * @brief The data that is propagated on the public inputs of a hiding kernel circuit + * @brief Manages the data that is propagated on the public inputs of a hiding kernel circuit */ -using HidingKernelIO = DefaultIO; // hiding kernel IO is always Mega +template class HidingKernelIO { + public: + using Builder = Builder_; + using Curve = stdlib::bn254; // curve is always bn254 + using G1 = Curve::Group; + using FF = Curve::ScalarField; + using PairingInputs = stdlib::recursion::PairingPoints; + using TableCommitments = std::array; + + using PublicPoint = stdlib::PublicInputComponent; + using PublicPairingPoints = stdlib::PublicInputComponent; + + PairingInputs pairing_inputs; // Inputs {P0, P1} to an EC pairing check + TableCommitments ecc_op_tables; // commitments to merged tables obtained from final Merge verification + + // Total size of the IO public inputs + static constexpr size_t PUBLIC_INPUTS_SIZE = + PairingInputs::PUBLIC_INPUTS_SIZE + Builder::NUM_WIRES * G1::PUBLIC_INPUTS_SIZE; + + /** + * @brief Reconstructs the IO components from a public inputs array. + * + * @param public_inputs Public inputs array containing the serialized kernel public inputs. + */ + void reconstruct_from_public(const std::vector& public_inputs) + { + // Assumes that the app-io public inputs are at the end of the public_inputs vector + uint32_t index = static_cast(public_inputs.size() - PUBLIC_INPUTS_SIZE); + pairing_inputs = PublicPairingPoints::reconstruct(public_inputs, PublicComponentKey{ index }); + index += PairingInputs::PUBLIC_INPUTS_SIZE; + for (auto& commitment : ecc_op_tables) { + commitment = PublicPoint::reconstruct(public_inputs, PublicComponentKey{ index }); + index += G1::PUBLIC_INPUTS_SIZE; + } + } + + /** + * @brief Set each IO component to be a public input of the underlying circuit. + * + */ + void set_public() + { + pairing_inputs.set_public(); + for (auto& commitment : ecc_op_tables) { + commitment.set_public(); + } + + // Finalize the public inputs to ensure no more public inputs can be added hereafter. + Builder* builder = pairing_inputs.P0.get_context(); + builder->finalize_public_inputs(); + } + + /** + * @brief Construct commitments to empty subtables + * + * @details In the first iteration of the Merge, the verifier sets the commitments to the previous full state of the + * op_queue equal to the commitments to the empty tables. This ensures that prover cannot lie, as the starting point + * of the merge is fixed. + * + * @param builder + * @return TableCommitments + */ + static TableCommitments empty_ecc_op_tables(Builder& builder) + { + TableCommitments empty_tables; + for (auto& table_commitment : empty_tables) { + table_commitment = G1::point_at_infinity(&builder); + } + + return empty_tables; + } + + static TableCommitments default_ecc_op_tables(Builder& builder) + { + TableCommitments default_tables; + for (auto& table_commitment : default_tables) { + table_commitment = G1(DEFAULT_ECC_COMMITMENT); + table_commitment.convert_constant_to_fixed_witness(&builder); + } + + return default_tables; + } + + /** + * @brief Add default public inputs when they are not present + * + */ + static void add_default(Builder& builder) + { + PairingInputs::add_default_to_public_inputs(builder); + for (auto& table_commitment : default_ecc_op_tables(builder)) { + table_commitment.set_public(); + } + }; +}; /** * @brief The data that is propagated on the public inputs of a rollup circuit @@ -176,6 +310,18 @@ class RollupIO { Builder* builder = pairing_inputs.P0.get_context(); builder->finalize_public_inputs(); } + + /** + * @brief Add default public inputs when they are not present + * + */ + static void add_default(Builder& builder) + { + PairingInputs::add_default_to_public_inputs(builder); + auto [stdlib_opening_claim, ipa_proof] = IPA>::create_fake_ipa_claim_and_proof(builder); + stdlib_opening_claim.set_public(); + builder.ipa_proof = ipa_proof; + }; }; } // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.test.cpp index 6ca90e0c35fb..fcd41bf4c1f5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/special_public_inputs/special_public_inputs.test.cpp @@ -21,10 +21,16 @@ TEST_F(SpecialPublicInputsTests, Basic) using G1Native = Curve::GroupNative::affine_element; using FFNative = Curve::ScalarFieldNative; + static constexpr size_t NUM_WIRES = Builder::NUM_WIRES; + G1Native P0_val = G1Native::random_element(); G1Native P1_val = G1Native::random_element(); G1Native kernel_return_data_val = G1Native::random_element(); G1Native app_return_data_val = G1Native::random_element(); + std::array ecc_op_tables_val; + for (auto& commitment : ecc_op_tables_val) { + commitment = G1Native::random_element(); + } // Store the public inputs of the first circuit to be used by the second std::vector public_inputs; @@ -39,6 +45,9 @@ TEST_F(SpecialPublicInputsTests, Basic) kernel_output.pairing_inputs = pairing_inputs; kernel_output.kernel_return_data = G1::from_witness(&builder, kernel_return_data_val); kernel_output.app_return_data = G1::from_witness(&builder, app_return_data_val); + for (auto [table_commitment, table_val] : zip_view(kernel_output.ecc_op_tables, ecc_op_tables_val)) { + table_commitment = G1::from_witness(&builder, table_val); + } // Propagate the kernel output via the public inputs kernel_output.set_public(); @@ -67,6 +76,9 @@ TEST_F(SpecialPublicInputsTests, Basic) EXPECT_EQ(kernel_input.pairing_inputs.P1.get_value(), P1_val); EXPECT_EQ(kernel_input.kernel_return_data.get_value(), kernel_return_data_val); EXPECT_EQ(kernel_input.app_return_data.get_value(), app_return_data_val); + for (auto [reconstructed_commitment, commitment] : zip_view(kernel_input.ecc_op_tables, ecc_op_tables_val)) { + EXPECT_EQ(reconstructed_commitment.get_value(), commitment); + } } } @@ -227,4 +239,95 @@ TEST_F(SpecialPublicInputsTests, RollUpIO) } } +// Demonstrates the basic functionality of the HidingKernelIO class for propagating public inputs between circuits +TEST_F(SpecialPublicInputsTests, HidingKernel) +{ + using Builder = MegaCircuitBuilder; + + // IO classes + using HidingIO = HidingKernelIO; + using HidingIONative = bb::HidingKernelIO; + + // Recursive types + using Curve = HidingIO::Curve; + using G1 = HidingIO::G1; + using FF = HidingIO::FF; + using PairingInputs = HidingIO::PairingInputs; + + // Native types + using G1Native = Curve::GroupNative::affine_element; + using FFNative = Curve::ScalarFieldNative; + + static constexpr size_t NUM_WIRES = Builder::NUM_WIRES; + + G1Native P0_val = G1Native::random_element(); + G1Native P1_val = G1Native::random_element(); + std::array ecc_op_tables_val; + for (auto& commitment : ecc_op_tables_val) { + commitment = G1Native::random_element(); + } + + // Store the public inputs of the first circuit to be used by the second + std::vector public_inputs; + + { // The first circuit propagates the kernel output via its public inputs + Builder builder; + + HidingIO hiding_output; + + // Set the output values + PairingInputs pairing_inputs{ G1::from_witness(&builder, P0_val), G1::from_witness(&builder, P1_val) }; + hiding_output.pairing_inputs = pairing_inputs; + + for (auto [table_commitment, table_val] : zip_view(hiding_output.ecc_op_tables, ecc_op_tables_val)) { + table_commitment = G1::from_witness(&builder, table_val); + } + + // Propagate the kernel output via the public inputs + hiding_output.set_public(); + + // Store the public inputs from this circuit for use in the second circuit + for (const auto& idx : builder.public_inputs()) { + public_inputs.push_back(builder.get_variable(idx)); + } + } + + { + // The second circuit reconstructs the kernel inputs from the public inputs + Builder builder; + + // Construct the stdlib public inputs (e.g. as a recursive verifier would do upon receiving them in the + // proof) + std::vector stdlib_public_inputs; + stdlib_public_inputs.reserve(public_inputs.size()); + for (const auto& val : public_inputs) { + stdlib_public_inputs.push_back(FF::from_witness(&builder, val)); + } + + HidingIO hiding_input; + hiding_input.reconstruct_from_public(stdlib_public_inputs); + + // Ensure the reconstructed data matches the original values + EXPECT_EQ(hiding_input.pairing_inputs.P0.get_value(), P0_val); + EXPECT_EQ(hiding_input.pairing_inputs.P1.get_value(), P1_val); + for (auto [reconstructed_commitment, commitment] : zip_view(hiding_input.ecc_op_tables, ecc_op_tables_val)) { + EXPECT_EQ(reconstructed_commitment.get_value(), commitment); + } + } + + { + // Reconstruct the public inputs from native elements + HidingIONative hiding_input_native; + hiding_input_native.reconstruct_from_public(public_inputs); + + // Ensure the reconstructed data matches the original values + EXPECT_EQ(hiding_input_native.pairing_inputs.P0, P0_val); + EXPECT_EQ(hiding_input_native.pairing_inputs.P1, P1_val); + for (auto [reconstructed_commitment, commitment] : + zip_view(hiding_input_native.ecc_op_tables, ecc_op_tables_val)) { + EXPECT_EQ(reconstructed_commitment, commitment); + } + } +} + } // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp index 4d4c7251f206..09d0e2057124 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp @@ -510,18 +510,11 @@ void UltraCircuitBuilder_::create_balanced_add_gate(const add_qu } check_selector_length_consistency(); ++this->num_gates; - // Why 3? TODO: return to this - // The purpose of this gate is to do enable lazy 32-bit addition. - // Consider a + b = c mod 2^32 - // We want the 4th wire to represent the quotient: - // w1 + w2 = w4 * 2^32 + w3 - // If we allow this overflow 'flag' to range from 0 to 3, instead of 0 to 1, - // we can get away with chaining a few addition operations together with basic add gates, - // before having to use this gate. - // (N.B. a larger value would be better, the value '3' is for Turbo backwards compatibility. - // In Turbo this method uses a custom gate, - // where we were limited to a 2-bit range check by the degree of the custom gate identity. - create_new_range_constraint(in.d, 3); + + // Range constrain the 4-th wire to {0, 1}. Since the inputs being added never exceed (2^x - 1) + // during uintx arithmetic, we can safely use a 1-bit range check here. In other words, we do not + // allow lazy uintx addition. + create_new_range_constraint(in.d, 1); } /** * @brief Create a multiplication gate with q_m * a * b + q_3 * c + q_const = 0 @@ -1413,6 +1406,7 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S auto& block = blocks.memory; block.q_memory().emplace_back(type == MEMORY_SELECTORS::MEM_NONE ? 0 : 1); // Set to zero the selectors that are not enabled for this gate + block.q_arith().emplace_back(0); block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); @@ -1431,7 +1425,6 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S block.q_4().emplace_back(0); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1446,11 +1439,10 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S // 'read', validate adjacent values do not change Used for ROM reads and RAM reads across read/write boundaries block.q_1().emplace_back(0); block.q_2().emplace_back(0); - block.q_3().emplace_back(0); + block.q_3().emplace_back(1); block.q_4().emplace_back(0); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(1); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1466,7 +1458,6 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S block.q_4().emplace_back(1); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1483,7 +1474,6 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S block.q_4().emplace_back(0); block.q_m().emplace_back(1); // validate record witness is correctly computed block.q_c().emplace_back(0); // read/write flag stored in q_c - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1500,7 +1490,6 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S block.q_4().emplace_back(0); block.q_m().emplace_back(1); // validate record witness is correctly computed block.q_c().emplace_back(0); // read/write flag stored in q_c - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1517,7 +1506,6 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S block.q_4().emplace_back(0); block.q_m().emplace_back(1); // validate record witness is correctly computed block.q_c().emplace_back(1); // read/write flag stored in q_c - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1531,7 +1519,6 @@ void UltraCircuitBuilder_::apply_memory_selectors(const MEMORY_S block.q_4().emplace_back(0); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1570,6 +1557,7 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO auto& block = blocks.nnf; block.q_nnf().emplace_back(type == NNF_SELECTORS::NNF_NONE ? 0 : 1); // Set to zero the selectors that are not enabled for this gate + block.q_arith().emplace_back(0); block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); @@ -1584,7 +1572,6 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO block.q_4().emplace_back(1); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1598,7 +1585,6 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO block.q_4().emplace_back(0); block.q_m().emplace_back(1); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1612,7 +1598,6 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO block.q_4().emplace_back(0); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1626,7 +1611,6 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO block.q_4().emplace_back(1); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1640,7 +1624,6 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO block.q_4().emplace_back(0); block.q_m().emplace_back(1); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } @@ -1654,7 +1637,6 @@ void UltraCircuitBuilder_::apply_nnf_selectors(const NNF_SELECTO block.q_4().emplace_back(0); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { block.pad_additional(); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index f1215d2d06ea..a47d70e5564e 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -83,13 +83,15 @@ template class MegaHonkTests : public ::testing::Test { auto merge_proof = merge_prover.construct_proof(); // Construct Merge commitments - MergeVerifier::WitnessCommitments merge_commitments; + MergeVerifier::InputCommitments merge_commitments; auto t_current = op_queue->construct_current_ultra_ops_subtable_columns(); + auto T_prev = op_queue->construct_previous_ultra_ops_table_columns(); for (size_t idx = 0; idx < Flavor::NUM_WIRES; idx++) { merge_commitments.t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]); + merge_commitments.T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]); } - bool verified = merge_verifier.verify_proof(merge_proof, merge_commitments, merge_commitments.T_commitments); + auto [verified, _] = merge_verifier.verify_proof(merge_proof, merge_commitments); return verified; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp index 2090cecf4cf1..1a27f64c2c9b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_transcript.test.cpp @@ -2,7 +2,7 @@ #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/stdlib/pairing_points.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/transcript/transcript.hpp" #include "barretenberg/ultra_honk/decider_proving_key.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" @@ -36,6 +36,8 @@ template class MegaTranscriptTests : public ::testing::Test { using Commitment = typename Flavor::Commitment; TranscriptManifest manifest_expected; + size_t NUM_PUBLIC_INPUTS = + stdlib::recursion::honk::HidingKernelIO::PUBLIC_INPUTS_SIZE; size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; @@ -47,7 +49,7 @@ template class MegaTranscriptTests : public ::testing::Test { size_t round = 0; manifest_expected.add_entry(round, "vk_hash", frs_per_Fr); manifest_expected.add_entry(round, "public_input_0", frs_per_Fr); - for (size_t i = 0; i < PAIRING_POINTS_SIZE; i++) { + for (size_t i = 0; i < NUM_PUBLIC_INPUTS; i++) { manifest_expected.add_entry(round, "public_input_" + std::to_string(1 + i), frs_per_Fr); } manifest_expected.add_entry(round, "W_L", frs_per_G); @@ -174,7 +176,7 @@ template class MegaTranscriptTests : public ::testing::Test { 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) }); - stdlib::recursion::PairingPoints::add_default_to_public_inputs(builder); + stdlib::recursion::honk::HidingKernelIO::add_default(builder); } }; TYPED_TEST_SUITE(MegaTranscriptTests, FlavorTypes); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp index 20f49ec98e0e..e1f4c9095c1a 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp @@ -90,10 +90,6 @@ MergeProver::MergeProof MergeProver::construct_proof() // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove generation of commitment to T_prev // Compute commitments [T_prev], [m_j], [g_j], and send to the verifier for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - // Note: This is hacky at the moment because the prover still needs to commit to T_prev. Once we connect two - // steps of the Merge, T_prev will not be sent by the Merge prover, so the following lines will be removed - auto previous_table = settings == MergeSettings::PREPEND ? right_table[idx] : left_table[idx]; - transcript->send_to_verifier("T_PREV" + std::to_string(idx), pcs_commitment_key.commit(previous_table)); transcript->send_to_verifier("MERGED_TABLE_" + std::to_string(idx), pcs_commitment_key.commit(merged_table[idx])); transcript->send_to_verifier("LEFT_TABLE_REVERSED_" + std::to_string(idx), diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 6c93142ca94a..00271caa7321 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -55,14 +55,12 @@ MergeVerifier::MergeVerifier(const MergeSettings settings, const std::shared_ptr * - \f$l_j = T_{prev,j}, r_j = t_j, m_j = T_j\f$ if we are appending the subtable * * @param proof - * @param subtable_commitments The subtable commitments data, containing the commitments to t_j read from the transcript - * by the PG verifier with which the Merge verifier shares a transcript - * @param merged_table_commitment The commitment to the merged table as read from the proof - * @return bool Verification result + * @param inputs_commitments The commitments used by the Merge verifier + * @return std::pair Pair of verification result and the commitments to the merged tables as + * read from the proof */ -bool MergeVerifier::verify_proof(const HonkProof& proof, - const SubtableWitnessCommitments& subtable_commitments, - std::array& merged_table_commitment) +std::pair MergeVerifier::verify_proof( + const HonkProof& proof, const InputCommitments& input_commitments) { using Claims = typename ShplonkVerifier_::LinearCombinationOfClaims; @@ -75,12 +73,10 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, // The vector is composed of: [l_1], [r_1], [m_1], [g_1], ..., [l_4], [r_4], [m_4], [g_4] std::vector table_commitments; for (size_t idx = 0; idx < NUM_WIRES; ++idx) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1473): remove receiving commitment to T_prev - auto T_prev_commitment = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx)); - auto left_table = - settings == MergeSettings::PREPEND ? subtable_commitments.t_commitments[idx] : T_prev_commitment; - auto right_table = - settings == MergeSettings::PREPEND ? T_prev_commitment : subtable_commitments.t_commitments[idx]; + auto left_table = settings == MergeSettings::PREPEND ? input_commitments.t_commitments[idx] + : input_commitments.T_prev_commitments[idx]; + auto right_table = settings == MergeSettings::PREPEND ? input_commitments.T_prev_commitments[idx] + : input_commitments.t_commitments[idx]; table_commitments.emplace_back(left_table); table_commitments.emplace_back(right_table); @@ -91,8 +87,9 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, } // Store T_commitments of the verifier + TableCommitments merged_table_commitments; size_t commitment_idx = 2; // Index of [m_j = T_j] in the vector of commitments - for (auto& commitment : merged_table_commitment) { + for (auto& commitment : merged_table_commitments) { commitment = table_commitments[commitment_idx]; commitment_idx += NUM_WIRES; } @@ -161,6 +158,6 @@ bool MergeVerifier::verify_proof(const HonkProof& proof, VerifierCommitmentKey pcs_vkey{}; bool claims_verified = pcs_vkey.pairing_check(pairing_points[0], pairing_points[1]); - return degree_check_verified && claims_verified; + return { degree_check_verified && claims_verified, merged_table_commitments }; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index 364aa417f3c0..3fb4468c4c70 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -32,50 +32,25 @@ class MergeVerifier { public: using Commitment = typename Curve::AffineElement; - - std::shared_ptr transcript; - MergeSettings settings; + using TableCommitments = std::array; // Commitments to the subtables and the merged table /** - * @brief Commitments to the subtable t_j on which the Merge verifier operates - * + * Commitments used by the verifier to run the verification algorithm. They contain: + * - `t_commitments`: the subtable commitments data, containing the commitments to t_j read from the transcript by + * the PG verifier with which the Merge verifier shares a transcript + * - `T_prev_commitments`: the commitments to the full op_queue table after the previous iteration of merge */ - class SubtableWitnessCommitments { - public: - std::array t_commitments; - // std::array T_prev_commitments; - - SubtableWitnessCommitments() = default; - - /** - * @brief Set t_commitments from RefArray - * - * @param t_commitments_ref - */ - void set_t_commitments(const RefArray& t_commitments_ref) - { - for (size_t idx = 0; idx < NUM_WIRES; idx++) { - t_commitments[idx] = t_commitments_ref[idx]; - } - } + struct InputCommitments { + TableCommitments t_commitments; + TableCommitments T_prev_commitments; }; - /** - * @brief Commitments used by the Merge verifier during the protocol - * - */ - class WitnessCommitments : public SubtableWitnessCommitments { - public: - std::array T_commitments; - - WitnessCommitments() = default; - }; + std::shared_ptr transcript; + MergeSettings settings; explicit MergeVerifier(const MergeSettings settings = MergeSettings::PREPEND, const std::shared_ptr& transcript = std::make_shared()); - bool verify_proof(const HonkProof& proof, - const SubtableWitnessCommitments& subtable_commitments, - std::array& merged_table_commitment); + std::pair verify_proof(const HonkProof& proof, const InputCommitments& input_commitments); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 0ee7f6899194..ff108de41aba 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -99,17 +99,12 @@ std::pair::Commitment, Flavor:: auto [public_inputs, decider_output] = verify_internal(proof); // Reconstruct the public inputs - DefaultIO inputs; // Will be HidingKernelIO + HidingKernelIO inputs; inputs.reconstruct_from_public(public_inputs); decider_output.pairing_points.aggregate(inputs.pairing_inputs); - // Dummy vector, will be fetched from inputs once we have HidingKernelIO - std::array dummy; - for (auto& commitment : dummy) { - commitment = Commitment::one(); - } - return std::make_pair(decider_output.check(), dummy); + return std::make_pair(decider_output.check(), inputs.ecc_op_tables); } template class UltraVerifier_; diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp index 372251e4eac1..c1d64523aa14 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp @@ -7,6 +7,7 @@ #include "barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.hpp" #include "barretenberg/stdlib/hash/poseidon2/poseidon2.hpp" #include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp" +#include "barretenberg/stdlib/special_public_inputs/special_public_inputs.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" #include "barretenberg/vm2/constraining/recursion/recursive_flavor.hpp" @@ -116,8 +117,9 @@ class AvmGoblinRecursiveVerifier { using MegaRecursiveVerifier = stdlib::recursion::honk::UltraRecursiveVerifier_; using GoblinRecursiveVerifier = stdlib::recursion::honk::GoblinRecursiveVerifier; using GoblinRecursiveVerifierOutput = stdlib::recursion::honk::GoblinRecursiveVerifierOutput; - using MergeCommitments = GoblinRecursiveVerifier::MergeVerifier::WitnessCommitments; + using MergeCommitments = GoblinRecursiveVerifier::MergeVerifier::InputCommitments; using FF = MegaRecursiveFlavor::FF; + using IO = stdlib::recursion::honk::HidingKernelIO; // Construct hash buffer containing the AVM proof, public inputs, and VK std::vector hash_buffer; @@ -137,11 +139,14 @@ class AvmGoblinRecursiveVerifier { auto mega_verifier_output = mega_verifier.verify_proof(mega_proof); // Recursively verify the goblin proof\pi_G in the Ultra circuit - MergeCommitments merge_commitments; - merge_commitments.set_t_commitments(mega_verifier.key->witness_commitments.get_ecc_op_wires()); + MergeCommitments merge_commitments{ + .t_commitments = mega_verifier.key->witness_commitments.get_ecc_op_wires().get_copy(), + .T_prev_commitments = + IO::empty_ecc_op_tables(ultra_builder) // Empty ecc op tables because there is only one layer of Goblin + }; GoblinRecursiveVerifier goblin_verifier{ &ultra_builder, inner_output.goblin_vk, transcript }; GoblinRecursiveVerifierOutput goblin_verifier_output = - goblin_verifier.verify(inner_output.goblin_proof, merge_commitments, merge_commitments.T_commitments); + goblin_verifier.verify(inner_output.goblin_proof, merge_commitments); goblin_verifier_output.points_accumulator.aggregate(mega_verifier_output.points_accumulator); // Validate the consistency of the AVM2 verifier inputs {\pi, pub_inputs, VK}_{AVM2} between the inner (Mega) @@ -172,6 +177,7 @@ class AvmGoblinRecursiveVerifier { using TranslatorVK = Goblin::TranslatorVerificationKey; using MegaVerificationKey = MegaFlavor::VerificationKey; using FF = AvmRecursiveFlavor::FF; + using IO = stdlib::recursion::honk::HidingKernelIO; // Instantiate Mega builder for the inner circuit (AVM2 proof recursive verifier) Goblin goblin; @@ -208,7 +214,16 @@ class AvmGoblinRecursiveVerifier { auto stdlib_key = std::make_shared(mega_builder, std::span(key_fields)); AvmRecursiveVerifier recursive_verifier{ mega_builder, stdlib_key }; MegaPairingPoints points_accumulator = recursive_verifier.verify_proof(mega_stdlib_proof, mega_public_inputs); - points_accumulator.set_public(); + + // Public inputs + IO inputs; + inputs.pairing_inputs = points_accumulator; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1489): Can we avoid paying for these public inputs + // given that they are not used? + inputs.ecc_op_tables = + IO::default_ecc_op_tables(mega_builder); // There is only one layer of Goblin, so the verifier will set + // T_prev to the empty table and disregard this value + inputs.set_public(); // All prover components share a single transcript std::shared_ptr transcript = std::make_shared(); diff --git a/barretenberg/sol/.gitignore b/barretenberg/sol/.gitignore index 9a39bcb1ccd7..422f2b1ddac5 100644 --- a/barretenberg/sol/.gitignore +++ b/barretenberg/sol/.gitignore @@ -13,3 +13,5 @@ out/ .foundry **/build*/* + +src/honk/keys diff --git a/barretenberg/sol/src/honk/Relations.sol b/barretenberg/sol/src/honk/Relations.sol index 74a50692d10f..e0545adba69f 100644 --- a/barretenberg/sol/src/honk/Relations.sol +++ b/barretenberg/sol/src/honk/Relations.sol @@ -468,12 +468,11 @@ library RelationsLib { // Putting it all together... evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = - ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 + evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_ARITH)); // deg 3 or 9 + ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 /** * RAM Timestamp Consistency Check diff --git a/barretenberg/sol/src/honk/keys/Add2HonkVerificationKey.sol b/barretenberg/sol/src/honk/keys/Add2HonkVerificationKey.sol deleted file mode 100644 index 7acd30341d06..000000000000 --- a/barretenberg/sol/src/honk/keys/Add2HonkVerificationKey.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 Aztec -pragma solidity >=0.8.21; - -import {Honk} from "../HonkTypes.sol"; - -uint256 constant N = 4096; -uint256 constant LOG_N = 12; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 19; - -library Add2HonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { - Honk.VerificationKey memory vk = Honk.VerificationKey({ - circuitSize: uint256(4096), - logCircuitSize: uint256(12), - publicInputsSize: uint256(19), - ql: Honk.G1Point({ - x: uint256(0x0480a80b708d88511983399d7d454290cd7fc44f01efd7cd0adabac1da5209b7), - y: uint256(0x2ae668b0ee73a123a9d90f5783ad3d938b72e3c7ff79fcccab796e842df5300e) - }), - qr: Honk.G1Point({ - x: uint256(0x1e7aa9fecacfbc874d011c148d75930b51c940588e6a380e41f799f9c69cfb88), - y: uint256(0x0b9b4ac921dfc8ce57cd538fbf365383670134d46e36172ddd5e919aab0f69fe) - }), - qo: Honk.G1Point({ - x: uint256(0x146befe71bfafd7c8cacf465bc0f6dba8fdd56185107db610953dd288c8ac4ef), - y: uint256(0x1dbac6c97cd87f07224a107deaa892a4351fa3a6c66c0b546c74d9183cfcc0e2) - }), - q4: Honk.G1Point({ - x: uint256(0x25a10a105906332d55a826bc2deea34ea123efabf2bcbe0aa480f07b4afd990f), - y: uint256(0x16cfacaba0fa48b46c8872e4e1006d63269f1028e8ad6541a15e55c50109efdb) - }), - qm: Honk.G1Point({ - x: uint256(0x011aa91dcbc9f73a47cf04fbb009c601b9d38faad1fe4e2769fb68a05bb79029), - y: uint256(0x1188cea81d85d65acc2612fdbf9efe6fe3acd41065d2e31b0d20dfabd0645015) - }), - qc: Honk.G1Point({ - x: uint256(0x21d8806ac728214aef9480cd6dceaab8c9a1683787bb21423977d63da55d960c), - y: uint256(0x1e71d022986981a229c8c5285409169bf87b9d5b84027a71f29c1359ffabeac1) - }), - qLookup: Honk.G1Point({ - x: uint256(0x0073e7c223dd4f3e4734c4d9d9c9df394bd2eee2e12bac2fc49429a0443ec8b0), - y: uint256(0x20fac57db30195c2427a75a4d67231c1d1c74c8f84f009ab21d3c88e9657403d) - }), - qArith: Honk.G1Point({ - x: uint256(0x1825408d0a4ad62b99c1e6929154bad54a08a289b15dab146e2fb6fa0573a023), - y: uint256(0x141d09f0721f2b88a1916e6535ab3daa95c19a8136892c58d1ed0f77868a6df1) - }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x25e69836196abcbacfc1c9a2bf7cc19417d235d8583a345fe1df0337c86f0c28), - y: uint256(0x00125a28683d96529c25b43a56648781127e4c1aec43349a37abdb4b77598a7a) - }), - qElliptic: Honk.G1Point({ - x: uint256(0x025c989a5fbbc39a745dfa0c526d1b2c120d25144b16975f344bb8e0911f50aa), - y: uint256(0x17dcb48f840e14a56297e5e157ab5d29c1683a4f2321682c17677f325c27de6a) - }), - qMemory: Honk.G1Point({ - x: uint256(0x0e37d60ed408d667df8521cfb6c11199144f17385f52e99a2cf25aa42d5b519e), - y: uint256(0x10e512a55f0b0f6843162f54501142264e8a0b784700897fec19f0d2dc956076) - }), - qNnf: Honk.G1Point({ - x: uint256(0x0671f0554a8d6cb5ad4babb7b649e0f980cba43095f503f1089195afbef3a909), - y: uint256(0x1b00274b15fea30b24d6388f95ed6c5abf1821cf05d2f63aeaab68d29a3c0b89) - }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x1e05165b8e92a199adc11aafdf37b7fa23724206b82e0864add6d4d3ef15d891), - y: uint256(0x1490b97e14d7a87ab24c2506b31a5f1c19e519f9e46735398b7d7d3a6e8b6291) - }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x0f87e2add2aecbbb44ff4d16be602514b0c3fcbf5d33c2dc672ebe1d288060fb), - y: uint256(0x1ed340000e71abffb57d96455891648518d41edccc459afeec240ec3c2d708e6) - }), - s1: Honk.G1Point({ - x: uint256(0x264144dd89013baad68f58a7ed1bee299d3cb30cef72c74f8281e54f393f992d), - y: uint256(0x1003297e229a545f611c421bbaadf4d4997c48ef653715c33bcb5e946e00da73) - }), - s2: Honk.G1Point({ - x: uint256(0x08a84242ac40108d36e4c353a0f53137b19f6605fef5357835f1c57672127246), - y: uint256(0x1f745be60bc64aa2c8fed031e02f28fb41d7bdf195734f3cdd98540e2f27b6ea) - }), - s3: Honk.G1Point({ - x: uint256(0x19f3714d613fdb9affa560dad993f689d244e15925fa8dbf102107dd45d2e3bb), - y: uint256(0x2f039724fd4feea838c73b8317d4e43e75b81af5630fa723e2f5c474b486ea3e) - }), - s4: Honk.G1Point({ - x: uint256(0x1d9551766b9ee2591e7eb430a0b5bb52ffde35ca49de4f3de1461a24db3baebd), - y: uint256(0x2bad3f850fdace27dbee1d25cd3d8f16eb76a973e7ece72335e37d5b7c8dbfc0) - }), - t1: Honk.G1Point({ - x: uint256(0x004067623374b7c3965c7d8444b57ac2d81269c7eb3cb4f7b16568b2f8234c96), - y: uint256(0x0e605f3ad72203e21301ef1b5333cae1d8063220d1996854beb0c4fbc33bba9d) - }), - t2: Honk.G1Point({ - x: uint256(0x17aafa80bf54a7e6cc66472f9ccd70efa5044207a95191716ba0195b5a432266), - y: uint256(0x233ecaca2ddbebb0484a44e6f55b8c8614c7b5e0ce31b51d59d6b21322a307a1) - }), - t3: Honk.G1Point({ - x: uint256(0x046d00a14d5c2e99d48c85c441284b5dfef894fba87965c1c75b9a5a7cf0fdde), - y: uint256(0x2113297215872f507a7668059f801ac9877e73cb6dcab3703c5f68b404abeded) - }), - t4: Honk.G1Point({ - x: uint256(0x0765bf6645e4cf63f05d9b0efd06acebce309c685a3b05e613574ccd7316677c), - y: uint256(0x09770f145625290cdcb08bae4e6f0a26897b5988fbaf9529e0a3326bfdb537ae) - }), - id1: Honk.G1Point({ - x: uint256(0x05bfb4ce0a9f6a69fb44205a742406e8ecd6195effb821fd74673f143b8fb784), - y: uint256(0x0cb4d1ea4ff2bbae4408bf5c042142805a5c269d2e04f39bc381e217ce7b7fa5) - }), - id2: Honk.G1Point({ - x: uint256(0x046c58b359c4b8877f65d0495cbc0ad2969f90382b6440180e10dcd89f01970a), - y: uint256(0x2ad062995f3aef527ee973dd72d46e673b8cd73b21cbf1de37684c7c3b73c77a) - }), - id3: Honk.G1Point({ - x: uint256(0x0fce0505d3be8c6c68ecf25ce305177b7fe909a519e1f67b510b045d54ecda18), - y: uint256(0x1f5f0d8ea09c635fbc27e46c3c2b121fb90faa52538146856a9f9fd357f1db26) - }), - id4: Honk.G1Point({ - x: uint256(0x0a28ef915cc27e1919e69bcf92fa524511a917c343a27eed2c8ae2035b01abe3), - y: uint256(0x0687fa4d062dbaaab480c0fe76f2559b96fbd9fe62ff167986f9fe55e673e4d2) - }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) - }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x2ed6a3b223499815a89227050bc92d10c56d4c487469fe1778117a317a37ba4d), - y: uint256(0x136619e4162f7df511e48b9cf191ac91e15550db414672a7b826b14dc6f8bdf3) - }) - }); - return vk; - } -} diff --git a/barretenberg/sol/src/honk/keys/BlakeHonkVerificationKey.sol b/barretenberg/sol/src/honk/keys/BlakeHonkVerificationKey.sol deleted file mode 100644 index 243f00e17f24..000000000000 --- a/barretenberg/sol/src/honk/keys/BlakeHonkVerificationKey.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 Aztec -pragma solidity >=0.8.21; - -import {Honk} from "../HonkTypes.sol"; - -uint256 constant N = 32768; -uint256 constant LOG_N = 15; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 20; - -library BlakeHonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { - Honk.VerificationKey memory vk = Honk.VerificationKey({ - circuitSize: uint256(32768), - logCircuitSize: uint256(15), - publicInputsSize: uint256(20), - ql: Honk.G1Point({ - x: uint256(0x1dbc2d49981f1318140ca1106a52550e1c079613c92a2b23206d1504cfb2f86b), - y: uint256(0x04d743fe1aa6c0e790573ff504c0b5068b8d630459835db49d24004e0f010ad3) - }), - qr: Honk.G1Point({ - x: uint256(0x06d4bd3d2520f2a248394d32ae446f689484f908ddcf272e978d431784e205f1), - y: uint256(0x175cf52a76ee209fd0ff22a663db695c0d290b60d71138236aef5b329ab19432) - }), - qo: Honk.G1Point({ - x: uint256(0x2381d95872adb9e4f3955b2c49f978ee03b98cdb0abdf39b0968a507501c9dba), - y: uint256(0x1b008ca9ebed2b85934fb415d074922e1def59790d010bb15729d3824beea8a7) - }), - q4: Honk.G1Point({ - x: uint256(0x2f2580b9ccf05cf1b0f017e01456a6bfdafcf9b3166c576c687de3c9e3c50304), - y: uint256(0x0b371c7aab9c618ce48d244ef8356cde119972b5c40caf4a5f38ad817d448451) - }), - qm: Honk.G1Point({ - x: uint256(0x2be5953099867a3a2150e243842f051637662c71e3d7c19eb666f2dcb7d35ed6), - y: uint256(0x1400e3f66ff58817c736185766bad7b06df6fc22d6394a458e2ee79f31d14797) - }), - qc: Honk.G1Point({ - x: uint256(0x1cebfae35f0e17cea692772e1b0f64a860a185a35fe4d91d52b1e08b133ef525), - y: uint256(0x1398b2c0e75952e2614ec248b7f2002e710035f2ec026a386c1940e12203a173) - }), - qLookup: Honk.G1Point({ - x: uint256(0x2f52fd71248e5fb7fcda49e0778edcf84065f4c837dc259c99350f66d2756526), - y: uint256(0x07f7f722d2341b84f37e028a0993f9ba6eb0539524e258a6666f2149f7edba7e) - }), - qArith: Honk.G1Point({ - x: uint256(0x0a2f3de6c4da1c2f6711875e52ee30c1eb7676fe3f04dee0cbe51d8e9314968d), - y: uint256(0x1163146d3736c646b9f0d3e446b742a925732850136119397601ab9c729406ac) - }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x0f75fa9241e6b995002a5dec650dd8ee11b2c95463b42b9bfd6886d861a81dcc), - y: uint256(0x000b33ecd7762627f56dd05319f6c2a8f577d84c23736426a14a815ea240dd10) - }), - qElliptic: Honk.G1Point({ - x: uint256(0x23d68410cad93a2213d42fc11507040613f1c36376c79fc119af71f9240ddf85), - y: uint256(0x08036d4655c57be0f4c5e4165dbb99102feb96cdff2eb5c7f02358c7ce06d1ea) - }), - qMemory: Honk.G1Point({ - x: uint256(0x1133465e96ae5ca432246d0fb87ce71c0f37b36dfdf404a6c97c487242a6bf71), - y: uint256(0x1edd6fa7f5b8c58ac5bcfea2db37b96f66e55376162e9230d6b8b88f5ae04c6d) - }), - qNnf: Honk.G1Point({ - x: uint256(0x2634efbf217db5182ee476472d9a87972acb13713640fbd542b74510b53823d3), - y: uint256(0x1f4efbc506f80a69e5185539cf24ea43e3d7a416989e8d5697fe651f5b525282) - }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x1bb2a291b05e1a09d92da67dce13ecfdf4311c3a6c717ed1822331033bb535a0), - y: uint256(0x2ce5b67d60b91124c3906f07d0ce01476a3fc9cfcca33200d2aafba321b282ca) - }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x292fc33ecaeee0a93a3db74c63ecb036702ae9d9e10f115b4a41ca026748a8e9), - y: uint256(0x191404cfbc6ecde452a8dc5e2f2971948fff39018c5ccd820c8454679a299e8d) - }), - s1: Honk.G1Point({ - x: uint256(0x0a185ce3c7f2823ad60e0217165c591d0fc4743a4ffd8df74e735eb842ec37d1), - y: uint256(0x16003f72a8338960f090006eb8313aa3773a445c2dbc974e03337c0f0a643ffe) - }), - s2: Honk.G1Point({ - x: uint256(0x274cf54ae7f12682a78a2682118ef13862e8697325d1280d3758ae907238ba0c), - y: uint256(0x06114456c109ea3e28becc1819131ca5902491ccf9738f27918a92c74d5808f4) - }), - s3: Honk.G1Point({ - x: uint256(0x1860e83dbaee0d906588cc79b49323f24d983b79a9dc90bf838d8fd8d5075c74), - y: uint256(0x197f83bc73cde1744420bbfb265c78c4f97beb3f4d89c988b431a2e002dd7aad) - }), - s4: Honk.G1Point({ - x: uint256(0x3037389763af5b68ca15943e765c1a58b2a5b3ac251a9d942bf6367bf718f9ee), - y: uint256(0x0ab24e2474238a7130b1da39c972873619dc1f2cdf8719f840daaeb14c04861e) - }), - t1: Honk.G1Point({ - x: uint256(0x2d063c46ff66cce30b90a92ac814ecdb93e8f4881222ee7ce76651bf3ad54e07), - y: uint256(0x0215718164a2dbf8fc7da2fcf053b162d84e8703001218f0ad90d1f8d7526ba0) - }), - t2: Honk.G1Point({ - x: uint256(0x1bdccd1181f8c909975dd24a69fd1c26ed6e513cd237106bacd9ac5e790374f2), - y: uint256(0x1ba438e74f962c1b769f452da854110d0635d48e4d74d282ad06ae0e2830ac91) - }), - t3: Honk.G1Point({ - x: uint256(0x20d80d8e50445042431974ff13f53c27c62c17d6d2100faac252917bc2666ac1), - y: uint256(0x04bffddce3617713d52791e3344987b29b7c3359a227a03ca26857e813a84278) - }), - t4: Honk.G1Point({ - x: uint256(0x2a0724cfe33e0ee4b3f81929ef0cd1da5e113987c9aed1534cca51dae3d9bc2d), - y: uint256(0x26983a78aa5c4f3103c7e6128a32f0fae2779a6f0efb2b60facdd09153d403c9) - }), - id1: Honk.G1Point({ - x: uint256(0x036e9faa607b6e7b97aa939face171293464ea9983674c2a23dc3586cb3646a0), - y: uint256(0x1c44f59189b7da985accbd2810512c34b938f6892324326f3d8ed0445abf7cb3) - }), - id2: Honk.G1Point({ - x: uint256(0x25e2e65c5b496b09b0fbb4a4f5f26b0d7525b1c4973efcedc641052b05d1eeca), - y: uint256(0x2ebbcc2e263835cdf1d29d1381895cadf5a74583998a7e23139e04d6ef110ecb) - }), - id3: Honk.G1Point({ - x: uint256(0x28bcb49916bccb9286a5fcc44bc513ed9df38d2042335556f7d7788ca87ad268), - y: uint256(0x004daa3b3de855f9aac2dd1a04392f9c1bc9d9678b96b94705ca30361ff10c2c) - }), - id4: Honk.G1Point({ - x: uint256(0x13756493eec9a875b3984e91dd380a82db0f76ec4cd9b7f7c7393eca89525d51), - y: uint256(0x1d1d4b3d152e00a6dc81dfd10caba54e964046c86ee19e39f43f1989bbab1d03) - }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) - }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x17e0906260294d3d5c54eac5f5d339729e238f870f5e304f258cad591b9f6e8f), - y: uint256(0x10dd66d911bcc3d85f85797e451edfd1d98b78130650208c3f8cf586c9e902c4) - }) - }); - return vk; - } -} diff --git a/barretenberg/sol/src/honk/keys/EcdsaHonkVerificationKey.sol b/barretenberg/sol/src/honk/keys/EcdsaHonkVerificationKey.sol deleted file mode 100644 index 6efd5b507307..000000000000 --- a/barretenberg/sol/src/honk/keys/EcdsaHonkVerificationKey.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 Aztec -pragma solidity >=0.8.21; - -import {Honk} from "../HonkTypes.sol"; - -uint256 constant N = 65536; -uint256 constant LOG_N = 16; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 22; - -library EcdsaHonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { - Honk.VerificationKey memory vk = Honk.VerificationKey({ - circuitSize: uint256(65536), - logCircuitSize: uint256(16), - publicInputsSize: uint256(22), - ql: Honk.G1Point({ - x: uint256(0x222da11caac0ef8c8d024bcd3ce7ef9da65cba415dc078d6c1e99efb9d296476), - y: uint256(0x06b0caa4e59eeea611e3d82aa4c1be032ea48d1ebe99a2120c6b1d34ad52cad2) - }), - qr: Honk.G1Point({ - x: uint256(0x21e30ea6ddc102c69e495eb2fea0c35a5ff332e9ee84f53b8fb4631334ea43da), - y: uint256(0x1f0949f1e19f70d19120b05fd63f5a0011d7d26d8d68c5126e8f2f87f2c96640) - }), - qo: Honk.G1Point({ - x: uint256(0x195fd185370fead6c4a67e4966ee902847709ff7b9a408fe61028fe8e41a4f6c), - y: uint256(0x2b7402e6aae9acf9aa178a122329b2337628d1ac1829d4436553a292fe6ee9db) - }), - q4: Honk.G1Point({ - x: uint256(0x2d86c5fcb734347d1fe12c89a3821942ad92f3d487e5248f4679821da50992d7), - y: uint256(0x2909d7ffd3e7bbff48ec38a63b31e9871b574da7513162f7e35f2adb2188b24e) - }), - qm: Honk.G1Point({ - x: uint256(0x198c7255cce12fc3ab78a81b317e7767b3bb2da41cbe6b704f6945afb88578b4), - y: uint256(0x1dd51e2a194f4302874917d4694a80e0876b503e7aa9be663b458daac22ae850) - }), - qc: Honk.G1Point({ - x: uint256(0x0928eca70f2df77dfe083e779ac86bfc03f0e4d1eac2bf07f7726e4be44844ea), - y: uint256(0x137c94cc81fb56857d48f64c3dde2877a79f8077ce08d481a1c57d90e59f3bb8) - }), - qLookup: Honk.G1Point({ - x: uint256(0x148815ca04dbcfecb81c13d5339275f8b670d99a36d80115c6c632ad74e4bb2e), - y: uint256(0x158c91fa2cb7239b8ed4514762fdefe02bf610e31c09c1a7e483716d1c0079ea) - }), - qArith: Honk.G1Point({ - x: uint256(0x20394d5902df2484805d610fa80bbca7e88fd770d69f95cf79fe68cb7f853395), - y: uint256(0x1cc036a3c3a9ffa1e690e85a2c8559d1c353d29958ca5423f78920352ce85440) - }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x15fcc88179a42b2e971f7d5a710cd683c5704bda5b988d71694f4dac3e520950), - y: uint256(0x017ecfec3f1aa9d402f7850e540a23a008ce4bf83a137a6cc0c859ddb6bd09cd) - }), - qElliptic: Honk.G1Point({ - x: uint256(0x0cbb876b4b320f9cf4a32400a6fd7fccf62c4eb5f973a8584fe76113f575b5fb), - y: uint256(0x2a7d7e704697d287c2fca5911ed04eac8345eb96fce690c0ec0ffcd696cea904) - }), - qMemory: Honk.G1Point({ - x: uint256(0x3030d61ef1f8e59aa0a5b50d08cad060a400a52075936ccc2b697fbbd5d350b6), - y: uint256(0x0ec3fee2986ad108a8780830283539990e53b70dc4d17508e5895da68d48af67) - }), - qNnf: Honk.G1Point({ - x: uint256(0x1cdcfdd117bf90784a61d894ca2ffcd755f8d38f31e2c6a02a835ca236b3ccae), - y: uint256(0x0556fc7b9419c4278ef1075b4ef24d0e4192340e73fd68c4e1f22b5d3b6f0ad5) - }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x0503a7b85dcc9b1807cb3c47b11d210a597bf4aa37f580cf52513c60b57bd75f), - y: uint256(0x08962166fbdcf779cb4a711abb3fc45a92717ce9237557a4a425df9d026b7dba) - }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x1118e6867495ec76ad45d30034f84ad2a8276c52b6e6cd1f225ae9f6bacaab6a), - y: uint256(0x26976de8a472a7c6761b297169b71178aaaf11140893e9add1c662d6ce68821b) - }), - s1: Honk.G1Point({ - x: uint256(0x0b91942d57362b440406e9668d4bed43f45f8a17ec2d94e8bbfb9c8ed51bcea9), - y: uint256(0x06542cd207ccb494f9445828ae6391860f43822f7329691e63cff82dc00ead7e) - }), - s2: Honk.G1Point({ - x: uint256(0x1b332b3aa473a04c80a16a2fea6977f2ab7a881c8e30cee89eaee5d0914a6d9c), - y: uint256(0x00c6ec7703d857a5bc384501e3ad7f219e5b6f504e44bb39c7b7deddf33b30a8) - }), - s3: Honk.G1Point({ - x: uint256(0x034c7dd1508dcd81b35e4650227b17250e2c5f727f845e2741207f3311e17b02), - y: uint256(0x1039bbd1e98f2a1c722d4fe012b035ac19d3376dcfe65097ddbf12bd781f773d) - }), - s4: Honk.G1Point({ - x: uint256(0x1ab810653d7f51a81fafad146e590655efcf7d657f40f9296692fa8e56bf5336), - y: uint256(0x02464db62a7f96655df1a58ed700c69c637965628cf8ad88efdac0efa4c981bb) - }), - t1: Honk.G1Point({ - x: uint256(0x0b7b8581cf25a963e5ab081785d7a70504db9b8b710bd019de5be4c980a6536e), - y: uint256(0x0c9c04b32d4d51cc162b703f571ad5748859b9133c961345d71273183f2a68b2) - }), - t2: Honk.G1Point({ - x: uint256(0x2d073920df90f0f98352d5bfc545f19e9622f5fa49d82300e5afb9acb6d030fd), - y: uint256(0x0cd29f3121acf9430707827d9b0805f991402d944261e1d648d9c08c7cec5475) - }), - t3: Honk.G1Point({ - x: uint256(0x028e38bb3aa2e17472eeeb097c9d6a2fb1249523df2ff33ba582e218e9d5a526), - y: uint256(0x0407008880940dfdef132dbcb27acc00e914e1b375c4d57c08d27202f1d99198) - }), - t4: Honk.G1Point({ - x: uint256(0x1d794f2aaa0524cb1d97c2ff125061a697ec693323edcff93f0e5a59bcd2101d), - y: uint256(0x1baa78d0546b9e189379cc5a85c90293b8c30eb1e6955e421866ef4454222a92) - }), - id1: Honk.G1Point({ - x: uint256(0x186cfb4b0390d6df09d96587fdb8b69341eb8ac82804140a1788a25a96ca678e), - y: uint256(0x0140d3802bb7ae2de28fd7838813d05b7c7752e2f5e2eb8fdf1a34aa30afe8c6) - }), - id2: Honk.G1Point({ - x: uint256(0x0c9130bdb71bcb34a79801d4a7339d34cc9156df2bfc87943af350689edbcb41), - y: uint256(0x1158cd1f937b53230ae2194f98169035f6fe234cc8569b0af9968cbb18878518) - }), - id3: Honk.G1Point({ - x: uint256(0x235d4676fb2b58d1be798f994d59ecb609099f1171c13ba03c8b94e627022e0f), - y: uint256(0x17eef40d8198347905bdccb6bdf6c0a3d644f98e33d431f751309c685a01b251) - }), - id4: Honk.G1Point({ - x: uint256(0x2eb5730274f685810be70c921eabc7c21c0ac1da5d258c932f3cb13ba0df6b20), - y: uint256(0x11379118f0c18ba026b5e3771cc4b1bbec2dc7a7b91394ae6fc8017a02b0d275) - }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) - }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x014334951df29e6970601497d10be93e00634f3e9fb0378838ce51953c7cbac6), - y: uint256(0x1479a189c5e510683391e1a710ac0152b0314c11e5ac820ceab13ef611319340) - }) - }); - return vk; - } -} diff --git a/barretenberg/sol/src/honk/keys/RecursiveHonkVerificationKey.sol b/barretenberg/sol/src/honk/keys/RecursiveHonkVerificationKey.sol deleted file mode 100644 index 3ac233a12a61..000000000000 --- a/barretenberg/sol/src/honk/keys/RecursiveHonkVerificationKey.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 Aztec -pragma solidity >=0.8.21; - -import {Honk} from "../HonkTypes.sol"; - -uint256 constant N = 1048576; -uint256 constant LOG_N = 20; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 16; - -library RecursiveHonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { - Honk.VerificationKey memory vk = Honk.VerificationKey({ - circuitSize: uint256(1048576), - logCircuitSize: uint256(20), - publicInputsSize: uint256(16), - ql: Honk.G1Point({ - x: uint256(0x2d26dcedf30775b10b7b5d23a575efd46e95045fbcafedfb05e144c2aa7edf6d), - y: uint256(0x189bf6c6697af3d3a2067f655f5216cd2e97938d4797a6bfba0691fc0277fada) - }), - qr: Honk.G1Point({ - x: uint256(0x0e7c54b4edab80856f4fabea396847d9c0e0dfb108d12f7cca3f66af637e6f55), - y: uint256(0x03a2c15b0527f285aef195962b9147ca4d6e551bc514a44a2d1bcb172dc979c6) - }), - qo: Honk.G1Point({ - x: uint256(0x16f7603dff1b4de3a408ababf5c1f0cb6d681200a68b908fdae639e6f7ff4511), - y: uint256(0x155e43df56ff09f3173964d4f16102bc685f0ded024a8919cf2a89b85cabe33f) - }), - q4: Honk.G1Point({ - x: uint256(0x1959af5df227eb226bdc5b28b150e3cfe698059a0280660afea908430493014e), - y: uint256(0x00a75ddb7c78411a5ec15357c7ae6f62847d96161cfafdc7d9d669e8e0231419) - }), - qm: Honk.G1Point({ - x: uint256(0x24b9ffc894adf6cd9e7cc8b4de6fff0f0ca7f9d3a2fdf0871075ec23fd301261), - y: uint256(0x23075f89aab092a5d5b2d6642f3b3275a6181ef9ef07087ab3e0a6ea629cc540) - }), - qc: Honk.G1Point({ - x: uint256(0x1a3d885069f88956a92a8345c0646777335ca800aab1e35f317d855e99aa531c), - y: uint256(0x0c47e6336854b472d15d75d14e1585fbaaf66671bf5ca30486f0ec15b4f574c2) - }), - qLookup: Honk.G1Point({ - x: uint256(0x17c6d9d50e48678a2ac344538de4c7ece661d9ddf8d6ce71e63ee377b120f70f), - y: uint256(0x19c51b736e4c5a7d8380246160d19aad54bcdd8f21bebc775e9dfb36b9a73d45) - }), - qArith: Honk.G1Point({ - x: uint256(0x2499cdf236366c4d57c2f73086e3611506d2001765312f0a6e7781b2ff84fbd8), - y: uint256(0x2e8dc357c969714b338e6541baf9652f50b2974dfb6190d3e5da521dcdb08af9) - }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x00fbf43060f5b779c78e58b0c15e12923a62045d9d876f2cdbd0d083ef9c45f7), - y: uint256(0x1ef290eab9cc24a075994fbbe42cd68c1f2fd36950d007d99e2e61a271cf1c13) - }), - qElliptic: Honk.G1Point({ - x: uint256(0x1c26f9d337c25239c45f67a8f00754bb6aaa64a14394b2a6cf0f3c8298d93ade), - y: uint256(0x01bc640aa67f45fcc4c61c921fe40299ea3a9440f7496d20a87f3ba721afd3bd) - }), - qMemory: Honk.G1Point({ - x: uint256(0x06704e80c73d522a6c0d271d0d7be32ccf123e5c295d32eb9b01cd469320c62f), - y: uint256(0x22eaaba8da07ab035b5dd26d0707400070c1cd433378309e45000c9f13c7624f) - }), - qNnf: Honk.G1Point({ - x: uint256(0x02000475a782569f2d194386cce38a6d710be971a1a81bd8c92c404f87f05a43), - y: uint256(0x2cebd5ca539168fbef16a07b91007906d9b98c6e03fb0ad6a4a25bfe6b05d7dd) - }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x2ee773f75be2976838a34e6d82c7132f5983544e2f3db31c1dfa90bf7d47de02), - y: uint256(0x2498bf496ac37d196ca51551ec3cdc07249c6082fb6fc7d7f0dfd37a721bafda) - }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x11e082b6336724c75334ad632e19a063ab65e853a19a588a70c02032fe0a4a76), - y: uint256(0x13ebf7e86554cd89006ed3914506c6d5328068d5e06c73af401184781c4040f8) - }), - s1: Honk.G1Point({ - x: uint256(0x067dc6b4dbb9968f7928c3b498bfd76ec79b803713ca25af9ca521d2c8039707), - y: uint256(0x08ff2df2516f5723801a6cb4be752cffe45fba164234dc251981fd249a39970c) - }), - s2: Honk.G1Point({ - x: uint256(0x045c8d3b6bd01cd90f5a09ef7ea60ff0ce6495f648caeb8146ace7384830411d), - y: uint256(0x0ac548f97b9872bf3ef717610125de3ddacc7d5f7e7662b3d4ebf05d2eb1ed1d) - }), - s3: Honk.G1Point({ - x: uint256(0x0138d46260c1914f238042755e184558919a30dad7bf5801ed2400d906be3669), - y: uint256(0x133a11205297d8f4ab8f890a0e373c1d579cb06e8e8f67356c51484be8937416) - }), - s4: Honk.G1Point({ - x: uint256(0x1ef60cf15852c1c439179a1de8d6270803f387111a2532d45a8332d838570267), - y: uint256(0x2679530b38dcc0d04eb4b7b14f44ec44aa1dfb3499671a277e9214537097390f) - }), - t1: Honk.G1Point({ - x: uint256(0x1f1156b93b4396e0dac3bd312fdc94243cf3e0cfba606d27d5999f4927ff92b3), - y: uint256(0x116a7935196d39ea9178a285c53a6b419d9961d76a65ed28914ca5cc3ffd2433) - }), - t2: Honk.G1Point({ - x: uint256(0x23aebc5efc1d0e6d03030b242308fdf369409c76a0245d4f389193b554c30065), - y: uint256(0x19f38f8e7cf18f375d75db06fca92a0cbfc1214af084c189478e34dc04c77419) - }), - t3: Honk.G1Point({ - x: uint256(0x1800723660742a70c0cc9a984e30274444a587c93d9f4742a9b96cd3572365e1), - y: uint256(0x08a91d28a9c758fed327095e282375ce84640883f7755c7d95e7ccb31cdcfd4c) - }), - t4: Honk.G1Point({ - x: uint256(0x1f3bd0ebf0709ac30745d0dafb183cdd5b4a42e59fe1e447cad24659049d13a7), - y: uint256(0x05900180ddd1cec6e340c70c9bff6f16c2efd51d298fee5fce4355fc26890195) - }), - id1: Honk.G1Point({ - x: uint256(0x2bd6a3cf99e1dc7eaef20cef7f35ea393999a1d7136a044a395481b6ba11e8e3), - y: uint256(0x12641696d74551bbb1dada90b63265e871a4828d3e075a77631600fe4b925bea) - }), - id2: Honk.G1Point({ - x: uint256(0x23ead4e558c7899cf02f54cea73220ce6a5a960499f3e0b83d4ccd2123177bad), - y: uint256(0x1b006d51b0a636626605560a5eaa3e3acbe0fca9eb9c29018a20ac7ba9d0728a) - }), - id3: Honk.G1Point({ - x: uint256(0x293fb43acbd84cb4f8ea0fa4a8484f6ee56221100d6fa19b1f26d237bf02d1e5), - y: uint256(0x04ea174248f7372df94bdf7f8475551bb24db92eaedeb8c6311bfa298e7ae897) - }), - id4: Honk.G1Point({ - x: uint256(0x12ff4a53b6d2e5a175ed657c757338ceb47fef1e725f65cede468374a416f108), - y: uint256(0x2da5490444810e3fb35d5fec5c27941833a71033794492a4940ec248b492bfbd) - }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) - }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x0165fcea6ebe5211b0ff2e488af14201f2ff309861695f95625be884ab65e2da), - y: uint256(0x2a43ae04d425e180c906d436a1c57beac2c613d6f5beeb9fc35e89fd24164d14) - }) - }); - return vk; - } -}