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

feat: adding aggregation to honk and rollup #7466

Merged
merged 10 commits into from
Jul 25, 2024
33 changes: 33 additions & 0 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,39 @@ void prove_tube(const std::string& output_path)
ClientIVC verifier{ builder, input };

verifier.verify(proof);

lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved
// TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted from a valid
// proof. This is a workaround because we can't represent the point at infinity in biggroup yet.
std::array<uint32_t, acir_format::HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE> current_aggregation_object = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
fq x0("0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf");
fq y0("0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4");
fq x1("0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38");
fq y1("0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f");
std::vector<fq> aggregation_object_fq_values = { x0, y0, x1, y1 };
size_t agg_obj_indices_idx = 0;
for (fq val : aggregation_object_fq_values) {
const uint256_t x = val;
std::array<fr, acir_format::fq_ct::NUM_LIMBS> val_limbs = {
x.slice(0, acir_format::fq_ct::NUM_LIMB_BITS),
x.slice(acir_format::fq_ct::NUM_LIMB_BITS, acir_format::fq_ct::NUM_LIMB_BITS * 2),
x.slice(acir_format::fq_ct::NUM_LIMB_BITS * 2, acir_format::fq_ct::NUM_LIMB_BITS * 3),
x.slice(acir_format::fq_ct::NUM_LIMB_BITS * 3, stdlib::field_conversion::TOTAL_BITS)
};
for (size_t i = 0; i < acir_format::fq_ct::NUM_LIMBS; ++i) {
uint32_t idx = builder->add_variable(val_limbs[i]);
builder->set_public_input(idx);
current_aggregation_object[agg_obj_indices_idx] = idx;
agg_obj_indices_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_aggregation_object.begin(),
current_aggregation_object.end());
builder->set_recursive_proof(proof_output_witness_indices);

info("num gates in tube circuit: ", builder->get_num_gates());
using Prover = UltraProver_<UltraFlavor>;
using Verifier = UltraVerifier_<UltraFlavor>;
Expand Down
110 changes: 52 additions & 58 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,21 +347,19 @@ void build_constraints(Builder& builder,
// 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 = {};
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++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]);
// }
for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++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 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::inner_public_input_offset
// +
// HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE));
constraint.proof.erase(constraint.proof.begin() + HonkRecursionConstraint::inner_public_input_offset,
constraint.proof.begin() +
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 All @@ -378,52 +376,48 @@ void build_constraints(Builder& builder,
// First add the output aggregation object as public inputs
// Set the indices as public inputs because they are no longer being
// created in ACIR
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// for (const auto& idx : current_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_aggregation_object.begin(),
// current_aggregation_object.end());
// builder.set_recursive_proof(proof_output_witness_indices);
for (const auto& idx : current_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_aggregation_object.begin(),
current_aggregation_object.end());
builder.set_recursive_proof(proof_output_witness_indices);
} else if (honk_recursion &&
builder.is_recursive_circuit) { // Set a default aggregation object if we don't have one.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted
// from a valid proof. This is a workaround because we can't represent the point at infinity in biggroup
// yet.
fq x0("0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf");
fq y0("0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4");

fq x1("0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38");
fq y1("0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f");
std::vector<fq> aggregation_object_fq_values = { x0, y0, x1, y1 };
size_t agg_obj_indices_idx = 0;
for (fq val : aggregation_object_fq_values) {
const uint256_t x = val;
std::array<fr, fq_ct::NUM_LIMBS> val_limbs = {
x.slice(0, fq_ct::NUM_LIMB_BITS),
x.slice(fq_ct::NUM_LIMB_BITS, fq_ct::NUM_LIMB_BITS * 2),
x.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 3),
x.slice(fq_ct::NUM_LIMB_BITS * 3, stdlib::field_conversion::TOTAL_BITS)
};
for (size_t i = 0; i < fq_ct::NUM_LIMBS; ++i) {
uint32_t idx = builder.add_variable(val_limbs[i]);
builder.set_public_input(idx);
current_aggregation_object[agg_obj_indices_idx] = idx;
agg_obj_indices_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_aggregation_object.begin(),
current_aggregation_object.end());
builder.set_recursive_proof(proof_output_witness_indices);
}
static_cast<void>(honk_recursion);
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// else if (honk_recursion &&
// builder.is_recursive_circuit) { // Set a default aggregation object if we don't have one.
// // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted
// from
// // a valid proof. This is a workaround because we can't represent the point at infinity in biggroup
// yet. fq x0("0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf"); fq
// y0("0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4");

// fq x1("0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38");
// fq y1("0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f");
// std::vector<fq> aggregation_object_fq_values = { x0, y0, x1, y1 };
// size_t agg_obj_indices_idx = 0;
// for (fq val : aggregation_object_fq_values) {
// const uint256_t x = val;
// std::array<fr, fq_ct::NUM_LIMBS> val_limbs = {
// x.slice(0, fq_ct::NUM_LIMB_BITS),
// x.slice(fq_ct::NUM_LIMB_BITS, fq_ct::NUM_LIMB_BITS * 2),
// x.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 3),
// x.slice(fq_ct::NUM_LIMB_BITS * 3, stdlib::field_conversion::TOTAL_BITS)
// };
// for (size_t i = 0; i < fq_ct::NUM_LIMBS; ++i) {
// uint32_t idx = builder.add_variable(val_limbs[i]);
// builder.set_public_input(idx);
// current_aggregation_object[agg_obj_indices_idx] = idx;
// agg_obj_indices_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_aggregation_object.begin(),
// current_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 @@ -55,7 +55,8 @@ std::array<uint32_t, HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE> create_ho
using RecursiveVerificationKey = Flavor::VerificationKey;
using RecursiveVerifier = bb::stdlib::recursion::honk::UltraRecursiveVerifier_<Flavor>;

// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044) reinstate aggregation
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1059): Handle aggregation

