use std::fs;
use std::path::Path;
use colored::Colorize;
use microscope_memory::*;
use microscope_memory::config::Config;
pub fn verify_integrity(config: &Config) {
let reader = crate::open_reader(config);
println!(
"{} {} blocks...",
"VERIFY".cyan().bold(),
reader.block_count
);
let mut checked = 0u64;
let mut skipped = 0u64;
let mut bad = 0u64;
for i in 0..reader.block_count {
let h = reader.header(i);
let stored = u16::from_le_bytes(h.crc16);
if stored == 0x0000 {
skipped += 1;
continue;
}
let start = h.data_offset as usize;
let end = start + h.data_len as usize;
if end > reader.data.len() {
println!(" {} Block {} offset out of bounds", "ERR".red(), i);
bad += 1;
continue;
}
let computed = crc16_ccitt(&reader.data[start..end]);
if computed != stored {
println!(
" {} Block {} D{}: CRC mismatch (stored=0x{:04X}, computed=0x{:04X})",
"FAIL".red().bold(),
i,
h.depth,
stored,
computed
);
bad += 1;
} else {
checked += 1;
}
}
if bad == 0 {
println!(
" {} {} blocks verified, {} skipped (no CRC)",
"OK".green().bold(),
checked,
skipped
);
} else {
println!(
" {} {} corrupted, {} ok, {} skipped",
"FAIL".red().bold(),
bad,
checked,
skipped
);
}
}
pub fn verify_merkle(config: &Config) {
use microscope_memory::merkle;
let output_dir = Path::new(&config.paths.output_dir);
let merkle_path = output_dir.join("merkle.bin");
let meta_path = output_dir.join("meta.bin");
if !merkle_path.exists() {
println!(
" {} merkle.bin not found — rebuild with v0.2.0 to generate",
"ERR".red()
);
return;
}
let meta = fs::read(&meta_path).expect("read meta.bin");
let magic = &meta[0..4];
if magic != b"MSC2" && magic != b"MSC3" {
println!(
" {} meta.bin is v1 (MSCM) — no merkle root stored. Rebuild first.",
"WARN".yellow()
);
return;
}
let meta_root_offset = META_HEADER_SIZE + 9 * DEPTH_ENTRY_SIZE;
let mut stored_root = [0u8; 32];
stored_root.copy_from_slice(&meta[meta_root_offset..meta_root_offset + 32]);
let merkle_data = fs::read(&merkle_path).expect("read merkle.bin");
let stored_tree = merkle::MerkleTree::from_bytes(&merkle_data).expect("parse merkle.bin");
println!(
"{} {} blocks...",
"VERIFY MERKLE".cyan().bold(),
stored_tree.leaf_count
);
println!(" Stored root: {}", hex_str(&stored_root));
println!(" Merkle root: {}", hex_str(&stored_tree.root));
if stored_root != stored_tree.root {
println!(
" {} meta.bin root != merkle.bin root!",
"MISMATCH".red().bold()
);
return;
}
let reader = crate::open_reader(config);
let mut bad_blocks = Vec::new();
for i in 0..reader.block_count {
let h = reader.header(i);
let start = h.data_offset as usize;
let end = start + h.data_len as usize;
if end > reader.data.len() {
bad_blocks.push(i);
continue;
}
let data = &reader.data[start..end];
if !stored_tree.verify_leaf(i, data) {
bad_blocks.push(i);
}
}
if bad_blocks.is_empty() {
println!(
" {} All {} blocks verified against Merkle root",
"OK".green().bold(),
reader.block_count
);
} else {
println!(
" {} {} block(s) failed verification:",
"FAIL".red().bold(),
bad_blocks.len()
);
for &idx in bad_blocks.iter().take(20) {
println!(" Block {}", idx);
}
if bad_blocks.len() > 20 {
println!(" ... and {} more", bad_blocks.len() - 20);
}
}
}
pub fn merkle_proof(config: &Config, block_index: usize) {
use microscope_memory::merkle;
let output_dir = Path::new(&config.paths.output_dir);
let merkle_path = output_dir.join("merkle.bin");
if !merkle_path.exists() {
println!(" {} merkle.bin not found — rebuild first", "ERR".red());
return;
}
let merkle_data = fs::read(&merkle_path).expect("read merkle.bin");
let tree = merkle::MerkleTree::from_bytes(&merkle_data).expect("parse merkle.bin");
if block_index >= tree.leaf_count {
println!(
" {} Block index {} out of range (max: {})",
"ERR".red(),
block_index,
tree.leaf_count - 1
);
return;
}
let reader = crate::open_reader(config);
let h = reader.header(block_index);
let text = reader.text(block_index);
let layer = LAYER_NAMES.get(h.layer_id as usize).unwrap_or(&"?");
println!("{} Block #{}", "MERKLE PROOF".cyan().bold(), block_index);
println!(" D{} [{}] {}", h.depth, layer, safe_truncate(text, 60));
println!(" Leaf hash: {}", hex_str(&tree.nodes[block_index]));
let proof = tree.proof(block_index);
println!(" Proof path ({} steps):", proof.len());
for (i, (hash, is_right)) in proof.iter().enumerate() {
let side = if *is_right { "R" } else { "L" };
println!(" [{}] {} sibling={}", i, side, hex_str(hash));
}
let data_start = h.data_offset as usize;
let data_end = data_start + h.data_len as usize;
let block_data = &reader.data[data_start..data_end];
let valid = merkle::MerkleTree::verify_proof(&tree.root, block_data, &proof);
if valid {
println!(
" {} Proof valid against root {}",
"VERIFIED".green().bold(),
hex_str(&tree.root)
);
} else {
println!(" {} Proof INVALID", "FAIL".red().bold());
}
}