Skip to content

Commit

Permalink
feat: Use full IPA recursive verifier in root rollup (#10962)
Browse files Browse the repository at this point in the history
Modifies the root rollup circuit to use different recursion proof type,
ROOT_ROLLUP_HONK and processing of honk_recursion_constraints, so the
backend knows to run the full IPA recursive verifier.

Resolves AztecProtocol/barretenberg#1183.
  • Loading branch information
lucasxia01 authored Jan 2, 2025
1 parent a1a4d76 commit 37095ce
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 21 deletions.
32 changes: 26 additions & 6 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
#include "barretenberg/common/throw_or_abort.hpp"
#include "barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp"
#include "barretenberg/flavor/flavor.hpp"
#include "barretenberg/stdlib/eccvm_verifier/verifier_commitment_key.hpp"
#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp"
#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp"
#include "barretenberg/stdlib/primitives/field/field_conversion.hpp"
#include "barretenberg/stdlib_circuit_builders/mega_circuit_builder.hpp"
#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp"
#include "barretenberg/transcript/transcript.hpp"
#include "proof_surgeon.hpp"
#include <cstddef>
#include <cstdint>
#include <memory>

namespace acir_format {

Expand Down Expand Up @@ -270,9 +273,8 @@ void build_constraints(Builder& builder, AcirProgram& program, const ProgramMeta
// final recursion output.
builder.add_pairing_point_accumulator(current_aggregation_object);
}
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1183): This assertion should be true, except for
// the root rollup as of now since the root rollup will not output a ipa proof.
// ASSERT((metadata.honk_recursion == 2) == (output.ipa_proof.size() > 0));
// If we are proving with UltraRollupFlavor, the IPA proof should have nonzero size.
ASSERT((metadata.honk_recursion == 2) == (output.ipa_proof.size() > 0));
if (metadata.honk_recursion == 2) {
builder.add_ipa_claim(output.ipa_claim.get_witness_indices());
builder.ipa_proof = output.ipa_proof;
Expand Down Expand Up @@ -379,13 +381,17 @@ HonkRecursionConstraintsOutput<Builder> process_honk_recursion_constraints(
size_t idx = 0;
std::vector<OpeningClaim<stdlib::grumpkin<Builder>>> nested_ipa_claims;
std::vector<StdlibProof<Builder>> nested_ipa_proofs;
bool is_root_rollup = false;
for (auto& constraint : constraint_system.honk_recursion_constraints) {
if (constraint.proof_type == HONK) {
auto [next_aggregation_object, _ipa_claim, _ipa_proof] =
create_honk_recursion_constraints<UltraRecursiveFlavor_<Builder>>(
builder, constraint, current_aggregation_object, has_valid_witness_assignments);
current_aggregation_object = next_aggregation_object;
} else if (constraint.proof_type == ROLLUP_HONK || constraint.proof_type == ROLLUP_ROOT_HONK) {
} else if (constraint.proof_type == ROLLUP_HONK || constraint.proof_type == ROOT_ROLLUP_HONK) {
if (constraint.proof_type == ROOT_ROLLUP_HONK) {
is_root_rollup = true;
}
auto [next_aggregation_object, ipa_claim, ipa_proof] =
create_honk_recursion_constraints<UltraRollupRecursiveFlavor_<Builder>>(
builder, constraint, current_aggregation_object, has_valid_witness_assignments);
Expand All @@ -400,6 +406,7 @@ HonkRecursionConstraintsOutput<Builder> process_honk_recursion_constraints(
gate_counter.track_diff(constraint_system.gates_per_opcode,
constraint_system.original_opcode_indices.honk_recursion_constraints.at(idx++));
}
ASSERT(!(is_root_rollup && nested_ipa_claims.size() != 2) && "Root rollup must accumulate two IPA proofs.");
// Accumulate the claims
if (nested_ipa_claims.size() == 2) {
auto commitment_key = std::make_shared<CommitmentKey<curve::Grumpkin>>(1 << CONST_ECCVM_LOG_N);
Expand All @@ -409,8 +416,21 @@ HonkRecursionConstraintsOutput<Builder> process_honk_recursion_constraints(
auto ipa_transcript_2 = std::make_shared<StdlibTranscript>(nested_ipa_proofs[1]);
auto [ipa_claim, ipa_proof] = IPA<stdlib::grumpkin<Builder>>::accumulate(
commitment_key, ipa_transcript_1, nested_ipa_claims[0], ipa_transcript_2, nested_ipa_claims[1]);
output.ipa_claim = ipa_claim;
output.ipa_proof = ipa_proof;
// If this is the root rollup, do full IPA verification
if (is_root_rollup) {
auto verifier_commitment_key = std::make_shared<VerifierCommitmentKey<stdlib::grumpkin<Builder>>>(
&builder,
1 << CONST_ECCVM_LOG_N,
std::make_shared<VerifierCommitmentKey<curve::Grumpkin>>(1 << CONST_ECCVM_LOG_N));
// do full IPA verification
auto accumulated_ipa_transcript =
std::make_shared<StdlibTranscript>(convert_native_proof_to_stdlib(&builder, ipa_proof));
IPA<stdlib::grumpkin<Builder>>::full_verify_recursive(
verifier_commitment_key, ipa_claim, accumulated_ipa_transcript);
} else {
output.ipa_claim = ipa_claim;
output.ipa_proof = ipa_proof;
}
} else if (nested_ipa_claims.size() == 1) {
output.ipa_claim = nested_ipa_claims[0];
// This conversion looks suspicious but there's no need to make this an output of the circuit since its a proof
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg,
// 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 (proof_type_in != HONK && proof_type_in != AVM && proof_type_in != ROLLUP_HONK &&
proof_type_in != ROLLUP_ROOT_HONK) {
proof_type_in != ROOT_ROLLUP_HONK) {
if (honk_recursion == 1) {
proof_type_in = HONK;
} else if (honk_recursion == 2) {
Expand All @@ -659,7 +659,7 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg,
break;
case HONK:
case ROLLUP_HONK:
case ROLLUP_ROOT_HONK:
case ROOT_ROLLUP_HONK:
af.honk_recursion_constraints.push_back(c);
af.original_opcode_indices.honk_recursion_constraints.push_back(opcode_index);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ HonkRecursionConstraintOutput create_honk_recursion_constraints(
using RecursiveVerifier = bb::stdlib::recursion::honk::UltraRecursiveVerifier_<Flavor>;

ASSERT(input.proof_type == HONK || HasIPAAccumulator<Flavor>);
ASSERT((input.proof_type == ROLLUP_HONK || input.proof_type == ROLLUP_ROOT_HONK) == HasIPAAccumulator<Flavor>);
ASSERT((input.proof_type == ROLLUP_HONK || input.proof_type == ROOT_ROLLUP_HONK) == HasIPAAccumulator<Flavor>);

// Construct an in-circuit representation of the verification key.
// For now, the v-key is a circuit constant and is fixed for the circuit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace acir_format {
// ACIR
// Keep this enum values in sync with their noir counterpart constants defined in
// noir-protocol-circuits/crates/types/src/constants.nr
enum PROOF_TYPE { PLONK, HONK, OINK, PG, AVM, ROLLUP_HONK, ROLLUP_ROOT_HONK };
enum PROOF_TYPE { PLONK, HONK, OINK, PG, AVM, ROLLUP_HONK, ROOT_ROLLUP_HONK };

using namespace bb::plonk;
using Builder = bb::UltraCircuitBuilder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::abis::block_root_or_block_merge_public_inputs::BlockRootOrBlockMergePublicInputs;
use dep::types::{
constants::{PROOF_TYPE_ROLLUP_HONK, VK_TREE_HEIGHT},
constants::VK_TREE_HEIGHT,
merkle_tree::{membership::assert_check_membership, MembershipWitness},
proof::{
rollup_recursive_proof::NestedRecursiveProof,
traits::Verifiable,
verification_key::{RollupHonkVerificationKey, VerificationKey},
},
traits::Empty,
Expand All @@ -18,8 +17,8 @@ pub struct PreviousRollupBlockData {
pub vk_witness: MembershipWitness<VK_TREE_HEIGHT>,
}

impl Verifiable for PreviousRollupBlockData {
fn verify(self) {
impl PreviousRollupBlockData {
fn verify(self, proof_type_id: u32) {
let inputs = BlockRootOrBlockMergePublicInputs::serialize(
self.block_root_or_block_merge_public_inputs,
);
Expand All @@ -28,7 +27,7 @@ impl Verifiable for PreviousRollupBlockData {
self.proof.fields,
inputs,
self.vk.hash,
PROOF_TYPE_ROLLUP_HONK,
proof_type_id,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::abis::block_root_or_block_merge_public_inputs::BlockRootOrBlockMergePublicInputs;
use crate::abis::previous_rollup_block_data::PreviousRollupBlockData;
use crate::components;
use dep::types::{constants::{BLOCK_MERGE_ROLLUP_INDEX, BLOCK_ROOT_ROLLUP_INDEX}, traits::Empty};
use dep::types::{
constants::{BLOCK_MERGE_ROLLUP_INDEX, BLOCK_ROOT_ROLLUP_INDEX, PROOF_TYPE_ROLLUP_HONK},
traits::Empty,
};
// TODO(#7346): Currently unused! Will be used when batch rollup circuits are integrated.
global ALLOWED_PREVIOUS_CIRCUITS: [u32; 2] = [BLOCK_ROOT_ROLLUP_INDEX, BLOCK_MERGE_ROLLUP_INDEX];

Expand All @@ -21,10 +24,10 @@ impl BlockMergeRollupInputs {
// we don't have a set of permitted kernel vks yet.
// Verify the previous rollup proofs
if !dep::std::runtime::is_unconstrained() {
self.previous_rollup_data[0].verify();
self.previous_rollup_data[0].verify(PROOF_TYPE_ROLLUP_HONK);
self.previous_rollup_data[0].validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS);

self.previous_rollup_data[1].verify();
self.previous_rollup_data[1].verify(PROOF_TYPE_ROLLUP_HONK);
self.previous_rollup_data[1].validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use crate::{
root::root_rollup_public_inputs::RootRollupPublicInputs,
};
use types::{
constants::{BLOCK_MERGE_ROLLUP_INDEX, BLOCK_ROOT_ROLLUP_EMPTY_INDEX, BLOCK_ROOT_ROLLUP_INDEX},
constants::{
BLOCK_MERGE_ROLLUP_INDEX, BLOCK_ROOT_ROLLUP_EMPTY_INDEX, BLOCK_ROOT_ROLLUP_INDEX,
PROOF_TYPE_ROLLUP_HONK, PROOF_TYPE_ROOT_ROLLUP_HONK,
},
traits::Empty,
};
// TODO(#7346): Currently unused! Will be used when batch rollup circuits are integrated.
Expand All @@ -28,10 +31,10 @@ impl RootRollupInputs {
pub fn root_rollup_circuit(self) -> RootRollupPublicInputs {
// Verify the previous rollup proofs
if !dep::std::runtime::is_unconstrained() {
self.previous_rollup_data[0].verify();
self.previous_rollup_data[0].verify(PROOF_TYPE_ROOT_ROLLUP_HONK); // root rollup honk proof type so we do full IPA recursive verifier
self.previous_rollup_data[0].validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS);

self.previous_rollup_data[1].verify();
self.previous_rollup_data[1].verify(PROOF_TYPE_ROOT_ROLLUP_HONK); // root rollup honk proof type so we do full IPA recursive verifier
self.previous_rollup_data[1].validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS);
}

Expand Down

0 comments on commit 37095ce

Please sign in to comment.