use super::{
super::{Trace, NUM_RAND_ROWS},
build_trace_from_ops_with_inputs, rand_array, AdviceInputs, Felt, Operation, Word, ONE, ZERO,
};
use crate::StackInputs;
use alloc::vec::Vec;
use miden_air::trace::{
chiplets::hasher::P1_COL_IDX, main_trace::MainTrace, AUX_TRACE_RAND_ELEMENTS,
};
use vm_core::{
crypto::merkle::{MerkleStore, MerkleTree, NodeIndex},
FieldElement,
};
#[test]
#[allow(clippy::needless_range_loop)]
fn hasher_p1_mp_verify() {
let (tree, _) = build_merkle_tree();
let store = MerkleStore::from(&tree);
let node = tree.get_node(NodeIndex::new(3, 1).unwrap()).unwrap();
let mut init_stack = vec![];
append_word(&mut init_stack, node.into());
init_stack.extend_from_slice(&[3, 1]);
append_word(&mut init_stack, tree.root().into());
init_stack.reverse();
let stack_inputs = StackInputs::try_from_ints(init_stack).unwrap();
let advice_inputs = AdviceInputs::default().with_merkle_store(store);
let ops = vec![Operation::MpVerify];
let mut trace = build_trace_from_ops_with_inputs(ops, stack_inputs, advice_inputs);
let alphas = rand_array::<Felt, AUX_TRACE_RAND_ELEMENTS>();
let aux_columns = trace.build_aux_segment(&[], &alphas).unwrap();
let p1 = aux_columns.get_column(P1_COL_IDX);
for i in 0..(p1.len() - NUM_RAND_ROWS) {
assert_eq!(ONE, p1[i]);
}
}
#[test]
#[allow(clippy::needless_range_loop)]
fn hasher_p1_mr_update() {
let (tree, _) = build_merkle_tree();
let index = 5_u64;
let old_node = tree.get_node(NodeIndex::new(3, index).unwrap()).unwrap();
let new_node = init_leaf(11);
let path = tree.get_path(NodeIndex::new(3, index).unwrap()).unwrap();
let mut init_stack = vec![];
append_word(&mut init_stack, old_node.into());
init_stack.extend_from_slice(&[3, index]);
append_word(&mut init_stack, tree.root().into());
append_word(&mut init_stack, new_node);
init_stack.reverse();
let stack_inputs = StackInputs::try_from_ints(init_stack).unwrap();
let store = MerkleStore::from(&tree);
let advice_inputs = AdviceInputs::default().with_merkle_store(store);
let ops = vec![Operation::MrUpdate];
let mut trace = build_trace_from_ops_with_inputs(ops, stack_inputs, advice_inputs);
let alphas = rand_array::<Felt, AUX_TRACE_RAND_ELEMENTS>();
let aux_columns = trace.build_aux_segment(&[], &alphas).unwrap();
let p1 = aux_columns.get_column(P1_COL_IDX);
let row_values = [
SiblingTableRow::new(Felt::new(index), path[0].into()).to_value(&trace.main_trace, &alphas),
SiblingTableRow::new(Felt::new(index >> 1), path[1].into())
.to_value(&trace.main_trace, &alphas),
SiblingTableRow::new(Felt::new(index >> 2), path[2].into())
.to_value(&trace.main_trace, &alphas),
];
let mut expected_value = ONE;
assert_eq!(expected_value, p1[0]);
for i in 1..8 {
assert_eq!(expected_value, p1[i]);
}
expected_value *= row_values[0];
assert_eq!(expected_value, p1[9]);
for i in 10..17 {
assert_eq!(expected_value, p1[i]);
}
expected_value *= row_values[1];
assert_eq!(expected_value, p1[17]);
for i in 18..25 {
assert_eq!(expected_value, p1[i]);
}
expected_value *= row_values[2];
assert_eq!(expected_value, p1[25]);
for i in 25..33 {
assert_eq!(expected_value, p1[i]);
}
expected_value *= row_values[0].inv();
assert_eq!(expected_value, p1[33]);
for i in 33..41 {
assert_eq!(expected_value, p1[i]);
}
expected_value *= row_values[1].inv();
assert_eq!(expected_value, p1[41]);
for i in 41..49 {
assert_eq!(expected_value, p1[i]);
}
expected_value *= row_values[2].inv();
assert_eq!(expected_value, p1[49]);
assert_eq!(expected_value, ONE);
for i in 50..(p1.len() - NUM_RAND_ROWS) {
assert_eq!(ONE, p1[i]);
}
}
fn build_merkle_tree() -> (MerkleTree, Vec<Word>) {
let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]);
(MerkleTree::new(leaves.clone()).unwrap(), leaves)
}
fn init_leaves(values: &[u64]) -> Vec<Word> {
values.iter().map(|&v| init_leaf(v)).collect()
}
fn init_leaf(value: u64) -> Word {
[Felt::new(value), ZERO, ZERO, ZERO]
}
fn append_word(target: &mut Vec<u64>, word: Word) {
word.iter().rev().for_each(|v| target.push(v.as_int()));
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SiblingTableRow {
index: Felt,
sibling: Word,
}
impl SiblingTableRow {
pub fn new(index: Felt, sibling: Word) -> Self {
Self { index, sibling }
}
pub fn to_value<E: FieldElement<BaseField = Felt>>(
&self,
_main_trace: &MainTrace,
alphas: &[E],
) -> E {
let lsb = self.index.as_int() & 1;
if lsb == 0 {
alphas[0]
+ alphas[3].mul_base(self.index)
+ alphas[12].mul_base(self.sibling[0])
+ alphas[13].mul_base(self.sibling[1])
+ alphas[14].mul_base(self.sibling[2])
+ alphas[15].mul_base(self.sibling[3])
} else {
alphas[0]
+ alphas[3].mul_base(self.index)
+ alphas[8].mul_base(self.sibling[0])
+ alphas[9].mul_base(self.sibling[1])
+ alphas[10].mul_base(self.sibling[2])
+ alphas[11].mul_base(self.sibling[3])
}
}
}