Skip to main content

ipfrs_network/
merkle_proof_verifier.rs

1//! Merkle inclusion proof verifier for content-addressed data.
2//!
3//! Supports multiple hash algorithms and proof formats, providing production-grade
4//! verification for IPFS/IPFRS content addressing.
5
6// ─── Pure-Rust SHA-256 ────────────────────────────────────────────────────────
7
8/// First 64 fractional bits of the cube roots of the first 64 primes.
9#[rustfmt::skip]
10const K: [u32; 64] = [
11    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
12    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
13    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
14    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
15    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
16    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
17    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
18    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
19    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
20    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
21    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
22    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
23    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
24    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
25    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
26    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
27];
28
29/// SHA-256 initial hash values (first 32 bits of fractional parts of sqrt of first 8 primes).
30const H0: [u32; 8] = [
31    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
32];
33
34/// Compute SHA-256 of `data`, returning a 32-byte digest.
35/// This is a self-contained pure-Rust implementation — no external crate used.
36pub fn sha256(data: &[u8]) -> [u8; 32] {
37    // ── Pre-processing: padding ───────────────────────────────────────────────
38    let bit_len = (data.len() as u64).wrapping_mul(8);
39    let mut msg = data.to_vec();
40    msg.push(0x80);
41    // Pad to 56 mod 64 bytes (leaving 8 bytes for length).
42    while msg.len() % 64 != 56 {
43        msg.push(0x00);
44    }
45    // Append big-endian 64-bit bit length.
46    msg.extend_from_slice(&bit_len.to_be_bytes());
47
48    // ── Processing: 512-bit (64-byte) chunks ─────────────────────────────────
49    let mut h = H0;
50    for chunk in msg.chunks(64) {
51        // Build message schedule W[0..64].
52        let mut w = [0u32; 64];
53        for (i, word) in w.iter_mut().enumerate().take(16) {
54            let b = &chunk[i * 4..i * 4 + 4];
55            *word = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
56        }
57        for i in 16..64 {
58            let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
59            let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
60            w[i] = w[i - 16]
61                .wrapping_add(s0)
62                .wrapping_add(w[i - 7])
63                .wrapping_add(s1);
64        }
65
66        // ── 64-round compression ──────────────────────────────────────────────
67        let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = h;
68        for i in 0..64 {
69            let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
70            let ch = (e & f) ^ ((!e) & g);
71            let temp1 = hh
72                .wrapping_add(s1)
73                .wrapping_add(ch)
74                .wrapping_add(K[i])
75                .wrapping_add(w[i]);
76            let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
77            let maj = (a & b) ^ (a & c) ^ (b & c);
78            let temp2 = s0.wrapping_add(maj);
79
80            hh = g;
81            g = f;
82            f = e;
83            e = d.wrapping_add(temp1);
84            d = c;
85            c = b;
86            b = a;
87            a = temp1.wrapping_add(temp2);
88        }
89
90        h[0] = h[0].wrapping_add(a);
91        h[1] = h[1].wrapping_add(b);
92        h[2] = h[2].wrapping_add(c);
93        h[3] = h[3].wrapping_add(d);
94        h[4] = h[4].wrapping_add(e);
95        h[5] = h[5].wrapping_add(f);
96        h[6] = h[6].wrapping_add(g);
97        h[7] = h[7].wrapping_add(hh);
98    }
99
100    // ── Produce final digest ──────────────────────────────────────────────────
101    let mut out = [0u8; 32];
102    for (i, &word) in h.iter().enumerate() {
103        out[i * 4..i * 4 + 4].copy_from_slice(&word.to_be_bytes());
104    }
105    out
106}
107
108/// FNV-1a 64-bit hash of `data`.
109fn fnv1a_64(data: &[u8]) -> u64 {
110    const FNV_OFFSET: u64 = 14_695_981_039_346_656_037;
111    const FNV_PRIME: u64 = 1_099_511_628_211;
112    let mut hash = FNV_OFFSET;
113    for &byte in data {
114        hash ^= byte as u64;
115        hash = hash.wrapping_mul(FNV_PRIME);
116    }
117    hash
118}
119
120// ─── Hash algorithm enum ─────────────────────────────────────────────────────
121
122/// Supported hashing algorithms for Merkle tree construction.
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
124pub enum MerkleHashAlgo {
125    /// Standard SHA-256 (pure Rust, no external crate).
126    Sha256,
127    /// Approximated Blake3: SHA-256 XOR'd with `[0xb3; 32]`.
128    Blake3,
129    /// FNV-1a 64-bit XOR approximation: first 8 bytes are the FNV-1a hash, rest zero,
130    /// then XOR'd with the reversed FNV-1a hash of the input.
131    FnvXor,
132}
133
134// ─── Core types ─────────────────────────────────────────────────────────────
135
136/// A node in a Merkle tree.
137#[derive(Debug, Clone, PartialEq, Eq)]
138pub struct MerkleNode {
139    /// The hash stored at this node.
140    pub hash: [u8; 32],
141    /// Left child, if any.
142    pub left: Option<Box<MerkleNode>>,
143    /// Right child, if any.
144    pub right: Option<Box<MerkleNode>>,
145}
146
147impl MerkleNode {
148    /// Create a leaf node (no children).
149    pub fn leaf(hash: [u8; 32]) -> Self {
150        Self {
151            hash,
152            left: None,
153            right: None,
154        }
155    }
156
157    /// Create an internal node from two children.
158    pub fn internal(hash: [u8; 32], left: MerkleNode, right: MerkleNode) -> Self {
159        Self {
160            hash,
161            left: Some(Box::new(left)),
162            right: Some(Box::new(right)),
163        }
164    }
165}
166
167/// A single step in a Merkle inclusion proof.
168///
169/// Each step supplies the sibling hash and indicates on which side the sibling sits:
170/// - `Left(h)` means the sibling is the *left* child → `hash_pair(h, current)`.
171/// - `Right(h)` means the sibling is the *right* child → `hash_pair(current, h)`.
172#[derive(Debug, Clone, PartialEq, Eq)]
173pub enum ProofStep {
174    /// The sibling is on the left.
175    Left([u8; 32]),
176    /// The sibling is on the right.
177    Right([u8; 32]),
178}
179
180/// A complete Merkle inclusion proof.
181#[derive(Debug, Clone, PartialEq, Eq)]
182pub struct MerkleProof {
183    /// Hash of the leaf being proved.
184    pub leaf_hash: [u8; 32],
185    /// Ordered list of proof steps from leaf to root.
186    pub steps: Vec<ProofStep>,
187    /// Expected root hash.
188    pub root_hash: [u8; 32],
189    /// Hash algorithm used to build the tree.
190    pub algo: MerkleHashAlgo,
191}
192
193/// Result of verifying a single `MerkleProof`.
194#[derive(Debug, Clone, PartialEq, Eq)]
195pub struct VerificationResult {
196    /// Whether the proof is valid.
197    pub valid: bool,
198    /// The root hash computed from the proof steps.
199    pub computed_root: [u8; 32],
200    /// The expected root from the proof.
201    pub expected_root: [u8; 32],
202    /// Number of proof steps successfully processed.
203    pub steps_verified: usize,
204}
205
206impl VerificationResult {
207    /// Returns `true` if the proof verified successfully.
208    #[inline]
209    pub fn is_valid(&self) -> bool {
210        self.valid
211    }
212}
213
214/// An in-memory Merkle tree.
215#[derive(Debug, Clone)]
216pub struct MerkleTree {
217    /// Original leaf hashes (after padding to next power-of-2).
218    pub leaves: Vec<[u8; 32]>,
219    /// All nodes stored level-order: leaves first, then their parents, … up to the root.
220    /// Index layout (0-based, leaves are at indices `[leaves.len()-1 .. 2*leaves.len()-2]`
221    /// in the canonical 1-indexed scheme; here we store them in a flat vec produced by
222    /// level-order traversal where index 0 is the root).
223    pub nodes: Vec<[u8; 32]>,
224    /// Hash algorithm used.
225    pub algo: MerkleHashAlgo,
226    /// Tree depth (0 = single leaf/root).
227    pub depth: usize,
228}
229
230// ─── Verifier ────────────────────────────────────────────────────────────────
231
232/// Production-grade Merkle inclusion proof verifier.
233///
234/// Supports multiple hash algorithms and maintains cumulative statistics.
235#[derive(Debug, Clone)]
236pub struct MerkleProofVerifier {
237    /// Hash algorithm to use for leaf and pair hashing.
238    pub algo: MerkleHashAlgo,
239    /// Total verifications performed (both valid and invalid).
240    pub verifications_done: u64,
241    /// Total failed (invalid) verifications.
242    pub failures: u64,
243}
244
245impl MerkleProofVerifier {
246    /// Create a new verifier using the specified algorithm.
247    pub fn new(algo: MerkleHashAlgo) -> Self {
248        Self {
249            algo,
250            verifications_done: 0,
251            failures: 0,
252        }
253    }
254
255    // ── Hashing primitives ────────────────────────────────────────────────────
256
257    /// Hash a single leaf's raw data bytes.
258    ///
259    /// - `Sha256`: standard SHA-256.
260    /// - `Blake3`: SHA-256 XOR `[0xb3; 32]`.
261    /// - `FnvXor`: FNV-1a 64-bit stored in first 8 bytes (big-endian), rest zero,
262    ///   then XOR with the reversed FNV-1a of the input (same 8-byte layout).
263    pub fn hash_leaf(&self, data: &[u8]) -> [u8; 32] {
264        Self::hash_leaf_with_algo(data, self.algo)
265    }
266
267    fn hash_leaf_with_algo(data: &[u8], algo: MerkleHashAlgo) -> [u8; 32] {
268        match algo {
269            MerkleHashAlgo::Sha256 => sha256(data),
270            MerkleHashAlgo::Blake3 => {
271                let mut digest = sha256(data);
272                for byte in digest.iter_mut() {
273                    *byte ^= 0xb3;
274                }
275                digest
276            }
277            MerkleHashAlgo::FnvXor => {
278                let fwd = fnv1a_64(data);
279                let rev = fnv1a_64(&data.iter().copied().rev().collect::<Vec<u8>>());
280                let mut out = [0u8; 32];
281                out[..8].copy_from_slice(&fwd.to_be_bytes());
282                // XOR the first 8 bytes with the reversed hash.
283                let rev_bytes = rev.to_be_bytes();
284                for i in 0..8 {
285                    out[i] ^= rev_bytes[i];
286                }
287                out
288            }
289        }
290    }
291
292    /// Hash a concatenated pair of child hashes (left ++ right = 64 bytes).
293    pub fn hash_pair(&self, left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
294        Self::hash_pair_with_algo(left, right, self.algo)
295    }
296
297    fn hash_pair_with_algo(left: &[u8; 32], right: &[u8; 32], algo: MerkleHashAlgo) -> [u8; 32] {
298        let mut combined = [0u8; 64];
299        combined[..32].copy_from_slice(left);
300        combined[32..].copy_from_slice(right);
301        Self::hash_leaf_with_algo(&combined, algo)
302    }
303
304    // ── Tree construction ─────────────────────────────────────────────────────
305
306    /// Build a Merkle tree from the given raw leaf data.
307    ///
308    /// Leaves are padded to the next power-of-two by duplicating the last leaf.
309    /// Nodes are stored in a flat vec (root at index 0, level-order / breadth-first).
310    pub fn build_tree(&self, leaves: &[Vec<u8>]) -> MerkleTree {
311        if leaves.is_empty() {
312            return MerkleTree {
313                leaves: vec![],
314                nodes: vec![],
315                algo: self.algo,
316                depth: 0,
317            };
318        }
319
320        // Hash each leaf.
321        let mut leaf_hashes: Vec<[u8; 32]> = leaves.iter().map(|l| self.hash_leaf(l)).collect();
322
323        // Pad to next power-of-two.
324        let n = leaf_hashes.len();
325        let padded_len = n.next_power_of_two();
326        if let Some(last) = leaf_hashes.last().copied() {
327            while leaf_hashes.len() < padded_len {
328                leaf_hashes.push(last);
329            }
330        }
331
332        let depth = if padded_len == 1 {
333            0
334        } else {
335            (padded_len as f64).log2() as usize
336        };
337
338        // Build nodes bottom-up. Total nodes = 2*padded_len - 1.
339        // We store them in a flat array of size 2*padded_len - 1.
340        // Index mapping (1-indexed): root = 1, children of i = 2i and 2i+1.
341        // We convert to 0-indexed by subtracting 1.
342        let total = 2 * padded_len - 1;
343        let mut nodes = vec![[0u8; 32]; total];
344
345        // Fill leaves at positions [padded_len-1 .. total-1] (0-indexed).
346        for (i, &hash) in leaf_hashes.iter().enumerate() {
347            nodes[padded_len - 1 + i] = hash;
348        }
349
350        // Build internal nodes bottom-up.
351        if padded_len > 1 {
352            for i in (0..padded_len - 1).rev() {
353                let left = &nodes[2 * i + 1];
354                let right = &nodes[2 * i + 2];
355                nodes[i] = Self::hash_pair_with_algo(left, right, self.algo);
356            }
357        }
358
359        MerkleTree {
360            leaves: leaf_hashes,
361            nodes,
362            algo: self.algo,
363            depth,
364        }
365    }
366
367    // ── Proof generation ─────────────────────────────────────────────────────
368
369    /// Generate an inclusion proof for the leaf at `leaf_index`.
370    ///
371    /// Returns `None` if `leaf_index` is out of range.
372    pub fn generate_proof(&self, tree: &MerkleTree, leaf_index: usize) -> Option<MerkleProof> {
373        let padded_len = tree.leaves.len();
374        if padded_len == 0 || leaf_index >= padded_len {
375            return None;
376        }
377
378        let total = tree.nodes.len();
379        if total == 0 {
380            return None;
381        }
382
383        let leaf_hash = tree.leaves[leaf_index];
384        let root_hash = tree.nodes[0];
385        let mut steps = Vec::new();
386
387        // Start at the leaf's node index (0-indexed array: leaf i → node padded_len-1+i).
388        let mut idx = padded_len - 1 + leaf_index;
389
390        while idx > 0 {
391            // Determine if this node is a left (even offset from parent's left child) or right child.
392            // Parent of node i (0-indexed): (i-1)/2
393            // Left child of parent p: 2*p+1
394            // Right child: 2*p+2
395            let is_left = (idx % 2) == 1; // odd index → left child, even → right child
396            if is_left {
397                // Sibling is to the right.
398                let sibling_idx = idx + 1;
399                if sibling_idx < total {
400                    steps.push(ProofStep::Right(tree.nodes[sibling_idx]));
401                }
402            } else {
403                // Sibling is to the left.
404                let sibling_idx = idx - 1;
405                steps.push(ProofStep::Left(tree.nodes[sibling_idx]));
406            }
407            idx = (idx - 1) / 2;
408        }
409
410        Some(MerkleProof {
411            leaf_hash,
412            steps,
413            root_hash,
414            algo: self.algo,
415        })
416    }
417
418    // ── Proof verification ────────────────────────────────────────────────────
419
420    /// Verify a single inclusion proof and update internal statistics.
421    pub fn verify_proof(&mut self, proof: &MerkleProof) -> VerificationResult {
422        let mut current = proof.leaf_hash;
423        let mut steps_verified = 0;
424
425        for step in &proof.steps {
426            current = match step {
427                ProofStep::Left(sibling) => {
428                    Self::hash_pair_with_algo(sibling, &current, proof.algo)
429                }
430                ProofStep::Right(sibling) => {
431                    Self::hash_pair_with_algo(&current, sibling, proof.algo)
432                }
433            };
434            steps_verified += 1;
435        }
436
437        let valid = current == proof.root_hash;
438        self.verifications_done += 1;
439        if !valid {
440            self.failures += 1;
441        }
442
443        VerificationResult {
444            valid,
445            computed_root: current,
446            expected_root: proof.root_hash,
447            steps_verified,
448        }
449    }
450
451    /// Verify a batch of proofs, returning one result per proof.
452    pub fn verify_batch(&mut self, proofs: &[MerkleProof]) -> Vec<VerificationResult> {
453        proofs.iter().map(|p| self.verify_proof(p)).collect()
454    }
455
456    // ── Convenience helpers ───────────────────────────────────────────────────
457
458    /// Build a tree from raw leaf data and return the root hash.
459    pub fn root_of(&self, leaves: &[Vec<u8>]) -> [u8; 32] {
460        let tree = self.build_tree(leaves);
461        tree.nodes.first().copied().unwrap_or([0u8; 32])
462    }
463
464    /// Return `(verifications_done, failures)`.
465    pub fn verifier_stats(&self) -> (u64, u64) {
466        (self.verifications_done, self.failures)
467    }
468}
469
470// ─── Tests ────────────────────────────────────────────────────────────────────
471
472#[cfg(test)]
473mod tests {
474    use crate::merkle_proof_verifier::{
475        fnv1a_64, sha256, MerkleHashAlgo, MerkleNode, MerkleProof, MerkleProofVerifier, MerkleTree,
476        ProofStep,
477    };
478
479    // ── SHA-256 primitive tests ────────────────────────────────────────────────
480
481    /// 1. SHA-256 of empty string matches the well-known value.
482    #[test]
483    fn test_sha256_empty() {
484        let digest = sha256(b"");
485        let expected =
486            hex_to_bytes("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
487        assert_eq!(digest, expected);
488    }
489
490    /// 2. SHA-256("abc") matches the known reference output.
491    ///
492    /// The reference value `ba7816bf...` is verified against Python `hashlib.sha256(b"abc")`.
493    #[test]
494    fn test_sha256_abc() {
495        let digest = sha256(b"abc");
496        let expected =
497            hex_to_bytes("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
498        assert_eq!(digest, expected);
499    }
500
501    /// 3. SHA-256 is deterministic.
502    #[test]
503    fn test_sha256_deterministic() {
504        let a = sha256(b"hello world");
505        let b = sha256(b"hello world");
506        assert_eq!(a, b);
507    }
508
509    /// 4. SHA-256 of different inputs produces different digests (collision resistance smoke test).
510    #[test]
511    fn test_sha256_distinct() {
512        let a = sha256(b"foo");
513        let b = sha256(b"bar");
514        assert_ne!(a, b);
515    }
516
517    /// 5. SHA-256 output is always 32 bytes.
518    #[test]
519    fn test_sha256_output_len() {
520        assert_eq!(sha256(b"test").len(), 32);
521        assert_eq!(sha256(b"").len(), 32);
522        assert_eq!(sha256(&[0u8; 1000]).len(), 32);
523    }
524
525    // ── FNV-1a tests ─────────────────────────────────────────────────────────
526
527    /// 6. FNV-1a of known value.
528    #[test]
529    fn test_fnv1a_known() {
530        // fnv1a_64("") = offset basis = 14695981039346656037
531        assert_eq!(fnv1a_64(b""), 14_695_981_039_346_656_037_u64);
532    }
533
534    /// 7. FNV-1a is deterministic.
535    #[test]
536    fn test_fnv1a_deterministic() {
537        assert_eq!(fnv1a_64(b"hello"), fnv1a_64(b"hello"));
538    }
539
540    /// 8. FNV-1a differs on different inputs.
541    #[test]
542    fn test_fnv1a_distinct() {
543        assert_ne!(fnv1a_64(b"hello"), fnv1a_64(b"world"));
544    }
545
546    // ── Hash-leaf tests ───────────────────────────────────────────────────────
547
548    /// 9. hash_leaf with Sha256 produces 32-byte output.
549    #[test]
550    fn test_hash_leaf_sha256_len() {
551        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
552        assert_eq!(v.hash_leaf(b"data").len(), 32);
553    }
554
555    /// 10. hash_leaf with Blake3 differs from Sha256 for same input.
556    #[test]
557    fn test_hash_leaf_blake3_differs_from_sha256() {
558        let vs = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
559        let vb = MerkleProofVerifier::new(MerkleHashAlgo::Blake3);
560        assert_ne!(vs.hash_leaf(b"data"), vb.hash_leaf(b"data"));
561    }
562
563    /// 11. hash_leaf with Blake3 equals SHA-256 XOR 0xb3 at every byte.
564    #[test]
565    fn test_hash_leaf_blake3_xor_correctness() {
566        let vb = MerkleProofVerifier::new(MerkleHashAlgo::Blake3);
567        let sha = sha256(b"test");
568        let blake = vb.hash_leaf(b"test");
569        for (s, b) in sha.iter().zip(blake.iter()) {
570            assert_eq!(s ^ 0xb3, *b);
571        }
572    }
573
574    /// 12. hash_leaf with FnvXor is deterministic.
575    #[test]
576    fn test_hash_leaf_fnvxor_deterministic() {
577        let v = MerkleProofVerifier::new(MerkleHashAlgo::FnvXor);
578        assert_eq!(v.hash_leaf(b"hello"), v.hash_leaf(b"hello"));
579    }
580
581    /// 13. hash_leaf with FnvXor differs from Sha256.
582    #[test]
583    fn test_hash_leaf_fnvxor_differs_from_sha256() {
584        let vs = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
585        let vf = MerkleProofVerifier::new(MerkleHashAlgo::FnvXor);
586        assert_ne!(vs.hash_leaf(b"data"), vf.hash_leaf(b"data"));
587    }
588
589    // ── hash_pair tests ───────────────────────────────────────────────────────
590
591    /// 14. hash_pair is not commutative (order matters).
592    #[test]
593    fn test_hash_pair_not_commutative() {
594        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
595        let a = [1u8; 32];
596        let b = [2u8; 32];
597        assert_ne!(v.hash_pair(&a, &b), v.hash_pair(&b, &a));
598    }
599
600    /// 15. hash_pair(h, h) == hash_pair(h, h) (idempotent for equal inputs).
601    #[test]
602    fn test_hash_pair_equal_inputs_deterministic() {
603        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
604        let h = [42u8; 32];
605        assert_eq!(v.hash_pair(&h, &h), v.hash_pair(&h, &h));
606    }
607
608    // ── MerkleNode tests ─────────────────────────────────────────────────────
609
610    /// 16. MerkleNode::leaf has no children.
611    #[test]
612    fn test_merkle_node_leaf() {
613        let n = MerkleNode::leaf([0u8; 32]);
614        assert!(n.left.is_none());
615        assert!(n.right.is_none());
616    }
617
618    /// 17. MerkleNode::internal stores children.
619    #[test]
620    fn test_merkle_node_internal() {
621        let l = MerkleNode::leaf([1u8; 32]);
622        let r = MerkleNode::leaf([2u8; 32]);
623        let parent = MerkleNode::internal([3u8; 32], l, r);
624        assert!(parent.left.is_some());
625        assert!(parent.right.is_some());
626    }
627
628    // ── Tree construction tests ───────────────────────────────────────────────
629
630    /// 18. build_tree on an empty slice returns an empty tree.
631    #[test]
632    fn test_build_tree_empty() {
633        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
634        let tree = v.build_tree(&[]);
635        assert!(tree.leaves.is_empty());
636        assert!(tree.nodes.is_empty());
637    }
638
639    /// 19. build_tree on a single leaf: root equals hash_leaf.
640    #[test]
641    fn test_build_tree_single_leaf() {
642        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
643        let data = vec![b"hello".to_vec()];
644        let tree = v.build_tree(&data);
645        assert_eq!(tree.depth, 0);
646        // Root should be hash_pair(leaf, leaf) for the padded single-leaf tree
647        // (padded_len = 1, so total = 1 node, which is the leaf itself).
648        assert_eq!(tree.nodes[0], v.hash_leaf(b"hello"));
649    }
650
651    /// 20. build_tree pads to next power-of-two.
652    #[test]
653    fn test_build_tree_padding() {
654        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
655        let data: Vec<Vec<u8>> = (0..3u8).map(|i| vec![i]).collect();
656        let tree = v.build_tree(&data);
657        assert_eq!(tree.leaves.len(), 4); // padded to 4
658    }
659
660    /// 21. build_tree with exactly 4 leaves has depth 2.
661    #[test]
662    fn test_build_tree_four_leaves_depth() {
663        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
664        let data: Vec<Vec<u8>> = (0..4u8).map(|i| vec![i]).collect();
665        let tree = v.build_tree(&data);
666        assert_eq!(tree.depth, 2);
667        assert_eq!(tree.nodes.len(), 7); // 2*4-1
668    }
669
670    /// 22. build_tree root equals root_of.
671    #[test]
672    fn test_build_tree_root_matches_root_of() {
673        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
674        let data: Vec<Vec<u8>> = (0..4u8).map(|i| vec![i]).collect();
675        let tree = v.build_tree(&data);
676        let root = v.root_of(&data);
677        assert_eq!(tree.nodes[0], root);
678    }
679
680    // ── Proof generation and verification (round-trip) ────────────────────────
681
682    fn make_leaves(n: usize) -> Vec<Vec<u8>> {
683        (0..n).map(|i| format!("leaf-{i}").into_bytes()).collect()
684    }
685
686    fn round_trip(algo: MerkleHashAlgo, n_leaves: usize, leaf_idx: usize) -> bool {
687        let mut v = MerkleProofVerifier::new(algo);
688        let leaves = make_leaves(n_leaves);
689        let tree = v.build_tree(&leaves);
690        let proof = v.generate_proof(&tree, leaf_idx).expect("proof");
691        v.verify_proof(&proof).valid
692    }
693
694    /// 23. Round-trip: generate + verify, Sha256, 4 leaves, leaf 0.
695    #[test]
696    fn test_round_trip_sha256_4_leaf0() {
697        assert!(round_trip(MerkleHashAlgo::Sha256, 4, 0));
698    }
699
700    /// 24. Round-trip: generate + verify, Sha256, 4 leaves, leaf 3.
701    #[test]
702    fn test_round_trip_sha256_4_leaf3() {
703        assert!(round_trip(MerkleHashAlgo::Sha256, 4, 3));
704    }
705
706    /// 25. Round-trip: generate + verify, Blake3, 8 leaves, leaf 5.
707    #[test]
708    fn test_round_trip_blake3_8_leaf5() {
709        assert!(round_trip(MerkleHashAlgo::Blake3, 8, 5));
710    }
711
712    /// 26. Round-trip: generate + verify, FnvXor, 4 leaves, leaf 2.
713    #[test]
714    fn test_round_trip_fnvxor_4_leaf2() {
715        assert!(round_trip(MerkleHashAlgo::FnvXor, 4, 2));
716    }
717
718    /// 27. Round-trip with non-power-of-2 leaves (5 leaves).
719    #[test]
720    fn test_round_trip_non_power_of_two() {
721        assert!(round_trip(MerkleHashAlgo::Sha256, 5, 2));
722        assert!(round_trip(MerkleHashAlgo::Sha256, 5, 4));
723    }
724
725    /// 28. Tampered leaf hash → invalid proof.
726    #[test]
727    fn test_tampered_leaf_fails() {
728        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
729        let leaves = make_leaves(4);
730        let tree = v.build_tree(&leaves);
731        let mut proof = v.generate_proof(&tree, 0).expect("proof");
732        proof.leaf_hash[0] ^= 0xff; // corrupt leaf
733        let result = v.verify_proof(&proof);
734        assert!(!result.valid);
735    }
736
737    /// 29. Tampered step hash → invalid proof.
738    #[test]
739    fn test_tampered_step_fails() {
740        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
741        let leaves = make_leaves(4);
742        let tree = v.build_tree(&leaves);
743        let mut proof = v.generate_proof(&tree, 1).expect("proof");
744        if let Some(step) = proof.steps.first_mut() {
745            match step {
746                ProofStep::Left(h) | ProofStep::Right(h) => h[0] ^= 0xff,
747            }
748        }
749        let result = v.verify_proof(&proof);
750        assert!(!result.valid);
751    }
752
753    /// 30. Tampered root hash → invalid proof.
754    #[test]
755    fn test_tampered_root_fails() {
756        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
757        let leaves = make_leaves(4);
758        let tree = v.build_tree(&leaves);
759        let mut proof = v.generate_proof(&tree, 0).expect("proof");
760        proof.root_hash[0] ^= 0x01;
761        let result = v.verify_proof(&proof);
762        assert!(!result.valid);
763    }
764
765    // ── Statistics tests ──────────────────────────────────────────────────────
766
767    /// 31. verifier_stats initially zero.
768    #[test]
769    fn test_stats_initial() {
770        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
771        assert_eq!(v.verifier_stats(), (0, 0));
772    }
773
774    /// 32. verifier_stats increments on each verify_proof call.
775    #[test]
776    fn test_stats_increments() {
777        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
778        let leaves = make_leaves(4);
779        let tree = v.build_tree(&leaves);
780        let proof = v.generate_proof(&tree, 0).expect("proof");
781        v.verify_proof(&proof);
782        v.verify_proof(&proof);
783        assert_eq!(v.verifier_stats(), (2, 0));
784    }
785
786    /// 33. failures counter increments on invalid proof.
787    #[test]
788    fn test_stats_failures() {
789        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
790        let leaves = make_leaves(4);
791        let tree = v.build_tree(&leaves);
792        let mut proof = v.generate_proof(&tree, 0).expect("proof");
793        proof.root_hash[0] ^= 0x01;
794        v.verify_proof(&proof);
795        assert_eq!(v.verifier_stats(), (1, 1));
796    }
797
798    // ── Batch verification ────────────────────────────────────────────────────
799
800    /// 34. verify_batch returns a result for each proof.
801    #[test]
802    fn test_verify_batch_count() {
803        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
804        let leaves = make_leaves(4);
805        let tree = v.build_tree(&leaves);
806        let proofs: Vec<MerkleProof> = (0..4).filter_map(|i| v.generate_proof(&tree, i)).collect();
807        let results = v.verify_batch(&proofs);
808        assert_eq!(results.len(), 4);
809    }
810
811    /// 35. verify_batch: all valid proofs from a correct tree.
812    #[test]
813    fn test_verify_batch_all_valid() {
814        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
815        let leaves = make_leaves(8);
816        let tree = v.build_tree(&leaves);
817        let proofs: Vec<MerkleProof> = (0..8).filter_map(|i| v.generate_proof(&tree, i)).collect();
818        let results = v.verify_batch(&proofs);
819        assert!(results.iter().all(|r| r.valid));
820    }
821
822    /// 36. verify_batch updates verifications_done.
823    #[test]
824    fn test_verify_batch_updates_stats() {
825        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
826        let leaves = make_leaves(4);
827        let tree = v.build_tree(&leaves);
828        let proofs: Vec<MerkleProof> = (0..4).filter_map(|i| v.generate_proof(&tree, i)).collect();
829        v.verify_batch(&proofs);
830        assert_eq!(v.verifications_done, 4);
831    }
832
833    // ── generate_proof edge cases ─────────────────────────────────────────────
834
835    /// 37. generate_proof returns None for out-of-range leaf_index.
836    #[test]
837    fn test_generate_proof_out_of_range() {
838        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
839        let leaves = make_leaves(4);
840        let tree = v.build_tree(&leaves);
841        assert!(v.generate_proof(&tree, 10).is_none());
842    }
843
844    /// 38. generate_proof returns None for an empty tree.
845    #[test]
846    fn test_generate_proof_empty_tree() {
847        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
848        let empty_tree = MerkleTree {
849            leaves: vec![],
850            nodes: vec![],
851            algo: MerkleHashAlgo::Sha256,
852            depth: 0,
853        };
854        assert!(v.generate_proof(&empty_tree, 0).is_none());
855    }
856
857    /// 39. Proof for a single-leaf tree has zero steps.
858    #[test]
859    fn test_proof_single_leaf_no_steps() {
860        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
861        let leaves = vec![b"only".to_vec()];
862        let tree = v.build_tree(&leaves);
863        let proof = v.generate_proof(&tree, 0).expect("proof");
864        assert_eq!(proof.steps.len(), 0);
865    }
866
867    /// 40. Proof steps count for depth-2 tree (4 leaves) is 2.
868    #[test]
869    fn test_proof_steps_count_depth2() {
870        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
871        let leaves = make_leaves(4);
872        let tree = v.build_tree(&leaves);
873        let proof = v.generate_proof(&tree, 0).expect("proof");
874        assert_eq!(proof.steps.len(), 2);
875    }
876
877    // ── VerificationResult fields ─────────────────────────────────────────────
878
879    /// 41. VerificationResult.computed_root matches expected_root on valid proof.
880    #[test]
881    fn test_verification_result_roots_match_on_valid() {
882        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
883        let leaves = make_leaves(4);
884        let tree = v.build_tree(&leaves);
885        let proof = v.generate_proof(&tree, 1).expect("proof");
886        let res = v.verify_proof(&proof);
887        assert_eq!(res.computed_root, res.expected_root);
888        assert!(res.is_valid());
889    }
890
891    /// 42. VerificationResult.steps_verified equals proof.steps.len() on valid proof.
892    #[test]
893    fn test_verification_result_steps_verified() {
894        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
895        let leaves = make_leaves(4);
896        let tree = v.build_tree(&leaves);
897        let proof = v.generate_proof(&tree, 2).expect("proof");
898        let n_steps = proof.steps.len();
899        let res = v.verify_proof(&proof);
900        assert_eq!(res.steps_verified, n_steps);
901    }
902
903    // ── Cross-algorithm correctness ────────────────────────────────────────────
904
905    /// 43. Different algo → different roots.
906    #[test]
907    fn test_different_algo_different_roots() {
908        let vs = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
909        let vb = MerkleProofVerifier::new(MerkleHashAlgo::Blake3);
910        let leaves = make_leaves(4);
911        assert_ne!(vs.root_of(&leaves), vb.root_of(&leaves));
912    }
913
914    /// 44. Proof built with Sha256 fails against Blake3 verifier.
915    #[test]
916    fn test_cross_algo_proof_fails() {
917        let vs = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
918        let leaves = make_leaves(4);
919        let sha_tree = vs.build_tree(&leaves);
920        let sha_proof = vs.generate_proof(&sha_tree, 0).expect("proof");
921
922        // Verify using a Blake3 verifier (by manually overriding proof.algo).
923        let mut blake_proof = sha_proof.clone();
924        blake_proof.algo = MerkleHashAlgo::Blake3;
925
926        let mut vb = MerkleProofVerifier::new(MerkleHashAlgo::Blake3);
927        let result = vb.verify_proof(&blake_proof);
928        // The computed root will differ from the sha256 root, so invalid.
929        assert!(!result.valid);
930    }
931
932    // ── Large tree tests ──────────────────────────────────────────────────────
933
934    /// 45. Round-trip for 1024-leaf tree (depth 10), several indices.
935    #[test]
936    fn test_large_tree_round_trip() {
937        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
938        let leaves: Vec<Vec<u8>> = (0u32..1024).map(|i| i.to_le_bytes().to_vec()).collect();
939        let tree = v.build_tree(&leaves);
940        assert_eq!(tree.depth, 10);
941        for &idx in &[0, 1, 511, 512, 1023] {
942            let proof = v.generate_proof(&tree, idx).expect("proof");
943            let res = v.verify_proof(&proof);
944            assert!(res.valid, "failed at leaf {idx}");
945        }
946    }
947
948    /// 46. All leaves in an 8-leaf tree can be proved and verified.
949    #[test]
950    fn test_all_leaves_8() {
951        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
952        let leaves = make_leaves(8);
953        let tree = v.build_tree(&leaves);
954        for i in 0..8 {
955            let proof = v.generate_proof(&tree, i).expect("proof");
956            assert!(v.verify_proof(&proof).valid, "leaf {i} failed");
957        }
958    }
959
960    // ── root_of tests ─────────────────────────────────────────────────────────
961
962    /// 47. root_of empty slice returns [0; 32].
963    #[test]
964    fn test_root_of_empty() {
965        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
966        assert_eq!(v.root_of(&[]), [0u8; 32]);
967    }
968
969    /// 48. root_of is consistent across calls.
970    #[test]
971    fn test_root_of_consistent() {
972        let v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
973        let leaves = make_leaves(4);
974        assert_eq!(v.root_of(&leaves), v.root_of(&leaves));
975    }
976
977    // ── ProofStep enum ────────────────────────────────────────────────────────
978
979    /// 49. ProofStep::Left and Right can be pattern-matched.
980    #[test]
981    fn test_proof_step_pattern_match() {
982        let h = [7u8; 32];
983        let step_l = ProofStep::Left(h);
984        let step_r = ProofStep::Right(h);
985        match step_l {
986            ProofStep::Left(inner) => assert_eq!(inner, h),
987            ProofStep::Right(_) => panic!("wrong variant"),
988        }
989        match step_r {
990            ProofStep::Right(inner) => assert_eq!(inner, h),
991            ProofStep::Left(_) => panic!("wrong variant"),
992        }
993    }
994
995    // ── MerkleProof round-trip with clone ─────────────────────────────────────
996
997    /// 50. MerkleProof can be cloned and still verifies.
998    #[test]
999    fn test_proof_clone_verifies() {
1000        let mut v = MerkleProofVerifier::new(MerkleHashAlgo::Sha256);
1001        let leaves = make_leaves(4);
1002        let tree = v.build_tree(&leaves);
1003        let proof = v.generate_proof(&tree, 2).expect("proof");
1004        let proof2 = proof.clone();
1005        assert!(v.verify_proof(&proof2).valid);
1006    }
1007
1008    // ── Helper ────────────────────────────────────────────────────────────────
1009
1010    fn hex_to_bytes(hex: &str) -> [u8; 32] {
1011        let mut out = [0u8; 32];
1012        for (i, chunk) in hex.as_bytes().chunks(2).enumerate() {
1013            if i >= 32 {
1014                break;
1015            }
1016            let hi = hex_nibble(chunk[0]);
1017            let lo = hex_nibble(chunk.get(1).copied().unwrap_or(b'0'));
1018            out[i] = (hi << 4) | lo;
1019        }
1020        out
1021    }
1022
1023    fn hex_nibble(b: u8) -> u8 {
1024        match b {
1025            b'0'..=b'9' => b - b'0',
1026            b'a'..=b'f' => b - b'a' + 10,
1027            b'A'..=b'F' => b - b'A' + 10,
1028            _ => 0,
1029        }
1030    }
1031}