Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions barretenberg/cpp/pil/vm2/bitwise.pil
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ start * (1 - start) = 0;
pol commit start_keccak;
pol commit start_sha256;
start_keccak * (1 - start_keccak) = 0;
start_sha256 * (1 - start_sha256) = 0;
// If any of the above selectors is 1, then start must be 1.
(start_keccak + start_sha256) * (1 - start) = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -579,5 +579,91 @@ TEST(BitwiseConstrainingTest, ExecBitwiseDispatchOnErrorFF)
check_interaction<ExecutionTraceBuilder, lookup_execution_dispatch_to_bitwise_settings>(trace);
}

// =========================================================================
// Audit-generated edge case tests
// =========================================================================

// Tests that start_sha256 must be boolean (0 or 1).
// This test verifies that the constraint `start_sha256 * (1 - start_sha256) = 0` is enforced.
TEST(BitwiseConstrainingTest, NegativeStartSha256NonBoolean)
{
// Test with start_sha256 = 2 (non-boolean value)
TestTraceContainer trace({
{
{ C::bitwise_start_sha256, 2 }, // Non-boolean value should fail
},
});

// Subrelation 3 is: start_sha256 * (1 - start_sha256) = 0
EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, 3UL), "");
}

// Tests that start_keccak must be boolean
TEST(BitwiseConstrainingTest, NegativeStartKeccakNonBoolean)
{
TestTraceContainer trace({
{
{ C::bitwise_start_keccak, 2 }, // Non-boolean value should fail
},
});

// Subrelation 2 is: start_keccak * (1 - start_keccak) = 0
EXPECT_THROW_WITH_MESSAGE(check_relation<bitwise>(trace, 2UL), "");
}

// Edge case: XOR of identical values should yield 0
TEST(BitwiseConstrainingTest, XorIdenticalValuesYieldsZero)
{
TestTraceContainer trace;
BitwiseTraceBuilder builder;

std::vector<simulation::BitwiseEvent> events = {
{ .operation = BitwiseOperation::XOR,
.a = MemoryValue::from<uint32_t>(0xDEADBEEF),
.b = MemoryValue::from<uint32_t>(0xDEADBEEF),
.res = 0 }, // x XOR x = 0
};

builder.process(events, trace);

check_relation<bitwise>(trace);
}

// Edge case: OR with all 1s should yield all 1s
TEST(BitwiseConstrainingTest, OrWithMaxValue)
{
TestTraceContainer trace;
BitwiseTraceBuilder builder;

std::vector<simulation::BitwiseEvent> events = {
{ .operation = BitwiseOperation::OR,
.a = MemoryValue::from<uint32_t>(0xFFFFFFFF),
.b = MemoryValue::from<uint32_t>(0x12345678),
.res = 0xFFFFFFFF },
};

builder.process(events, trace);

check_relation<bitwise>(trace);
}

// Edge case: AND with 0 should yield 0
TEST(BitwiseConstrainingTest, AndWithZero)
{
TestTraceContainer trace;
BitwiseTraceBuilder builder;

std::vector<simulation::BitwiseEvent> events = {
{ .operation = BitwiseOperation::AND,
.a = MemoryValue::from<uint32_t>(0xDEADBEEF),
.b = MemoryValue::from<uint32_t>(0x00000000),
.res = 0 },
};

builder.process(events, trace);

check_relation<bitwise>(trace);
}

} // namespace
} // namespace bb::avm2::constraining
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ template <typename FF_> class bitwiseImpl {
public:
using FF = FF_;

static constexpr std::array<size_t, 23> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 5,
3, 4, 4, 5, 3, 3, 3, 3, 3, 3, 3 };
static constexpr std::array<size_t, 24> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5,
5, 3, 4, 4, 5, 3, 3, 3, 3, 3, 3, 3 };

