Skip to content

Commit a0551ee

Browse files
authored
feat: Single commitment key allocation in CIVC (#9974)
Previously we allocated the BN254 commitment key freely (I counted 11 times in one small ClientIVC test). This is unnecessary and could lead to memory fragmentation. This PR implements size functions on a `TraceSetting` object and, when structured traces are used, allocates the commitment key at CIVC construction time. It passes this along to dependent classes via a shared pointer. I didn't handle the case of Grumpkin since it's not an issue. I was curious to validate the effect in the browser directly through the browser app in the ivc-integration test suite. Though it's tangential, I updated that app to display console logs on the page for easy sharing.
1 parent e608742 commit a0551ee

File tree

20 files changed

+172
-51
lines changed

20 files changed

+172
-51
lines changed

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

+15-5
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,11 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<Verific
176176
proving_key = std::make_shared<DeciderProvingKey>(circuit, trace_settings);
177177
trace_usage_tracker = ExecutionTraceUsageTracker(trace_settings);
178178
} else {
179-
proving_key = std::make_shared<DeciderProvingKey>(
180-
circuit, trace_settings, fold_output.accumulator->proving_key.commitment_key);
179+
proving_key = std::make_shared<DeciderProvingKey>(circuit, trace_settings);
181180
}
182181

182+
proving_key->proving_key.commitment_key = bn254_commitment_key;
183+
183184
vinfo("getting honk vk... precomputed?: ", precomputed_vk);
184185
// Update the accumulator trace usage based on the present circuit
185186
trace_usage_tracker.update(circuit);
@@ -278,7 +279,7 @@ HonkProof ClientIVC::construct_and_prove_hiding_circuit()
278279
MergeProof merge_proof = goblin.prove_merge(builder);
279280
merge_verification_queue.emplace_back(merge_proof);
280281

281-
auto decider_pk = std::make_shared<DeciderProvingKey>(builder);
282+
auto decider_pk = std::make_shared<DeciderProvingKey>(builder, TraceSettings(), bn254_commitment_key);
282283
honk_vk = std::make_shared<VerificationKey>(decider_pk->proving_key);
283284
MegaProver prover(decider_pk);
284285

@@ -338,6 +339,7 @@ bool ClientIVC::verify(const Proof& proof)
338339
HonkProof ClientIVC::decider_prove() const
339340
{
340341
vinfo("prove decider...");
342+
fold_output.accumulator->proving_key.commitment_key = bn254_commitment_key;
341343
MegaDeciderProver decider_prover(fold_output.accumulator);
342344
return decider_prover.construct_proof();
343345
vinfo("finished decider proving.");
@@ -352,11 +354,19 @@ HonkProof ClientIVC::decider_prove() const
352354
bool ClientIVC::prove_and_verify()
353355
{
354356
auto start = std::chrono::steady_clock::now();
355-
auto proof = prove();
357+
const auto proof = prove();
356358
auto end = std::chrono::steady_clock::now();
357359
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
358360
vinfo("time to call ClientIVC::prove: ", diff.count(), " ms.");
359-
return verify(proof);
361+
362+
start = end;
363+
const bool verified = verify(proof);
364+
end = std::chrono::steady_clock::now();
365+
366+
diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
367+
vinfo("time to verify ClientIVC proof: ", diff.count(), " ms.");
368+
369+
return verified;
360370
}
361371

362372
/**

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ class ClientIVC {
9898
using ProverFoldOutput = FoldingResult<Flavor>;
9999

100100
public:
101-
GoblinProver goblin;
102-
103101
ProverFoldOutput fold_output; // prover accumulator and fold proof
104102

105103
std::shared_ptr<DeciderVerificationKey> verifier_accumulator; // verifier accumulator
@@ -122,11 +120,19 @@ class ClientIVC {
122120
// Setting auto_verify_mode = true will cause kernel completion logic to be added to kernels automatically
123121
bool auto_verify_mode;
124122

123+
std::shared_ptr<typename MegaFlavor::CommitmentKey> bn254_commitment_key;
124+
125+
GoblinProver goblin;
126+
125127
bool initialized = false; // Is the IVC accumulator initialized
126128

127129
ClientIVC(TraceSettings trace_settings = {}, bool auto_verify_mode = false)
128130
: trace_settings(trace_settings)
129131
, auto_verify_mode(auto_verify_mode)
132+
, bn254_commitment_key(trace_settings.structure.has_value()
133+
? std::make_shared<CommitmentKey<curve::BN254>>(trace_settings.dyadic_size())
134+
: nullptr)
135+
, goblin(bn254_commitment_key)
130136
{}
131137

132138
void instantiate_stdlib_verification_queue(

barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack,
236236
}
237237
// TODO(#7371) dedupe this with the rest of the similar code
238238
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode
239-
ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true };
239+
ClientIVC ivc{ { CLIENT_IVC_BENCH_STRUCTURE }, /*auto_verify_mode=*/true };
240240

