Skip to content

Commit f25ce51

Browse files
authored
feat!: remove avm fallback and constrain public inputs validation (#18957)
Remove the AVM fallback and constrain AVM public inputs validation in recursive verifier.
1 parent c78066b commit f25ce51

File tree

35 files changed

+4418
-8497
lines changed

35 files changed

+4418
-8497
lines changed

barretenberg/cpp/src/barretenberg/vm2/common/aztec_constants.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175
#define AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH 4685
176176
#define AVM_NUM_PUBLIC_INPUT_COLUMNS 4
177177
#define AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH 18740
178-
#define AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED 20000
178+
#define AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED 16200
179179
#define AVM_V2_VERIFICATION_KEY_LENGTH_IN_FIELDS_PADDED 1000
180180
#define AVM_MAX_PROCESSABLE_L2_GAS 6000000
181181
#define AVM_PC_SIZE_IN_BITS 32

barretenberg/cpp/src/barretenberg/vm2/constraining/prover.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,8 @@ HonkProof AvmProver::construct_proof()
219219
// Add circuit size public input size and public inputs to transcript.
220220
execute_preamble_round();
221221

222-
// TODO(https://github.com/AztecProtocol/aztec-packages/pull/17045): make the protocols secure at some point
223-
// // Add public inputs to transcript.
224-
// AVM_TRACK_TIME("prove/public_inputs_round", execute_public_inputs_round());
222+
// Add public inputs to transcript.
223+
AVM_TRACK_TIME("prove/public_inputs_round", execute_public_inputs_round());
225224

226225
// Compute wire commitments.
227226
AVM_TRACK_TIME("prove/wire_commitments_round", execute_wire_commitments_round());

barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.cpp

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include "barretenberg/honk/proof_system/types/proof.hpp"
1010
#include "barretenberg/polynomials/polynomial.hpp"
1111
#include "barretenberg/polynomials/shared_shifted_virtual_zeroes_array.hpp"
12-
#include "barretenberg/stdlib/primitives/bool/bool.hpp"
1312
#include "barretenberg/stdlib/primitives/field/field.hpp"
1413
#include "barretenberg/stdlib/primitives/padding_indicator_array/padding_indicator_array.hpp"
1514
#include "barretenberg/transcript/transcript.hpp"
@@ -70,9 +69,8 @@ AvmRecursiveVerifier::PairingPoints AvmRecursiveVerifier::verify_proof(
7069
}
7170

7271
// TODO(#991): (see https://github.com/AztecProtocol/barretenberg/issues/991)
73-
// TODO(#14234)[Unconditional PIs validation]: rename stdlib_proof_with_pi_flag to stdlib_proof
7472
AvmRecursiveVerifier::PairingPoints AvmRecursiveVerifier::verify_proof(
75-
const stdlib::Proof<Builder>& stdlib_proof_with_pi_flag, const std::vector<std::vector<FF>>& public_inputs)
73+
const stdlib::Proof<Builder>& stdlib_proof, const std::vector<std::vector<FF>>& public_inputs)
7674
{
7775
using Curve = typename Flavor::Curve;
7876
using PCS = typename Flavor::PCS;
@@ -81,16 +79,6 @@ AvmRecursiveVerifier::PairingPoints AvmRecursiveVerifier::verify_proof(
8179
using Shplemini = ShpleminiVerifier_<Curve, Flavor::HasZK>;
8280
using ClaimBatcher = ClaimBatcher_<Curve>;
8381
using ClaimBatch = ClaimBatcher::Batch;
84-
using stdlib::bool_t;
85-
86-
// TODO(#14234)[Unconditional PIs validation]: Remove the next 3 lines
87-
StdlibProof stdlib_proof = stdlib_proof_with_pi_flag;
88-
bool_t<Builder> pi_validation = !bool_t<Builder>(stdlib_proof.at(0));
89-
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/16716) Origin Tag security mechanism is screaming
90-
// that there is a free witness affecting proof verificaton. Because it is and this bool allows completely disabling
91-
// public input logic. So this has to be removed in the future.
92-
pi_validation.unset_free_witness_tag();
93-
stdlib_proof.erase(stdlib_proof.begin());
9482

9583
if (public_inputs.size() != AVM_NUM_PUBLIC_INPUT_COLUMNS) {
9684
throw_or_abort("AvmRecursiveVerifier::verify_proof: public inputs size mismatch");
@@ -110,21 +98,11 @@ AvmRecursiveVerifier::PairingPoints AvmRecursiveVerifier::verify_proof(
11098
RelationParams relation_parameters;
11199
VerifierCommitments commitments{ key };
112100

113-
// TODO(https://github.com/AztecProtocol/aztec-packages/pull/17045): make the protocols secure at some point
114-
// // Add public inputs to transcript
115-
// for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
116-
// for (size_t j = 0; j < public_inputs[i].size(); j++) {
117-
// transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
118-
// public_inputs[i][j]);
119-
// }
120-
// }
121-
101+
// Add public inputs to transcript for Fiat-Shamir
122102
for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
123103
for (size_t j = 0; j < public_inputs[i].size(); j++) {
124-
// TODO(https://github.com/AztecProtocol/aztec-packages/pull/17045): make the protocols secure at some point
125-
// transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
126-
// public_inputs[i][j]);
127-
public_inputs[i][j].unset_free_witness_tag();
104+
transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
105+
public_inputs[i][j]);
128106
}
129107
}
130108
// Get commitments to VM wires
@@ -168,12 +146,11 @@ AvmRecursiveVerifier::PairingPoints AvmRecursiveVerifier::verify_proof(
168146
output.claimed_evaluations.get(C::public_inputs_cols_3_),
169147
};
170148

171-
// TODO(#14234)[Unconditional PIs validation]: Inside of loop, replace pi_validation.must_imply() by
172-
// public_input_evaluation.assert_equal(claimed_evaluations[i]
149+
// Validate public inputs match the claimed evaluations
173150
for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
174151
FF public_input_evaluation = evaluate_public_input_column(public_inputs[i], output.challenge);
175-
pi_validation.must_imply(public_input_evaluation == claimed_evaluations[i],
176-
format("public_input_evaluation failed at column ", i));
152+
public_input_evaluation.assert_equal(claimed_evaluations[i],
153+
format("public_input_evaluation failed at column ", i));
177154
}
178155