template <typename AllEntities> inline static bool skip(const AllEntities& in)
{
Expand All @@ -36,20 +36,20 @@ template <typename FF> class bitwise : public Relation<bitwiseImpl<FF>> {
static constexpr const std::string_view NAME = "bitwise";

// Subrelation indices constants, to be used in tests.
static constexpr size_t SR_LAST_ON_ERROR = 8;
static constexpr size_t SR_RES_TAG_SHOULD_MATCH_INPUT = 9;
static constexpr size_t SR_INPUT_TAG_CANNOT_BE_FF = 10;
static constexpr size_t SR_INPUT_TAGS_SHOULD_MATCH = 11;
static constexpr size_t SR_BITW_OP_ID_REL = 12;
static constexpr size_t SR_BITW_CTR_DECREMENT = 13;
static constexpr size_t SR_BITW_SEL_CTR_NON_ZERO = 14;
static constexpr size_t SR_BITW_LAST_FOR_CTR_ONE = 15;
static constexpr size_t SR_BITW_INIT_A = 16;
static constexpr size_t SR_BITW_INIT_B = 17;
static constexpr size_t SR_BITW_INIT_C = 18;
static constexpr size_t SR_BITW_ACC_REL_A = 19;
static constexpr size_t SR_BITW_ACC_REL_B = 20;
static constexpr size_t SR_BITW_ACC_REL_C = 21;
static constexpr size_t SR_LAST_ON_ERROR = 9;
static constexpr size_t SR_RES_TAG_SHOULD_MATCH_INPUT = 10;
static constexpr size_t SR_INPUT_TAG_CANNOT_BE_FF = 11;
static constexpr size_t SR_INPUT_TAGS_SHOULD_MATCH = 12;
static constexpr size_t SR_BITW_OP_ID_REL = 13;
static constexpr size_t SR_BITW_CTR_DECREMENT = 14;
static constexpr size_t SR_BITW_SEL_CTR_NON_ZERO = 15;
static constexpr size_t SR_BITW_LAST_FOR_CTR_ONE = 16;
static constexpr size_t SR_BITW_INIT_A = 17;
static constexpr size_t SR_BITW_INIT_B = 18;
static constexpr size_t SR_BITW_INIT_C = 19;
static constexpr size_t SR_BITW_ACC_REL_A = 20;
static constexpr size_t SR_BITW_ACC_REL_B = 21;
static constexpr size_t SR_BITW_ACC_REL_C = 22;

static std::string get_subrelation_label(size_t index)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,143 +37,149 @@ void bitwiseImpl<FF_>::accumulate(ContainerOverSubrelations& evals,
}
{
using View = typename std::tuple_element_t<3, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_start_sha256)) *
(FF(1) - static_cast<View>(in.get(C::bitwise_start_sha256)));
std::get<3>(evals) += (tmp * scaling_factor);
}
{
using View = typename std::tuple_element_t<4, ContainerOverSubrelations>::View;
auto tmp =
(static_cast<View>(in.get(C::bitwise_start_keccak)) + static_cast<View>(in.get(C::bitwise_start_sha256))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_start)));
std::get<3>(evals) += (tmp * scaling_factor);
std::get<4>(evals) += (tmp * scaling_factor);
}
{
using View = typename std::tuple_element_t<4, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<5, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_sel_tag_ff_err)) *
(FF(1) - static_cast<View>(in.get(C::bitwise_sel_tag_ff_err)));
std::get<4>(evals) += (tmp * scaling_factor);
std::get<5>(evals) += (tmp * scaling_factor);
}
{
using View = typename std::tuple_element_t<5, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<6, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_sel_tag_mismatch_err)) *
(FF(1) - static_cast<View>(in.get(C::bitwise_sel_tag_mismatch_err)));
std::get<5>(evals) += (tmp * scaling_factor);
std::get<6>(evals) += (tmp * scaling_factor);
}
{
using View = typename std::tuple_element_t<6, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<7, ContainerOverSubrelations>::View;
auto tmp = (static_cast<View>(in.get(C::bitwise_err)) -
(FF(1) - (FF(1) - static_cast<View>(in.get(C::bitwise_sel_tag_mismatch_err))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_sel_tag_ff_err)))));
std::get<6>(evals) += (tmp * scaling_factor);
std::get<7>(evals) += (tmp * scaling_factor);
}
{
using View = typename std::tuple_element_t<7, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<8, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_last)) * (FF(1) - static_cast<View>(in.get(C::bitwise_last)));
std::get<7>(evals) += (tmp * scaling_factor);
std::get<8>(evals) += (tmp * scaling_factor);
}
{ // LAST_ON_ERROR
using View = typename std::tuple_element_t<8, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<9, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_err)) * (static_cast<View>(in.get(C::bitwise_last)) - FF(1));
std::get<8>(evals) += (tmp * scaling_factor);
std::get<9>(evals) += (tmp * scaling_factor);
}
{ // RES_TAG_SHOULD_MATCH_INPUT
using View = typename std::tuple_element_t<9, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<10, ContainerOverSubrelations>::View;
auto tmp = (FF(1) - static_cast<View>(in.get(C::bitwise_err))) * static_cast<View>(in.get(C::bitwise_start)) *
(static_cast<View>(in.get(C::bitwise_tag_c)) - static_cast<View>(in.get(C::bitwise_tag_a)));
std::get<9>(evals) += (tmp * scaling_factor);
std::get<10>(evals) += (tmp * scaling_factor);
}
{ // INPUT_TAG_CANNOT_BE_FF
using View = typename std::tuple_element_t<10, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<11, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_start)) *
((CView(bitwise_TAG_A_DIFF) * (static_cast<View>(in.get(C::bitwise_sel_tag_ff_err)) *
(FF(1) - static_cast<View>(in.get(C::bitwise_tag_a_inv))) +
static_cast<View>(in.get(C::bitwise_tag_a_inv))) -
FF(1)) +
static_cast<View>(in.get(C::bitwise_sel_tag_ff_err)));
std::get<10>(evals) += (tmp * scaling_factor);
std::get<11>(evals) += (tmp * scaling_factor);
}
{ // INPUT_TAGS_SHOULD_MATCH
using View = typename std::tuple_element_t<11, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<12, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_start)) *
(CView(bitwise_TAG_AB_DIFF) * ((FF(1) - static_cast<View>(in.get(C::bitwise_sel_tag_mismatch_err))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_tag_ab_diff_inv))) +
static_cast<View>(in.get(C::bitwise_tag_ab_diff_inv))) -
static_cast<View>(in.get(C::bitwise_sel_tag_mismatch_err)));
std::get<11>(evals) += (tmp * scaling_factor);
std::get<12>(evals) += (tmp * scaling_factor);
}
{ // BITW_OP_ID_REL
using View = typename std::tuple_element_t<12, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<13, ContainerOverSubrelations>::View;
auto tmp = (static_cast<View>(in.get(C::bitwise_op_id_shift)) - static_cast<View>(in.get(C::bitwise_op_id))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_last)));
std::get<12>(evals) += (tmp * scaling_factor);
std::get<13>(evals) += (tmp * scaling_factor);
}
{ // BITW_CTR_DECREMENT
using View = typename std::tuple_element_t<13, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<14, ContainerOverSubrelations>::View;
auto tmp =
static_cast<View>(in.get(C::bitwise_sel)) *
((static_cast<View>(in.get(C::bitwise_ctr_shift)) - static_cast<View>(in.get(C::bitwise_ctr))) + FF(1)) *
(FF(1) - static_cast<View>(in.get(C::bitwise_last)));
std::get<13>(evals) += (tmp * scaling_factor);
std::get<14>(evals) += (tmp * scaling_factor);
}
{ // BITW_SEL_CTR_NON_ZERO
using View = typename std::tuple_element_t<14, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<15, ContainerOverSubrelations>::View;
auto tmp =
(static_cast<View>(in.get(C::bitwise_ctr)) * ((FF(1) - static_cast<View>(in.get(C::bitwise_sel))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_ctr_inv))) +
static_cast<View>(in.get(C::bitwise_ctr_inv))) -
static_cast<View>(in.get(C::bitwise_sel)));
std::get<14>(evals) += (tmp * scaling_factor);
std::get<15>(evals) += (tmp * scaling_factor);
}
{ // BITW_LAST_FOR_CTR_ONE
using View = typename std::tuple_element_t<15, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<16, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_sel)) *
(((static_cast<View>(in.get(C::bitwise_ctr)) - FF(1)) *
(static_cast<View>(in.get(C::bitwise_last)) *
(FF(1) - static_cast<View>(in.get(C::bitwise_ctr_min_one_inv))) +
static_cast<View>(in.get(C::bitwise_ctr_min_one_inv))) +
static_cast<View>(in.get(C::bitwise_last))) -
FF(1));
std::get<15>(evals) += (tmp * scaling_factor);
std::get<16>(evals) += (tmp * scaling_factor);
}
{ // BITW_INIT_A
using View = typename std::tuple_element_t<16, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<17, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_last)) *
(static_cast<View>(in.get(C::bitwise_acc_ia)) - static_cast<View>(in.get(C::bitwise_ia_byte)));
std::get<16>(evals) += (tmp * scaling_factor);
std::get<17>(evals) += (tmp * scaling_factor);
}
{ // BITW_INIT_B
using View = typename std::tuple_element_t<17, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<18, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_last)) *
(static_cast<View>(in.get(C::bitwise_acc_ib)) - static_cast<View>(in.get(C::bitwise_ib_byte)));
std::get<17>(evals) += (tmp * scaling_factor);
std::get<18>(evals) += (tmp * scaling_factor);
}
{ // BITW_INIT_C
using View = typename std::tuple_element_t<18, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<19, ContainerOverSubrelations>::View;
auto tmp = static_cast<View>(in.get(C::bitwise_last)) *
(static_cast<View>(in.get(C::bitwise_acc_ic)) - static_cast<View>(in.get(C::bitwise_ic_byte)));
std::get<18>(evals) += (tmp * scaling_factor);
std::get<19>(evals) += (tmp * scaling_factor);
}
{ // BITW_ACC_REL_A
using View = typename std::tuple_element_t<19, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<20, ContainerOverSubrelations>::View;
auto tmp = ((static_cast<View>(in.get(C::bitwise_acc_ia)) - static_cast<View>(in.get(C::bitwise_ia_byte))) -
FF(256) * static_cast<View>(in.get(C::bitwise_acc_ia_shift))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_last)));
std::get<19>(evals) += (tmp * scaling_factor);
std::get<20>(evals) += (tmp * scaling_factor);
}
{ // BITW_ACC_REL_B
using View = typename std::tuple_element_t<20, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<21, ContainerOverSubrelations>::View;
auto tmp = ((static_cast<View>(in.get(C::bitwise_acc_ib)) - static_cast<View>(in.get(C::bitwise_ib_byte))) -
FF(256) * static_cast<View>(in.get(C::bitwise_acc_ib_shift))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_last)));
std::get<20>(evals) += (tmp * scaling_factor);
std::get<21>(evals) += (tmp * scaling_factor);
}
{ // BITW_ACC_REL_C
using View = typename std::tuple_element_t<21, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<22, ContainerOverSubrelations>::View;
auto tmp = ((static_cast<View>(in.get(C::bitwise_acc_ic)) - static_cast<View>(in.get(C::bitwise_ic_byte))) -
FF(256) * static_cast<View>(in.get(C::bitwise_acc_ic_shift))) *
(FF(1) - static_cast<View>(in.get(C::bitwise_last)));
std::get<21>(evals) += (tmp * scaling_factor);
std::get<22>(evals) += (tmp * scaling_factor);
}
{
using View = typename std::tuple_element_t<22, ContainerOverSubrelations>::View;
using View = typename std::tuple_element_t<23, ContainerOverSubrelations>::View;
auto tmp = (static_cast<View>(in.get(C::bitwise_sel_get_ctr)) -
static_cast<View>(in.get(C::bitwise_start)) * (FF(1) - static_cast<View>(in.get(C::bitwise_err))));
std::get<22>(evals) += (tmp * scaling_factor);
std::get<23>(evals) += (tmp * scaling_factor);
}
}

Expand Down
Loading