Skip to content

Commit df14182

Browse files
authored
feat: merge-train/barretenberg (#19038)
See [merge-train-readme.md](https://github.com/AztecProtocol/aztec-packages/blob/next/.github/workflows/merge-train-readme.md). This is a merge-train.
2 parents 8c36ee7 + 86aed58 commit df14182

24 files changed

+213
-178
lines changed

barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_dsl.fuzzer.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,9 +1232,7 @@ bool test_acir_circuit(const uint8_t* data, size_t size)
12321232
// Build circuit using the proper constructor that initializes witnesses
12331233
// NOTE: Must use the witness-aware constructor, not default constructor!
12341234
// The default constructor leaves witnesses uninitialized, causing false negatives.
1235-
UltraCircuitBuilder builder{
1236-
/*size_hint*/ 0, witness_vec, acir_format.public_inputs, /*is_write_vk_mode=*/false
1237-
};
1235+
UltraCircuitBuilder builder{ witness_vec, acir_format.public_inputs, /*is_write_vk_mode=*/false };
12381236

12391237
build_constraints(builder, acir_format, ProgramMetadata{});
12401238

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// === AUDIT STATUS ===
2-
// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
2+
// internal: { status: Completed, auditors: [Federico], date: 2025-12-12 }
33
// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
44
// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
55
// =====================
@@ -70,7 +70,10 @@ void build_constraints(Builder& builder, AcirFormat& constraints, const ProgramM
7070
// Add range constraint
7171
for (const auto& [constraint, opcode_idx] :
7272
zip_view(constraints.range_constraints, constraints.original_opcode_indices.range_constraints)) {
73-
builder.create_dyadic_range_constraint(constraint.witness, constraint.num_bits, "");
73+
builder.create_dyadic_range_constraint(
74+
constraint.witness,
75+
constraint.num_bits,
76+
std::format("acir_format::build_constraints: range constraint at opcode index {} failed", opcode_idx));
7477
gate_counter.track_diff(constraints.gates_per_opcode, opcode_idx);
7578
}
7679

@@ -150,6 +153,8 @@ void build_constraints(Builder& builder, AcirFormat& constraints, const ProgramM
150153
zip_view(constraints.block_constraints, constraints.original_opcode_indices.block_constraints)) {
151154
create_block_constraints(builder, constraint);
152155
if (collect_gates_per_opcode) {
156+
// Each block constraint may correspond to multiple opcodes, so we record the average number of gates added
157+
// by the entire constraint as the number of gates for each opcode.
153158
size_t avg_gates_per_opcode = gate_counter.compute_diff() / opcode_indices.size();
154159
for (size_t opcode_index : opcode_indices) {
155160
constraints.gates_per_opcode[opcode_index] = avg_gates_per_opcode;
@@ -193,13 +198,13 @@ template <> UltraCircuitBuilder create_circuit(AcirProgram& program, const Progr
193198
if (!is_write_vk_mode) {
194199
BB_ASSERT_EQ(witness.size(),
195200
constraints.max_witness_index + 1,
196-
"ACIR witness size (" << witness.size() << ") does not match max witness index ("
197-
<< constraints.max_witness_index << ").");
201+
"ACIR witness size (" << witness.size() << ") does not match max witness index + 1 ("
202+
<< (constraints.max_witness_index + 1) << ").");
198203
} else {
199204
witness.resize(constraints.max_witness_index + 1, 0);
200205
}
201206

202-
UltraCircuitBuilder builder{ metadata.size_hint, witness, constraints.public_inputs, is_write_vk_mode };
207+
UltraCircuitBuilder builder{ witness, constraints.public_inputs, is_write_vk_mode };
203208

204209
// Populate constraints in the builder
205210
build_constraints(builder, constraints, metadata);
@@ -225,8 +230,8 @@ template <> MegaCircuitBuilder create_circuit(AcirProgram& program, const Progra
225230
if (!is_write_vk_mode) {
226231
BB_ASSERT_EQ(witness.size(),
227232
constraints.max_witness_index + 1,
228-
"ACIR witness size (" << witness.size() << ") does not match max witness index ("
229-
<< constraints.max_witness_index << ").");
233+
"ACIR witness size (" << witness.size() << ") does not match max witness index + 1 ("
234+
<< (constraints.max_witness_index + 1) << ").");
230235
} else {
231236
witness.resize(constraints.max_witness_index + 1, 0);
232237
}

barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ struct AcirFormatOriginalOpcodeIndices {
5959
std::vector<size_t> avm_recursion_constraints;
6060
std::vector<size_t> hn_recursion_constraints;
6161
std::vector<size_t> chonk_recursion_constraints;
62-
std::vector<size_t> arithmetic_triple_constraints;
6362
std::vector<size_t> quad_constraints;
6463
std::vector<size_t> big_quad_constraints;
6564
// Multiple opcode indices per block:
@@ -105,9 +104,9 @@ struct AcirFormat {
105104
std::vector<RecursionConstraint> hn_recursion_constraints;
106105
std::vector<RecursionConstraint> chonk_recursion_constraints;
107106
std::vector<QuadConstraints> quad_constraints; // Standard honk arithmetic constraint of width 4
108-
// A vector of vector of mul_quad gates (i.e arithmetic constraints of width 4)
107+
// A vector of vector of QuadConstraints gates (i.e arithmetic constraints of width 4)
109108
// Each vector of gates represente a 'big' expression (a polynomial of degree 1 or 2 which does not fit inside one
110-
// mul_gate) that has been splitted into multiple mul_gates, using w4_shift (the 4th wire of the next gate), to
109+
// mul_gate) that has been split into multiple mul_gates, using w4_shift (the 4th wire of the next gate), to
111110
// reduce the number of intermediate variables.
112111
std::vector<std::vector<QuadConstraints>> big_quad_constraints;
113112
std::vector<BlockConstraint> block_constraints;
@@ -172,7 +171,6 @@ struct ProgramMetadata {
172171
// should propagate an IPA claim. In our codebase, circuits that propagate IPA claims are the ones whose
173172
// proof is constructed/verified using Rollup flavors.
174173
bool collect_gates_per_opcode = false;
175-
size_t size_hint = 0;
176174
};
177175

178176
/**

barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format_mocks.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ AcirFormatOriginalOpcodeIndices create_empty_original_opcode_indices()
2727
.avm_recursion_constraints = {},
2828
.hn_recursion_constraints = {},
2929
.chonk_recursion_constraints = {},
30-
.arithmetic_triple_constraints = {},
3130
.quad_constraints = {},
3231
.big_quad_constraints = {},
3332
.block_constraints = {},

barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ std::vector<mul_quad_<fr>> split_into_mul_quad_gates(Acir::Expression const& arg
472472
// We cannot precompute the exact number of gates that will result from the expression. Therefore, we reserve the
473473
// maximum number of gates that could ever be needed: one per multiplication term plus one per linear term. The real
474474
// number of gates will in general be lower than this.
475+
BB_ASSERT_LTE(arg.mul_terms.size(),
476+
SIZE_MAX - linear_terms.size(),
477+
"split_into_mul_quad_gates: overflow when reserving space for mul_quad_ gates.");
475478
result.reserve(arg.mul_terms.size() + linear_terms.size());
476479

477480
// Step 1. Add multiplication terms and linear terms with the same witness index

barretenberg/cpp/src/barretenberg/dsl/acir_format/arithmetic_constraints.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// === AUDIT STATUS ===
2-
// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
2+
// internal: { status: Completed, auditors: [Federico], date: 2025-12-12 }
33
// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
44
// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
55
// =====================
@@ -21,6 +21,10 @@ template <typename Builder> void set_zero_idx(const Builder& builder, mul_quad_<
2121
}
2222
};
2323

24+
BB_ASSERT_NEQ(mul_quad.a,
25+
bb::stdlib::IS_CONSTANT,
26+
"mul_quad_ gate cannot have IS_CONSTANT for witness a. An error here probably means a conversion "
27+
"issue in acir_to_constraint_buf.");
2428
replace_and_check_zero_scaling(mul_quad.b, mul_quad.b_scaling);
2529
replace_and_check_zero_scaling(mul_quad.c, mul_quad.c_scaling);
2630
replace_and_check_zero_scaling(mul_quad.d, mul_quad.d_scaling);

barretenberg/cpp/src/barretenberg/dsl/acir_format/blake2s_constraint.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ template <typename Builder> void create_blake2s_constraints(Builder& builder, co
3939

4040
byte_array_ct output_bytes = stdlib::Blake2s<Builder>::hash(arr);
4141

42-
for (size_t i = 0; i < output_bytes.size(); ++i) {
43-
output_bytes[i].assert_equal(field_ct::from_witness_index(&builder, constraint.result[i]));
42+
for (const auto& [output_byte, result_byte_idx] : zip_view(output_bytes.bytes(), constraint.result)) {
43+
// Constrain each output byte to equal the corresponding witness
44+
// This equality also constrains the result witnesses to be bytes
45+
output_byte.assert_equal(field_ct::from_witness_index(&builder, result_byte_idx));
4446
}
4547
}
4648

barretenberg/cpp/src/barretenberg/dsl/acir_format/blake2s_constraint.test.cpp

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
using namespace bb;
1313
using namespace acir_format;
1414

15-
template <class BuilderType> class Blake2sTestingFunctions {
15+
template <class BuilderType, bool IsInputConstant> class Blake2sTestingFunctions {
1616
public:
1717
using Builder = BuilderType;
1818
using AcirConstraint = Blake2sConstraint;
19+
using FF = Builder::FF;
1920

2021
struct InvalidWitness {
2122
public:
@@ -37,7 +38,12 @@ template <class BuilderType> class Blake2sTestingFunctions {
3738
switch (invalid_witness_target) {
3839
case InvalidWitness::Target::Input: {
3940
// Tamper with the first input element
40-
witness_values[constraint.inputs[0].blackbox_input.index] += bb::fr(1);
41+
if constexpr (IsInputConstant) {
42+
constraint.inputs[0].blackbox_input =
43+
WitnessOrConstant<FF>::from_constant(constraint.inputs[0].blackbox_input.value + bb::fr(1));
44+
} else {
45+
witness_values[constraint.inputs[0].blackbox_input.index] += bb::fr(1);
46+
}
4147
break;
4248
}
4349
case InvalidWitness::Target::Output: {
@@ -55,53 +61,83 @@ template <class BuilderType> class Blake2sTestingFunctions {
5561
*/
5662
void generate_constraints(Blake2sConstraint& blake2s_constraint, WitnessVector& witness_values)
5763
{
58-
// Start with the zero variable at index 0
59-
witness_values.emplace_back(bb::fr(0));
64+
// Helper to add a state: either as witness or constant
65+
auto construct_state = [&](const std::vector<uint8_t>& state,
66+
bool as_constant) -> std::vector<WitnessOrConstant<FF>> {
67+
std::vector<WitnessOrConstant<FF>> result;
68+
if (as_constant) {
69+
for (const auto& byte : state) {
70+
result.push_back(WitnessOrConstant<FF>::from_constant(FF(byte)));
71+
}
72+
return result;
73+
}
74+
auto indices = add_to_witness_and_track_indices(witness_values, state);
75+
for (const auto& idx : indices) {
76+
result.push_back(WitnessOrConstant<FF>::from_index(idx));
77+
}
78+
return result;
79+
};
6080

6181
// Input: 64-byte message
6282
std::vector<uint8_t> input_state(64);
6383

6484
// Expected Blake2s hash output
6585
std::array<uint8_t, 32> output_state = crypto::blake2s(input_state);
6686

67-
// Add input and output state to witness
68-
auto input_indices = add_to_witness_and_track_indices<std::vector<uint8_t>, 64>(witness_values, input_state);
69-
auto output_indices =
70-
add_to_witness_and_track_indices<std::array<uint8_t, 32>, 32>(witness_values, output_state);
71-
7287
// Create the constraint
7388
blake2s_constraint.inputs.reserve(input_state.size());
74-
for (size_t i = 0; i < input_state.size(); ++i) {
75-
Blake2sInput input{
76-
.blackbox_input = WitnessOrConstant<fr>::from_index(static_cast<uint32_t>(input_indices[i])),
77-
.num_bits = 8,
78-
};
89+
for (const auto& state : construct_state(input_state, IsInputConstant)) {
90+
Blake2sInput input{ .blackbox_input = state, .num_bits = 8 };
7991
blake2s_constraint.inputs.push_back(input);
8092
}
81-
for (size_t i = 0; i < 32; ++i) {
82-
blake2s_constraint.result[i] = static_cast<uint32_t>(output_indices[i]);
93+
94+
// Add output state to witness
95+
auto output_indices = add_to_witness_and_track_indices(witness_values, output_state);
96+
// Add output indices to constraint
97+
for (auto [blake_result, output_idx] : zip_view(blake2s_constraint.result, output_indices)) {
98+
blake_result = output_idx;
8399
}
84100
}
85101
};
86102

87103
template <class Builder>
88-
class Blake2sConstraintsTest : public ::testing::Test, public TestClass<Blake2sTestingFunctions<Builder>> {
104+
class Blake2sConstraintsTestInputConstant : public ::testing::Test,
105+
public TestClass<Blake2sTestingFunctions<Builder, true>> {
89106
protected:
90107
static void SetUpTestSuite() { srs::init_file_crs_factory(srs::bb_crs_path()); }
91108
};
92109

93110
using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
94111

95-
TYPED_TEST_SUITE(Blake2sConstraintsTest, BuilderTypes);
112+
TYPED_TEST_SUITE(Blake2sConstraintsTestInputConstant, BuilderTypes);
113+
TYPED_TEST(Blake2sConstraintsTestInputConstant, GenerateVKFromConstraints)
114+
{
115+
using Flavor = std::conditional_t<std::is_same_v<TypeParam, UltraCircuitBuilder>, UltraFlavor, MegaFlavor>;
116+
TestFixture::template test_vk_independence<Flavor>();
117+
}
118+
119+
TYPED_TEST(Blake2sConstraintsTestInputConstant, Tampering)
120+
{
121+
[[maybe_unused]] std::vector<std::string> _ = TestFixture::test_tampering();
122+
}
123+
124+
template <class Builder>
125+
class Blake2sConstraintsTestInputWitness : public ::testing::Test,
126+
public TestClass<Blake2sTestingFunctions<Builder, false>> {
127+
protected:
128+
static void SetUpTestSuite() { srs::init_file_crs_factory(srs::bb_crs_path()); }
129+
};
130+
131+
using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
96132

97-
TYPED_TEST(Blake2sConstraintsTest, GenerateVKFromConstraints)
133+
TYPED_TEST_SUITE(Blake2sConstraintsTestInputWitness, BuilderTypes);
134+
TYPED_TEST(Blake2sConstraintsTestInputWitness, GenerateVKFromConstraints)
98135
{
99136
using Flavor = std::conditional_t<std::is_same_v<TypeParam, UltraCircuitBuilder>, UltraFlavor, MegaFlavor>;
100137
TestFixture::template test_vk_independence<Flavor>();
101138
}
102139

103-
TYPED_TEST(Blake2sConstraintsTest, Tampering)
140+
TYPED_TEST(Blake2sConstraintsTestInputWitness, Tampering)
104141
{
105-
BB_DISABLE_ASSERTS();
106142
[[maybe_unused]] std::vector<std::string> _ = TestFixture::test_tampering();
107143
}

barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ template <typename Builder> void create_blake3_constraints(Builder& builder, con
3838

3939
byte_array_ct output_bytes = bb::stdlib::Blake3s<Builder>::hash(arr);
4040

41-
// Convert byte array to vector of field_t
42-
43-
for (size_t i = 0; i < output_bytes.size(); ++i) {
44-
output_bytes[i].assert_equal(field_ct::from_witness_index(&builder, constraint.result[i]));
41+
for (const auto& [output_byte, result_byte_idx] : zip_view(output_bytes.bytes(), constraint.result)) {
42+
// Constrain each output byte to equal the corresponding witness
43+
// This equality also constrains the result witnesses to be bytes
44+
output_byte.assert_equal(field_ct::from_witness_index(&builder, result_byte_idx));
4545
}
4646
}
4747

0 commit comments

Comments
 (0)