use super::{
build_trace_from_ops, rand_array, rand_value, ExecutionTrace, Felt, FieldElement, Operation,
Trace, AUX_TRACE_RAND_ELEMENTS, CHIPLETS_AUX_TRACE_OFFSET, HASH_CYCLE_LEN, NUM_RAND_ROWS, ONE,
};
use vm_core::chiplets::{
bitwise::{BITWISE_AND, BITWISE_AND_LABEL, BITWISE_XOR, BITWISE_XOR_LABEL, OP_CYCLE_LEN},
BITWISE_A_COL_IDX, BITWISE_B_COL_IDX, BITWISE_OUTPUT_COL_IDX, BITWISE_TRACE_OFFSET,
};
#[test]
#[allow(clippy::needless_range_loop)]
fn b_aux_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(a)),
Operation::Push(Felt::from(b)),
Operation::U32and,
Operation::Pad,
Operation::Pad,
Operation::Pad,
Operation::Pad,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Push(Felt::from(a)),
Operation::Push(Felt::from(b)),
Operation::U32xor,
Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::Drop,
];
let mut trace = build_trace_from_ops(operations, &stack);
let rand_elements = rand_array::<Felt, AUX_TRACE_RAND_ELEMENTS>();
let aux_columns = trace.build_aux_segment(&[], &rand_elements).unwrap();
let b_aux = aux_columns.get_column(CHIPLETS_AUX_TRACE_OFFSET);
assert_eq!(trace.length(), b_aux.len());
assert_eq!(ONE, b_aux[0]);
assert_eq!(ONE, b_aux[1]);
let value = build_expected_bitwise(
&rand_elements,
BITWISE_AND_LABEL,
Felt::from(a),
Felt::from(b),
Felt::from(a & b),
);
let mut expected = value.inv();
assert_eq!(expected, b_aux[2]);
for row in 3..5 {
assert_eq!(expected, b_aux[row]);
}
let value = build_expected_bitwise(
&rand_elements,
BITWISE_AND_LABEL,
Felt::from(a),
Felt::from(b),
Felt::from(a & b),
);
expected *= value.inv();
assert_eq!(expected, b_aux[5]);
for row in 6..8 {
assert_eq!(expected, b_aux[row]);
}
assert_ne!(expected, b_aux[8]);
let span_result = b_aux[8] * b_aux[7].inv();
expected = b_aux[8];
for row in 9..16 {
assert_eq!(expected, b_aux[row]);
}
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;
let value = build_expected_bitwise(
&rand_elements,
BITWISE_XOR_LABEL,
Felt::from(a),
Felt::from(b),
Felt::from(a ^ b),
);
expected *= value.inv();
expected *= build_expected_bitwise_from_trace(&trace, &rand_elements, response_1_row - 1);
assert_eq!(expected, b_aux[response_1_row]);
for row in response_1_row..21 {
assert_eq!(expected, b_aux[row]);
}
assert_ne!(expected, b_aux[22]);
expected *= span_result.inv();
assert_eq!(expected, b_aux[22]);
for row in 23..response_2_row {
assert_eq!(expected, b_aux[row]);
}
expected *= build_expected_bitwise_from_trace(&trace, &rand_elements, response_2_row - 1);
assert_eq!(expected, b_aux[response_2_row]);
for row in response_2_row..response_3_row {
assert_eq!(expected, b_aux[row]);
}
expected *= build_expected_bitwise_from_trace(&trace, &rand_elements, response_3_row - 1);
assert_eq!(expected, b_aux[response_3_row]);
for row in response_3_row..trace.length() - NUM_RAND_ROWS {
assert_eq!(ONE, b_aux[row]);
}
}
fn build_expected_bitwise(alphas: &[Felt], label: Felt, a: Felt, b: Felt, result: Felt) -> Felt {
alphas[0] + alphas[1] * label + alphas[2] * a + alphas[3] * b + alphas[4] * result
}
fn build_expected_bitwise_from_trace(trace: &ExecutionTrace, alphas: &[Felt], row: usize) -> 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(alphas, op_id, a, b, output)
}