-
Notifications
You must be signed in to change notification settings - Fork 580
feat: Add pairing points for all Honk circuits #13701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…points-client-ivc
| const size_t num_public_inputs_in_final_circuit = get_num_public_inputs_in_final_circuit(input_path); | ||
| info("num_public_inputs_in_final_circuit: ", num_public_inputs_in_final_circuit); | ||
| // MAGIC_NUMBER is bb::PAIRING_POINT_ACCUMULATOR_SIZE or bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE | ||
| static constexpr size_t MAGIC_NUMBER = 16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this hack is not needed
| a = b * b; | ||
| b = c * c; | ||
| } | ||
| stdlib::recursion::aggregation_state<Builder>::add_default_pairing_points_to_public_inputs(builder); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some circuit generation functions will have add_default_pairing_points_to_public_inputs like this one. Unfortunately, for ease, I didn't opt for always excluding them from these kind of functions, so there are also functions which don't have this
| decider_vk->public_inputs, | ||
| decider_vk->verification_key->databus_propagation_data); | ||
|
|
||
| // WORKTODO: extract agg obj from the decider_vk->public_inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do in followup
| current_aggregation_object = perform_recursive_verification_and_databus_consistency_checks( | ||
| circuit, verifier_input, current_aggregation_object); | ||
| } | ||
| current_aggregation_object.set_public(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one of the core changes was to set the agg obj public here
| using namespace bb; | ||
|
|
||
| static constexpr size_t MAX_NUM_KERNELS = 17; | ||
| static constexpr size_t MAX_NUM_KERNELS = 16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
had to decrease this unfortunately, not sure of its effects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be any immediate effect because we dont test anything pushing this limit
| { | ||
| ClientCircuit circuit{ ivc.goblin.op_queue }; | ||
| circuit = create_mock_circuit(ivc, log2_num_gates); // construct mock base logic | ||
| if (is_kernel) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should come after the inner public inputs get added. not sure how things were passing before, maybe the databus stuff is broken?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe we only use this in circuits where the databus is ignored
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the databus shouldnt ever be ignored so its hard to say
barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp
Outdated
Show resolved
Hide resolved
| // default one if the circuit is recursive and honk_recursion is true. | ||
| if (!constraint_system.honk_recursion_constraints.empty() || | ||
| !constraint_system.avm_recursion_constraints.empty()) { | ||
| // TODO(https://github.com/AztecProtocol/barretenberg/issues/1336): Delete this if statement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this part of the code is only reached if its UltraBuilder, so the if is useless
| } | ||
|
|
||
| // Accumulate the IPA claims and set it to be public inputs | ||
| if constexpr (IsUltraBuilder<Builder>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, the if is useless
| process_ivc_recursion_constraints( | ||
| builder, constraint_system, metadata.ivc, has_valid_witness_assignments, gate_counter); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code checks that we don't have both honk_recursion_constraints and ivc_recursion_constraints.
It also will add a default pairing point object for any circuit that doesn't set one through the recursion constraints.
| .busread = 3, | ||
| .lookup = 2, | ||
| .pub_inputs = 1, | ||
| .pub_inputs = 20, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needed to increase this to accommodate for agg obj
| [[maybe_unused]] auto merge_pairing_points = merge_verifier.verify_proof(stdlib_merge_proof); | ||
| return { opening_claim, ipa_transcript }; | ||
| auto merge_pairing_points = merge_verifier.verify_proof(stdlib_merge_proof); | ||
| return { merge_pairing_points, opening_claim, ipa_transcript }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getting ahead of myself
| * @param recursion_separator | ||
| */ | ||
| void aggregate(aggregation_state const& other, typename Curve::ScalarField recursion_separator) | ||
| void aggregate(aggregation_state const& other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved the recursion_separator generation into the aggregate call itself since I think we'll just generate a new one every time. The cost shouldn't be too bad since its just 70 for a hash and we do very few aggregates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, maybe it would be cheaper to batch the aggregation over several points but idk if it matters too much with goblin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this mean we eventually have to pass the transcript into this method once we're generating the challenge correctly though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that's the right separation of concerns if so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, there shouldn't be a need to pass in a transcript. To properly generate this challenge, we won't be using the same Transcript as the recursive verifier. In fact, we don't need to use a Transcript at all since this isn't even a verifier challenge - it's a "random" separator to linearly combine the points with. We really only need to call some hash function to generate it, and the Transcript is a way to easily do that.
| // Kernel return data is the first public input, followed by app return data | ||
| data.kernel_return_data_commitment_pub_input_key.start_idx = 0; | ||
| data.app_return_data_commitment_pub_input_key.start_idx = 8; | ||
| data.kernel_return_data_commitment_pub_input_key.start_idx = PAIRING_POINT_ACCUMULATOR_SIZE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
had to update this to fix a vk comparison test, but we definitely some better fix than randomly updating constants
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is bad, would you mind spinning up an issue for this?
| proving_key.ipa_proof = circuit.ipa_proof; | ||
| } | ||
| // Set the pairing point accumulator indices | ||
| ASSERT(circuit.contains_pairing_point_accumulator && "Honk circuit must output a pairing point accumulator"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core change: check that we set a pairing point accumulator
| uint32_t set_public() | ||
| { | ||
| Builder* ctx = P0.get_context(); | ||
| if (ctx->contains_pairing_point_accumulator) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core change: check that we don't set 2 pairing point objects to be public inputs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait, this is now wrong as this is a plonk only thing oops
…ecProtocol/aztec-packages into lx/turn-on-pairing-points-client-ivc
…points-client-ivc
| uint32_t set_public() | ||
| { | ||
| Builder* ctx = P0.get_context(); | ||
| if (ctx->contains_pairing_point_accumulator || ctx->pairing_inputs_public_input_key.is_set()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core change: check that we don't set this before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can remove the contains_pairing_point_accumulator check from this conditional, its not used for Honk. Unless this is giving us something useful for plonk but I didnt think set_public was used there
ledwards2225
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG, just a few comments/things to consider
| using namespace bb; | ||
|
|
||
| static constexpr size_t MAX_NUM_KERNELS = 17; | ||
| static constexpr size_t MAX_NUM_KERNELS = 16; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be any immediate effect because we dont test anything pushing this limit
| { | ||
| ClientCircuit circuit{ ivc.goblin.op_queue }; | ||
| circuit = create_mock_circuit(ivc, log2_num_gates); // construct mock base logic | ||
| if (is_kernel) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the databus shouldnt ever be ignored so its hard to say
barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp
Outdated
Show resolved
Hide resolved
| GoblinMockCircuits::add_some_ecc_op_gates(circuit); | ||
| MockCircuits::add_arithmetic_gates(circuit); | ||
|
|
||
| AggregationObject::add_default_pairing_points_to_public_inputs(circuit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to just do this defaulting in circuit finalization instead of in all these individual places? Would that cause issues somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed on slack - it seems possible but would require some ugly code to do so (manual variable instantiation with a lot of random-looking constants). Maybe its still a better pattern than adding this line everywhere.
Another minor issue with this idea is that it would allow for more circuits to silently forget the pairing points, whereas you MUST address them in this current format, either through a set_public() call or a add_default_pairing_points_to_public_inputs() call.
| uint32_t set_public() | ||
| { | ||
| Builder* ctx = P0.get_context(); | ||
| if (ctx->contains_pairing_point_accumulator || ctx->pairing_inputs_public_input_key.is_set()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can remove the contains_pairing_point_accumulator check from this conditional, its not used for Honk. Unless this is giving us something useful for plonk but I didnt think set_public was used there
| * @param recursion_separator | ||
| */ | ||
| void aggregate(aggregation_state const& other, typename Curve::ScalarField recursion_separator) | ||
| void aggregate(aggregation_state const& other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this mean we eventually have to pass the transcript into this method once we're generating the challenge correctly though?
| * @param recursion_separator | ||
| */ | ||
| void aggregate(aggregation_state const& other, typename Curve::ScalarField recursion_separator) | ||
| void aggregate(aggregation_state const& other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that's the right separation of concerns if so
| // Kernel return data is the first public input, followed by app return data | ||
| data.kernel_return_data_commitment_pub_input_key.start_idx = 0; | ||
| data.app_return_data_commitment_pub_input_key.start_idx = 8; | ||
| data.kernel_return_data_commitment_pub_input_key.start_idx = PAIRING_POINT_ACCUMULATOR_SIZE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is bad, would you mind spinning up an issue for this?
|
|
||
| try { | ||
| const args = ['--scheme', 'client_ivc', '-p', proofPath, '-k', keyPath]; | ||
| const args = ['--scheme', 'client_ivc', '-p', proofPath, '-k', keyPath, '-v']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this intended to stay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it shouldn't hurt. We already have -v in the arguments for prove
We add a couple of checks to enforce that honk circuits add exactly ONE pairing point object to its public outputs. The first check is in the DeciderProvingKey constructor, which all flows use to create the proving key from the circuit, and it checks that the pairing point object has been set in the builder. The second check happens in the aggregation_state itself, where if we try to call set_public() and the builder already has one set, it will throw an error.
These checks require us to add pairing point objects to a lot of different tests and also move around some of the logic to more proper positions (like from accumulate() to complete_kernel_circuit_logic()). Previously, we had varying amounts of pairing point objects for Mega circuits, but now that shouldn't be the case.