-
Notifications
You must be signed in to change notification settings - Fork 325
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
feat: unify all acir recursion constraints based on RecursionConstraint and proof_type #7993
Changes from 16 commits
8110a60
04ea98f
1730d04
758d6a4
745099d
a58f2ca
4856474
8c009ee
49adb68
8625ba0
3154647
1bfa5cc
ae5936f
c8c9de9
ed01ea6
1ef5048
8a18513
60fb90f
cb3353b
4704c64
4e75b87
0404933
44b20e0
88e26f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -543,4 +543,26 @@ TEST_F(AcirIntegrationTest, DISABLED_UpdateAcirCircuit) | |
EXPECT_TRUE(prove_and_verify_honk<Flavor>(circuit)); | ||
} | ||
|
||
/** | ||
* @brief Test recursive honk recursive verification | ||
* | ||
*/ | ||
TEST_F(AcirIntegrationTest, DISABLED_HonkRecursion) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just a convenient way to debug honk recursion without getting |
||
{ | ||
using Flavor = UltraFlavor; | ||
using Builder = Flavor::CircuitBuilder; | ||
|
||
std::string test_name = "verify_honk_proof"; // arbitrary program with RAM gates | ||
auto acir_program = get_program_data_from_test_file( | ||
test_name, | ||
/*honk_recursion=*/false); // WORKTODO: TODO(https://github.com/AztecProtocol/barretenberg/issues/1013): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this false here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its false because with this new pattern, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added a comment to this effect |
||
// Assumes Flavor is not UltraHonk | ||
|
||
// Construct a bberg circuit from the acir representation | ||
auto circuit = acir_format::create_circuit<Builder>(acir_program.constraints, 0, acir_program.witness); | ||
|
||
EXPECT_TRUE(CircuitChecker::check(circuit)); | ||
EXPECT_TRUE(prove_and_verify_honk<Flavor>(circuit)); | ||
} | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -415,27 +415,35 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, | |||
}); | ||||
af.original_opcode_indices.keccak_permutations.push_back(opcode_index); | ||||
} else if constexpr (std::is_same_v<T, Program::BlackBoxFuncCall::RecursiveAggregation>) { | ||||
if (honk_recursion) { // if we're using the honk recursive verifier | ||||
auto c = HonkRecursionConstraint{ | ||||
.key = map(arg.verification_key, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.proof = map(arg.proof, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.public_inputs = | ||||
map(arg.public_inputs, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
}; | ||||
|
||||
auto input_key = get_witness_from_function_input(arg.key_hash); | ||||
|
||||
auto proof_type_in = arg.proof_type; | ||||
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1074): Eventually arg.proof_type will be | ||||
// the only means for setting the proof type. use of honk_recursion flag in this context can go away | ||||
// once all noir programs (e.g. protocol circuits) are updated to use the new pattern. | ||||
if (honk_recursion && proof_type_in != HONK_RECURSION) { | ||||
// info("WARNING: Recursion type is not being specified correctly via noir verify_proof()!"); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having prints here seemed to make the gate_counts tests on CI complain? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was suggesting to delete this as I was surprised to see it left here with no comment |
||||
proof_type_in = HONK_RECURSION; | ||||
} | ||||
|
||||
auto c = RecursionConstraint{ | ||||
.key = map(arg.verification_key, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.proof = map(arg.proof, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.public_inputs = map(arg.public_inputs, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.key_hash = input_key, | ||||
.proof_type = proof_type_in, | ||||
}; | ||||
// Add the recursion constraint to the appropriate container based on proof type | ||||
if (c.proof_type == PLONK_RECURSION) { | ||||
af.recursion_constraints.push_back(c); | ||||
af.original_opcode_indices.recursion_constraints.push_back(opcode_index); | ||||
} else if (c.proof_type == HONK_RECURSION) { | ||||
af.honk_recursion_constraints.push_back(c); | ||||
af.original_opcode_indices.honk_recursion_constraints.push_back(opcode_index); | ||||
} else { | ||||
auto input_key = get_witness_from_function_input(arg.key_hash); | ||||
|
||||
auto c = RecursionConstraint{ | ||||
.key = map(arg.verification_key, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.proof = map(arg.proof, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.public_inputs = | ||||
map(arg.public_inputs, [](auto& e) { return get_witness_from_function_input(e); }), | ||||
.key_hash = input_key, | ||||
}; | ||||
af.recursion_constraints.push_back(c); | ||||
af.original_opcode_indices.recursion_constraints.push_back(opcode_index); | ||||
info("Invalid PROOF_TYPE in RecursionConstraint!"); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: could probably print the valid proof types here vs. what was specified but this is a nit and can come later. In general, before moving to honk as the main public facing backend for noir we probably need to improve some of the error messages There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll leave this one for a follow on since I'll be touching this code a lot in coming weeks |
||||
ASSERT(false); | ||||
} | ||||
} else if constexpr (std::is_same_v<T, Program::BlackBoxFuncCall::BigIntFromLeBytes>) { | ||||
af.bigint_from_le_bytes_constraints.push_back(BigIntFromLeBytes{ | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
#pragma once | ||
#include "barretenberg/dsl/acir_format/recursion_constraint.hpp" | ||
#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" | ||
#include <vector> | ||
|
||
|
@@ -7,55 +8,12 @@ using Builder = bb::UltraCircuitBuilder; | |
|
||
using namespace bb; | ||
|
||
/** | ||
* @brief HonkRecursionConstraint struct contains information required to recursively verify a proof! | ||
* | ||
* @details The recursive verifier algorithm produces an 'aggregation object' representing 2 G1 points, expressed as 16 | ||
* witness values. The smart contract Verifier must be aware of this aggregation object in order to complete the full | ||
* recursive verification. If the circuit verifies more than 1 proof, the recursion algorithm will update a pre-existing | ||
* aggregation object (`input_aggregation_object`). | ||
* | ||
* @details We currently require that the inner circuit being verified only has a single public input. If more are | ||
* required, the outer circuit can hash them down to 1 input. | ||
* | ||
* @param verification_key_data The inner circuit vkey. Is converted into circuit witness values (internal to the | ||
* backend) | ||
* @param proof The honk proof. Is converted into circuit witness values (internal to the backend) | ||
* @param is_aggregation_object_nonzero A flag to tell us whether the circuit has already recursively verified proofs | ||
* (and therefore an aggregation object is present) | ||
* @param public_input The index of the single public input | ||
* @param input_aggregation_object Witness indices of pre-existing aggregation object (if it exists) | ||
* @param output_aggregation_object Witness indices of the aggregation object produced by recursive verification | ||
* @param nested_aggregation_object Public input indices of an aggregation object inside the proof. | ||
* | ||
* @note If input_aggregation_object witness indices are all zero, we interpret this to mean that the inner proof does | ||
* NOT contain a previously recursively verified proof | ||
* @note nested_aggregation_object is used for cases where the proof being verified contains an aggregation object in | ||
* its public inputs! If this is the case, we record the public input locations in `nested_aggregation_object`. If the | ||
* inner proof is of a circuit that does not have a nested aggregation object, these values are all zero. | ||
* | ||
* To outline the interaction between the input_aggergation_object and the nested_aggregation_object take the following | ||
* example: If we have a circuit that verifies 2 proofs A and B, the recursion constraint for B will have an | ||
* input_aggregation_object that points to the aggregation output produced by verifying A. If circuit B also verifies a | ||
* proof, in the above example the recursion constraint for verifying B will have a nested object that describes the | ||
* aggregation object in B’s public inputs as well as an input aggregation object that points to the object produced by | ||
* the previous recursion constraint in the circuit (the one that verifies A) | ||
* | ||
* TODO(https://github.com/AztecProtocol/barretenberg/issues/996): Update these comments for Honk. | ||
*/ | ||
struct HonkRecursionConstraint { | ||
// In Honk, the proof starts with circuit_size, num_public_inputs, and pub_input_offset. We use this offset to keep | ||
// track of where the public inputs start. | ||
static constexpr size_t inner_public_input_offset = 3; | ||
std::vector<uint32_t> key; | ||
std::vector<uint32_t> proof; | ||
std::vector<uint32_t> public_inputs; | ||
|
||
friend bool operator==(HonkRecursionConstraint const& lhs, HonkRecursionConstraint const& rhs) = default; | ||
}; | ||
// In Honk, the proof starts with circuit_size, num_public_inputs, and pub_input_offset. We use this offset to keep | ||
// track of where the public inputs start. | ||
static constexpr size_t HONK_RECURSION_PUBLIC_INPUT_OFFSET = 3; | ||
|
||
AggregationObjectIndices create_honk_recursion_constraints(Builder& builder, | ||
const HonkRecursionConstraint& input, | ||
const RecursionConstraint& input, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should add an assert in this function that it's actually taking in a honk recursion constraint There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good idea. added |
||
AggregationObjectIndices input_aggregation_object, | ||
bool has_valid_witness_assignments = false); | ||
|
||
|
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.
Eventually we can probably move to a model where there is only one vector of
RecursionConstraint
s and they are handled accordingly based onproof_type
but that's going to require a larger refactor and I've already strayed a bit from the original intent of this PR :)