Skip to content
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

chore!: cleanup recursion interface #3528

Merged
merged 18 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b4d82ff
add comment about `add_recursive_proof` being suspicious
kevaundray Dec 3, 2023
ac146a4
create and process input_aggregation object and output_aggregation_ob…
kevaundray Dec 3, 2023
92e247d
`create_recursion_constraints` now takes in the input and nested aggr…
kevaundray Dec 3, 2023
f36661d
add comment on removing the is_recursive flag
kevaundray Dec 3, 2023
738fb17
modify `create_recursion_constraints` to append the public inputs to …
kevaundray Dec 3, 2023
cab6ef6
update double_verify_proof program
kevaundray Dec 3, 2023
7a4e9be
update double_verify_proof
kevaundray Dec 3, 2023
7acd611
fix: set input_aggregation for next iteration
kevaundray Dec 3, 2023
a85ba41
fix: remove public inputs from proof
kevaundray Dec 3, 2023
c11d812
set the public input values for the inner circuit in tests
kevaundray Dec 4, 2023
c589331
fix: remove output aggregation being set as public input twice
kevaundray Dec 4, 2023
40eaf29
Merge branch 'master' into kw/modify-recursion-interface
kevaundray Dec 4, 2023
19ae424
Merge branch 'master' into kw/modify-recursion-interface
kevaundray Dec 5, 2023
d0065a3
Merge branch 'master' into kw/modify-recursion-interface
kevaundray Dec 7, 2023
12baf28
Merge branch 'master' into kw/modify-recursion-interface
kevaundray Dec 9, 2023
50666b8
Merge branch 'master' into kw/modify-recursion-interface
kevaundray Dec 16, 2023
ebcdc29
Update noir/test_programs/execution_success/double_verify_proof/src/m…
kevaundray Dec 18, 2023
e8aec35
Merge branch 'master' into kw/modify-recursion-interface
kevaundray Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "acir_format.hpp"
#include "barretenberg/common/log.hpp"
#include "barretenberg/dsl/acir_format/pedersen.hpp"
#include "barretenberg/dsl/acir_format/recursion_constraint.hpp"

