-
Notifications
You must be signed in to change notification settings - Fork 305
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: proof surgery class #8236
Changes from 7 commits
b9023a9
5599967
8f43637
3df7fc0
7dd94c2
6204cef
3595775
302cdc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" | ||
#include "barretenberg/stdlib/primitives/curves/bn254.hpp" | ||
#include "barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp" | ||
#include "proof_surgeon.hpp" | ||
#include "recursion_constraint.hpp" | ||
|
||
namespace acir_format { | ||
|
@@ -22,39 +23,41 @@ using aggregation_state_ct = bb::stdlib::recursion::aggregation_state<bn254>; | |
* aggregation object, and commitments. | ||
* | ||
* @param builder | ||
* @param input | ||
* @param proof_size Size of proof with NO public inputs | ||
* @param public_inputs_size Total size of public inputs including aggregation object | ||
* @param key_fields | ||
* @param proof_fields | ||
*/ | ||
void create_dummy_vkey_and_proof(Builder& builder, | ||
const RecursionConstraint& input, | ||
std::vector<field_ct>& key_fields, | ||
std::vector<field_ct>& proof_fields) | ||
size_t proof_size, | ||
size_t public_inputs_size, | ||
const std::vector<field_ct>& key_fields, | ||
const std::vector<field_ct>& proof_fields) | ||
{ | ||
using Flavor = UltraRecursiveFlavor_<Builder>; | ||
using Flavor = UltraFlavor; | ||
|
||
// Set vkey->circuit_size correctly based on the proof size | ||
size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs<UltraFlavor::Commitment>(); | ||
size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs<UltraFlavor::FF>(); | ||
assert((input.proof.size() - HONK_RECURSION_PUBLIC_INPUT_OFFSET - UltraFlavor::NUM_WITNESS_ENTITIES * num_frs_comm - | ||
UltraFlavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) % | ||
(num_frs_comm + num_frs_fr * UltraFlavor::BATCHED_RELATION_PARTIAL_LENGTH) == | ||
size_t num_frs_comm = bb::field_conversion::calc_num_bn254_frs<Flavor::Commitment>(); | ||
size_t num_frs_fr = bb::field_conversion::calc_num_bn254_frs<Flavor::FF>(); | ||
assert((proof_size - HONK_RECURSION_PUBLIC_INPUT_OFFSET - Flavor::NUM_WITNESS_ENTITIES * num_frs_comm - | ||
Flavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) % | ||
(num_frs_comm + num_frs_fr * Flavor::BATCHED_RELATION_PARTIAL_LENGTH) == | ||
0); | ||
// Note: this computation should always result in log_circuit_size = CONST_PROOF_SIZE_LOG_N | ||
auto log_circuit_size = | ||
(input.proof.size() - HONK_RECURSION_PUBLIC_INPUT_OFFSET - UltraFlavor::NUM_WITNESS_ENTITIES * num_frs_comm - | ||
UltraFlavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) / | ||
(num_frs_comm + num_frs_fr * UltraFlavor::BATCHED_RELATION_PARTIAL_LENGTH); | ||
(proof_size - HONK_RECURSION_PUBLIC_INPUT_OFFSET - Flavor::NUM_WITNESS_ENTITIES * num_frs_comm - | ||
Flavor::NUM_ALL_ENTITIES * num_frs_fr - 2 * num_frs_comm) / | ||
(num_frs_comm + num_frs_fr * Flavor::BATCHED_RELATION_PARTIAL_LENGTH); | ||
// First key field is circuit size | ||
builder.assert_equal(builder.add_variable(1 << log_circuit_size), key_fields[0].witness_index); | ||
// Second key field is number of public inputs | ||
builder.assert_equal(builder.add_variable(input.public_inputs.size()), key_fields[1].witness_index); | ||
builder.assert_equal(builder.add_variable(public_inputs_size), key_fields[1].witness_index); | ||
// Third key field is the pub inputs offset | ||
builder.assert_equal(builder.add_variable(UltraFlavor::has_zero_row ? 1 : 0), key_fields[2].witness_index); | ||
builder.assert_equal(builder.add_variable(Flavor::has_zero_row ? 1 : 0), key_fields[2].witness_index); | ||
// Fourth key field is the whether the proof contains an aggregation object. | ||
builder.assert_equal(builder.add_variable(1), key_fields[4].witness_index); | ||
builder.assert_equal(builder.add_variable(1), key_fields[4].witness_index); // WORKTODO: 4 = bug? | ||
uint32_t offset = 4; | ||
size_t num_inner_public_inputs = input.public_inputs.size() - bb::AGGREGATION_OBJECT_SIZE; | ||
size_t num_inner_public_inputs = public_inputs_size - bb::AGGREGATION_OBJECT_SIZE; | ||
|
||
// We are making the assumption that the aggregation object are behind all the inner public inputs | ||
for (size_t i = 0; i < bb::AGGREGATION_OBJECT_SIZE; i++) { | ||
|
@@ -75,8 +78,8 @@ void create_dummy_vkey_and_proof(Builder& builder, | |
offset = HONK_RECURSION_PUBLIC_INPUT_OFFSET; | ||
// first 3 things | ||
builder.assert_equal(builder.add_variable(1 << log_circuit_size), proof_fields[0].witness_index); | ||
builder.assert_equal(builder.add_variable(input.public_inputs.size()), proof_fields[1].witness_index); | ||
builder.assert_equal(builder.add_variable(UltraFlavor::has_zero_row ? 1 : 0), proof_fields[2].witness_index); | ||
builder.assert_equal(builder.add_variable(public_inputs_size), proof_fields[1].witness_index); | ||
builder.assert_equal(builder.add_variable(Flavor::has_zero_row ? 1 : 0), proof_fields[2].witness_index); | ||
|
||
// the inner public inputs | ||
for (size_t i = 0; i < num_inner_public_inputs; i++) { | ||
|
@@ -134,7 +137,7 @@ void create_dummy_vkey_and_proof(Builder& builder, | |
builder.assert_equal(builder.add_variable(frs[3]), proof_fields[offset + 3].witness_index); | ||
offset += 4; | ||
} | ||
ASSERT(offset == input.proof.size() + input.public_inputs.size()); | ||
ASSERT(offset == proof_size + public_inputs_size); | ||
} | ||
|
||
/** | ||
|
@@ -171,27 +174,26 @@ AggregationObjectIndices create_honk_recursion_constraints(Builder& builder, | |
} | ||
|
||
std::vector<field_ct> proof_fields; | ||
// Insert the public inputs in the middle the proof fields after 'inner_public_input_offset' because this is how the | ||
// core barretenberg library processes proofs (with the public inputs starting at the third element and not | ||
// separate from the rest of the proof) | ||
proof_fields.reserve(input.proof.size() + input.public_inputs.size()); | ||
size_t i = 0; | ||
for (const auto& idx : input.proof) { | ||
|
||
// Create witness indices for the proof with public inputs reinserted | ||
std::vector<uint32_t> proof_indices = | ||
ProofSurgeon::create_indices_for_reconstructed_proof(input.proof, input.public_inputs); | ||
proof_fields.reserve(proof_indices.size()); | ||
for (const auto& idx : proof_indices) { | ||
auto field = field_ct::from_witness_index(&builder, idx); | ||
proof_fields.emplace_back(field); | ||
i++; | ||
if (i == HONK_RECURSION_PUBLIC_INPUT_OFFSET) { | ||
for (const auto& idx : input.public_inputs) { | ||
auto field = field_ct::from_witness_index(&builder, idx); | ||
proof_fields.emplace_back(field); | ||
} | ||
} | ||
} | ||
// Populate the key fields and proof fields with dummy values to prevent issues (usually with points not being on | ||
// the curve). | ||
|
||
// Populate the key fields and proof fields with dummy values to prevent issues (e.g. points must be on curve). | ||
if (!has_valid_witness_assignments) { | ||
create_dummy_vkey_and_proof(builder, input, key_fields, proof_fields); | ||
// In the constraint, the agg object public inputs are still contained in the proof. To get the 'raw' size of | ||
// the proof and public_inputs we subtract and add the corresponding amount from the respective sizes. | ||
size_t size_of_proof_with_no_pub_inputs = input.proof.size() - bb::AGGREGATION_OBJECT_SIZE; | ||
size_t total_num_public_inputs = input.public_inputs.size() + bb::AGGREGATION_OBJECT_SIZE; | ||
create_dummy_vkey_and_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. @lucas you were right that the moving of the agg object from proof to pub inputs was needed in a sense but it was just because this method expects the "raw" sizes of each. Rather than actually move it back and forth I just provide this method the adjusted sizes. BTW I think the long term solution for this dummy proof is just to read in some data from a file or something. This is too brittle 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. well we could just pass the unadjusted values to 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. I actually did it that way first but found this to be slightly clearer since its external to the method where we know about the structure of the proof/pub inputs. Either way its kind of bad but its better than it was. I'll hopefully have time to clean all of this up more soon |
||
builder, size_of_proof_with_no_pub_inputs, total_num_public_inputs, key_fields, proof_fields); | ||
} | ||
|
||
// Recursively verify the proof | ||
auto vkey = std::make_shared<RecursiveVerificationKey>(builder, key_fields); | ||
RecursiveVerifier verifier(&builder, vkey); | ||
|
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.
Also note this weird index that looks like a bug to me. If not then its definitely worth a comment explaining why
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.
hm yeah, it should be 3...
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.
not sure why we wouldn't get some sort of failure if we assert_equal the 4th index with both 1 and 0 variables...?
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, a little concerning. My vague guess was that the 4th-index value was always non-zero and was somehow just getting converted to "true" somewhere along the way. not sure