celestia_types/nmt/
namespaced_hash.rs

1use crate::nmt::{NS_SIZE, NamespacedHash, NamespacedSha2Hasher};
2use crate::{Error, Result};
3
4use nmt_rs::simple_merkle::tree::MerkleHash;
5
6/// Size of the [`NamespacedHash`] in bytes.
7pub const NAMESPACED_HASH_SIZE: usize = NamespacedHash::size();
8/// Size of the Sha256 hash in [`NamespacedHash`] in bytes.
9pub const HASH_SIZE: usize = 32;
10
11/// Byte representation of the [`NamespacedHash`].
12pub type RawNamespacedHash = [u8; NAMESPACED_HASH_SIZE];
13
14/// An extention trait for the [`NamespacedHash`] to perform additional actions.
15pub trait NamespacedHashExt {
16    /// Get the hash of the root of an empty [`Nmt`].
17    ///
18    /// [`Nmt`]: crate::nmt::Nmt
19    fn empty_root() -> NamespacedHash;
20    /// Try to decode [`NamespacedHash`] from the raw bytes.
21    fn from_raw(bytes: &[u8]) -> Result<NamespacedHash>;
22    /// Encode [`NamespacedHash`] into [`Vec`].
23    fn to_vec(&self) -> Vec<u8>;
24    /// Encode [`NamespacedHash`] into [`array`].
25    fn to_array(&self) -> RawNamespacedHash;
26    /// Validate if the [`Namespace`]s covered by this hash are in correct order.
27    ///
28    /// I.e. this verifies that the minimum [`Namespace`] of this hash is lower
29    /// or equal to the maximum [`Namespace`].
30    ///
31    /// [`Namespace`]: crate::nmt::Namespace
32    fn validate_namespace_order(&self) -> Result<()>;
33}
34
35impl NamespacedHashExt for NamespacedHash {
36    fn empty_root() -> NamespacedHash {
37        NamespacedSha2Hasher::EMPTY_ROOT
38    }
39
40    fn from_raw(bytes: &[u8]) -> Result<NamespacedHash> {
41        Ok(bytes.try_into()?)
42    }
43
44    fn to_vec(&self) -> Vec<u8> {
45        self.iter().collect()
46    }
47
48    fn to_array(&self) -> RawNamespacedHash {
49        let mut out = [0; NAMESPACED_HASH_SIZE];
50        out[..NS_SIZE].copy_from_slice(&self.min_namespace().0);
51        out[NS_SIZE..2 * NS_SIZE].copy_from_slice(&self.max_namespace().0);
52        out[2 * NS_SIZE..].copy_from_slice(&self.hash());
53        out
54    }
55
56    fn validate_namespace_order(&self) -> Result<()> {
57        if self.min_namespace() > self.max_namespace() {
58            return Err(Error::InvalidNmtNodeOrder);
59        }
60
61        Ok(())
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use crate::nmt::{NS_ID_V0_SIZE, Namespace};
69
70    #[test]
71    fn namespaced_hash_validate_namespace_order() {
72        let n0 = Namespace::new_v0(&[1]).unwrap();
73        let n1 = Namespace::new_v0(&[2]).unwrap();
74
75        assert!(
76            NamespacedHash::with_min_and_max_ns(*n0, *n1)
77                .validate_namespace_order()
78                .is_ok()
79        );
80        assert!(
81            NamespacedHash::with_min_and_max_ns(*n1, *n1)
82                .validate_namespace_order()
83                .is_ok()
84        );
85        assert!(
86            NamespacedHash::with_min_and_max_ns(*n1, *n0)
87                .validate_namespace_order()
88                .is_err()
89        );
90    }
91
92    #[test]
93    fn hash_to_array() {
94        let ns_min = [9; NS_ID_V0_SIZE];
95        let ns_max = [2; NS_ID_V0_SIZE];
96
97        let mut ns_bytes_min = [0; NS_SIZE];
98        ns_bytes_min[NS_SIZE - NS_ID_V0_SIZE..].copy_from_slice(&ns_min);
99        let mut ns_bytes_max = [0; NS_SIZE];
100        ns_bytes_max[NS_SIZE - NS_ID_V0_SIZE..].copy_from_slice(&ns_max);
101
102        let buff = NamespacedHash::with_min_and_max_ns(
103            *Namespace::new_v0(&ns_min).unwrap(),
104            *Namespace::new_v0(&ns_max).unwrap(),
105        )
106        .to_array();
107
108        assert_eq!(buff[..NS_SIZE], ns_bytes_min);
109        assert_eq!(buff[NS_SIZE..NS_SIZE * 2], ns_bytes_max);
110        assert_eq!(buff[NS_SIZE * 2..], [0; HASH_SIZE]);
111    }
112}