use miden_air::trace::{
Challenges, RowIndex,
chiplets::{
MEMORY_CLK_COL_IDX, MEMORY_CTX_COL_IDX, MEMORY_IDX0_COL_IDX, MEMORY_IDX1_COL_IDX,
MEMORY_IS_READ_COL_IDX, MEMORY_IS_WORD_ACCESS_COL_IDX, MEMORY_V_COL_RANGE,
MEMORY_WORD_COL_IDX,
memory::{
MEMORY_ACCESS_ELEMENT, MEMORY_ACCESS_WORD, MEMORY_READ, MEMORY_READ_ELEMENT_LABEL,
MEMORY_READ_WORD_LABEL, MEMORY_WRITE, MEMORY_WRITE_ELEMENT_LABEL,
MEMORY_WRITE_WORD_LABEL,
},
},
};
use miden_core::{WORD_SIZE, field::Field};
use super::{
AUX_TRACE_RAND_CHALLENGES, CHIPLETS_BUS_AUX_TRACE_OFFSET, ExecutionTrace, Felt, HASH_CYCLE_LEN,
LAST_CYCLE_ROW, ONE, Operation, Word, ZERO, build_trace_from_ops, rand_array,
};
#[test]
#[expect(clippy::needless_range_loop)]
fn b_chip_trace_mem() {
const FOUR: Felt = Felt::new(4);
let stack = [0, 1, 2, 3, 4];
let word = [ONE, Felt::new(2), Felt::new(3), Felt::new(4)];
let operations = vec![
Operation::MStoreW, Operation::Drop, Operation::Drop,
Operation::Drop,
Operation::Drop,
Operation::MLoad, Operation::MovDn5, Operation::MLoadW, Operation::Push(ONE), Operation::Push(FOUR), Operation::MStore, Operation::Drop, Operation::MStream, ];
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_bus_word_msg(
&challenges,
MEMORY_WRITE_WORD_LABEL,
ZERO,
ZERO,
ONE,
word.into(),
);
let mut expected = value.inverse();
assert_eq!(expected, b_chip[2]);
for row in 3..7 {
assert_eq!(expected, b_chip[row]);
}
let value = build_expected_bus_element_msg(
&challenges,
MEMORY_READ_ELEMENT_LABEL,
ZERO,
ZERO,
Felt::new(6),
word[0],
);
expected *= value.inverse();
assert_eq!(expected, b_chip[7]);
let value = build_expected_bus_word_msg(
&challenges,
MEMORY_READ_WORD_LABEL,
ZERO,
ZERO,
Felt::new(8),
word.into(),
);
expected *= value.inverse();
assert_eq!(expected, b_chip[9]);
assert_eq!(expected, b_chip[10]);
let value = build_expected_bus_element_msg(
&challenges,
MEMORY_WRITE_ELEMENT_LABEL,
ZERO,
FOUR,
Felt::new(11),
ONE,
);
expected *= value.inverse();
assert_eq!(expected, b_chip[12]);
assert_eq!(expected, b_chip[13]);
let value1 = build_expected_bus_word_msg(
&challenges,
MEMORY_READ_WORD_LABEL,
ZERO,
ZERO,
Felt::new(13),
word.into(),
);
let value2 = build_expected_bus_word_msg(
&challenges,
MEMORY_READ_WORD_LABEL,
ZERO,
Felt::new(4),
Felt::new(13),
[ONE, ZERO, ZERO, ZERO].into(),
);
expected *= (value1 * value2).inverse();
assert_eq!(expected, b_chip[14]);
assert_ne!(expected, b_chip[15]);
let span_request_mult = b_chip[15] * expected.inverse();
expected = b_chip[15];
for row in 16..HASH_CYCLE_LEN {
assert_eq!(expected, b_chip[row]);
}
let memory_start = HASH_CYCLE_LEN;
assert_ne!(expected, b_chip[memory_start]);
let span_response_mult = b_chip[memory_start] * b_chip[LAST_CYCLE_ROW].inverse();
assert_eq!(span_request_mult * span_response_mult, ONE);
expected *= span_response_mult;
assert_eq!(expected, b_chip[memory_start]);
expected *= build_expected_bus_msg_from_trace(&trace, &challenges, memory_start.into());
assert_eq!(expected, b_chip[memory_start + 1]);
expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 1).into());
assert_eq!(expected, b_chip[memory_start + 2]);
expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 2).into());
assert_eq!(expected, b_chip[memory_start + 3]);
expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 3).into());
assert_eq!(expected, b_chip[memory_start + 4]);
expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 4).into());
assert_eq!(expected, b_chip[memory_start + 5]);
expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 5).into());
assert_eq!(expected, b_chip[memory_start + 6]);
for row in (memory_start + 6)..trace.length() {
assert_eq!(ONE, b_chip[row]);
}
}
#[test]
fn crypto_stream_missing_chiplets_bus_requests() {
let stack = [
1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 8, 0, 0, ];
let trace = build_trace_from_ops(vec![Operation::CryptoStream], &stack);
let rand_challenges = rand_array::<Felt, AUX_TRACE_RAND_CHALLENGES>();
let aux_columns = trace.build_aux_trace(&rand_challenges).unwrap();
let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET);
let challenges = Challenges::<Felt>::new(rand_challenges[0], rand_challenges[1]);
let ctx = ZERO;
let clk = ONE;
let read1 = build_expected_bus_word_msg(
&challenges,
MEMORY_READ_WORD_LABEL,
ctx,
ZERO, clk,
[ZERO, ZERO, ZERO, ZERO].into(),
);
let read2 = build_expected_bus_word_msg(
&challenges,
MEMORY_READ_WORD_LABEL,
ctx,
Felt::new(4), clk,
[ZERO, ZERO, ZERO, ZERO].into(),
);
let write1 = build_expected_bus_word_msg(
&challenges,
MEMORY_WRITE_WORD_LABEL,
ctx,
Felt::new(8), clk,
[ONE, Felt::new(2), Felt::new(3), Felt::new(4)].into(),
);
let write2 = build_expected_bus_word_msg(
&challenges,
MEMORY_WRITE_WORD_LABEL,
ctx,
Felt::new(12), clk,
[Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into(),
);
let combined_request = (read1 * read2 * write1 * write2).inverse();
assert_eq!(ONE, b_chip[0]);
assert_eq!(ONE, b_chip[1]);
assert_eq!(combined_request, b_chip[2]);
assert_eq!(*b_chip.last().unwrap(), ONE);
}
fn build_expected_bus_element_msg(
challenges: &Challenges<Felt>,
op_label: u8,
ctx: Felt,
addr: Felt,
clk: Felt,
value: Felt,
) -> Felt {
assert!(op_label == MEMORY_READ_ELEMENT_LABEL || op_label == MEMORY_WRITE_ELEMENT_LABEL);
challenges.encode([Felt::from_u8(op_label), ctx, addr, clk, value])
}
fn build_expected_bus_word_msg(
challenges: &Challenges<Felt>,
op_label: u8,
ctx: Felt,
addr: Felt,
clk: Felt,
word: Word,
) -> Felt {
assert!(op_label == MEMORY_READ_WORD_LABEL || op_label == MEMORY_WRITE_WORD_LABEL);
challenges.encode([Felt::from_u8(op_label), ctx, addr, clk, word[0], word[1], word[2], word[3]])
}
fn build_expected_bus_msg_from_trace(
trace: &ExecutionTrace,
challenges: &Challenges<Felt>,
row: RowIndex,
) -> Felt {
let read_write = trace.main_trace.get_column(MEMORY_IS_READ_COL_IDX)[row];
let element_or_word = trace.main_trace.get_column(MEMORY_IS_WORD_ACCESS_COL_IDX)[row];
let op_label = if read_write == MEMORY_WRITE {
if element_or_word == MEMORY_ACCESS_ELEMENT {
MEMORY_WRITE_ELEMENT_LABEL
} else {
MEMORY_WRITE_WORD_LABEL
}
} else if read_write == MEMORY_READ {
if element_or_word == MEMORY_ACCESS_ELEMENT {
MEMORY_READ_ELEMENT_LABEL
} else {
MEMORY_READ_WORD_LABEL
}
} else {
panic!("invalid read_write value: {read_write}");
};
let ctx = trace.main_trace.get_column(MEMORY_CTX_COL_IDX)[row];
let addr = {
let word = trace.main_trace.get_column(MEMORY_WORD_COL_IDX)[row];
let idx1 = trace.main_trace.get_column(MEMORY_IDX1_COL_IDX)[row];
let idx0 = trace.main_trace.get_column(MEMORY_IDX0_COL_IDX)[row];
word + idx1.double() + idx0
};
let clk = trace.main_trace.get_column(MEMORY_CLK_COL_IDX)[row];
let mut word = [ZERO; WORD_SIZE];
for (i, element) in word.iter_mut().enumerate() {
*element = trace.main_trace.get_column(MEMORY_V_COL_RANGE.start + i)[row];
}
if element_or_word == MEMORY_ACCESS_ELEMENT {
let idx1 = trace.main_trace.get_column(MEMORY_IDX1_COL_IDX)[row].as_canonical_u64();
let idx0 = trace.main_trace.get_column(MEMORY_IDX0_COL_IDX)[row].as_canonical_u64();
let idx = idx1 * 2 + idx0;
build_expected_bus_element_msg(challenges, op_label, ctx, addr, clk, word[idx as usize])
} else if element_or_word == MEMORY_ACCESS_WORD {
build_expected_bus_word_msg(challenges, op_label, ctx, addr, clk, word.into())
} else {
panic!("invalid element_or_word value: {element_or_word}");
}
}