Skip to content

Commit 01bfead

Browse files
authored
feat: merge-train/barretenberg (#16850)
BEGIN_COMMIT_OVERRIDE chore: audit of lookup relations in the ECCVM (#16712) feat: translator handles no-op range (#16628) chore: audit wnaf relations in the ECCVM (#16573) feat: add option to choose between tmpfs and $HOME/tmp in docker_isolate (#16854) refactor(bb-prover): don't use --write_vk in yarn-project (#16834) chore: cycle group cleanup (#16830) END_COMMIT_OVERRIDE
2 parents 1053ba9 + c10c642 commit 01bfead

File tree

53 files changed

+1941
-1547
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1941
-1547
lines changed

barretenberg/cpp/scripts/test_civc_standalone_vks_havent_changed.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ cd ..
1313
# - Generate a hash for versioning: sha256sum bb-civc-inputs.tar.gz
1414
# - 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
1515
# Note: In case of the "Test suite failed to run ... Unexpected token 'with' " error, need to run: docker pull aztecprotocol/build:3.0
16-
17-
pinned_short_hash="ec9b5be3"
16+
pinned_short_hash="16b530e4"
1817
pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-${pinned_short_hash}.tar.gz"
1918

2019
function compress_and_upload {

barretenberg/cpp/src/barretenberg/boomerang_value_detection/graph_description_goblin.test.cpp

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,37 +40,25 @@ class BoomerangGoblinRecursiveVerifierTests : public testing::Test {
4040
*
4141
* @return ProverOutput
4242
*/
43-
static ProverOutput create_goblin_prover_output(const size_t NUM_CIRCUITS = 3)
43+
static ProverOutput create_goblin_prover_output()
4444
{
4545
Goblin goblin;
46-
// Construct and accumulate multiple circuits
47-
for (size_t idx = 0; idx < NUM_CIRCUITS - 1; ++idx) {
48-
MegaCircuitBuilder builder{ goblin.op_queue };
49-
GoblinMockCircuits::construct_simple_circuit(builder);
50-
goblin.prove_merge();
51-
}
52-
53-
auto goblin_transcript = std::make_shared<Goblin::Transcript>();
46+
GoblinMockCircuits::construct_and_merge_mock_circuits(goblin, 5);
5447

55-
Goblin goblin_final;
56-
goblin_final.op_queue = goblin.op_queue;
57-
MegaCircuitBuilder builder{ goblin_final.op_queue };
58-
GoblinMockCircuits::construct_simple_circuit(builder, /*last_circuit=*/true);
59-
goblin_final.op_queue->merge();
48+
// Merge the ecc ops from the newly constructed circuit
49+
auto goblin_proof = goblin.prove(MergeSettings::APPEND);
6050
// Subtable values and commitments - needed for (Recursive)MergeVerifier
6151
MergeCommitments merge_commitments;
62-
auto t_current = goblin_final.op_queue->construct_current_ultra_ops_subtable_columns();
63-
auto T_prev = goblin_final.op_queue->construct_previous_ultra_ops_table_columns();
64-
CommitmentKey<curve::BN254> pcs_commitment_key(goblin_final.op_queue->get_ultra_ops_table_num_rows());
52+
auto t_current = goblin.op_queue->construct_current_ultra_ops_subtable_columns();
53+
auto T_prev = goblin.op_queue->construct_previous_ultra_ops_table_columns();
54+
CommitmentKey<curve::BN254> pcs_commitment_key(goblin.op_queue->get_ultra_ops_table_num_rows());
6555
for (size_t idx = 0; idx < MegaFlavor::NUM_WIRES; idx++) {
6656
merge_commitments.t_commitments[idx] = pcs_commitment_key.commit(t_current[idx]);
6757
merge_commitments.T_prev_commitments[idx] = pcs_commitment_key.commit(T_prev[idx]);
6858
}
6959

7060
// Output is a goblin proof plus ECCVM/Translator verification keys
71-
return { goblin_final.prove(),
72-
{ std::make_shared<ECCVMVK>(), std::make_shared<TranslatorVK>() },
73-
merge_commitments };
61+
return { goblin_proof, { std::make_shared<ECCVMVK>(), std::make_shared<TranslatorVK>() }, merge_commitments };
7462
}
7563
};
7664

@@ -96,7 +84,7 @@ TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic)
9684
}
9785

9886
GoblinRecursiveVerifier verifier{ &builder, verifier_input };
99-
GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_commitments);
87+
GoblinRecursiveVerifierOutput output = verifier.verify(proof, recursive_merge_commitments, MergeSettings::APPEND);
10088
output.points_accumulator.set_public();
10189
// Construct and verify a proof for the Goblin Recursive Verifier circuit
10290
{

barretenberg/cpp/src/barretenberg/circuit_checker/translator_circuit_checker.cpp

Lines changed: 381 additions & 362 deletions
Large diffs are not rendered by default.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks(
268268
pairing_points.aggregate(nested_pairing_points);
269269
if (is_hiding_kernel) {
270270
pairing_points.aggregate(decider_pairing_points);
271+
// Placeholder for randomness at the end of the hiding circuit (to be handled in subsequent PR)
272+
circuit.queue_ecc_no_op();
273+
circuit.queue_ecc_no_op();
271274
}
272275

273276
return { output_verifier_accumulator, pairing_points, merged_table_commitments };
@@ -310,6 +313,12 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit)
310313
// to ensure the op queue wires in translator are shiftable, i.e. their 0th coefficient is 0. (The tail kernel
311314
// subtable is at the top of the final aggregate table since it is the last to be prepended).
312315
if (is_tail_kernel) {
316+
BB_ASSERT_EQ(circuit.op_queue->get_current_subtable_size(),
317+
0U,
318+
"tail kernel ecc ops table should be empty at this point");
319+
circuit.queue_ecc_no_op();
320+
// Placeholder for randomness at the beginning of tail circuit
321+
circuit.queue_ecc_no_op();
313322
circuit.queue_ecc_no_op();
314323
}
315324
circuit.queue_ecc_eq();

barretenberg/cpp/src/barretenberg/constants.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ namespace bb {
88
// permutation argument polynomials (sigmas, ids) are unique, e.g. id[i][j] == id[m][n] iff (i == m && j == n)
99
constexpr uint32_t PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28;
1010

11+
// The fixed size of the Translator trace where each accumulation gate, corresponding to one UltraOp, will occupy two
12+
// rows.
13+
static constexpr uint32_t CONST_TRANSLATOR_MINI_CIRCUIT_LOG_SIZE = 14;
14+
15+
// -1 as each op occupies two rows in Translator trace
16+
static constexpr uint32_t CONST_OP_QUEUE_LOG_SIZE = CONST_TRANSLATOR_MINI_CIRCUIT_LOG_SIZE - 1;
17+
1118
// The log of the max circuit size assumed in order to achieve constant sized Honk proofs
1219
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1046): Remove the need for const sized proofs
1320
static constexpr uint32_t CONST_PROOF_SIZE_LOG_N = 28;

barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ class ECCVMFlavor {
512512
* transcript_msm_count_at_transition_inverse: used to validate transcript_msm_count_zero_at_transition
513513
* precompute_pc: point counter for Straus precomputation columns
514514
* precompute_select: if 1, evaluate Straus precomputation algorithm at current row
515-
* precompute_point_transition: 1 if current row operating on a different point to previous row
515+
* precompute_point_transition: 1 if next row operating on a different point than current row.
516516
* precompute_round: round counter for Straus precomputation algorithm
517517
* precompute_scalar_sum: accumulating sum of Straus scalar slices
518518
* precompute_s1hi/lo: 2-bit hi/lo components of a Straus 4-bit scalar slice

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "barretenberg/crypto/merkle_tree/memory_store.hpp"
1313
#include "barretenberg/crypto/merkle_tree/merkle_tree.hpp"
1414
#include "barretenberg/flavor/mega_flavor.hpp"
15+
#include "barretenberg/goblin/goblin.hpp"
1516
#include "barretenberg/srs/global_crs.hpp"
1617
#include "barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp"
1718
#include "barretenberg/stdlib/hash/keccak/keccak.hpp"
@@ -136,19 +137,34 @@ class GoblinMockCircuits {
136137
*
137138
* @param builder
138139
*/
139-
static void construct_simple_circuit(MegaBuilder& builder, bool last_circuit = false)
140+
static void construct_simple_circuit(MegaBuilder& builder)
140141
{
141142
BB_BENCH();
142-
// The last circuit to be accumulated must contain a no-op
143-
if (last_circuit) {
144-
builder.queue_ecc_no_op();
145-
}
146143

147144
add_some_ecc_op_gates(builder);
148145
MockCircuits::construct_arithmetic_circuit(builder);
149146
bb::stdlib::recursion::honk::DefaultIO<MegaBuilder>::add_default(builder);
150147
}
151148

149+
static void construct_and_merge_mock_circuits(Goblin& goblin, const size_t num_circuits = 3)
150+
{
151+
for (size_t idx = 0; idx < num_circuits - 1; ++idx) {
152+
MegaCircuitBuilder builder{ goblin.op_queue };
153+
if (idx == num_circuits - 2) {
154+
// Last circuit appended needs to begin with a no-op for translator to be shiftable
155+
builder.queue_ecc_no_op();
156+
}
157+
construct_simple_circuit(builder);
158+
goblin.prove_merge();
159+
// Pop the merge proof from the queue, Goblin will be verified at the end
160+
goblin.merge_verification_queue.pop_front();
161+
}
162+
MegaCircuitBuilder builder{ goblin.op_queue };
163+
GoblinMockCircuits::construct_simple_circuit(builder);
164+
builder.queue_ecc_no_op();
165+
builder.queue_ecc_no_op();
166+
}
167+
152168
/**
153169
* @brief Construct a mock kernel circuit
154170
* @details Construct an arbitrary circuit meant to represent the aztec private function execution kernel. Recursive

barretenberg/cpp/src/barretenberg/op_queue/ecc_op_queue.hpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class ECCOpQueue {
4848
EccvmRowTracker eccvm_row_tracker;
4949

5050
public:
51+
static const size_t OP_QUEUE_SIZE = 1 << CONST_OP_QUEUE_LOG_SIZE;
5152
/**
5253
* @brief Instantiate an initial ECC op subtable.
5354
*/
@@ -63,6 +64,8 @@ class ECCOpQueue {
6364
ultra_ops_table.create_new_subtable();
6465
}
6566

67+
size_t get_current_subtable_size() const { return ultra_ops_table.get_current_subtable_size(); }
68+
6669
void merge(MergeSettings settings = MergeSettings::PREPEND, std::optional<size_t> ultra_fixed_offset = std::nullopt)
6770
{
6871
eccvm_ops_table.merge(settings);
@@ -75,7 +78,8 @@ class ECCOpQueue {
7578
return ultra_ops_table.construct_table_columns();
7679
}
7780

78-
// Construct polys corresponding to the columns of the aggregate ultra ops table, excluding the most recent subtable
81+
// Construct polys corresponding to the columns of the aggregate ultra ops table, excluding the most recent
82+
// subtable
7983
std::array<Polynomial<Fr>, ULTRA_TABLE_WIDTH> construct_previous_ultra_ops_table_columns() const
8084
{
8185
return ultra_ops_table.construct_previous_table_columns();
@@ -97,8 +101,8 @@ class ECCOpQueue {
97101
size_t get_current_ultra_ops_subtable_num_rows() const { return ultra_ops_table.current_ultra_subtable_size(); }
98102
size_t get_previous_ultra_ops_table_num_rows() const { return ultra_ops_table.previous_ultra_table_size(); }
99103

100-
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1339): Consider making the ultra and eccvm ops getters
101-
// more memory efficient
104+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1339): Consider making the ultra and eccvm ops
105+
// getters more memory efficient
102106

103107
// Get the full table of ECCVM ops in contiguous memory; construct it if it has not been constructed already
104108
std::vector<ECCVMOperation>& get_eccvm_ops()
@@ -225,8 +229,8 @@ class ECCOpQueue {
225229
/**
226230
* @brief Writes randomness to the ultra ops table but adds no eccvm operations.
227231
*
228-
* @details This method is used to add randomness to the ultra ops table with the aim of randomising the commitment
229-
* and evaluations of its corresponding columns
232+
* @details This method is used to add randomness to the ultra ops table with the aim of randomising the
233+
* commitment and evaluations of its corresponding columns
230234
* @return UltraOp
231235
*/
232236
UltraOp random_op_ultra_only()

barretenberg/cpp/src/barretenberg/op_queue/ecc_op_queue.test.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class ECCOpQueueTest {
5454
} else {
5555
// APPEND merge performs concatenation directly to end of previous table or at a specified fixed offset
5656
const size_t prev_table_size = op_queue->get_previous_ultra_ops_table_num_rows(); // k
57-
const size_t shift_magnitude = ultra_fixed_offset.value_or(prev_table_size);
57+
const size_t shift_magnitude = ultra_fixed_offset.has_value()
58+
? ultra_fixed_offset.value() * bb::UltraEccOpsTable::NUM_ROWS_PER_OP
59+
: prev_table_size; // k
5860
// T(x) = T_prev(x) + x^k * t_current(x), where k is the shift magnitude
5961
const Fr prev_table_eval = prev_table_poly.evaluate(eval_challenge); // T_prev(x)
6062
const Fr shifted_subtable_eval =
@@ -74,10 +76,12 @@ class ECCOpQueueTest {
7476
auto ultra_table = op_queue->get_ultra_ops();
7577
auto eccvm_table = op_queue->get_eccvm_ops();
7678

77-
EXPECT_EQ(eccvm_table.size(), ultra_table.size());
78-
79-
for (auto [ultra_op, eccvm_op] : zip_view(ultra_table, eccvm_table)) {
80-
EXPECT_EQ(ultra_op.op_code.value(), eccvm_op.op_code.value());
79+
size_t j = 0;
80+
for (const auto& ultra_op : ultra_table) {
81+
if (ultra_op.op_code.value() == 0) {
82+
continue;
83+
}
84+
EXPECT_EQ(ultra_op.op_code.value(), eccvm_table[j++].op_code.value());
8185
}
8286
};
8387
};

barretenberg/cpp/src/barretenberg/op_queue/ecc_ops_table.hpp

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ struct UltraOp {
7474
Fr z_2;
7575
bool return_is_infinity;
7676

77+
bool operator==(const UltraOp& other) const = default;
78+
7779
/**
7880
* @brief Get the point in standard form i.e. as two coordinates x and y in the base field or as a point at
7981
* infinity whose coordinates are set to (0,0).
@@ -130,6 +132,7 @@ template <typename OpFormat> class EccOpsTable {
130132
}
131133

132134
size_t num_subtables() const { return table.size(); }
135+
size_t get_current_subtable_size() const { return current_subtable.size(); }
133136

134137
auto& get() const { return table; }
135138

@@ -246,7 +249,7 @@ class UltraEccOpsTable {
246249
// The last subtable in deque is the fixed-location one
247250
last_subtable_size = table.get().back().size() * NUM_ROWS_PER_OP;
248251
}
249-
return std::max(base_size, fixed_append_offset.value() + last_subtable_size);
252+
return std::max(base_size, (fixed_append_offset.value() * NUM_ROWS_PER_OP) + last_subtable_size);
250253
}
251254
return base_size;
252255
}
@@ -270,7 +273,46 @@ class UltraEccOpsTable {
270273
}
271274
}
272275

273-
std::vector<UltraOp> get_reconstructed() const { return table.get_reconstructed(); }
276+
size_t get_current_subtable_size() const { return table.get_current_subtable_size(); }
277+
278+
std::vector<UltraOp> get_reconstructed() const
279+
{
280+
if (has_fixed_append && fixed_append_offset.has_value()) {
281+
return get_reconstructed_with_fixed_append();
282+
}
283+
return table.get_reconstructed();
284+
}
285+
std::vector<UltraOp> get_reconstructed_with_fixed_append() const
286+
{
287+
288+
ASSERT(get_current_subtable_size() == 0,
289+
"current subtable should be merged before reconstructing the full table of operations.");
290+
291+
std::vector<UltraOp> reconstructed_table;
292+
reconstructed_table.reserve(1 << CONST_OP_QUEUE_LOG_SIZE);
293+
294+
for (size_t subtable_idx = 0; subtable_idx < table.num_subtables() - 1; subtable_idx++) {
295+
const auto& subtable = table.get()[subtable_idx];
296+
for (const auto& op : subtable) {
297+
reconstructed_table.push_back(op);
298+
}
299+
}
300+
301+
// Add zeros if fixed offset is larger than current size
302+
if (has_fixed_append && fixed_append_offset.has_value()) {
303+
size_t current_size = reconstructed_table.size();
304+
size_t target_offset = fixed_append_offset.value();
305+
// Fill gap with no-ops if needed
306+
reconstructed_table.insert(reconstructed_table.end(), target_offset - current_size, UltraOp{ /*no-op*/ });
307+
}
308+
309+
// Add the final subtable (appended at fixed location)
310+
const auto& final_subtable = table.get()[table.num_subtables() - 1];
311+
for (const auto& op : final_subtable) {
312+
reconstructed_table.push_back(op);
313+
}
314+
return reconstructed_table;
315+
}
274316

275317
// Construct the columns of the full ultra ecc ops table
276318
ColumnPolynomials construct_table_columns() const
@@ -342,7 +384,7 @@ class UltraEccOpsTable {
342384

343385
// Process all prepended subtables (all except last)
344386
size_t i = 0;
345-
for (size_t subtable_idx = 0; subtable_idx < table.num_subtables() - 1; ++subtable_idx) {
387+
for (size_t subtable_idx = 0; subtable_idx < table.num_subtables() - 1; subtable_idx++) {
346388
const auto& subtable = table.get()[subtable_idx];
347389
for (const auto& op : subtable) {
348390
write_op_to_polynomials(column_polynomials, op, i);
@@ -351,7 +393,7 @@ class UltraEccOpsTable {
351393
}
352394

353395
// Place the appended subtable at the fixed offset
354-
size_t append_position = fixed_append_offset.value_or(i);
396+
size_t append_position = fixed_append_offset.has_value() ? fixed_append_offset.value() * NUM_ROWS_PER_OP : i;
355397
const auto& appended_subtable = table.get()[table.num_subtables() - 1];
356398

357399
size_t j = append_position;

0 commit comments

Comments
 (0)