static_cast<void>(input_aggregation_object);
static_cast<void>(nested_aggregation_object);
// Construct aggregation points from the nested aggregation witness indices
Expand Down Expand Up @@ -214,7 +215,7 @@ std::array<uint32_t, HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE> create_ho
std::array<typename Flavor::GroupElement, 2> pairing_points = verifier.verify_proof(proof_fields);

// Aggregate the current aggregation object with these pairing points from verify_proof
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1059): Handle aggregation
aggregation_state_ct cur_aggregation_object;
cur_aggregation_object.P0 = pairing_points[0]; // * recursion_separator;
cur_aggregation_object.P1 = pairing_points[1]; // * recursion_separator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,17 +158,17 @@ class AcirHonkRecursionConstraint : public ::testing::Test {
const size_t inner_public_input_offset = 3;
// - 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
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
std::vector<fr> inner_public_input_values(
proof_witnesses.begin() + static_cast<std::ptrdiff_t>(inner_public_input_offset),
proof_witnesses.begin() +
static_cast<std::ptrdiff_t>(inner_public_input_offset + num_inner_public_inputs));
static_cast<std::ptrdiff_t>(inner_public_input_offset + num_inner_public_inputs -
RecursionConstraint::AGGREGATION_OBJECT_SIZE));

// We want to make sure that we do not remove the nested aggregation object.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
proof_witnesses.erase(proof_witnesses.begin() + static_cast<std::ptrdiff_t>(inner_public_input_offset),
proof_witnesses.begin() +
static_cast<std::ptrdiff_t>(inner_public_input_offset + num_inner_public_inputs));
static_cast<std::ptrdiff_t>(inner_public_input_offset + num_inner_public_inputs -
RecursionConstraint::AGGREGATION_OBJECT_SIZE));

std::vector<bb::fr> key_witnesses = verification_key->to_field_elements();