179156
// Batch commitments and evaluations using short scalars to reduce ECCVM circuit size

barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.hpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ class AvmRecursiveVerifier {
2929
[[nodiscard("IPA claim and Pairing points should be accumulated")]] PairingPoints verify_proof(
3030
const HonkProof& proof, const std::vector<std::vector<fr>>& public_inputs_vec_nt);
3131
[[nodiscard("IPA claim and Pairing points should be accumulated")]] PairingPoints verify_proof(
32-
const StdlibProof& stdlib_proof_with_pi_flag, // TODO(#14234)[Unconditional PIs validation]: rename
33-
// stdlib_proof_with_pi_flag to stdlib_proof
34-
const std::vector<std::vector<typename Flavor::FF>>& public_inputs);
32+
const StdlibProof& stdlib_proof, const std::vector<std::vector<typename Flavor::FF>>& public_inputs);
3533

3634
Builder& builder;
3735
std::shared_ptr<VerificationKey> key;

barretenberg/cpp/src/barretenberg/vm2/constraining/recursion/recursive_verifier.test.cpp

Lines changed: 28 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "barretenberg/ultra_honk/prover_instance.hpp"
77
#include "barretenberg/ultra_honk/ultra_prover.hpp"
88
#include "barretenberg/ultra_honk/ultra_verifier.hpp"
9+
#include "barretenberg/vm2/common/aztec_constants.hpp"
910
#include "barretenberg/vm2/constraining/prover.hpp"
1011
#include "barretenberg/vm2/constraining/recursion/goblin_avm_recursive_verifier.hpp"
1112
#include "barretenberg/vm2/constraining/recursion/recursive_flavor.hpp"
@@ -57,19 +58,26 @@ class AvmRecursiveTests : public ::testing::Test {
5758
}
5859
};
5960

