Skip to content

Commit

Permalink
feat: update honk recursion constraint (#6545)
Browse files Browse the repository at this point in the history
Closes #933.

Updates recursion constraint for honk so that it calls the ultra honk
recursive verifier.
Removes key hash from the constraint. Also recursively aggregates the
aggregation objects.

Ignores the case where we don't have the witness values and want to use
dummy witnesses.
  • Loading branch information
lucasxia01 authored and AztecBot committed May 29, 2024
1 parent 339b703 commit 72efb12
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 414 deletions.
2 changes: 2 additions & 0 deletions cpp/src/barretenberg/dsl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ barretenberg_module(
stdlib_poseidon2
crypto_merkle_tree
stdlib_schnorr
ultra_honk
stdlib_honk_recursion
)
51 changes: 15 additions & 36 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,53 +222,32 @@ void build_constraints(Builder& builder,
// These are set and modified whenever we encounter a recursion opcode
//
// These should not be set by the caller
// TODO(maxim): Check if this is always the case. ie I won't receive a proof that will set the first
// TODO(maxim): input_aggregation_object to be non-zero.
// TODO(maxim): if not, we can add input_aggregation_object to the proof too for all recursive proofs
// TODO(maxim): This might be the case for proof trees where the proofs are created on different machines
// TODO(https://github.com/AztecProtocol/barretenberg/issues/996): this usage of all zeros is a hack and could
// use types or enums to properly fix.
std::array<uint32_t, HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE> current_aggregation_object = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

// Get the size of proof with no public inputs prepended to it
// This is used while processing recursion constraints to determine whether
// the proof we are verifying contains a recursive proof itself
auto proof_size_no_pub_inputs = recursion_honk_proof_size_without_public_inputs();

// Add recursion constraints
for (auto constraint : constraint_system.honk_recursion_constraints) {
// A proof passed into the constraint should be stripped of its public inputs, except in the case where a
// proof contains an aggregation object itself. We refer to this as the `nested_aggregation_object`. The
// verifier circuit requires that the indices to a nested proof aggregation state are a circuit constant.
// The user tells us they how they want these constants set by keeping the nested aggregation object
// attached to the proof as public inputs. As this is the only object that can prepended to the proof if the
// proof is above the expected size (with public inputs stripped)
// A proof passed into the constraint should be stripped of its inner public inputs, but not the nested
// aggregation object itself. The verifier circuit requires that the indices to a nested proof aggregation
// state are a circuit constant. The user tells us they how they want these constants set by keeping the
// nested aggregation object attached to the proof as public inputs.
std::array<uint32_t, HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE> nested_aggregation_object = {};
// If the proof has public inputs attached to it, we should handle setting the nested aggregation object
// The public inputs attached to a proof should match the aggregation object in size
if (constraint.proof.size() - proof_size_no_pub_inputs !=
HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE) {
auto error_string = format(
"Public inputs are always stripped from proofs unless we have a recursive proof.\n"
"Thus, public inputs attached to a proof must match the recursive aggregation object in size "
"which is ",
HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE);
throw_or_abort(error_string);
}
for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) {
// Set the nested aggregation object indices to the current size of the public inputs
// This way we know that the nested aggregation object indices will always be the last
// indices of the public inputs
nested_aggregation_object[i] = static_cast<uint32_t>(constraint.public_inputs.size());
// Attach the nested aggregation object to the end of the public inputs to fill in
// the slot where the nested aggregation object index will point into
constraint.public_inputs.emplace_back(constraint.proof[i]);
// Set the nested aggregation object indices to witness indices from the proof
nested_aggregation_object[i] =
static_cast<uint32_t>(constraint.proof[HonkRecursionConstraint::inner_public_input_offset + i]);
// Adding the nested aggregation object to the constraint's public inputs
constraint.public_inputs.emplace_back(nested_aggregation_object[i]);
}
// Remove the aggregation object so that they can be handled as normal public inputs
// in they way taht the recursion constraint expects
constraint.proof.erase(constraint.proof.begin(),
// in they way that the recursion constraint expects
constraint.proof.erase(constraint.proof.begin() + HonkRecursionConstraint::inner_public_input_offset,
constraint.proof.begin() +
static_cast<std::ptrdiff_t>(HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE));
static_cast<std::ptrdiff_t>(HonkRecursionConstraint::inner_public_input_offset +
HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE));
current_aggregation_object = create_honk_recursion_constraints(builder,
constraint,
current_aggregation_object,
Expand Down
Loading

0 comments on commit 72efb12

Please sign in to comment.