From 0f3ca1c6a84ef6ed14d4b29564ffcf4d37645619 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Fri, 3 Apr 2026 12:53:28 +0000 Subject: [PATCH 1/5] fix(bb): propagate OriginTag in logic gadget (audit L-2) --- .../stdlib/primitives/logic/logic.cpp | 3 + .../stdlib/primitives/logic/logic.test.cpp | 61 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp index e9414e3ed14d..bf0018b89ba9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp @@ -58,6 +58,7 @@ field_t logic::create_logic_constraint( Builder* ctx = b.get_context(); uint256_t a_native(a.get_value()); field_pt a_witness = field_pt::from_witness_index(ctx, ctx->put_constant_variable(a_native)); + a_witness.set_origin_tag(a.get_origin_tag()); return create_logic_constraint(a_witness, b, num_bits, is_xor_gate, get_chunk); } @@ -65,6 +66,7 @@ field_t logic::create_logic_constraint( Builder* ctx = a.get_context(); uint256_t b_native(b.get_value()); field_pt b_witness = field_pt::from_witness_index(ctx, ctx->put_constant_variable(b_native)); + b_witness.set_origin_tag(b.get_origin_tag()); return create_logic_constraint(a, b_witness, num_bits, is_xor_gate, get_chunk); } @@ -111,6 +113,7 @@ field_t logic::create_logic_constraint( a.assert_equal(a_accumulator, "stdlib logic: failed to reconstruct left operand"); b.assert_equal(b_accumulator, "stdlib logic: failed to reconstruct right operand"); + res.set_origin_tag(OriginTag(a.get_origin_tag(), b.get_origin_tag())); return res; } template class logic; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp index e7d4dd568300..1cbf428468d1 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp @@ -143,3 +143,64 @@ TYPED_TEST(LogicTest, DifferentWitnessSameResult) bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } + +// Regression test: OriginTag must propagate through all logic constraint paths. +TYPED_TEST(LogicTest, OriginTagPropagation) +{ + STDLIB_TYPE_ALIASES + STANDARD_TESTING_TAGS + + auto builder = Builder(); + uint256_t a_val = 0xAB; + uint256_t b_val = 0xCD; + + // Both witnesses + { + field_ct x = witness_ct(&builder, a_val); + field_ct y = witness_ct(&builder, b_val); + x.set_origin_tag(submitted_value_origin_tag); + y.set_origin_tag(challenge_origin_tag); + + field_ct and_result = stdlib::logic::create_logic_constraint(x, y, 8, false); + field_ct xor_result = stdlib::logic::create_logic_constraint(x, y, 8, true); + + EXPECT_EQ(and_result.get_origin_tag(), first_two_merged_tag); + EXPECT_EQ(xor_result.get_origin_tag(), first_two_merged_tag); + } + + // Left constant, right witness + { + field_ct x_const(&builder, a_val); + field_ct y = witness_ct(&builder, b_val); + x_const.set_origin_tag(submitted_value_origin_tag); + y.set_origin_tag(challenge_origin_tag); + + field_ct result = stdlib::logic::create_logic_constraint(x_const, y, 8, false); + EXPECT_EQ(result.get_origin_tag(), first_two_merged_tag); + } + + // Right constant, left witness + { + field_ct x = witness_ct(&builder, a_val); + field_ct y_const(&builder, b_val); + x.set_origin_tag(submitted_value_origin_tag); + y_const.set_origin_tag(challenge_origin_tag); + + field_ct result = stdlib::logic::create_logic_constraint(x, y_const, 8, false); + EXPECT_EQ(result.get_origin_tag(), first_two_merged_tag); + } + + // Both constants + { + field_ct x_const(&builder, a_val); + field_ct y_const(&builder, b_val); + x_const.set_origin_tag(submitted_value_origin_tag); + y_const.set_origin_tag(challenge_origin_tag); + + field_ct result = stdlib::logic::create_logic_constraint(x_const, y_const, 8, false); + EXPECT_EQ(result.get_origin_tag(), first_two_merged_tag); + } + + bool result = CircuitChecker::check(builder); + EXPECT_EQ(result, true); +} From 249bfdc76053f41455e048f182605a871f970cce Mon Sep 17 00:00:00 2001 From: suyash67 Date: Fri, 3 Apr 2026 13:10:15 +0000 Subject: [PATCH 2/5] fix(bb): add validate_context in logic gadget (audit L-3) --- .../cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp index bf0018b89ba9..e286ff112657 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.cpp @@ -70,7 +70,7 @@ field_t logic::create_logic_constraint( return create_logic_constraint(a, b_witness, num_bits, is_xor_gate, get_chunk); } - Builder* ctx = a.get_context(); + Builder* ctx = validate_context(a.get_context(), b.get_context()); // We slice the input values into 32-bit chunks, and then use a multi-table lookup to compute the AND or XOR // of each chunk. Since we perform the lookup from 32-bit multi-tables, the lookup operation implicitly enforces a From 5b3d4b857a2233f863d40d837d8df3dbd5e65b03 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Fri, 3 Apr 2026 13:37:31 +0000 Subject: [PATCH 3/5] fix L4, write vk mode works corrrectly now for constant inputs. --- .../src/barretenberg/dsl/acir_format/logic_constraint.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp index 83b66882f4ba..f0b7a94efb68 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp @@ -23,6 +23,14 @@ void create_logic_gate(Builder& builder, field_ct right = to_field_ct(b, builder); field_ct computed_result = bb::stdlib::logic::create_logic_constraint(left, right, num_bits, is_xor_gate); + + // In write-VK mode the result witness holds a dummy zero. When both inputs are constant the computed result is a + // compile-time constant, so assert_equal would spuriously fail. Patch the witness value so the downstream + // assertion sees the correct value. + if (builder.is_write_vk_mode() && computed_result.is_constant()) { + builder.set_variable(result, computed_result.get_value()); + } + field_ct acir_result = field_ct::from_witness_index(&builder, result); computed_result.assert_equal(acir_result); } From 2a597fb73b75f71ef7ddfd579eee8f749996dd67 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Fri, 3 Apr 2026 14:38:06 +0000 Subject: [PATCH 4/5] fix I3, operator precedence bug in logic constraint test --- .../barretenberg/dsl/acir_format/logic_constraint.test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp index 10b1b2c69229..96a408e13879 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp @@ -73,8 +73,8 @@ class LogicConstraintTestingFunctions { return WitnessOrConstant::from_index(input_index); }; - bb::fr lhs = FF(static_cast(1) << num_bits - 1); // All bits from 0 to num_bits-1 are set - bb::fr rhs = FF(static_cast(1) << num_bits - 1); // All bits from 0 to num_bits-1 are set + bb::fr lhs = FF((static_cast(1) << num_bits) - 1); // All bits from 0 to num_bits-1 are set + bb::fr rhs = FF((static_cast(1) << num_bits) - 1); // All bits from 0 to num_bits-1 are set bb::fr result = is_xor_gate ? (static_cast(lhs) ^ static_cast(rhs)) : (static_cast(lhs) & static_cast(rhs)); From a4837fef0294826c391125686cce671199d055f6 Mon Sep 17 00:00:00 2001 From: suyash67 Date: Mon, 6 Apr 2026 09:51:28 +0000 Subject: [PATCH 5/5] fix write_vk mode. --- .../barretenberg/dsl/acir_format/logic_constraint.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp index f0b7a94efb68..b8522cd06852 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp @@ -24,10 +24,11 @@ void create_logic_gate(Builder& builder, field_ct computed_result = bb::stdlib::logic::create_logic_constraint(left, right, num_bits, is_xor_gate); - // In write-VK mode the result witness holds a dummy zero. When both inputs are constant the computed result is a - // compile-time constant, so assert_equal would spuriously fail. Patch the witness value so the downstream - // assertion sees the correct value. - if (builder.is_write_vk_mode() && computed_result.is_constant()) { + // In write-VK mode the result witness holds a dummy zero. In certain cases, the computed result is non-zero so the + // assert_equal would spuriously fail. Patch the witness value so the downstream assertion sees the correct value. + // Eg. for an XOR gate, if the inputs are constants such that the result is a non-zero constant, the assert_equal + // will fail in write-VK mode since the result witness is initialized to zero. + if (builder.is_write_vk_mode()) { builder.set_variable(result, computed_result.get_value()); }