use alloc::vec;
use miden_protocol::Word;
use crate::{DecodeMessage, Verify, proto};
#[test]
fn merkle_path_verifies() {
let decoded = proto::primitives::MerklePath { siblings: vec![Word::empty().into()] }
.decode_fields()
.unwrap();
assert_eq!(decoded.verify().unwrap().nodes(), &[Word::empty()]);
}
#[test]
fn sparse_path_defers_depth_validation() {
let decoded = proto::primitives::SparseMerklePath {
empty_nodes_mask: 0,
siblings: vec![Word::empty().into(); 65],
}
.decode_fields()
.unwrap();
assert!(decoded.verify().is_err());
}
#[test]
fn mmr_delta_verifies_forest_size_after_decoding() {
let decoded = proto::primitives::MmrDelta {
forest: 3,
update_data: vec![Word::empty().into()],
}
.decode_fields()
.unwrap();
let delta = decoded.verify().unwrap();
assert_eq!(delta.forest.num_leaves(), 3);
assert_eq!(delta.data, vec![Word::empty()]);
let invalid = proto::primitives::MmrDelta { forest: u64::MAX, update_data: vec![] }
.decode_fields()
.unwrap();
assert!(invalid.verify().is_err());
}
#[test]
fn tracked_mmr_leaf_verifies() {
let decoded = proto::primitives::TrackedMmrLeaf {
position: 2,
leaf: Some(Word::empty().into()),
path: vec![],
}
.decode_fields()
.unwrap();
assert_eq!(decoded.verify().unwrap(), (2, Word::empty(), vec![]));
}
#[test]
fn partial_mmr_rejects_invalid_forest() {
use assert_matches::assert_matches;
use miden_protocol::crypto::merkle::mmr::Forest;
use miden_protocol::utils::serde::DeserializationError;
let error = proto::primitives::PartialMmr {
forest: (Forest::MAX_LEAVES as u64) + 1,
..Default::default()
}
.decode_fields()
.unwrap()
.verify()
.unwrap_err();
assert_matches!(
crate::test_utils::error_source::<DeserializationError>(&error),
Some(DeserializationError::InvalidValue(_))
);
}
#[test]
fn partial_mmr_rejects_wrong_peak_count() {
use assert_matches::assert_matches;
use miden_protocol::crypto::merkle::mmr::MmrError;
for (forest, peak_count) in [(0, 1), (3, 1), (1, 2)] {
let error = proto::primitives::PartialMmr {
forest,
peaks: vec![Word::empty().into(); peak_count],
tracked_leaves: vec![],
}
.decode_fields()
.unwrap()
.verify()
.unwrap_err();
assert_matches!(
crate::test_utils::error_source::<MmrError>(&error),
Some(MmrError::InvalidPeaks(_))
);
}
}
fn tracked_partial_mmr() -> proto::primitives::PartialMmr {
let mut mmr = miden_protocol::crypto::merkle::mmr::PartialMmr::default();
for index in 0..7u32 {
mmr.add(crate::test_utils::dummy_word(index), true).unwrap();
}
mmr.into()
}
#[test]
fn partial_mmr_rejects_out_of_range_position() {
use assert_matches::assert_matches;
use crate::decoded::primitives::PartialMmrError;
let mut message = tracked_partial_mmr();
message.tracked_leaves[6].position = message.forest;
let error = message.decode_fields().unwrap().verify().unwrap_err();
assert_matches!(
crate::test_utils::error_source::<PartialMmrError>(&error),
Some(PartialMmrError::Position { position: 7, size: 7 })
);
}
#[test]
fn partial_mmr_rejects_duplicate_or_unordered_leaves() {
use assert_matches::assert_matches;
use crate::decoded::primitives::PartialMmrError;
for duplicate in [false, true] {
let mut message = tracked_partial_mmr();
if duplicate {
message.tracked_leaves[1] = message.tracked_leaves[0].clone();
} else {
message.tracked_leaves.swap(0, 1);
}
let error = message.decode_fields().unwrap().verify().unwrap_err();
assert_matches!(
crate::test_utils::error_source::<PartialMmrError>(&error),
Some(PartialMmrError::LeafOrder)
);
}
}
#[test]
fn partial_mmr_rejects_invalid_inclusion_proof() {
use assert_matches::assert_matches;
use miden_protocol::crypto::merkle::mmr::MmrError;
for corrupt_leaf in [false, true] {
let mut message = tracked_partial_mmr();
let tracked = &mut message.tracked_leaves[0];
let wrong_word = crate::test_utils::dummy_word(42).into();
if corrupt_leaf {
tracked.leaf = Some(wrong_word);
} else {
tracked.path[0] = wrong_word;
}
let error = message.decode_fields().unwrap().verify().unwrap_err();
assert_matches!(
crate::test_utils::error_source::<MmrError>(&error),
Some(MmrError::PeakPathMismatch)
);
}
}
#[test]
fn partial_mmr_rejects_path_depth_for_another_peak() {
use assert_matches::assert_matches;
use miden_protocol::crypto::merkle::mmr::MmrError;
for path_depth in [0, 3] {
let mut message = tracked_partial_mmr();
message.tracked_leaves[0].path = vec![Word::empty().into(); path_depth];
let error = message.decode_fields().unwrap().verify().unwrap_err();
let source = crate::test_utils::error_source::<MmrError>(&error);
if path_depth == 0 {
assert_matches!(source, Some(MmrError::PositionNotFound(0)));
} else {
assert_matches!(source, Some(MmrError::UnknownPeak(3)));
}
}
}