Skip to content

Commit 78c93ea

Browse files
AztecBotAztecBotlucasxia01
authored
feat: merge-train/barretenberg (#16334)
See [merge-train-readme.md](https://github.com/AztecProtocol/aztec-packages/blob/next/.github/workflows/merge-train-readme.md). BEGIN_COMMIT_OVERRIDE feat!: fiat-shamir PG accumulator (#16243) fix vk check test END_COMMIT_OVERRIDE --------- Co-authored-by: AztecBot <tech@aztecprotocol.com> Co-authored-by: Lucas Xia <lucasxia01@gmail.com>
1 parent 7be3515 commit 78c93ea

14 files changed

Lines changed: 173 additions & 42 deletions

barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +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-
pinned_short_hash="9e41a005"
14+
pinned_short_hash="42c72e0d"
1515
pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-${pinned_short_hash}.tar.gz"
1616

1717
function compress_and_upload {

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "barretenberg/serialize/msgpack_impl.hpp"
1212
#include "barretenberg/special_public_inputs/special_public_inputs.hpp"
1313
#include "barretenberg/ultra_honk/oink_prover.hpp"
14+
#include "barretenberg/ultra_honk/oink_verifier.hpp"
1415

1516
namespace bb {
1617

@@ -112,7 +113,8 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
112113
case QUEUE_TYPE::PG_TAIL:
113114
case QUEUE_TYPE::PG: {
114115
// Construct stdlib verifier accumulator from the native counterpart computed on a previous round
115-
auto stdlib_verifier_accum = std::make_shared<RecursiveDeciderVerificationKey>(&circuit, verifier_accumulator);
116+
auto stdlib_verifier_accum =
117+
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, recursive_verifier_native_accum);
116118

117119
// Perform folding recursive verification to update the verifier accumulator
118120
FoldingRecursiveVerifier verifier{
@@ -121,7 +123,7 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
121123
auto verifier_accum = verifier.verify_folding_proof(verifier_inputs.proof);
122124

123125
// Extract native verifier accumulator from the stdlib accum for use on the next round
124-
verifier_accumulator = std::make_shared<DeciderVerificationKey>(verifier_accum->get_value());
126+
recursive_verifier_native_accum = std::make_shared<DeciderVerificationKey>(verifier_accum->get_value());
125127

126128
witness_commitments = std::move(verifier.keys_to_fold[1]->witness_commitments);
127129
public_inputs = std::move(verifier.public_inputs);
@@ -140,9 +142,9 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::
140142
verifier_accum->is_accumulator = true; // indicate to PG that it should not run oink
141143

142144
// Extract native verifier accumulator from the stdlib accum for use on the next round
143-
verifier_accumulator = std::make_shared<DeciderVerificationKey>(verifier_accum->get_value());
145+
recursive_verifier_native_accum = std::make_shared<DeciderVerificationKey>(verifier_accum->get_value());
144146
// Initialize the gate challenges to zero for use in first round of folding
145-
verifier_accumulator->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
147+
recursive_verifier_native_accum->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
146148

147149
witness_commitments = std::move(verifier_accum->witness_commitments);
148150
public_inputs = std::move(verifier.public_inputs);
@@ -321,7 +323,7 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
321323
// Transcript to be shared across folding of K_{i} (kernel) (the current kernel), A_{i+1,1} (app), .., A_{i+1,
322324
// n} (app)
323325
if (is_kernel) {
324-
accumulation_transcript = std::make_shared<Transcript>();
326+
prover_accumulation_transcript = std::make_shared<Transcript>();
325327
}
326328

327329
VerifierInputs queue_entry{ .honk_vk = honk_vk,
@@ -330,7 +332,9 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
330332
if (num_circuits_accumulated == 0) { // First circuit in the IVC
331333
BB_ASSERT_EQ(queue_entry.is_kernel, false, "First circuit accumulated is always be an app");
332334
// For first circuit in the IVC, use oink to complete the decider proving key and generate an oink proof
333-
MegaOinkProver oink_prover{ proving_key, honk_vk, accumulation_transcript };
335+
auto oink_verifier_transcript =
336+
Transcript::convert_prover_transcript_to_verifier_transcript(prover_accumulation_transcript);
337+
MegaOinkProver oink_prover{ proving_key, honk_vk, prover_accumulation_transcript };
334338
vinfo("computing oink proof...");
335339
oink_prover.prove();
336340
HonkProof oink_proof = oink_prover.export_proof();
@@ -341,17 +345,31 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
341345

342346
fold_output.accumulator = proving_key; // initialize the prover accum with the completed key
343347

348+
auto decider_vk = std::make_shared<DeciderVerificationKey>(honk_vk);
349+
oink_verifier_transcript->load_proof(oink_proof);
350+
OinkVerifier<Flavor> oink_verifier{ decider_vk, oink_verifier_transcript };
351+
oink_verifier.verify();
352+
native_verifier_accum = decider_vk;
353+
native_verifier_accum->is_accumulator = true;
354+
native_verifier_accum->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
355+
344356
queue_entry.type = QUEUE_TYPE::OINK;
345357
queue_entry.proof = oink_proof;
346358
} else { // Otherwise, fold the new key into the accumulator
347359
vinfo("computing folding proof");
348360
auto vk = std::make_shared<DeciderVerificationKey_<Flavor>>(honk_vk);
361+
// make a copy of the prover_accumulation_transcript for the verifier to use
362+
auto verifier_accumulation_transcript =
363+
Transcript::convert_prover_transcript_to_verifier_transcript(prover_accumulation_transcript);
364+
349365
FoldingProver folding_prover({ fold_output.accumulator, proving_key },
350-
{ verifier_accumulator, vk },
351-
accumulation_transcript,
366+
{ native_verifier_accum, vk },
367+
prover_accumulation_transcript,
352368
trace_usage_tracker);
353369
fold_output = folding_prover.prove();
354370
vinfo("constructed folding proof");
371+
FoldingVerifier folding_verifier({ native_verifier_accum, vk }, verifier_accumulation_transcript);
372+
native_verifier_accum = folding_verifier.verify_folding_proof(fold_output.proof);
355373

356374
if (num_circuits_accumulated == num_circuits - 1) {
357375
// we are folding in the "Tail" kernel, so the verification_queue entry should have type PG_FINAL
@@ -369,7 +387,7 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer
369387
verification_queue.push_back(queue_entry);
370388

371389
// Construct merge proof for the present circuit
372-
goblin.prove_merge(accumulation_transcript);
390+
goblin.prove_merge(prover_accumulation_transcript);
373391

374392
num_circuits_accumulated++;
375393
}
@@ -414,7 +432,7 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::comp
414432

415433
// Construct stdlib accumulator, decider vkey and folding proof
416434
auto stdlib_verifier_accumulator =
417-
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, verifier_accumulator);
435+
std::make_shared<RecursiveDeciderVerificationKey>(&circuit, recursive_verifier_native_accum);
418436

419437
// Propagate the public inputs of the tail kernel by converting them to public inputs of the hiding circuit.
420438
auto num_public_inputs = static_cast<size_t>(honk_vk->num_public_inputs);
@@ -427,7 +445,7 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::comp
427445
FoldingRecursiveVerifier folding_verifier{
428446
&circuit, stdlib_verifier_accumulator, { stdlib_vk_and_hash }, pg_merge_transcript
429447
};
430-
auto recursive_verifier_accumulator = folding_verifier.verify_folding_proof(stdlib_proof);
448+
auto recursive_verifier_native_accum = folding_verifier.verify_folding_proof(stdlib_proof);
431449
verification_queue.clear();
432450

433451
// Get the completed decider verification key corresponding to the tail kernel from the folding verifier
@@ -452,7 +470,7 @@ std::pair<ClientIVC::PairingPoints, ClientIVC::TableCommitments> ClientIVC::comp
452470
points_accumulator.aggregate(kernel_input.pairing_inputs);
453471

454472
// Perform recursive decider verification
455-
DeciderRecursiveVerifier decider{ &circuit, recursive_verifier_accumulator };
473+
DeciderRecursiveVerifier decider{ &circuit, recursive_verifier_native_accum };
456474
BB_ASSERT_EQ(!decider_proof.empty(), true, "Decider proof is empty!");
457475
PairingPoints decider_pairing_points = decider.verify_proof(decider_proof);
458476
points_accumulator.aggregate(decider_pairing_points);

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "barretenberg/goblin/goblin.hpp"
1111
#include "barretenberg/honk/execution_trace/execution_trace_usage_tracker.hpp"
1212
#include "barretenberg/protogalaxy/protogalaxy_prover.hpp"
13+
#include "barretenberg/protogalaxy/protogalaxy_verifier.hpp"
1314
#include "barretenberg/stdlib/honk_verifier/decider_recursive_verifier.hpp"
1415
#include "barretenberg/stdlib/honk_verifier/oink_recursive_verifier.hpp"
1516
#include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp"
@@ -53,6 +54,7 @@ class ClientIVC {
5354
using DeciderProvingKeys = DeciderProvingKeys_<Flavor>;
5455
using FoldingProver = ProtogalaxyProver_<Flavor>;
5556
using DeciderVerificationKeys = DeciderVerificationKeys_<Flavor>;
57+
using FoldingVerifier = ProtogalaxyVerifier_<DeciderVerificationKeys>;
5658
using ECCVMVerificationKey = bb::ECCVMFlavor::VerificationKey;
5759
using TranslatorVerificationKey = bb::TranslatorFlavor::VerificationKey;
5860
using MegaProver = UltraProver_<Flavor>;
@@ -166,7 +168,7 @@ class ClientIVC {
166168
std::shared_ptr<Transcript> transcript = std::make_shared<Transcript>();
167169

168170
// Transcript to be shared across the folding of K_{i-1} (kernel), A_{i,1} (app), .., A_{i, n}
169-
std::shared_ptr<Transcript> accumulation_transcript = std::make_shared<Transcript>();
171+
std::shared_ptr<Transcript> prover_accumulation_transcript = std::make_shared<Transcript>();
170172

171173
std::unique_ptr<ClientCircuit> hiding_circuit;
172174

@@ -178,7 +180,10 @@ class ClientIVC {
178180
HonkProof decider_proof; // decider proof to be verified in the hiding circuit
179181
HonkProof mega_proof; // proof of the hiding circuit
180182

181-
std::shared_ptr<DeciderVerificationKey> verifier_accumulator; // verifier accumulator
183+
std::shared_ptr<DeciderVerificationKey>
184+
recursive_verifier_native_accum; // native verifier accumulator used in recursive folding
185+
std::shared_ptr<DeciderVerificationKey>
186+
native_verifier_accum; // native verifier accumulator used in prover folding
182187
std::shared_ptr<MegaVerificationKey> honk_vk; // honk vk to be completed and folded into the accumulator
183188

184189
// Set of tuples {proof, verification_key, type (Oink/PG)} to be recursively verified

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ std::shared_ptr<ClientIVC> create_mock_ivc_from_constraints(const std::vector<Re
5757

5858
// Case: RESET kernel; single PG recursive verification of a kernel
5959
if (constraints.size() == 1 && constraints[0].proof_type == pg_type) {
60-
ivc->verifier_accumulator = create_mock_decider_vk<ClientIVC::Flavor>();
60+
ivc->recursive_verifier_native_accum = create_mock_decider_vk<ClientIVC::Flavor>();
6161
mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true);
6262
return ivc;
6363
}
6464

6565
// Case: TAIL kernel; single PG recursive verification of a kernel
6666
if (constraints.size() == 1 && constraints[0].proof_type == pg_tail_type) {
67-
ivc->verifier_accumulator = create_mock_decider_vk<ClientIVC::Flavor>();
67+
ivc->recursive_verifier_native_accum = create_mock_decider_vk<ClientIVC::Flavor>();
6868
mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG_TAIL, /*is_kernel=*/true);
6969
return ivc;
7070
}
@@ -73,20 +73,20 @@ std::shared_ptr<ClientIVC> create_mock_ivc_from_constraints(const std::vector<Re
7373
if (constraints.size() == 2) {
7474
BB_ASSERT_EQ(constraints[0].proof_type, pg_type);
7575
BB_ASSERT_EQ(constraints[1].proof_type, pg_type);
76-
ivc->verifier_accumulator = create_mock_decider_vk<ClientIVC::Flavor>();
76+
ivc->recursive_verifier_native_accum = create_mock_decider_vk<ClientIVC::Flavor>();
7777
mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true);
7878
mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false);
7979
return ivc;
8080
}
8181

8282
// Case: HIDING kernel; single PG_FINAL recursive verification of a kernel
8383
if (constraints.size() == 1 && constraints[0].proof_type == pg_final_type) {
84-
ivc->verifier_accumulator = create_mock_decider_vk<ClientIVC::Flavor>();
84+
ivc->recursive_verifier_native_accum = create_mock_decider_vk<ClientIVC::Flavor>();
8585

8686
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1283): We need to set the log circuit size here due
8787
// to an invalid out of circuit max operation in the PG recursive verifier. Once that is resolved this should
8888
// not be necessary.
89-
ivc->verifier_accumulator->vk->log_circuit_size = 18;
89+
ivc->recursive_verifier_native_accum->vk->log_circuit_size = 18;
9090
mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG_FINAL, /*is_kernel=*/true);
9191
return ivc;
9292
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ class NativeVerificationKey_ : public PrecomputedCommitments {
226226
transcript.add_to_independent_hash_buffer(domain_separator + "vk_commitment", commitment);
227227
}
228228

229-
return transcript.hash_independent_buffer(domain_separator + "vk_hash");
229+
fr vk_hash = transcript.hash_independent_buffer();
230+
transcript.add_to_hash_buffer(domain_separator + "vk_hash", vk_hash);
231+
return vk_hash;
230232
};
231233
};
232234

@@ -316,8 +318,9 @@ class StdlibVerificationKey_ : public PrecomputedCommitments {
316318
for (const Commitment& commitment : this->get_all()) {
317319
transcript.add_to_independent_hash_buffer(domain_separator + "vk_commitment", commitment);
318320
}
319-
320-
return transcript.hash_independent_buffer(domain_separator + "vk_hash");
321+
FF vk_hash = transcript.hash_independent_buffer();
322+
transcript.add_to_hash_buffer(domain_separator + "vk_hash", vk_hash);
323+
return vk_hash;
321324
};
322325
};
323326

barretenberg/cpp/src/barretenberg/flavor/native_verification_key.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ TYPED_TEST(NativeVerificationKeyTests, VKHashingConsistency)
7979
for (const auto& field_element : vk_field_elements) {
8080
transcript.add_to_independent_hash_buffer("vk_element", field_element);
8181
}
82-
fr vkey_hash_1 = transcript.hash_independent_buffer("vk_hash");
82+
fr vkey_hash_1 = transcript.hash_independent_buffer();
8383
// Second method of hashing: using hash().
8484
fr vkey_hash_2 = vk.hash();
8585
EXPECT_EQ(vkey_hash_1, vkey_hash_2);

barretenberg/cpp/src/barretenberg/flavor/stdlib_verification_key.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ TYPED_TEST(StdlibVerificationKeyTests, VKHashingConsistency)
7777
for (const auto& field_element : vk_field_elements) {
7878
transcript.add_to_independent_hash_buffer("vk_element", field_element);
7979
}
80-
FF vkey_hash_1 = transcript.hash_independent_buffer("vk_hash");
80+
FF vkey_hash_1 = transcript.hash_independent_buffer();
8181
// Second method of hashing: using hash().
8282
FF vkey_hash_2 = vk.hash(outer_builder);
8383
EXPECT_EQ(vkey_hash_1.get_value(), vkey_hash_2.get_value());

barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ void ProtogalaxyProver_<Flavor, NUM_KEYS>::run_oink_prover_on_each_incomplete_ke
3232
size_t idx = 0;
3333
auto& key = keys_to_fold[0];
3434
auto domain_separator = std::to_string(idx);
35-
auto& vk = vks_to_fold[0];
35+
auto& verifier_accum = vks_to_fold[0];
3636
if (!key->is_accumulator) {
37-
run_oink_prover_on_one_incomplete_key(key, vk, domain_separator);
37+
run_oink_prover_on_one_incomplete_key(key, verifier_accum, domain_separator);
3838
key->target_sum = 0;
3939
key->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
40+
} else {
41+
// Fiat-Shamir the verifier accumulator
42+
FF accum_hash = verifier_accum->add_hash_to_transcript("", *transcript);
43+
info("Accumulator hash in PG prover: ", accum_hash);
4044
}
4145

4246
idx++;

barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ void ProtogalaxyVerifier_<DeciderVerificationKeys>::run_oink_verifier_on_each_in
2424
oink_verifier.verify();
2525
key->target_sum = 0;
2626
key->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
27+
} else {
28+
// Fiat-Shamir the verifier accumulator
29+
FF accum_hash = key->add_hash_to_transcript("", *transcript);
30+
info("Accumulator hash in PG verifier: ", accum_hash);
2731
}
2832

2933
key = keys_to_fold[1];

barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ void ProtogalaxyRecursiveVerifier_<DeciderVerificationKeys>::run_oink_verifier_o
2626
oink_verifier.verify();
2727
key->target_sum = 0;
2828
key->gate_challenges = std::vector<FF>(CONST_PG_LOG_N, 0);
29+
} else {
30+
// Fiat-Shamir the accumulator.
31+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1390): assert_equal on accumulator hash with public
32+
// input hash.
33+
FF accum_hash = key->add_hash_to_transcript("", *transcript);
34+
info("Accumulator hash in PG rec verifier: ", accum_hash);
2935
}
3036

