Skip to content

Commit 7d1833d

Browse files
AztecBotcritesjosh
authored andcommitted
fix: add clear error for unsatisfiable ACIR AssertZero opcode (#22417)
## Summary When an ACIR `AssertZero` opcode has no variables but a non-zero constant, the circuit is fundamentally unsatisfiable (`nonzero == 0` can never hold). Previously this hit a generic assertion about empty gates with no indication of the real problem. Added an early check in `assert_zero_to_quad_constraints` that detects this case and produces a clear error: "circuit is unsatisfiable. An AssertZero opcode contains no variables but has a non-zero constant, which can never equal zero." ## Test plan - All 60 existing quad/big-quad constraint tests pass - Built and ran `dsl_tests` successfully ClaudeBox log: https://claudebox.work/s/bcd66a8253a37704?run=1
1 parent ac5707a commit 7d1833d

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ TYPED_TEST(AcirFormatTests, ExpressionWithOnlyConstantTermFails)
3636
.return_values = {},
3737
};
3838

39-
EXPECT_THROW_WITH_MESSAGE(circuit_serde_to_acir_format(circuit),
40-
"split_into_mul_quad_gates: resulted in zero gates.");
39+
EXPECT_THROW_WITH_MESSAGE(circuit_serde_to_acir_format(circuit), "circuit is unsatisfiable");
4140
}
4241

4342
TYPED_TEST(AcirFormatTests, ExpressionWithCancellingCoefficientsFails)

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,17 @@ void assert_zero_to_quad_constraints(Acir::Opcode::AssertZero const& arg, AcirFo
571571
};
572572

573573
auto linear_terms = process_linear_terms(arg.value);
574+
575+
// Check for unsatisfiable constraint: no variables but a non-zero constant means the circuit requires
576+
// `constant == 0` which can never be satisfied.
577+
if (arg.value.mul_terms.empty() && linear_terms.empty()) {
578+
fr constant = from_buffer_with_bound_checks(arg.value.q_c);
579+
BB_ASSERT_EQ(constant,
580+
fr::zero(),
581+
"circuit is unsatisfiable. An AssertZero opcode contains no variables but has a non-zero "
582+
"constant, which can never equal zero.");
583+
}
584+
574585
bool is_single_gate = is_single_arithmetic_gate(arg.value, linear_terms);
575586
std::vector<mul_quad_<fr>> mul_quads = split_into_mul_quad_gates(arg.value, linear_terms);
576587

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,26 @@ TYPED_TEST(BigQuadOpcodeGateCountTest, OpcodeGateCount)
385385

386386
EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BIG_QUAD<TypeParam> }));
387387
}
388+
389+
TEST(AssertZeroConstraintTest, UnsatisfiableCircuitWithNonZeroConstantOnly)
390+
{
391+
// An AssertZero opcode with no variables and a non-zero constant is fundamentally unsatisfiable:
392+
// it asserts `nonzero_constant == 0` which can never hold.
393+
Acir::Expression expr{ .q_c = bb::fr::one().to_buffer() };
394+
Acir::Opcode::AssertZero assert_zero{ .value = expr };
395+
AcirFormat af;
396+
EXPECT_THROW_WITH_MESSAGE(
397+
assert_zero_to_quad_constraints(assert_zero, af, 0),
398+
"circuit is unsatisfiable. An AssertZero opcode contains no variables but has a non-zero constant");
399+
}
400+
401+
TEST(AssertZeroConstraintTest, SatisfiableCircuitWithZeroConstantOnly)
402+
{
403+
// An AssertZero opcode with no variables and a zero constant is trivially satisfiable (0 == 0),
404+
// but should still be rejected since it produces a zero gate.
405+
Acir::Expression expr{ .q_c = bb::fr::zero().to_buffer() };
406+
Acir::Opcode::AssertZero assert_zero{ .value = expr };
407+
AcirFormat af;
408+
EXPECT_THROW_WITH_MESSAGE(assert_zero_to_quad_constraints(assert_zero, af, 0),
409+
"split_into_mul_quad_gates: resulted in zero gates");
410+
}

0 commit comments

Comments
 (0)