61+
// Parameterized test class for testing with and without proof padding
62+
class AvmRecursiveTestsParameterized : public AvmRecursiveTests, public ::testing::WithParamInterface<bool> {};
63+
6064
/**
6165
* @brief A test of the Goblinized AVM recursive verifier.
6266
* @details Constructs a simple AVM circuit for which a proof is verified using the Goblinized AVM recursive verifier. A
6367
* proof is constructed and verified for the outer (Ultra) circuit produced by this algorithm. See the documentation in
6468
* AvmGoblinRecursiveVerifier for details of the recursive verification algorithm.
6569
*
70+
* When pad_proof=true (Padded variant), the proof is padded to AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED to match production
71+
* behavior where TypeScript pads the proof before passing it to noir circuits.
6672
*/
67-
TEST_F(AvmRecursiveTests, GoblinRecursion)
73+
TEST_P(AvmRecursiveTestsParameterized, GoblinRecursion)
6874
{
6975
if (testing::skip_slow_tests()) {
7076
GTEST_SKIP() << "Skipping slow test";
7177
}
7278

79+
const bool pad_proof = GetParam();
80+
7381
// Type aliases specific to GoblinRecursion test
7482
using AvmRecursiveVerifier = AvmGoblinRecursiveVerifier;
7583
using OuterBuilder = typename UltraRollupFlavor::CircuitBuilder;
@@ -86,7 +94,14 @@ TEST_F(AvmRecursiveTests, GoblinRecursion)
8694
<< "s" << std::endl;
8795

8896
auto [proof, public_inputs_cols] = proof_result;
89-
proof.insert(proof.begin(), 0); // TODO(#14234)[Unconditional PIs validation]: remove this
97+
98+
// Optionally pad the proof to match production behavior
99+
if (pad_proof) {
100+
std::cout << "Padding proof from " << proof.size() << " to " << AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED
101+
<< " fields" << std::endl;
102+
ASSERT_LE(proof.size(), AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED) << "Proof exceeds padded length";
103+
proof.resize(AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED, 0);
104+
}
90105

91106
// Construct stdlib representations of the proof, public inputs and verification key
92107
OuterBuilder outer_circuit;
@@ -106,7 +121,8 @@ TEST_F(AvmRecursiveTests, GoblinRecursion)
106121
// Construct the AVM recursive verifier and verify the proof
107122
// Scoped to free memory of AvmRecursiveVerifier.
108123
auto verifier_output = [&]() {
109-
std::cout << "Constructing AvmRecursiveVerifier and verifying proof..." << std::endl;
124+
std::cout << "Constructing AvmRecursiveVerifier and verifying " << (pad_proof ? "padded " : "") << "proof..."
125+
<< std::endl;
110126
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
111127
AvmRecursiveVerifier avm_rec_verifier(outer_circuit);
112128
auto result = avm_rec_verifier.verify_proof(stdlib_proof, public_inputs_ct);
@@ -129,7 +145,10 @@ TEST_F(AvmRecursiveTests, GoblinRecursion)
129145
ASSERT_TRUE(agg_output_valid) << "Pairing points (aggregation state) are not valid.";
130146
ASSERT_FALSE(outer_circuit.failed()) << "Outer circuit has failed.";
131147

132-
vinfo("Recursive verifier: finalized num gates = ", outer_circuit.num_gates());
148+
vinfo("Recursive verifier",
149+
(pad_proof ? " (padded proof)" : ""),
150+
": finalized num gates = ",
151+
outer_circuit.num_gates());
133152

134153
// Construct and verify an Ultra Rollup proof of the AVM recursive verifier circuit. This proof carries an IPA claim
135154
// from ECCVM recursive verification in its public inputs that will be verified as part of the UltraRollupVerifier.
@@ -153,99 +172,10 @@ TEST_F(AvmRecursiveTests, GoblinRecursion)
153172
EXPECT_TRUE(result);
154173
}
155174

156-
// Similar to GoblinRecursion, but with PI validation disabled and garbage PIs in the public inputs.
157-
// This is important as long as we use a fallback mechanism for the AVM proofs.
158-
TEST_F(AvmRecursiveTests, GoblinRecursionWithoutPIValidation)
159-
{
160-
if (testing::skip_slow_tests()) {
161-
GTEST_SKIP() << "Skipping slow test";
162-
}
163-
164-
// Type aliases specific to GoblinRecursion test
165-
using AvmRecursiveVerifier = AvmGoblinRecursiveVerifier;
166-
using OuterBuilder = typename UltraRollupFlavor::CircuitBuilder;
167-
using UltraFF = UltraRecursiveFlavor_<OuterBuilder>::FF;
168-
using UltraRollupProver = UltraProver_<UltraRollupFlavor>;
169-
using NativeVerifierCommitmentKey = typename AvmFlavor::VerifierCommitmentKey;
170-
171-
NativeProofResult proof_result;
172-
std::cout << "Creating and verifying native proof..." << std::endl;
173-
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
174-
ASSERT_NO_FATAL_FAILURE({ create_and_verify_native_proof(proof_result); });
175-
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
176-
std::cout << "Time taken (native proof): " << std::chrono::duration_cast<std::chrono::seconds>(end - start).count()
177-
<< "s" << std::endl;
178-
179-
auto [proof, public_inputs_cols] = proof_result;
180-
// Set fallback / disable PI validation
181-
proof.insert(proof.begin(),
182-
1); // TODO(#14234)[Unconditional PIs validation]: PI validation is disabled for this test.
183-
184-
// Construct stdlib representations of the proof, public inputs and verification key
185-
OuterBuilder outer_circuit;
186-
stdlib::Proof<OuterBuilder> stdlib_proof(outer_circuit, proof);
187-
188-
std::vector<std::vector<UltraFF>> public_inputs_ct;
189-
public_inputs_ct.reserve(public_inputs_cols.size());
190-
// Use GARBAGE in public inputs and confirm that PI validation is disabled!
191-
for (const auto& vec : public_inputs_cols) {
192-
std::vector<UltraFF> vec_ct;
193-
vec_ct.reserve(vec.size());
194-
for (const auto& _ : vec) {
195-
vec_ct.push_back(UltraFF::from_witness(&outer_circuit, FF::random_element()));
196-
}
197-
public_inputs_ct.push_back(vec_ct);
198-
}
199-
200-
// Construct the AVM recursive verifier and verify the proof
201-
// Scoped to free memory of AvmRecursiveVerifier.
202-
auto verifier_output = [&]() {
203-
std::cout << "Constructing AvmRecursiveVerifier and verifying proof..." << std::endl;
204-
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
205-
AvmRecursiveVerifier avm_rec_verifier(outer_circuit);
206-
auto result = avm_rec_verifier.verify_proof(stdlib_proof, public_inputs_ct);
207-
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
208-
std::cout << "Time taken (recursive verification): "
209-
<< std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << "s" << std::endl;
210-
return result;
211-
}();
212-
213-
stdlib::recursion::honk::RollupIO inputs;
214-
inputs.pairing_inputs = verifier_output.points_accumulator;
215-
inputs.ipa_claim = verifier_output.ipa_claim;
216-
inputs.set_public();
217-
outer_circuit.ipa_proof = verifier_output.ipa_proof.get_value();
218-
219-
// Ensure that the pairing check is satisfied on the outputs of the recursive verifier
220-
NativeVerifierCommitmentKey pcs_vkey{};
221-
bool agg_output_valid = pcs_vkey.pairing_check(verifier_output.points_accumulator.P0.get_value(),
222-
verifier_output.points_accumulator.P1.get_value());
223-
ASSERT_TRUE(agg_output_valid) << "Pairing points (aggregation state) are not valid.";
224-
ASSERT_FALSE(outer_circuit.failed()) << "Outer circuit has failed.";
225-
226-
vinfo("Recursive verifier: finalized num gates = ", outer_circuit.num_gates());
227-
228-
// Construct and verify an Ultra Rollup proof of the AVM recursive verifier circuit. This proof carries an IPA claim
229-
// from ECCVM recursive verification in its public inputs that will be verified as part of the UltraRollupVerifier.
230-
auto outer_proving_key = std::make_shared<ProverInstance_<UltraRollupFlavor>>(outer_circuit);
231-
232-
// Scoped to free memory of UltraRollupProver.
233-
auto outer_proof = [&]() {
234-
auto verification_key =
235-
std::make_shared<UltraRollupFlavor::VerificationKey>(outer_proving_key->get_precomputed());
236-
UltraRollupProver outer_prover(outer_proving_key, verification_key);
237-
return outer_prover.construct_proof();
238-
}();
239-
240-
// Verify the proof of the Ultra circuit that verified the AVM recursive verifier circuit
241-
auto outer_verification_key =
242-
std::make_shared<UltraRollupFlavor::VerificationKey>(outer_proving_key->get_precomputed());
243-
auto outer_vk_and_hash = std::make_shared<UltraRollupFlavor::VKAndHash>(outer_verification_key);
244-
UltraRollupVerifier final_verifier(outer_vk_and_hash);
245-
246-
bool result = final_verifier.verify_proof(outer_proof).result;
247-
EXPECT_TRUE(result);
248-
}
175+
INSTANTIATE_TEST_SUITE_P(PaddingVariants,
176+
AvmRecursiveTestsParameterized,
177+
::testing::Values(false, true),
178+
[](const auto& info) { return info.param ? "Padded" : "Unpadded"; });
249179

250180
// Ensures that the recursive verifier fails with wrong PIs.
251181
TEST_F(AvmRecursiveTests, GoblinRecursionFailsWithWrongPIs)
@@ -268,8 +198,6 @@ TEST_F(AvmRecursiveTests, GoblinRecursionFailsWithWrongPIs)
268198
<< "s" << std::endl;
269199

270200
auto [proof, public_inputs_cols] = proof_result;
271-
// PI validation is enabled.
272-
proof.insert(proof.begin(), 0); // TODO(#14234)[Unconditional PIs validation]: remove this
273201

274202
// Construct stdlib representations of the proof, public inputs and verification key
275203
OuterBuilder outer_circuit;
@@ -285,7 +213,7 @@ TEST_F(AvmRecursiveTests, GoblinRecursionFailsWithWrongPIs)
285213
}
286214
public_inputs_ct.push_back(vec_ct);
287215
}
288-
// Mutate some PI entry so that we can confirm that PI validation is enabled and fails!
216+
// Mutate a PI entry to verify that validation correctly fails with incorrect public inputs
289217
public_inputs_ct[1][5] += 1;
290218