241241
// Accumulate the entire program stack into the IVC
242242
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once databus
@@ -267,6 +267,10 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack,
267267
bool result = ivc.prove_and_verify();
268268
info("verified?: ", result);
269269

270+
end = std::chrono::steady_clock::now();
271+
diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
272+
vinfo("time to construct, accumulate, prove and verify all circuits: ", diff.count());
273+
270274
*verified = result;
271275
}
272276

barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,7 @@ void ECCVMProver::execute_relation_check_rounds()
104104
gate_challenges[idx] = transcript->template get_challenge<FF>("Sumcheck:gate_challenge_" + std::to_string(idx));
105105
}
106106

107-
auto commitment_key = std::make_shared<CommitmentKey>(Flavor::BATCHED_RELATION_PARTIAL_LENGTH);
108-
zk_sumcheck_data = ZKSumcheckData<Flavor>(key->log_circuit_size, transcript, commitment_key);
107+
zk_sumcheck_data = ZKSumcheckData<Flavor>(key->log_circuit_size, transcript, key->commitment_key);
109108

110109
sumcheck_output = sumcheck.prove(key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data);
111110
}

barretenberg/cpp/src/barretenberg/goblin/goblin.hpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class GoblinProver {
5151
*/
5252

5353
std::shared_ptr<OpQueue> op_queue = std::make_shared<OpQueue>();
54+
std::shared_ptr<CommitmentKey<curve::BN254>> commitment_key;
5455

5556
MergeProof merge_proof;
5657
GoblinProof goblin_proof;
@@ -70,11 +71,12 @@ class GoblinProver {
7071
GoblinAccumulationOutput accumulator; // Used only for ACIR methods for now
7172

7273
public:
73-
GoblinProver()
74+
GoblinProver(const std::shared_ptr<CommitmentKey<curve::BN254>>& bn254_commitment_key = nullptr)
7475
{ // Mocks the interaction of a first circuit with the op queue due to the inability to currently handle zero
7576
// commitments (https://github.com/AztecProtocol/barretenberg/issues/871) which would otherwise appear in the
7677
// first round of the merge protocol. To be removed once the issue has been resolved.
77-
GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(op_queue);
78+
commitment_key = bn254_commitment_key ? bn254_commitment_key : nullptr;
79+
GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(op_queue, commitment_key);
7880
}
7981
/**
8082
* @brief Construct a MegaHonk proof and a merge proof for the present circuit.
@@ -160,7 +162,7 @@ class GoblinProver {
160162
merge_proof_exists = true;
161163
}
162164

163-
MergeProver merge_prover{ circuit_builder.op_queue };
165+
MergeProver merge_prover{ circuit_builder.op_queue, commitment_key };
164166
return merge_prover.construct_proof();
165167
};
166168

@@ -209,7 +211,7 @@ class GoblinProver {
209211

210212
auto translator_builder =
211213
std::make_unique<TranslatorBuilder>(translation_batching_challenge_v, evaluation_challenge_x, op_queue);
212-
translator_prover = std::make_unique<TranslatorProver>(*translator_builder, transcript);
214+
translator_prover = std::make_unique<TranslatorProver>(*translator_builder, transcript, commitment_key);
213215
}
214216

215217
{

barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ class GoblinMockCircuits {
121121
*
122122
* @param op_queue
123123
*/
124-
static void perform_op_queue_interactions_for_mock_first_circuit(std::shared_ptr<bb::ECCOpQueue>& op_queue)
124+
static void perform_op_queue_interactions_for_mock_first_circuit(
125+
std::shared_ptr<bb::ECCOpQueue>& op_queue, std::shared_ptr<CommitmentKey> commitment_key = nullptr)
125126
{
126127
PROFILE_THIS();
127128

@@ -134,11 +135,12 @@ class GoblinMockCircuits {
134135

135136
// Manually compute the op queue transcript commitments (which would normally be done by the merge prover)
136137
bb::srs::init_crs_factory("../srs_db/ignition");
137-
auto commitment_key = CommitmentKey(op_queue->get_current_size());
138+
auto bn254_commitment_key =
139+
commitment_key ? commitment_key : std::make_shared<CommitmentKey>(op_queue->get_current_size());
138140
std::array<Point, Flavor::NUM_WIRES> op_queue_commitments;
139141
size_t idx = 0;
140142
for (auto& entry : op_queue->get_aggregate_transcript()) {
141-
op_queue_commitments[idx++] = commitment_key.commit({ 0, entry });
143+
op_queue_commitments[idx++] = bn254_commitment_key->commit({ 0, entry });
142144
}
143145
// Store the commitment data for use by the prover of the next circuit
144146
op_queue->set_commitment_data(op_queue_commitments);

barretenberg/cpp/src/barretenberg/plonk_honk_shared/execution_trace/mega_execution_trace.hpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,15 @@ template <typename T> struct MegaTraceBlockData {
5959
};
6060
}
6161

62-
static uint32_t size() { return 0; }
63-
static uint32_t dyadic_size() { return 0; }
62+
size_t size() const
63+
requires std::same_as<T, uint32_t>
64+
{
65+
size_t result{ 0 };
66+
for (const auto& block_size : get()) {
67+
result += block_size;
68+
}
69+
return static_cast<size_t>(result);
70+
}
6471

6572
bool operator==(const MegaTraceBlockData& other) const = default;
6673
};
@@ -72,6 +79,15 @@ struct TraceSettings {
7279
// The size of the overflow block. Specified separately because it is allowed to be determined at runtime in the
7380
// context of VK computation
7481
uint32_t overflow_capacity = 0;
82+
83+
size_t size() const { return structure->size() + static_cast<size_t>(overflow_capacity); }
84+
85+
size_t dyadic_size() const
86+
{
87+
const size_t total_size = size();
88+
const size_t lower_dyadic = 1 << numeric::get_msb(total_size);
89+
return total_size > lower_dyadic ? lower_dyadic << 1 : lower_dyadic;
90+
}
7591
};
7692

7793
class MegaTraceBlock : public ExecutionTraceBlock<fr, /*NUM_WIRES_ */ 4, /*NUM_SELECTORS_*/ 14> {

barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_flavor.hpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,12 @@ class MegaFlavor {
581581
VerificationKey(ProvingKey& proving_key)
582582
{
583583
set_metadata(proving_key);
584-
if (proving_key.commitment_key == nullptr) {
585-
proving_key.commitment_key = std::make_shared<CommitmentKey>(proving_key.circuit_size);
584+
auto& ck = proving_key.commitment_key;
585+
if (!ck || ck->srs->get_monomial_size() < proving_key.circuit_size) {
586+
ck = std::make_shared<CommitmentKey>(proving_key.circuit_size);
586587
}
587588
for (auto [polynomial, commitment] : zip_view(proving_key.polynomials.get_precomputed(), this->get_all())) {
588-
commitment = proving_key.commitment_key->commit(polynomial);
589+
commitment = ck->commit(polynomial);
589590
}
590591
}
591592

barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88

99
namespace bb {
1010

11-
TranslatorProver::TranslatorProver(CircuitBuilder& circuit_builder, const std::shared_ptr<Transcript>& transcript)
11+
TranslatorProver::TranslatorProver(CircuitBuilder& circuit_builder,
12+
const std::shared_ptr<Transcript>& transcript,
13+
std::shared_ptr<CommitmentKey> commitment_key)
1214
: dyadic_circuit_size(Flavor::compute_dyadic_circuit_size(circuit_builder))
1315
, mini_circuit_dyadic_size(Flavor::compute_mini_circuit_dyadic_size(circuit_builder))
1416
, transcript(transcript)
17+
, key(std::make_shared<ProvingKey>(circuit_builder))
1518
{
1619
PROFILE_THIS();
1720

18-
// Compute total number of gates, dyadic circuit size, etc.
19-
key = std::make_shared<ProvingKey>(circuit_builder);
21+
key->commitment_key = commitment_key ? commitment_key : std::make_shared<CommitmentKey>(key->circuit_size);
2022
compute_witness(circuit_builder);
21-
compute_commitment_key(key->circuit_size);
2223
}
2324

2425
/**
@@ -159,9 +160,8 @@ void TranslatorProver::execute_relation_check_rounds()
159160
gate_challenges[idx] = transcript->template get_challenge<FF>("Sumcheck:gate_challenge_" + std::to_string(idx));
160161
}
161162

162-
// create masking polynomials for sumcheck round univariates and auxiliary data
163-
auto commitment_key = std::make_shared<CommitmentKey>(Flavor::BATCHED_RELATION_PARTIAL_LENGTH);
164-
zk_sumcheck_data = ZKSumcheckData<Flavor>(key->log_circuit_size, transcript, commitment_key);
163+
// // create masking polynomials for sumcheck round univariates and auxiliary data
164+
zk_sumcheck_data = ZKSumcheckData<Flavor>(key->log_circuit_size, transcript, key->commitment_key);
165165

166166
sumcheck_output = sumcheck.prove(key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data);
167167
}

barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ class TranslatorProver {
2828
size_t dyadic_circuit_size = 0; // final power-of-2 circuit size
2929
size_t mini_circuit_dyadic_size = 0; // The size of the small circuit that contains non-range constraint relations
3030

31-
explicit TranslatorProver(CircuitBuilder& circuit_builder, const std::shared_ptr<Transcript>& transcript);
31+
explicit TranslatorProver(CircuitBuilder& circuit_builder,
32+
const std::shared_ptr<Transcript>& transcript,
33+
std::shared_ptr<CommitmentKey> commitment_key = nullptr);
3234

3335
void compute_witness(CircuitBuilder& circuit_builder);
3436
void compute_commitment_key(size_t circuit_size);

barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp

+6-8
Original file line numberDiff line numberDiff line change
@@ -57,33 +57,31 @@ template <IsUltraFlavor Flavor> void DeciderProver_<Flavor>::execute_relation_ch
5757
*/
5858
template <IsUltraFlavor Flavor> void DeciderProver_<Flavor>::execute_pcs_rounds()
5959
{
60-
if (proving_key->proving_key.commitment_key == nullptr) {
61-
proving_key->proving_key.commitment_key =
62-
std::make_shared<CommitmentKey>(proving_key->proving_key.circuit_size);
63-
}
64-
vinfo("made commitment key");
6560
using OpeningClaim = ProverOpeningClaim<Curve>;
6661

62+
auto& ck = proving_key->proving_key.commitment_key;
63+
ck = ck ? ck : std::make_shared<CommitmentKey>(proving_key->proving_key.circuit_size);
64+
6765
OpeningClaim prover_opening_claim;
6866
if constexpr (!Flavor::HasZK) {
6967
prover_opening_claim = ShpleminiProver_<Curve>::prove(proving_key->proving_key.circuit_size,
7068
proving_key->proving_key.polynomials.get_unshifted(),
7169
proving_key->proving_key.polynomials.get_to_be_shifted(),
7270
sumcheck_output.challenge,
73-
proving_key->proving_key.commitment_key,
71+
ck,
7472
transcript);
7573
} else {
7674
prover_opening_claim = ShpleminiProver_<Curve>::prove(proving_key->proving_key.circuit_size,
7775
proving_key->proving_key.polynomials.get_unshifted(),
7876
proving_key->proving_key.polynomials.get_to_be_shifted(),
7977
sumcheck_output.challenge,
80-
proving_key->proving_key.commitment_key,
78+
ck,
8179
transcript,
8280
zk_sumcheck_data.libra_univariates_monomial,
8381
sumcheck_output.claimed_libra_evaluations);
8482
}
8583
vinfo("executed multivariate-to-univarite reduction");
86-
PCS::compute_opening_proof(proving_key->proving_key.commitment_key, prover_opening_claim, transcript);
84+
PCS::compute_opening_proof(ck, prover_opening_claim, transcript);
8785
vinfo("computed opening proof");
8886
}
8987

barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ template <IsUltraFlavor Flavor> class DeciderProvingKey_ {
4545
std::vector<FF> gate_challenges;
4646
// The target sum, which is typically nonzero for a ProtogalaxyProver's accmumulator
4747
FF target_sum;
48-
4948
size_t final_active_wire_idx{ 0 }; // idx of last non-trivial wire value in the trace
49+
size_t dyadic_circuit_size{ 0 }; // final power-of-2 circuit size
5050

5151
DeciderProvingKey_(Circuit& circuit,
5252
TraceSettings trace_settings = {},
53-
std::shared_ptr<typename Flavor::CommitmentKey> commitment_key = nullptr)
53+
std::shared_ptr<CommitmentKey> commitment_key = nullptr)
5454
: is_structured(trace_settings.structure.has_value())
5555
{
5656
PROFILE_THIS_NAME("DeciderProvingKey(Circuit&)");
@@ -105,6 +105,7 @@ template <IsUltraFlavor Flavor> class DeciderProvingKey_ {
105105
if ((IsMegaFlavor<Flavor> && !is_structured) || (is_structured && circuit.blocks.has_overflow)) {
106106
// Allocate full size polynomials
107107
proving_key.polynomials = typename Flavor::ProverPolynomials(dyadic_circuit_size);
108+
vinfo("allocated polynomials object in proving key");
108109
} else { // Allocate only a correct amount of memory for each polynomial
109110
// Allocate the wires and selectors polynomials
110111
{
@@ -262,6 +263,7 @@ template <IsUltraFlavor Flavor> class DeciderProvingKey_ {
262263
/* size=*/dyadic_circuit_size, /*virtual size=*/dyadic_circuit_size, /*start_idx=*/0);
263264
}
264265
}
266+
vinfo("allocated polynomials object in proving key");
265267
// We can finally set the shifted polynomials now that all of the to_be_shifted polynomials are
266268
// defined.
267269
proving_key.polynomials.set_shifted(); // Ensure shifted wires are set correctly
@@ -334,7 +336,6 @@ template <IsUltraFlavor Flavor> class DeciderProvingKey_ {
334336
private:
335337
static constexpr size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0;
336338
static constexpr size_t NUM_WIRES = Circuit::NUM_WIRES;
337-
size_t dyadic_circuit_size = 0; // final power-of-2 circuit size
338339

339340
size_t compute_dyadic_size(Circuit&);
340341

barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ namespace bb {
1010
*
1111
*/
1212
template <class Flavor>
13-
MergeProver_<Flavor>::MergeProver_(const std::shared_ptr<ECCOpQueue>& op_queue)
13+
MergeProver_<Flavor>::MergeProver_(const std::shared_ptr<ECCOpQueue>& op_queue,
14+
std::shared_ptr<CommitmentKey> commitment_key)
1415
: op_queue(op_queue)
1516
{
1617
// Update internal size data in the op queue that allows for extraction of e.g. previous aggregate transcript
1718
op_queue->set_size_data();
18-
// Get the appropriate commitment based on the updated ultra ops size
19-
pcs_commitment_key = std::make_shared<CommitmentKey>(op_queue->get_current_size());
19+
pcs_commitment_key =
20+
commitment_key ? commitment_key : std::make_shared<CommitmentKey>(op_queue->get_current_size());
2021
}
2122

2223
/**

barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ template <typename Flavor> class MergeProver_ {
2727
public:
2828
std::shared_ptr<Transcript> transcript;
2929

30-
explicit MergeProver_(const std::shared_ptr<ECCOpQueue>&);
30+
explicit MergeProver_(const std::shared_ptr<ECCOpQueue>& op_queue,
31+
std::shared_ptr<CommitmentKey> commitment_key = nullptr);
3132

3233
BB_PROFILE HonkProof construct_proof();
3334

barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ template <IsUltraFlavor Flavor> void OinkProver<Flavor>::prove()
5858
// Generate relation separators alphas for sumcheck/combiner computation
5959
proving_key->alphas = generate_alphas_round();
6060

61+
#ifndef __wasm__
6162
// Free the commitment key
6263
proving_key->proving_key.commitment_key = nullptr;
64+
#endif
6365
}
6466

6567
/**

0 commit comments

Comments
 (0)