Skip to content

Commit be1d142

Browse files
authored
feat!: Protogalaxy accumulator hash consistency check (#16547)
Adds the hash consistency check to make sure the input PG accumulator is same as the output one from the previous fold. Closes AztecProtocol/barretenberg#1390.
1 parent 0daa299 commit be1d142

File tree

13 files changed

+131
-81
lines changed

13 files changed

+131
-81
lines changed

barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ cd ..
1111
# - Generate a hash for versioning: sha256sum bb-civc-inputs.tar.gz
1212
# - Upload the compressed results: aws s3 cp bb-civc-inputs.tar.gz s3://aztec-ci-artifacts/protocol/bb-civc-inputs-[hash(0:8)].tar.gz
1313
# Note: In case of the "Test suite failed to run ... Unexpected token 'with' " error, need to run: docker pull aztecprotocol/build:3.0
14-
15-
pinned_short_hash="884109c4"
16-
14+
pinned_short_hash="197c2f73"
1715
pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-${pinned_short_hash}.tar.gz"
1816

1917
function compress_and_upload {

barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp

Lines changed: 93 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,18 @@ void ClientIVC::instantiate_stdlib_verification_queue(
8989
* @param accumulation_recursive_transcript Transcript shared across recursive verification of the folding of
9090
* K_{i-1} (kernel), A_{i,1} (app), .., A_{i, n} (app)
9191
*
92-
* @return Pair of PairingPoints for final verification and commitments to the merged tables as read from the proof by
93-
* the Merge verifier
92+
* @return Triple of output verifier accumulator, PairingPoints for final verification and commitments to the merged
93+
* tables as read from the proof by the Merge verifier
9494
*/
95-
std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
96-
perform_recursive_verification_and_databus_consistency_checks(
97-
ClientCircuit& circuit,
98-
const StdlibVerifierInputs& verifier_inputs,
99-
const TableCommitments& T_prev_commitments,
100-
const std::shared_ptr<RecursiveTranscript>& accumulation_recursive_transcript)
95+
std::tuple<std::shared_ptr<ClientIVC::RecursiveDeciderVerificationKey>,
96+
ClientIVC::PairingPoints,
97+
ClientIVC::TableCommitments>
98+
ClientIVC::perform_recursive_verification_and_databus_consistency_checks(
99+
ClientCircuit& circuit,
100+
const StdlibVerifierInputs& verifier_inputs,
101+
const std::shared_ptr<ClientIVC::RecursiveDeciderVerificationKey>& input_stdlib_verifier_accumulator,
102+
const TableCommitments& T_prev_commitments,
103+
const std::shared_ptr<RecursiveTranscript>& accumulation_recursive_transcript)
101104
{
102105
using MergeCommitments = Goblin::MergeRecursiveVerifier::InputCommitments;
103106

@@ -110,24 +113,30 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
110113
// Input commitments to be passed to the merge recursive verification
111114
MergeCommitments merge_commitments;
112115
merge_commitments.T_prev_commitments = T_prev_commitments;
116+
std::shared_ptr<ClientIVC::RecursiveDeciderVerificationKey> output_stdlib_verifier_accumulator;
117+
std::optional<StdlibFF> prev_accum_hash = std::nullopt;
113118
// The decider proof exists if the tail kernel has been accumulated
114119
bool is_hiding_kernel = !decider_proof.empty();
115120

116121
switch (verifier_inputs.type) {
117122
case QUEUE_TYPE::PG_TAIL:
118123
case QUEUE_TYPE::PG: {
119-
// Construct stdlib verifier accumulator from the native counterpart computed on a previous round
120-
auto stdlib_verifier_accum =
121-
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, recursive_verifier_native_accum);
122-
124+
BB_ASSERT_NEQ(input_stdlib_verifier_accumulator, nullptr);
125+
if (verifier_inputs
126+
.is_kernel) { // this is what I'm using to determine if this is the first circuit we're folding...
127+
// Fiat-Shamir the accumulator.
128+
prev_accum_hash =
129+
input_stdlib_verifier_accumulator->hash_through_transcript("", *accumulation_recursive_transcript);
130+
accumulation_recursive_transcript->add_to_hash_buffer("accum_hash", *prev_accum_hash);
131+
info("Previous accumulator hash in PG rec verifier: ", *prev_accum_hash);
132+
}
123133
// Perform folding recursive verification to update the verifier accumulator
124-
FoldingRecursiveVerifier verifier{
125-
&circuit, stdlib_verifier_accum, { verifier_inputs.honk_vk_and_hash }, accumulation_recursive_transcript
126-
};
127-
auto verifier_accum = verifier.verify_folding_proof(verifier_inputs.proof);
128-
129-
// Extract native verifier accumulator from the stdlib accum for use on the next round
130-
recursive_verifier_native_accum = std::make_shared<DeciderVerificationKey>(verifier_accum->get_value());
134+
FoldingRecursiveVerifier verifier{ &circuit,
135+
input_stdlib_verifier_accumulator,
136+
{ verifier_inputs.honk_vk_and_hash },
137+
accumulation_recursive_transcript };
138+
output_stdlib_verifier_accumulator =
139+
verifier.verify_folding_proof(verifier_inputs.proof); // WORKTODO: connect this to previous/next accumulator
131140

132141
witness_commitments = std::move(verifier.keys_to_fold[1]->witness_commitments);
133142
public_inputs = std::move(verifier.public_inputs);
@@ -136,20 +145,22 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
136145
}
137146

138147
case QUEUE_TYPE::OINK: {
148+
BB_ASSERT_EQ(input_stdlib_verifier_accumulator, nullptr);
139149
// Construct an incomplete stdlib verifier accumulator from the corresponding stdlib verification key
140-
auto verifier_accum =
150+
output_stdlib_verifier_accumulator =
141151
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, verifier_inputs.honk_vk_and_hash);
142152

143153
// Perform oink recursive verification to complete the initial verifier accumulator
144-
OinkRecursiveVerifier verifier{ &circuit, verifier_accum, accumulation_recursive_transcript };
154+
OinkRecursiveVerifier verifier{ &circuit,
155+
output_stdlib_verifier_accumulator,
156+
accumulation_recursive_transcript };
145157
verifier.verify_proof(verifier_inputs.proof);
146158

147-
// Extract native verifier accumulator from the stdlib accum for use on the next round
148-
recursive_verifier_native_accum = std::make_shared<DeciderVerificationKey>(verifier_accum->get_value());
149-
// Initialize the gate challenges to zero for use in first round of folding
150-
recursive_verifier_native_accum->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
159+
output_stdlib_verifier_accumulator->target_sum = StdlibFF::from_witness_index(&circuit, circuit.zero_idx);
160+
output_stdlib_verifier_accumulator->gate_challenges.assign(
161+
CONST_PG_LOG_N, StdlibFF::from_witness_index(&circuit, circuit.zero_idx));
151162

152-
witness_commitments = std::move(verifier_accum->witness_commitments);
163+
witness_commitments = std::move(output_stdlib_verifier_accumulator->witness_commitments);
153164
public_inputs = std::move(verifier.public_inputs);
154165

155166
// T_prev = 0 in the first recursive verification
@@ -158,6 +169,7 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
158169
break;
159170
}
160171
case QUEUE_TYPE::PG_FINAL: {
172+
BB_ASSERT_NEQ(input_stdlib_verifier_accumulator, nullptr);
161173
BB_ASSERT_EQ(stdlib_verification_queue.size(), size_t(1));
162174
auto stdlib_proof = verifier_inputs.proof;
163175
auto stdlib_vk_and_hash = verifier_inputs.honk_vk_and_hash;
@@ -169,20 +181,21 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
169181

170182
hide_op_queue_accumulation_result(circuit);
171183

172-
// Construct stdlib accumulator, decider vkey and folding proof
173-
auto stdlib_verifier_accumulator =
174-
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, recursive_verifier_native_accum);
175-
176184
// Propagate the public inputs of the tail kernel by converting them to public inputs of the hiding circuit.
177185
auto num_public_inputs = static_cast<size_t>(honk_vk->num_public_inputs);
178186
num_public_inputs -= KernelIO::PUBLIC_INPUTS_SIZE; // exclude fixed kernel_io public inputs
179187
for (size_t i = 0; i < num_public_inputs; i++) {
180188
stdlib_proof[i].set_public();
181189
}
182190

191+
// Fiat-Shamir the accumulator.
192+
prev_accum_hash =
193+
input_stdlib_verifier_accumulator->hash_through_transcript("", *accumulation_recursive_transcript);
194+
accumulation_recursive_transcript->add_to_hash_buffer("accum_hash", *prev_accum_hash);
195+
info("Previous accumulator hash in PG rec verifier: ", *prev_accum_hash);
183196
// Perform recursive folding verification of the last folding proof
184197
FoldingRecursiveVerifier folding_verifier{
185-
&circuit, stdlib_verifier_accumulator, { stdlib_vk_and_hash }, accumulation_recursive_transcript
198+
&circuit, input_stdlib_verifier_accumulator, { stdlib_vk_and_hash }, accumulation_recursive_transcript
186199
};
187200
auto recursive_verifier_native_accum = folding_verifier.verify_folding_proof(verifier_inputs.proof);
188201
verification_queue.clear();
@@ -197,6 +210,8 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
197210
BB_ASSERT_EQ(decider_proof.empty(), false, "Decider proof is empty!");
198211

199212
decider_pairing_points = decider.verify_proof(decider_proof);
213+
214+
BB_ASSERT_EQ(output_stdlib_verifier_accumulator, nullptr);
200215
break;
201216
}
202217
default: {
@@ -220,7 +235,14 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
220235
// happens in K_{i}
221236
merge_commitments.T_prev_commitments = std::move(kernel_input.ecc_op_tables);
222237

223-
// Set the kernel return data commitment to be propagated via the public inputs
238+
BB_ASSERT_EQ(verifier_inputs.type == QUEUE_TYPE::PG || verifier_inputs.type == QUEUE_TYPE::PG_TAIL ||
239+
verifier_inputs.type == QUEUE_TYPE::PG_FINAL,
240+
true,
241+
"Kernel circuits should be folded.");
242+
// Get the previous accum hash
243+
info("PG accum hash from IO: ", kernel_input.output_pg_accum_hash);
244+
ASSERT(prev_accum_hash.has_value());
245+
kernel_input.output_pg_accum_hash.assert_equal(*prev_accum_hash);
224246

225247
if (!is_hiding_kernel) {
226248
// The hiding kernel has no return data but uses the traditional public-inputs mechanism
@@ -248,7 +270,7 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
248270
pairing_points.aggregate(decider_pairing_points);
249271
}
250272

251-
return { pairing_points, merged_table_commitments };
273+
return { output_stdlib_verifier_accumulator, pairing_points, merged_table_commitments };
252274
}
253275

254276
/**
@@ -298,35 +320,53 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit)
298320

299321
// Perform Oink/PG and Merge recursive verification + databus consistency checks for each entry in the queue
300322
PairingPoints points_accumulator;
323+
std::shared_ptr<RecursiveDeciderVerificationKey> current_stdlib_verifier_accumulator = nullptr;
324+
bool is_init_kernel = (recursive_verifier_native_accum == nullptr); // Should clean this up ideally
325+
if (!is_init_kernel) {
326+
current_stdlib_verifier_accumulator =
327+
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, recursive_verifier_native_accum);
328+
}
301329
while (!stdlib_verification_queue.empty()) {
302330
const StdlibVerifierInputs& verifier_input = stdlib_verification_queue.front();
303331

304-
auto [pairing_points, merged_table_commitments] = perform_recursive_verification_and_databus_consistency_checks(
305-
circuit, verifier_input, T_prev_commitments, accumulation_recursive_transcript);
306-
332+
auto [output_stdlib_verifier_accumulator, pairing_points, merged_table_commitments] =
333+
perform_recursive_verification_and_databus_consistency_checks(circuit,
334+
verifier_input,
335+
current_stdlib_verifier_accumulator,
336+
T_prev_commitments,
337+
accumulation_recursive_transcript);
307338
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1376): Optimize recursion aggregation - seems
308339
// we can use `batch_mul` here to decrease the size of the `ECCOpQueue`, but must be cautious with FS security.
309340
points_accumulator.aggregate(pairing_points);
310-
311341
// Update commitment to the status of the op_queue
312342
T_prev_commitments = merged_table_commitments;
343+
// Update the output verifier accumulator
344+
current_stdlib_verifier_accumulator = output_stdlib_verifier_accumulator;
313345

314346
stdlib_verification_queue.pop_front();
315347
}
316-
317348
// Set the kernel output data to be propagated via the public inputs
318349
if (is_hiding_kernel) {
350+
BB_ASSERT_EQ(current_stdlib_verifier_accumulator, nullptr);
319351
HidingKernelIO hiding_output{ points_accumulator, T_prev_commitments };
320352
hiding_output.set_public();
321353
// preserve the hiding circuit so a proof for it can be created
322354
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1502): reconsider approach once integration is
323355
} else {
356+
BB_ASSERT_NEQ(current_stdlib_verifier_accumulator, nullptr);
357+
// Extract native verifier accumulator from the stdlib accum for use on the next round
358+
recursive_verifier_native_accum =
359+
std::make_shared<DeciderVerificationKey>(current_stdlib_verifier_accumulator->get_value());
360+
324361
KernelIO kernel_output;
325362
kernel_output.pairing_inputs = points_accumulator;
326363
kernel_output.kernel_return_data = bus_depot.get_kernel_return_data_commitment(circuit);
327364
kernel_output.app_return_data = bus_depot.get_app_return_data_commitment(circuit);
328365
kernel_output.ecc_op_tables = T_prev_commitments;
329-
366+
RecursiveTranscript hash_transcript;
367+
kernel_output.output_pg_accum_hash =
368+
current_stdlib_verifier_accumulator->hash_through_transcript("", hash_transcript);
369+
info("kernel output pg hash: ", kernel_output.output_pg_accum_hash);
330370
kernel_output.set_public();
331371
}
332372
}
@@ -410,13 +450,26 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
410450
// make a copy of the prover_accumulation_transcript for the verifier to use
411451
auto verifier_accumulation_transcript =
412452
Transcript::convert_prover_transcript_to_verifier_transcript(prover_accumulation_transcript);
413-
453+
// Only fiat shamir if this is a kernel with the assumption that kernels are always the first being recursively
454+
// verified.
455+
if (is_kernel) {
456+
// Fiat-Shamir the verifier accumulator
457+
FF accum_hash = native_verifier_accum->hash_through_transcript("", *prover_accumulation_transcript);
458+
prover_accumulation_transcript->add_to_hash_buffer("accum_hash", accum_hash);
459+
info("Accumulator hash in PG prover: ", accum_hash);
460+
}
414461
FoldingProver folding_prover({ fold_output.accumulator, proving_key },
415462
{ native_verifier_accum, vk },
416463
prover_accumulation_transcript,
417464
trace_usage_tracker);
418465
fold_output = folding_prover.prove();
419466
vinfo("constructed folding proof");
467+
if (is_kernel) {
468+
// Fiat-Shamir the verifier accumulator
469+
FF accum_hash = native_verifier_accum->hash_through_transcript("", *verifier_accumulation_transcript);
470+
verifier_accumulation_transcript->add_to_hash_buffer("accum_hash", accum_hash);
471+
info("Accumulator hash in PG verifier: ", accum_hash);
472+
}
420473
FoldingVerifier folding_verifier({ native_verifier_accum, vk }, verifier_accumulation_transcript);
421474
native_verifier_accum = folding_verifier.verify_folding_proof(fold_output.proof);
422475

barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,14 @@ class ClientIVC {
246246
void instantiate_stdlib_verification_queue(ClientCircuit& circuit,
247247
const std::vector<std::shared_ptr<RecursiveVKAndHash>>& input_keys = {});
248248

249-
[[nodiscard("Pairing points should be accumulated")]] std::pair<PairingPoints, TableCommitments>
250-
perform_recursive_verification_and_databus_consistency_checks(
251-
ClientCircuit& circuit,
252-
const StdlibVerifierInputs& verifier_inputs,
253-
const TableCommitments& T_prev_commitments,
254-
const std::shared_ptr<RecursiveTranscript>& accumulation_recursive_transcript);
249+
[[nodiscard("Pairing points should be accumulated")]] std::
250+
tuple<std::shared_ptr<RecursiveDeciderVerificationKey>, PairingPoints, TableCommitments>
251+
perform_recursive_verification_and_databus_consistency_checks(
252+
ClientCircuit& circuit,
253+
const StdlibVerifierInputs& verifier_inputs,
254+
const std::shared_ptr<RecursiveDeciderVerificationKey>& input_stdlib_verifier_accumulator,
255+
const TableCommitments& T_prev_commitments,
256+
const std::shared_ptr<RecursiveTranscript>& accumulation_recursive_transcript);
255257

256258
// Complete the logic of a kernel circuit (e.g. PG/merge recursive verification, databus consistency checks)
257259
void complete_kernel_circuit_logic(ClientCircuit& circuit);

barretenberg/cpp/src/barretenberg/common/assert.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define ASSERT(expression, ...) DONT_EVALUATE((expression))
3232

3333
#define BB_ASSERT_EQ(actual, expected, ...) DONT_EVALUATE((actual) == (expected))
34+
#define BB_ASSERT_NEQ(actual, expected, ...) DONT_EVALUATE((actual) != (expected))
3435
#define BB_ASSERT_GT(left, right, ...) DONT_EVALUATE((left) > (right))
3536
#define BB_ASSERT_GTE(left, right, ...) DONT_EVALUATE((left) >= (right))
3637
#define BB_ASSERT_LT(left, right, ...) DONT_EVALUATE((left) < (right))
@@ -69,6 +70,20 @@
6970
} \
7071
} while (0)
7172

73+
#define BB_ASSERT_NEQ(actual, expected, ...) \
74+
do { \
75+
auto _actual = (actual); \
76+
auto _expected = (expected); \
77+
if (!(_actual != _expected)) { \
78+
std::ostringstream oss; \
79+
oss << "Assertion failed: (" #actual " != " #expected ")\n"; \
80+
oss << " Actual : " << _actual << "\n"; \
81+
oss << " Not expected: " << _expected; \
82+
__VA_OPT__(oss << "\n Reason : " << __VA_ARGS__;) \
83+
throw_or_abort(oss.str()); \
84+
} \
85+
} while (0)
86+
7287
#define BB_ASSERT_GT(left, right, ...) \
7388
do { \
7489
auto _left = (left); \

0 commit comments

Comments
 (0)