namespace acir_format {

Expand Down Expand Up @@ -103,19 +104,47 @@ void build_constraints(Builder& builder, acir_format const& constraint_system, b
create_block_constraints(builder, constraint, has_valid_witness_assignments);
}

// These are set and modified whenever we encounter a recursion opcode
//
// These should not be set by the caller
// TODO: Check if this is always the case. ie I won't receive a proof that will set the first
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
// TODO input_aggregation_object to be non-zero.
// TODO: if not, we can add input_aggregation_object to the proof too for all recursive proofs
// TODO: This might be the case for proof trees where the proofs are created on different machines
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> current_input_aggregation_object = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> current_output_aggregation_object = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

// Add recursion constraints
for (size_t i = 0; i < constraint_system.recursion_constraints.size(); ++i) {
auto& constraint = constraint_system.recursion_constraints[i];
create_recursion_constraints(builder, constraint, has_valid_witness_assignments);

// make sure the verification key records the public input indices of the final recursion output
// (N.B. up to the ACIR description to make sure that the final output aggregation object wires are public
// inputs!)
if (i == constraint_system.recursion_constraints.size() - 1) {
std::vector<uint32_t> proof_output_witness_indices(constraint.output_aggregation_object.begin(),
constraint.output_aggregation_object.end());
builder.set_recursive_proof(proof_output_witness_indices);
current_output_aggregation_object = create_recursion_constraints(builder,
constraint,
current_input_aggregation_object,
constraint.nested_aggregation_object,
has_valid_witness_assignments);
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
current_input_aggregation_object = current_output_aggregation_object;
}

// Now that the circuit has been completely built, we add the output aggregation as public
// inputs.
if (!constraint_system.recursion_constraints.empty()) {

// First add the output aggregation object as public inputs
// Set the indices as public inputs because they are no longer being
// created in ACIR
for (const auto& idx : current_output_aggregation_object) {
builder.set_public_input(idx);
}

// Make sure the verification key records the public input indices of the
// final recursion output.
std::vector<uint32_t> proof_output_witness_indices(current_output_aggregation_object.begin(),
current_output_aggregation_object.end());
builder.set_recursive_proof(proof_output_witness_indices);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "barretenberg/plonk/transcript/transcript_wrappers.hpp"
#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp"
#include "barretenberg/stdlib/recursion/verifier/verifier.hpp"
#include <cstddef>

namespace acir_format {

Expand All @@ -28,11 +29,19 @@ void generate_dummy_proof() {}
* We would either need a separate ACIR opcode where inner_proof_contains_recursive_proof = true,
* or we need non-witness data to be provided as metadata in the ACIR opcode
*/
void create_recursion_constraints(Builder& builder,
const RecursionConstraint& input,
bool has_valid_witness_assignments)
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> create_recursion_constraints(
Builder& builder,
const RecursionConstraint& input,
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> input_aggregation_object,
// TODO: does this need to be a part of the recursion opcode?
// TODO: or can we figure it out from the vk?
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
// TODO: either way we could probably have the user explicitly provide it
// TODO: in Noir.
// Note: this is not being used in Noir at the moment
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> nested_aggregation_object,
bool has_valid_witness_assignments)
{
const auto& nested_aggregation_indices = input.nested_aggregation_object;
const auto& nested_aggregation_indices = nested_aggregation_object;
bool nested_aggregation_indices_all_zero = true;
for (const auto& idx : nested_aggregation_indices) {
nested_aggregation_indices_all_zero &= (idx == 0);
Expand All @@ -46,8 +55,12 @@ void create_recursion_constraints(Builder& builder,
const std::vector<fr> dummy_key = export_dummy_key_in_recursion_format(
PolynomialManifest(Builder::CIRCUIT_TYPE), inner_proof_contains_recursive_proof);
const auto manifest = Composer::create_manifest(input.public_inputs.size());
const std::vector<barretenberg::fr> dummy_proof =
std::vector<barretenberg::fr> dummy_proof =
export_dummy_transcript_in_recursion_format(manifest, inner_proof_contains_recursive_proof);

// Remove the public inputs from the dummy proof
dummy_proof.erase(dummy_proof.begin(),
dummy_proof.begin() + static_cast<std::ptrdiff_t>(input.public_inputs.size()));
for (size_t i = 0; i < input.proof.size(); ++i) {
const auto proof_field_idx = input.proof[i];
// if we do NOT have a witness assignment (i.e. are just building the proving/verification keys),
Expand All @@ -73,7 +86,7 @@ void create_recursion_constraints(Builder& builder,
// Construct an in-circuit representation of the verification key.
// For now, the v-key is a circuit constant and is fixed for the circuit.
// (We may need a separate recursion opcode for this to vary, or add more config witnesses to this opcode)
const auto& aggregation_input = input.input_aggregation_object;
const auto& aggregation_input = input_aggregation_object;
aggregation_state_ct previous_aggregation;

// If we have previously recursively verified proofs, `is_aggregation_object_nonzero = true`
Expand Down Expand Up @@ -112,7 +125,13 @@ void create_recursion_constraints(Builder& builder,
}

std::vector<field_ct> proof_fields;
proof_fields.reserve(input.proof.size());
// Prepend the public inputs to the proof fields because this is how the
// core barretenberg library processes proofs (with the public inputs first and not separated)
proof_fields.reserve(input.proof.size() + input.public_inputs.size());
for (const auto& idx : input.public_inputs) {
auto field = field_ct::from_witness_index(&builder, idx);
proof_fields.emplace_back(field);
}
for (const auto& idx : input.proof) {
auto field = field_ct::from_witness_index(&builder, idx);
proof_fields.emplace_back(field);
Expand All @@ -136,12 +155,14 @@ void create_recursion_constraints(Builder& builder,
result.public_inputs[i].assert_equal(field_ct::from_witness_index(&builder, input.public_inputs[i]));
}

// Assign the recursive proof outputs to `output_aggregation_object`
for (size_t i = 0; i < result.proof_witness_indices.size(); ++i) {
const auto lhs = field_ct::from_witness_index(&builder, result.proof_witness_indices[i]);
const auto rhs = field_ct::from_witness_index(&builder, input.output_aggregation_object[i]);
lhs.assert_equal(rhs);
}
// We want to return an array, so just copy the vector into the array
ASSERT(result.proof_witness_indices.size() == RecursionConstraint::AGGREGATION_OBJECT_SIZE);
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> resulting_output_aggregation_object;
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
std::copy(result.proof_witness_indices.begin(),
result.proof_witness_indices.begin() + RecursionConstraint::AGGREGATION_OBJECT_SIZE,
resulting_output_aggregation_object.begin());

return resulting_output_aggregation_object;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,24 @@ struct RecursionConstraint {
std::vector<uint32_t> proof;
std::vector<uint32_t> public_inputs;
uint32_t key_hash;
// TODO:This is now unused, but we keep it here for backwards compatibility
std::array<uint32_t, AGGREGATION_OBJECT_SIZE> input_aggregation_object;
// TODO: This is now unused, but we keep it here for backwards compatibility
std::array<uint32_t, AGGREGATION_OBJECT_SIZE> output_aggregation_object;
// TODO: This is currently not being used on the Noir level at all
// TODO: we don't have a way to specify that the proof we are creating contains a
// TODO: aggregation object (ie it is also verifying a proof)
std::array<uint32_t, AGGREGATION_OBJECT_SIZE> nested_aggregation_object;
kevaundray marked this conversation as resolved.
Show resolved Hide resolved

friend bool operator==(RecursionConstraint const& lhs, RecursionConstraint const& rhs) = default;
};

void create_recursion_constraints(Builder& builder,
const RecursionConstraint& input,
bool has_valid_witness_assignments = false);
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> create_recursion_constraints(
Builder& builder,
const RecursionConstraint& input,
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> input_aggregation_object,
std::array<uint32_t, RecursionConstraint::AGGREGATION_OBJECT_SIZE> nested_aggregation_object,
bool has_valid_witness_assignments = false);

std::vector<barretenberg::fr> export_key_in_recursion_format(std::shared_ptr<verification_key> const& vkey);
std::vector<barretenberg::fr> export_dummy_key_in_recursion_format(const PolynomialManifest& polynomial_manifest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,15 @@ Builder create_outer_circuit(std::vector<Builder>& inner_circuits)
transcript::HashType::PedersenBlake3s,
16);

const std::vector<barretenberg::fr> proof_witnesses = export_transcript_in_recursion_format(transcript);
std::vector<barretenberg::fr> proof_witnesses = export_transcript_in_recursion_format(transcript);
// - Save the public inputs so that we can set their values.
// - Then truncate them from the proof because the ACIR API expects proofs without public inputs

std::vector<barretenberg::fr> inner_public_input_values(
proof_witnesses.begin(), proof_witnesses.begin() + static_cast<std::ptrdiff_t>(num_inner_public_inputs));
proof_witnesses.erase(proof_witnesses.begin(),
proof_witnesses.begin() + static_cast<std::ptrdiff_t>(num_inner_public_inputs));

const std::vector<barretenberg::fr> key_witnesses = export_key_in_recursion_format(inner_verifier.key);

const uint32_t key_hash_start_idx = static_cast<uint32_t>(witness_offset);
Expand Down Expand Up @@ -202,14 +210,18 @@ Builder create_outer_circuit(std::vector<Builder>& inner_circuits)
for (const auto& wit : key_witnesses) {
witness.emplace_back(wit);
}
// Set the values for the inner public inputs
// Note: this is confusing, but we minus one here due to the fact that the
// witness values have not taken into account that zero is taken up by the zero_idx
for (size_t i = 0; i < num_inner_public_inputs; ++i) {
witness[inner_public_inputs[i] - 1] = inner_public_input_values[i];
}
witness_offset = key_indices_start_idx + key_witnesses.size();
circuit_idx++;
}

std::vector<uint32_t> public_inputs(output_aggregation_object.begin(), output_aggregation_object.end());

acir_format constraint_system{ .varnum = static_cast<uint32_t>(witness.size() + 1),
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
.public_inputs = public_inputs,
.public_inputs = {},
.logic_constraints = {},
.range_constraints = {},
.sha256_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ bool AcirComposer::verify_proof(std::vector<uint8_t> const& proof, bool is_recur
// Hack. Shouldn't need to do this. 2144 is size with no public inputs.
builder_.public_inputs.resize((proof.size() - 2144) / 32);

// TODO: We could get rid of this, if we made the Noir program specify whether something should be
// TODO: created with the recursive setting or not. ie:
//
// #[recursive_friendly]
// fn main() {}
// would put in the ACIR that we want this to be recursion friendly with a flag maybe and the backend
// would set the is_recursive flag to be true.
// This would eliminate the need for nargo to have a --recursive flag
//
// End result is that we may just be able to get it off of builder_, like builder_.is_recursive_friendly
if (is_recursive) {
auto verifier = composer.create_verifier(builder_);
return verifier.verify_proof({ proof });
Expand All @@ -123,6 +133,8 @@ std::string AcirComposer::get_solidity_verifier()
}

/**
* TODO: We should change this to return a proof without public inputs, since that is what std::verify_proof
* TODO: takes.
* @brief Takes in a proof buffer and converts into a vector of field elements.
* The Recursion opcode requires the proof serialized as a vector of witnesses.
* Use this method to get the witness values!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,15 @@ template <typename FF_> class CircuitBuilderBase {

for (const auto& idx : proof_output_witness_indices) {
set_public_input(idx);
// Why is it adding the size of the public input instead of the idx?
recursive_proof_public_input_indices.push_back((uint32_t)(public_inputs.size() - 1));
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* TODO: We can remove this and use `add_recursive_proof` once my question has been addressed
* TODO: using `add_recursive_proof` also means that we will need to remove the cde which is
* TODO: adding the public_inputs
* @brief Update recursive_proof_public_input_indices with existing public inputs that represent a recursive proof
*
* @param proof_output_witness_indices
Expand Down
Binary file not shown.
Binary file not shown.
Loading