Skip to content
Closed
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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to keep these two boolean checks then we should use an alias for the sub-relation instead of calling check_relation<bitwise>(trace, 3UL) with an integer literal.

{
// 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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that the 3 following tests are really edge cases (we precompute) but we can keep them as "sanity test vectors".

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