3137
key = keys_to_fold[1];
@@ -61,8 +67,8 @@ std::shared_ptr<typename DeciderVerificationKeys::DeciderVK> ProtogalaxyRecursiv
6167
const FF perturbator_evaluation = evaluate_perturbator(perturbator_coeffs, perturbator_challenge);
6268

6369
std::array<FF, COMBINER_LENGTH>
64-
combiner_quotient_evals; // The degree of the combiner quotient (K in the paper) is dk - k - 1 = k(d - 1) - 1.
65-
// Hence we need k(d - 1) evaluations to represent it.
70+
combiner_quotient_evals; // The degree of the combiner quotient (K in the paper) is dk - k - 1 = k(d - 1)
71+
// - 1. Hence we need k(d - 1) evaluations to represent it.
6672
for (size_t idx = 0; idx < COMBINER_LENGTH; idx++) {
6773
combiner_quotient_evals[idx] =
6874
transcript->template receive_from_prover<FF>("combiner_quotient_" + std::to_string(idx + NUM_KEYS));
@@ -98,13 +104,13 @@ std::shared_ptr<typename DeciderVerificationKeys::DeciderVK> ProtogalaxyRecursiv
98104
(1 - combiner_challenge).[A] + combiner_challenge.[B] == [C]
99105
100106
101-
This reduces the relation to 3 large MSMs where each commitment requires 3 size-128bit scalar multiplications
102-
For a flavor with 53 instance/witness commitments, this is 53 * 24 rows
107+
This reduces the relation to 3 large MSMs where each commitment requires 3 size-128bit scalar
108+
multiplications For a flavor with 53 instance/witness commitments, this is 53 * 24 rows
103109
104-
Note: there are more efficient ways to evaluate this relationship if one solely wants to reduce number of scalar
105-
muls, however we must also consider the number of ECCVM operations being executed, as each operation incurs a
106-
cost in the translator circuit Each ECCVM opcode produces 5 rows in the translator circuit, which is approx.
107-
equivalent to 9 ECCVM rows. Something to pay attention to
110+
Note: there are more efficient ways to evaluate this relationship if one solely wants to reduce number of
111+
scalar muls, however we must also consider the number of ECCVM operations being executed, as each operation
112+
incurs a cost in the translator circuit Each ECCVM opcode produces 5 rows in the translator circuit, which is
113+
approx. equivalent to 9 ECCVM rows. Something to pay attention to
108114
*/
109115

110116
// New transcript for challenge generation

0 commit comments

Comments
 (0)