Skip to content

Commit

Permalink
feat: Recursive folding verifier and decider as ultra circuits and ci…
Browse files Browse the repository at this point in the history
…rcuit simulator (#6150)

Gets the folding recursive verifiers tests working on
`UltraCircuitBuilder` and `CircuitSimulator`. The former required
working around an edge case of `batch_mul` (see
[971](AztecProtocol/aztec-packages#6150)).

---------

Co-authored-by: ludamad <[email protected]>
Co-authored-by: codygunton <[email protected]>
Co-authored-by: ludamad <[email protected]>
  • Loading branch information
4 people authored and AztecBot committed May 4, 2024
1 parent 4211302 commit ff460a8
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 159 deletions.
3 changes: 1 addition & 2 deletions cpp/src/barretenberg/circuit_checker/circuit_checker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ class CircuitChecker {
template <typename Builder> static bool check(const Builder& builder)
{
static_assert(IsCheckable<Builder>);

if constexpr (IsUltraBuilder<Builder>) {
if constexpr (IsUltraBuilder<Builder> || IsGoblinUltraBuilder<Builder>) {
return UltraCircuitChecker::check(builder);
} else if constexpr (IsStandardBuilder<Builder>) {
return StandardCircuitChecker::check(builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ bool UltraCircuitChecker::check_block(Builder& builder,
info("Failed Lookup check relation at row idx = ", idx);
return false;
}
if constexpr (IsGoblinBuilder<Builder>) {
if constexpr (IsGoblinUltraBuilder<Builder>) {
result = result && check_relation<PoseidonInternal>(values, params);
if (result == false) {
info("Failed PoseidonInternal relation at row idx = ", idx);
Expand Down Expand Up @@ -285,7 +285,7 @@ void UltraCircuitChecker::populate_values(
values.q_elliptic = block.q_elliptic()[idx];
values.q_aux = block.q_aux()[idx];
values.q_lookup = block.q_lookup_type()[idx];
if constexpr (IsGoblinBuilder<Builder>) {
if constexpr (IsGoblinUltraBuilder<Builder>) {
values.q_busread = block.q_busread()[idx];
values.q_poseidon2_internal = block.q_poseidon2_internal()[idx];
values.q_poseidon2_external = block.q_poseidon2_external()[idx];
Expand Down
3 changes: 3 additions & 0 deletions cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ TEST_F(MockKernelTest, PinFoldingKernelSizes)
ivc.initialize(circuit_1);
auto kernel_acc = std::make_shared<ClientIVC::VerifierInstance>(ivc.vks.first_func_vk);
kernel_acc->verification_key = ivc.vks.first_func_vk;
EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17);

GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue };
GoblinMockCircuits::construct_mock_function_circuit(circuit_2);
auto func_fold_proof = ivc.accumulate(circuit_2);
EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17);

// Construct kernel circuit
GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue };
Expand All @@ -42,6 +44,7 @@ TEST_F(MockKernelTest, PinFoldingKernelSizes)
GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue };
GoblinMockCircuits::construct_mock_function_circuit(circuit_3);
func_fold_proof = ivc.accumulate(circuit_3);
EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17);

kernel_circuit = GoblinUltraCircuitBuilder{ ivc.goblin.op_queue };
kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit,
Expand Down
2 changes: 1 addition & 1 deletion cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo

// TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet
// dealing with proper recursion
if constexpr (IsGoblinBuilder<Builder>) {
if constexpr (IsGoblinUltraBuilder<Builder>) {
if (!constraint_system.recursion_constraints.empty()) {
info("WARNING: this circuit contains recursion_constraints!");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace bb::stdlib {
template <typename Params, typename Builder>
typename Poseidon2Permutation<Params, Builder>::State Poseidon2Permutation<Params, Builder>::permutation(
Builder* builder, const typename Poseidon2Permutation<Params, Builder>::State& input)
requires IsGoblinBuilder<Builder>
requires IsGoblinUltraBuilder<Builder>
{
// deep copy
State current_state(input);
Expand Down Expand Up @@ -120,7 +120,7 @@ typename Poseidon2Permutation<Params, Builder>::State Poseidon2Permutation<Param
template <typename Params, typename Builder>
typename Poseidon2Permutation<Params, Builder>::State Poseidon2Permutation<Params, Builder>::permutation(
Builder* builder, const typename Poseidon2Permutation<Params, Builder>::State& input)
requires IsNotGoblinBuilder<Builder>
requires IsNotGoblinUltraBuilder<Builder>
{
// deep copy
State current_state(input);
Expand Down Expand Up @@ -156,7 +156,7 @@ typename Poseidon2Permutation<Params, Builder>::State Poseidon2Permutation<Param
template <typename Params, typename Builder>
void Poseidon2Permutation<Params, Builder>::add_round_constants(
State& input, const typename Poseidon2Permutation<Params, Builder>::RoundConstants& rc)
requires IsNotGoblinBuilder<Builder>
requires IsNotGoblinUltraBuilder<Builder>

{
for (size_t i = 0; i < t; ++i) {
Expand All @@ -166,7 +166,7 @@ void Poseidon2Permutation<Params, Builder>::add_round_constants(

template <typename Params, typename Builder>
void Poseidon2Permutation<Params, Builder>::apply_sbox(State& input)
requires IsNotGoblinBuilder<Builder>
requires IsNotGoblinUltraBuilder<Builder>
{
for (auto& in : input) {
apply_single_sbox(in);
Expand All @@ -175,7 +175,7 @@ void Poseidon2Permutation<Params, Builder>::apply_sbox(State& input)

template <typename Params, typename Builder>
void Poseidon2Permutation<Params, Builder>::apply_single_sbox(field_t<Builder>& input)
requires IsNotGoblinBuilder<Builder>
requires IsNotGoblinUltraBuilder<Builder>
{
// hardcoded assumption that d = 5. should fix this or not make d configurable
auto xx = input.sqr();
Expand All @@ -185,7 +185,7 @@ void Poseidon2Permutation<Params, Builder>::apply_single_sbox(field_t<Builder>&

template <typename Params, typename Builder>
void Poseidon2Permutation<Params, Builder>::matrix_multiplication_internal(State& input)
requires IsNotGoblinBuilder<Builder>
requires IsNotGoblinUltraBuilder<Builder>
{
// for t = 4
auto sum = input[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,18 @@ template <typename Params, typename Builder> class Poseidon2Permutation {
* @return State
*/
static State permutation(Builder* builder, const State& input)
requires IsGoblinBuilder<Builder>;
requires IsGoblinUltraBuilder<Builder>;
static State permutation(Builder* builder, const State& input)
requires IsNotGoblinBuilder<Builder>;
requires IsNotGoblinUltraBuilder<Builder>;

static void add_round_constants(State& input, const RoundConstants& rc)
requires IsNotGoblinBuilder<Builder>;
requires IsNotGoblinUltraBuilder<Builder>;
static void apply_sbox(State& input)
requires IsNotGoblinBuilder<Builder>;
requires IsNotGoblinUltraBuilder<Builder>;
static void apply_single_sbox(field_t<Builder>& input)
requires IsNotGoblinBuilder<Builder>;
requires IsNotGoblinUltraBuilder<Builder>;
static void matrix_multiplication_internal(State& input)
requires IsNotGoblinBuilder<Builder>;
requires IsNotGoblinUltraBuilder<Builder>;

/**
* @brief Separate function to do just the first linear layer (equivalent to external matrix mul).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ std::array<typename Flavor::GroupElement, 2> DeciderRecursiveVerifier_<Flavor>::

template class DeciderRecursiveVerifier_<bb::UltraRecursiveFlavor_<UltraCircuitBuilder>>;
template class DeciderRecursiveVerifier_<bb::GoblinUltraRecursiveFlavor_<GoblinUltraCircuitBuilder>>;
template class DeciderRecursiveVerifier_<bb::UltraRecursiveFlavor_<GoblinUltraCircuitBuilder>>;
template class DeciderRecursiveVerifier_<bb::GoblinUltraRecursiveFlavor_<UltraCircuitBuilder>>;
template class DeciderRecursiveVerifier_<bb::UltraRecursiveFlavor_<CircuitSimulatorBN254>>;
template class DeciderRecursiveVerifier_<bb::GoblinUltraRecursiveFlavor_<CircuitSimulatorBN254>>;
} // namespace bb::stdlib::recursion::honk
Original file line number Diff line number Diff line change
Expand Up @@ -165,42 +165,17 @@ std::shared_ptr<typename VerifierInstances::Instance> ProtoGalaxyRecursiveVerifi
next_accumulator->verification_key->pcs_verification_key = accumulator->verification_key->pcs_verification_key;
next_accumulator->verification_key->pub_inputs_offset = accumulator->verification_key->pub_inputs_offset;
next_accumulator->public_inputs = accumulator->public_inputs;
size_t vk_idx = 0;
for (auto& expected_vk : next_accumulator->verification_key->get_all()) {
size_t inst = 0;
std::vector<FF> scalars;
std::vector<Commitment> commitments;
for (auto& instance : instances) {
scalars.emplace_back(lagranges[inst]);
commitments.emplace_back(instance->verification_key->get_all()[vk_idx]);
inst++;
}
expected_vk = Commitment::batch_mul(commitments, scalars);
vk_idx++;
}

next_accumulator->is_accumulator = true;

// Compute next folding parameters and verify against the ones received from the prover
// Compute next folding parameters
next_accumulator->target_sum =
perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge;
next_accumulator->gate_challenges =
update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas);

// Compute ϕ and verify against the data received from the prover
auto& acc_witness_commitments = next_accumulator->witness_commitments;
size_t comm_idx = 0;
for (auto& comm : acc_witness_commitments.get_all()) {
std::vector<FF> scalars;
std::vector<Commitment> commitments;
size_t inst = 0;
for (auto& instance : instances) {
scalars.emplace_back(lagranges[inst]);
commitments.emplace_back(instance->witness_commitments.get_all()[comm_idx]);
inst++;
}
comm = Commitment::batch_mul(commitments, scalars);
comm_idx++;
}
// Compute ϕ
fold_commitments(lagranges, instances, next_accumulator);

next_accumulator->public_inputs =
std::vector<FF>(static_cast<size_t>(next_accumulator->verification_key->num_public_inputs), 0);
Expand Down Expand Up @@ -248,4 +223,12 @@ template class ProtoGalaxyRecursiveVerifier_<
RecursiveVerifierInstances_<UltraRecursiveFlavor_<UltraCircuitBuilder>, 2>>;
template class ProtoGalaxyRecursiveVerifier_<
RecursiveVerifierInstances_<GoblinUltraRecursiveFlavor_<GoblinUltraCircuitBuilder>, 2>>;
template class ProtoGalaxyRecursiveVerifier_<
RecursiveVerifierInstances_<UltraRecursiveFlavor_<GoblinUltraCircuitBuilder>, 2>>;
template class ProtoGalaxyRecursiveVerifier_<
RecursiveVerifierInstances_<GoblinUltraRecursiveFlavor_<UltraCircuitBuilder>, 2>>;
template class ProtoGalaxyRecursiveVerifier_<
RecursiveVerifierInstances_<UltraRecursiveFlavor_<CircuitSimulatorBN254>, 2>>;
template class ProtoGalaxyRecursiveVerifier_<
RecursiveVerifierInstances_<GoblinUltraRecursiveFlavor_<CircuitSimulatorBN254>, 2>>;
} // namespace bb::stdlib::recursion::honk
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,83 @@ template <class VerifierInstances> class ProtoGalaxyRecursiveVerifier_ {
}
return result;
};

/**
* @brief Hack method to fold the witness commitments and verification key without the batch_mul in the case where
* the recursive folding verifier is instantiated as a vanilla ultra circuit.
*
* @details In the folding recursive verifier we might hit the scenerio where we do a batch_mul(commitments,
* lagranges) where the commitments are equal. That is because when we add gates to ensure no zero commitments,
* these will be the same for all circuits, hitting an edge case in batch_mul that creates a failing constraint.
* Specifically, at some point in the algorithm we compute the difference between the points which, if they are
* equal, would be zero, case that is not supported. See https://github.com/AztecProtocol/barretenberg/issues/971.
*/
void fold_commitments(std::vector<FF> lagranges,
VerifierInstances& instances,
std::shared_ptr<Instance>& accumulator)
requires IsUltraBuilder<Builder>
{
using ElementNative = typename Flavor::Curve::ElementNative;
using AffineElementNative = typename Flavor::Curve::AffineElementNative;

auto offset_generator = Commitment::from_witness(builder, AffineElementNative(ElementNative::random_element()));

size_t vk_idx = 0;
for (auto& expected_vk : accumulator->verification_key->get_all()) {
expected_vk = offset_generator;
size_t inst = 0;
for (auto& instance : instances) {
expected_vk += instance->verification_key->get_all()[vk_idx] * lagranges[inst];
inst++;
}
expected_vk -= offset_generator;
vk_idx++;
}

size_t comm_idx = 0;
for (auto& comm : accumulator->witness_commitments.get_all()) {
comm = offset_generator;
size_t inst = 0;
for (auto& instance : instances) {
comm += instance->witness_commitments.get_all()[comm_idx] * lagranges[inst];
inst++;
}
comm -= offset_generator;
comm_idx++;
}
}

/**
* @brief Folds the witness commitments and verification key (part of ϕ) and stores the values in the accumulator.
*
*
*/

void fold_commitments(std::vector<FF> lagranges,
VerifierInstances& instances,
std::shared_ptr<Instance>& accumulator)
requires(!IsUltraBuilder<Builder>)
{
size_t vk_idx = 0;
for (auto& expected_vk : accumulator->verification_key->get_all()) {
std::vector<Commitment> commitments;
for (auto& instance : instances) {
commitments.emplace_back(instance->verification_key->get_all()[vk_idx]);
}
expected_vk = Commitment::batch_mul(commitments, lagranges);
vk_idx++;
}

size_t comm_idx = 0;
for (auto& comm : accumulator->witness_commitments.get_all()) {
std::vector<Commitment> commitments;
for (auto& instance : instances) {
commitments.emplace_back(instance->witness_commitments.get_all()[comm_idx]);
}
comm = Commitment::batch_mul(commitments, lagranges);
comm_idx++;
}
}
};

} // namespace bb::stdlib::recursion::honk
Loading

0 comments on commit ff460a8

Please sign in to comment.