291219
// Construct the AVM recursive verifier and verify the proof

barretenberg/cpp/src/barretenberg/vm2/constraining/verifier.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,10 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector<std::ve
7171
vinfo("Public input size mismatch");
7272
return false;
7373
}
74-
// TODO(https://github.com/AztecProtocol/aztec-packages/pull/17045): make the protocols secure at some point
75-
// for (size_t j = 0; j < public_inputs[i].size(); j++) {
76-
// transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
77-
// public_inputs[i][j]);
78-
// }
74+
for (size_t j = 0; j < public_inputs[i].size(); j++) {
75+
transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
76+
public_inputs[i][j]);
77+
}
7978
}
8079
VerifierCommitments commitments{ key };
8180
// Get commitments to VM wires

barretenberg/cpp/src/barretenberg/vm2/dsl/avm2_recursion_constraint.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,8 @@ void create_dummy_proof(Builder& builder, [[maybe_unused]] size_t proof_size, co
6767
offset++;
6868
};
6969

70-
size_t offset = 0;
71-
7270
// This routine is adding some placeholders for avm proof and avm vk in the case where witnesses are not present.
73-
// TODO(#14234)[Unconditional PIs validation]: Remove next line and use offset == 0 for subsequent line.
74-
builder.set_variable(proof_fields[0].get_witness_index(), 1);
75-
offset = 1; // TODO(#14234)[Unconditional PIs validation]: reset offset = 1
71+
size_t offset = 0;
7672

7773
// Witness Commitments
7874
for (size_t i = 0; i < Flavor::NUM_WITNESS_ENTITIES; i++) {

barretenberg/cpp/src/barretenberg/vm2/dsl/avm2_recursion_constraint.test.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ class AcirAvm2RecursionConstraint : public ::testing::Test {
5454

5555
const auto public_inputs_flat = PublicInputs::columns_to_flat(public_inputs.to_columns());
5656

57-
// TODO(#14234)[Unconditional PIs validation]: Remove next line
58-
proof.insert(proof.begin(), 0);
5957
return { proof, public_inputs_flat };
6058
}
6159

0 commit comments

Comments
 (0)