Expand All @@ -179,9 +179,8 @@ class AcirHonkRecursionConstraint : public ::testing::Test {
const uint32_t public_input_start_idx =
static_cast<uint32_t>(inner_public_input_offset + witness_offset); // points to public_input_0
const uint32_t proof_indices_start_idx =
static_cast<uint32_t>(public_input_start_idx + num_inner_public_inputs);
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// - RecursionConstraint::AGGREGATION_OBJECT_SIZE); // points to agg_obj_0
static_cast<uint32_t>(public_input_start_idx + num_inner_public_inputs -
RecursionConstraint::AGGREGATION_OBJECT_SIZE); // points to agg_obj_0
const uint32_t key_indices_start_idx =
static_cast<uint32_t>(proof_indices_start_idx + proof_witnesses.size() -
inner_public_input_offset); // would point to vkey_3 without the -
Expand All @@ -204,8 +203,7 @@ class AcirHonkRecursionConstraint : public ::testing::Test {
// We keep the nested aggregation object attached to the proof,
// thus we do not explicitly have to keep the public inputs while setting up the initial recursion
// constraint. They will later be attached as public inputs when creating the circuit.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
for (size_t i = 0; i < num_inner_public_inputs; ++i) {
for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) {
inner_public_inputs.push_back(static_cast<uint32_t>(i + public_input_start_idx));
}

Expand Down Expand Up @@ -244,8 +242,7 @@ class AcirHonkRecursionConstraint : public ::testing::Test {
//
// We once again have to check whether we have a nested proof, because if we do have one
// then we could get a segmentation fault as `inner_public_inputs` was never filled with values.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
for (size_t i = 0; i < num_inner_public_inputs; ++i) {
for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) {
witness[inner_public_inputs[i]] = inner_public_input_values[i];
}

Expand Down
6 changes: 3 additions & 3 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ library Constants {
uint256 internal constant LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 64;
uint256 internal constant NUM_MSGS_PER_BASE_PARITY = 4;
uint256 internal constant NUM_BASE_PARITY_PER_ROOT_PARITY = 4;
uint256 internal constant RECURSIVE_PROOF_LENGTH = 393;
uint256 internal constant NESTED_RECURSIVE_PROOF_LENGTH = 393;
uint256 internal constant TUBE_PROOF_LENGTH = 393;
uint256 internal constant RECURSIVE_PROOF_LENGTH = 409;
uint256 internal constant NESTED_RECURSIVE_PROOF_LENGTH = 409;
uint256 internal constant TUBE_PROOF_LENGTH = 409;
uint256 internal constant VERIFICATION_KEY_LENGTH_IN_FIELDS = 103;
uint256 internal constant SENDER_SELECTOR = 0;
uint256 internal constant ADDRESS_SELECTOR = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,9 @@ global NUM_MSGS_PER_BASE_PARITY: u32 = 4;
// FIX: Sadly, writing this as above causes a type error in type_conversion.ts.
global NUM_BASE_PARITY_PER_ROOT_PARITY: u32 = 4;

// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// Lengths of the different types of proofs in fields
global RECURSIVE_PROOF_LENGTH = 393;
global NESTED_RECURSIVE_PROOF_LENGTH = 393;
global RECURSIVE_PROOF_LENGTH = 409;
global NESTED_RECURSIVE_PROOF_LENGTH = 409;
global TUBE_PROOF_LENGTH = RECURSIVE_PROOF_LENGTH; // in the future these can differ

global VERIFICATION_KEY_LENGTH_IN_FIELDS = 103;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

// This circuit aggregates a single Honk proof from `assert_statement_recursive`.
global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 393;
global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 409;
fn main(
verification_key: [Field; 103],
// This is the proof without public inputs attached.
Expand Down
2 changes: 1 addition & 1 deletion noir/verify_honk_proof/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

// This circuit aggregates a single Honk proof from `assert_statement_recursive`.
global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 393;
global SIZE_OF_PROOF_IF_LOGN_IS_28 : u32 = 409;
fn main(
verification_key: [Field; 103],
// This is the proof without public inputs attached.
Expand Down
7 changes: 3 additions & 4 deletions yarn-project/bb-prover/src/prover/bb_private_kernel_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '@aztec/circuit-types';
import { type CircuitSimulationStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
import {
AGGREGATION_OBJECT_LENGTH,
ClientIvcProof,
Fr,
type PrivateCircuitPublicInputs,
Expand Down Expand Up @@ -350,10 +351,8 @@ export class BBNativePrivateKernelProver implements PrivateKernelProver {
]);
const json = JSON.parse(proofString);
const fields = json.map(Fr.fromString);
const numPublicInputs = vkData.numPublicInputs;
// const numPublicInputs =
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1044): Reinstate aggregation
// circuitType === 'App' ? vkData.numPublicInputs : vkData.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
const numPublicInputs = vkData.numPublicInputs - AGGREGATION_OBJECT_LENGTH;

const fieldsWithoutPublicInputs = fields.slice(numPublicInputs);
this.log.info(
`Circuit type: ${circuitType}, complete proof length: ${fields.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`,
Expand Down
Loading
Loading