Skip to content

Conversation

@lucasxia01
Copy link
Contributor

@lucasxia01 lucasxia01 commented Apr 21, 2025

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.

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;
Copy link
Contributor Author

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);
Copy link
Contributor Author

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
Copy link
Contributor Author

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();
Copy link
Contributor Author

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;
Copy link
Contributor Author

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

Copy link
Contributor

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) {
Copy link
Contributor Author

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?

Copy link
Contributor Author

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

Copy link
Contributor

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

// 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
Copy link
Contributor Author

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>) {
Copy link
Contributor Author

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);
}

Copy link
Contributor Author

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,
Copy link
Contributor Author

@lucasxia01 lucasxia01 Apr 23, 2025

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 };
Copy link
Contributor Author

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)
Copy link
Contributor Author

@lucasxia01 lucasxia01 Apr 23, 2025

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

Copy link
Contributor Author

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

Copy link
Contributor

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?

Copy link
Contributor

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

Copy link
Contributor Author

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;
Copy link
Contributor Author

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

Copy link
Contributor

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");
Copy link
Contributor Author

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) {
Copy link
Contributor Author

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.

Copy link
Contributor Author

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

uint32_t set_public()
{
Builder* ctx = P0.get_context();
if (ctx->contains_pairing_point_accumulator || ctx->pairing_inputs_public_input_key.is_set()) {
Copy link
Contributor Author

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

Copy link
Contributor

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

Copy link
Contributor

@ledwards2225 ledwards2225 left a 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;
Copy link
Contributor

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) {
Copy link
Contributor

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

GoblinMockCircuits::add_some_ecc_op_gates(circuit);
MockCircuits::add_arithmetic_gates(circuit);

AggregationObject::add_default_pairing_points_to_public_inputs(circuit);
Copy link
Contributor

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?

Copy link
Contributor Author

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()) {
Copy link
Contributor

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)
Copy link
Contributor

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)
Copy link
Contributor

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;
Copy link
Contributor

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'];
Copy link
Contributor

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?

Copy link
Contributor Author

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

@lucasxia01 lucasxia01 enabled auto-merge April 24, 2025 19:20
@lucasxia01 lucasxia01 added this pull request to the merge queue Apr 24, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 24, 2025
@lucasxia01 lucasxia01 added this pull request to the merge queue Apr 24, 2025
Merged via the queue into master with commit eadb87d Apr 24, 2025
7 checks passed
@lucasxia01 lucasxia01 deleted the lx/turn-on-pairing-points-client-ivc branch April 24, 2025 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants