Skip to content

Commit baea4b3

Browse files
feat: Zw/goblin avm tests (#12904)
Introduces a new class `AvmGoblinRecursiveVerifier` that manages the Goblinized AVM recursive verification algorithm. The algorithm involves the construction of two circuits. The first is a Mega-arithmetized AVM recursive verifier. The second is an Ultra circuit that recursively verifies the proof of the first (which consists of a Mega proof plus a Goblin proof). The output of the algorithm is equivalent to a that of a Rollup Honk recursive verifier: a pairing point accumulator plus an IPA claim/proof (stemming from recursive verification of the ECCVM). See the class description for a more detailed description of the algorithm. Currently the algorithm is tested in a standalone test only and is not yet integrated into ACIR. E.g. at this stage a noir program with a verify_proof call of type AVM will still generate a vanilla Ultra recursive verifier. Note: This work is incomplete in a number of ways, the most significant of which I've documented in several sub-issues under this umbrella [issue](AztecProtocol/barretenberg#1303). --------- Co-authored-by: zac-williamson <[email protected]>
1 parent 2b8d136 commit baea4b3

File tree

14 files changed

+459
-98
lines changed

14 files changed

+459
-98
lines changed

barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,8 @@ PairingPointAccumulatorIndices process_avm_recursion_constraints(
520520
// Add recursion constraints
521521
size_t idx = 0;
522522
for (auto& constraint : constraint_system.avm_recursion_constraints) {
523+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1303): Utilize the version of this method that
524+
// employs the Goblinized AVM recursive verifier.
523525
current_aggregation_object = create_avm_recursion_constraints(
524526
builder, constraint, current_aggregation_object, has_valid_witness_assignments);
525527

barretenberg/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.cpp

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp"
77
#include "barretenberg/stdlib/primitives/curves/bn254.hpp"
88
#include "barretenberg/stdlib_circuit_builders/ultra_flavor.hpp"
9+
#include "barretenberg/vm/avm/recursion/goblin_avm_recursive_verifier.hpp"
910
#include "barretenberg/vm/avm/recursion/recursive_flavor.hpp"
1011
#include "barretenberg/vm/avm/recursion/recursive_verifier.hpp"
1112
#include "barretenberg/vm/avm/trace/common.hpp"
@@ -161,24 +162,17 @@ PairingPointAccumulatorIndices create_avm_recursion_constraints(
161162

162163
ASSERT(input.proof_type == AVM);
163164

164-
// Construct an in-circuit representation of the verification key.
165-
std::vector<field_ct> key_fields;
166-
key_fields.reserve(input.key.size());
167-
for (const auto& idx : input.key) {
168-
auto field = field_ct::from_witness_index(&builder, idx);
169-
key_fields.emplace_back(field);
170-
}
171-
172165
auto fields_from_witnesses = [&](std::vector<uint32_t> const& input) {
173166
std::vector<field_ct> result;
174167
result.reserve(input.size());
175168
for (const auto& idx : input) {
176-
auto field = field_ct::from_witness_index(&builder, idx);
177-
result.emplace_back(field);
169+
result.emplace_back(field_ct::from_witness_index(&builder, idx));
178170
}
179171
return result;
180172
};
181173

174+
// Construct in-circuit representation of the verification key, proof and public inputs
175+
const auto key_fields = fields_from_witnesses(input.key);
182176
const auto proof_fields = fields_from_witnesses(input.proof);
183177
const auto public_inputs_flattened = fields_from_witnesses(input.public_inputs);
184178

@@ -209,5 +203,67 @@ PairingPointAccumulatorIndices create_avm_recursion_constraints(
209203
return output_agg_object.get_witness_indices();
210204
}
211205

206+
/**
207+
* @brief Add constraints associated with recursive verification an AVM proof using Goblin
208+
*
209+
* @param builder
210+
* @param input
211+
* @param input_aggregation_object_indices
212+
* @param has_valid_witness_assignments
213+
* @return HonkRecursionConstraintOutput {pairing agg object, ipa claim, ipa proof}
214+
*/
215+
HonkRecursionConstraintOutput create_avm_recursion_constraints_goblin(
216+
Builder& builder,
217+
const RecursionConstraint& input,
218+
PairingPointAccumulatorIndices input_aggregation_object_indices,
219+
bool has_valid_witness_assignments)
220+
{
221+
using RecursiveVerifier = bb::avm::AvmGoblinRecursiveVerifier;
222+
223+
ASSERT(input.proof_type == AVM);
224+
225+
auto fields_from_witnesses = [&](std::vector<uint32_t> const& input) {
226+
std::vector<field_ct> result;
227+
result.reserve(input.size());
228+
for (const auto& idx : input) {
229+
result.emplace_back(field_ct::from_witness_index(&builder, idx));
230+
}
231+
return result;
232+
};
233+
234+
// Construct in-circuit representations of the verification key, proof and public inputs
235+
const auto key_fields = fields_from_witnesses(input.key);
236+
const auto proof_fields = fields_from_witnesses(input.proof);
237+
const auto public_inputs_flattened = fields_from_witnesses(input.public_inputs);
238+
239+
auto it = public_inputs_flattened.begin();
240+
VmPublicInputs vm_public_inputs =
241+
avm_trace::convert_public_inputs(std::vector(it, it + PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH));
242+
it += PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH;
243+
std::vector<field_ct> calldata(it, it + AVM_PUBLIC_COLUMN_MAX_SIZE);
244+
it += AVM_PUBLIC_COLUMN_MAX_SIZE;
245+
std::vector<field_ct> return_data(it, it + AVM_PUBLIC_COLUMN_MAX_SIZE);
246+
247+
auto public_inputs_vectors = avm_trace::copy_public_inputs_columns(vm_public_inputs, calldata, return_data);
248+
249+
// Populate the key fields and proof fields with dummy values to prevent issues (e.g. points must be on curve).
250+
if (!has_valid_witness_assignments) {
251+
create_dummy_vkey_and_proof(builder, input.proof.size(), input.public_inputs.size(), key_fields, proof_fields);
252+
}
253+
254+
// Execute the Goblin AVM recursive verifier
255+
RecursiveVerifier verifier(&builder, key_fields);
256+
aggregation_state_ct input_agg_obj = bb::stdlib::recursion::convert_witness_indices_to_agg_obj<Builder, bn254>(
257+
builder, input_aggregation_object_indices);
258+
auto output_agg_object = verifier.verify_proof(proof_fields, public_inputs_vectors, input_agg_obj);
259+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/996): investigate whether assert_equal on public
260+
// inputs is important, like what the plonk recursion constraint does.
261+
262+
HonkRecursionConstraintOutput result{ .agg_obj_indices = output_agg_object.aggregation_object.get_witness_indices(),
263+
.ipa_claim = output_agg_object.ipa_claim,
264+
.ipa_proof = output_agg_object.ipa_proof };
265+
return result;
266+
}
267+
212268
} // namespace acir_format
213269
#endif // DISABLE_AZTEC_VM

barretenberg/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#ifndef DISABLE_AZTEC_VM
22
#pragma once
3+
#include "barretenberg/dsl/acir_format/honk_recursion_constraint.hpp"
34
#include "barretenberg/dsl/acir_format/recursion_constraint.hpp"
45
#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp"
5-
66
namespace acir_format {
77
using Builder = bb::UltraCircuitBuilder;
88

@@ -13,5 +13,11 @@ PairingPointAccumulatorIndices create_avm_recursion_constraints(Builder& builder
1313
PairingPointAccumulatorIndices input_aggregation_object,
1414
bool has_valid_witness_assignments);
1515

16+
HonkRecursionConstraintOutput create_avm_recursion_constraints_goblin(
17+
Builder& builder,
18+
const RecursionConstraint& input,
19+
PairingPointAccumulatorIndices input_aggregation_object,
20+
bool has_valid_witness_assignments);
21+
1622
} // namespace acir_format
17-
#endif // DISABLE_AZTEC_VM
23+
#endif // DISABLE_AZTEC_VM

barretenberg/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.test.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ class AcirAvmRecursionConstraint : public ::testing::Test {
4242
using OuterVerificationKey = UltraFlavor::VerificationKey;
4343
using OuterBuilder = UltraCircuitBuilder;
4444

45-
static void SetUpTestSuite() { bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); }
45+
static void SetUpTestSuite()
46+
{
47+
bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path());
48+
bb::srs::init_grumpkin_crs_factory(bb::srs::get_grumpkin_crs_path());
49+
}
4650

4751
// mutate the input kernel_public_inputs_vec to add end gas values
4852
static InnerBuilder create_inner_circuit([[maybe_unused]] std::vector<FF>& kernel_public_inputs_vec)

barretenberg/cpp/src/barretenberg/flavor/flavor.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ concept IsRecursiveFlavor = IsAnyOf<T, UltraRecursiveFlavor_<UltraCircuitBuilder
406406
TranslatorRecursiveFlavor_<MegaCircuitBuilder>,
407407
TranslatorRecursiveFlavor_<CircuitSimulatorBN254>,
408408
ECCVMRecursiveFlavor_<UltraCircuitBuilder>,
409-
AvmRecursiveFlavor_<UltraCircuitBuilder>>;
409+
AvmRecursiveFlavor_<UltraCircuitBuilder>,
410+
AvmRecursiveFlavor_<MegaCircuitBuilder>>;
410411

411412
// These concepts are relevant for Sumcheck, where the logic is different for BN254 and Grumpkin Flavors
412413
template <typename T> concept IsGrumpkinFlavor = IsAnyOf<T, ECCVMFlavor, ECCVMRecursiveFlavor_<UltraCircuitBuilder>>;

barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ namespace bb::stdlib::recursion::honk {
44

55
/**
66
* @brief Runs the Goblin recursive verifier consisting of ECCVM, Translator and Merge verifiers.
7+
* // TODO(https://github.com/AztecProtocol/barretenberg/issues/1309): Implement correct pairing point aggregation.
8+
* Method needs to accept an input agg object, aggregate the pairing points from both translator and merge, then return
9+
* the updated agg object.
710
*/
811
GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof& proof)
912
{
@@ -15,8 +18,7 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof&
1518
TranslatorVerifier translator_verifier{ builder,
1619
verification_keys.translator_verification_key,
1720
eccvm_verifier.transcript };
18-
19-
translator_verifier.verify_proof(
21+
[[maybe_unused]] auto translator_pairing_points = translator_verifier.verify_proof(
2022
proof.translator_proof, eccvm_verifier.evaluation_challenge_x, eccvm_verifier.batching_challenge_v);
2123

2224
// Verify the consistency between the ECCVM and Translator transcript polynomial evaluations
@@ -35,7 +37,7 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof&
3537

3638
MergeVerifier merge_verifier{ builder };
3739
StdlibProof<Builder> stdlib_merge_proof = bb::convert_native_proof_to_stdlib(builder, proof.merge_proof);
38-
merge_verifier.verify_proof(stdlib_merge_proof);
40+
[[maybe_unused]] auto merge_pairing_points = merge_verifier.verify_proof(stdlib_merge_proof);
3941
return { opening_claim, ipa_transcript };
4042
}
4143
} // namespace bb::stdlib::recursion::honk

barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ UltraRecursiveVerifier_<Flavor>::Output UltraRecursiveVerifier_<Flavor>::verify_
100100
// TODO(https://github.com/AztecProtocol/barretenberg/issues/995): generate this challenge properly.
101101
typename Curve::ScalarField recursion_separator =
102102
Curve::ScalarField::from_witness_index(builder, builder->add_variable(42));
103-
agg_obj.template aggregate<Builder>(nested_agg_obj, recursion_separator);
103+
agg_obj.aggregate(nested_agg_obj, recursion_separator);
104104

105105
// Execute Sumcheck Verifier and extract multivariate opening point u = (u_0, ..., u_{d-1}) and purported
106106
// multivariate evaluations at u
@@ -144,7 +144,7 @@ UltraRecursiveVerifier_<Flavor>::Output UltraRecursiveVerifier_<Flavor>::verify_
144144
pairing_points[0] = pairing_points[0].normalize();
145145
pairing_points[1] = pairing_points[1].normalize();
146146
// TODO(https://github.com/AztecProtocol/barretenberg/issues/995): generate recursion separator challenge properly.
147-
agg_obj.template aggregate<Builder>(pairing_points, recursion_separator);
147+
agg_obj.aggregate(pairing_points, recursion_separator);
148148
output.agg_obj = std::move(agg_obj);
149149

150150
// Extract the IPA claim from the public inputs

barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ template <typename Curve> struct aggregation_state {
2020
{
2121
return P0 == other.P0 && P1 == other.P1;
2222
};
23-
template <typename BuilderType = void>
23+
2424
void aggregate(aggregation_state const& other, typename Curve::ScalarField recursion_separator)
2525
{
26-
if constexpr (std::is_same_v<BuilderType, MegaCircuitBuilder>) {
26+
using Builder = typename Curve::Builder;
27+
28+
if constexpr (std::is_same_v<Builder, MegaCircuitBuilder>) {
2729
P0 += other.P0 * recursion_separator;
2830
P1 += other.P1 * recursion_separator;
2931
} else {
@@ -36,10 +38,11 @@ template <typename Curve> struct aggregation_state {
3638
}
3739
}
3840

39-
template <typename BuilderType = void>
4041
void aggregate(std::array<typename Curve::Group, 2> const& other, typename Curve::ScalarField recursion_separator)
4142
{
42-
if constexpr (std::is_same_v<BuilderType, MegaCircuitBuilder>) {
43+
using Builder = typename Curve::Builder;
44+
45+
if constexpr (std::is_same_v<Builder, MegaCircuitBuilder>) {
4346
P0 += other[0] * recursion_separator;
4447
P1 += other[1] * recursion_separator;
4548
} else {
@@ -74,6 +77,7 @@ template <typename Curve> struct aggregation_state {
7477
};
7578
return witness_indices;
7679
}
80+
7781
void assign_object_to_proof_outputs()
7882
{
7983
P0 = P0.reduce();

barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ template <class Builder_, class Fq, class Fr, class NativeGroup> class goblin_el
349349
bool_ct _is_infinity;
350350
};
351351

352+
using BiggroupGoblin = goblin_element<bb::MegaCircuitBuilder,
353+
bb::stdlib::goblin_field<MegaCircuitBuilder>,
354+
stdlib::field_t<MegaCircuitBuilder>,
355+
bb::g1>;
356+
352357
template <typename C, typename Fq, typename Fr, typename G>
353358
inline std::ostream& operator<<(std::ostream& os, goblin_element<C, Fq, Fr, G> const& v)
354359
{
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
if(NOT DISABLE_AZTEC_VM)
2-
barretenberg_module(vm sumcheck stdlib_honk_verifier)
3-
endif()
2+
barretenberg_module(vm sumcheck stdlib_honk_verifier stdlib_goblin_verifier)
3+
endif()

0 commit comments

Comments
 (0)