use miden_air::trace::{
Challenges, RowIndex,
chiplets::{
BITWISE_A_COL_IDX, BITWISE_B_COL_IDX, BITWISE_OUTPUT_COL_IDX, BITWISE_TRACE_OFFSET,
bitwise::{BITWISE_AND, BITWISE_AND_LABEL, BITWISE_XOR, BITWISE_XOR_LABEL, OP_CYCLE_LEN},
},
};
use miden_core::field::Field;
use super::{
AUX_TRACE_RAND_CHALLENGES, CHIPLETS_BUS_AUX_TRACE_OFFSET, ExecutionTrace, Felt, HASH_CYCLE_LEN,
LAST_CYCLE_ROW, ONE, Operation, build_trace_from_ops, rand_array, rand_value,
};
#[test]
#[expect(clippy::needless_range_loop)]
fn b_chip_trace_bitwise() {
let a = rand_value::<u32>();
let b = rand_value::<u32>();
let stack = [a as u64, b as u64];
let operations = vec![
Operation::U32and,
Operation::Push(Felt::from_u32(a)),
Operation::Push(Felt::from_u32(b)),
Operation::U32and,
Operation::Pad,
Operation::Pad,
Operation::Pad,
Operation::Pad,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Push(Felt::from_u32(a)),
Operation::Push(Felt::from_u32(b)),
Operation::U32xor,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
];
let trace = build_trace_from_ops(operations, &stack);
let challenges = rand_array::<Felt, AUX_TRACE_RAND_CHALLENGES>();
let aux_columns = trace.build_aux_trace(&challenges).unwrap();
let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET);
let challenges = Challenges::<Felt>::new(challenges[0], challenges[1]);
assert_eq!(trace.length(), b_chip.len());
assert_eq!(ONE, b_chip[0]);
assert_eq!(ONE, b_chip[1]);
let value = build_expected_bitwise(
&challenges,
BITWISE_AND_LABEL,
Felt::from_u32(a),
Felt::from_u32(b),
Felt::from_u32(a & b),
);
let mut expected = value.inverse();
assert_eq!(expected, b_chip[2]);
for row in 3..5 {
assert_eq!(expected, b_chip[row]);
}
let value = build_expected_bitwise(
&challenges,
BITWISE_AND_LABEL,
Felt::from_u32(b),
Felt::from_u32(a),
Felt::from_u32(a & b),
);
expected *= value.inverse();
assert_eq!(expected, b_chip[5]);
for row in 6..16 {
assert_eq!(expected, b_chip[row]);
}
let value = build_expected_bitwise(
&challenges,
BITWISE_XOR_LABEL,
Felt::from_u32(b),
Felt::from_u32(a),
Felt::from_u32(a ^ b),
);
expected *= value.inverse();
assert_eq!(expected, b_chip[16]);
for row in 17..22 {
assert_eq!(expected, b_chip[row]);
}
assert_ne!(expected, b_chip[22]);
let span_request_mult = b_chip[22] * b_chip[21].inverse();
expected *= span_request_mult;
assert_eq!(expected, b_chip[22]);
for row in 23..HASH_CYCLE_LEN {
assert_eq!(expected, b_chip[row]);
}
assert_ne!(expected, b_chip[HASH_CYCLE_LEN]);
let span_response_mult = b_chip[HASH_CYCLE_LEN] * b_chip[LAST_CYCLE_ROW].inverse();
assert_eq!(span_request_mult * span_response_mult, ONE);
expected *= span_response_mult;
assert_eq!(expected, b_chip[HASH_CYCLE_LEN]);
let response_1_row = HASH_CYCLE_LEN + OP_CYCLE_LEN;
let response_2_row = response_1_row + OP_CYCLE_LEN;
let response_3_row = response_2_row + OP_CYCLE_LEN;
for row in (HASH_CYCLE_LEN + 1)..response_1_row {
assert_eq!(expected, b_chip[row]);
}
expected *= build_expected_bitwise_from_trace(&trace, &challenges, (response_1_row - 1).into());
assert_eq!(expected, b_chip[response_1_row]);
for row in (response_1_row + 1)..response_2_row {
assert_eq!(expected, b_chip[row]);
}
expected *= build_expected_bitwise_from_trace(&trace, &challenges, (response_2_row - 1).into());
assert_eq!(expected, b_chip[response_2_row]);
for row in (response_2_row + 1)..response_3_row {
assert_eq!(expected, b_chip[row]);
}
expected *= build_expected_bitwise_from_trace(&trace, &challenges, (response_3_row - 1).into());
assert_eq!(expected, b_chip[response_3_row]);
for row in response_3_row..trace.length() {
assert_eq!(ONE, b_chip[row]);
}
}
fn build_expected_bitwise(
challenges: &Challenges<Felt>,
label: Felt,
s0: Felt,
s1: Felt,
result: Felt,
) -> Felt {
challenges.encode([label, s0, s1, result])
}
fn build_expected_bitwise_from_trace(
trace: &ExecutionTrace,
challenges: &Challenges<Felt>,
row: RowIndex,
) -> Felt {
let selector = trace.main_trace.get_column(BITWISE_TRACE_OFFSET)[row];
let op_id = if selector == BITWISE_AND {
BITWISE_AND_LABEL
} else if selector == BITWISE_XOR {
BITWISE_XOR_LABEL
} else {
panic!("Execution trace contains an invalid bitwise operation.")
};
let a = trace.main_trace.get_column(BITWISE_A_COL_IDX)[row];
let b = trace.main_trace.get_column(BITWISE_B_COL_IDX)[row];
let output = trace.main_trace.get_column(BITWISE_OUTPUT_COL_IDX)[row];
build_expected_bitwise(challenges, op_id, a, b, output)
}