Skip to main content

slahasher/
hash.rs

1use std::sync::Arc;
2
3use crate::Keccak256;
4use crate::Keccak384;
5use crate::Keccak512;
6use crate::Ripemd160;
7use crate::Sha256;
8use crate::hasher::Hasher;
9
10use base_xx::ByteVec;
11use base_xx::SerialiseError;
12use base_xx::byte_vec::TryIntoByteVec;
13use base_xx::encoded_string::Decodable;
14
15use crate::HashAlgorithm;
16
17/// A cryptographic hash value with its associated algorithm.
18///
19/// This type represents the result of applying a cryptographic hash function to some data.
20/// It stores both the resulting hash value and the algorithm used to create it.
21#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
22pub struct Hash {
23    /// The algorithm used to create this hash
24    algorithm: HashAlgorithm,
25    /// The raw bytes of the hash value
26    bytes: ByteVec,
27}
28
29impl Hash {
30    /// Creates a new hash value with the specified algorithm and bytes.
31    ///
32    /// # Arguments
33    /// * `algorithm` - The hash algorithm used to create this hash
34    /// * `bytes` - The raw hash value bytes
35    #[must_use]
36    pub const fn new(algorithm: HashAlgorithm, bytes: ByteVec) -> Self {
37        Self { algorithm, bytes }
38    }
39
40    /// Returns a reference to the raw hash value bytes.
41    #[must_use]
42    pub const fn get_bytes(&self) -> &ByteVec {
43        &self.bytes
44    }
45
46    /// Returns the algorithm used to create this hash.
47    #[must_use]
48    pub const fn get_algorithm(&self) -> HashAlgorithm {
49        self.algorithm
50    }
51
52    /// Verifies that this hash matches the hash of the provided bytes.
53    ///
54    /// # Arguments
55    /// * `bytes` - The bytes to verify against this hash
56    ///
57    /// # Returns
58    /// `true` if the hash of the provided bytes matches this hash, `false` otherwise
59    #[must_use]
60    pub fn verify(&self, bytes: Arc<ByteVec>) -> bool {
61        match self.algorithm {
62            HashAlgorithm::SHA256 => {
63                Sha256::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
64            }
65            HashAlgorithm::KECCAK512 => {
66                Keccak512::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
67            }
68            HashAlgorithm::KECCAK256 => {
69                Keccak256::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
70            }
71            HashAlgorithm::KECCAK384 => {
72                Keccak384::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
73            }
74            HashAlgorithm::RIPEMD160 => {
75                Ripemd160::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
76            }
77        }
78    }
79
80    fn try_as_bytes(&self) -> Result<Vec<u8>, SerialiseError> {
81        let mut bytes = vec![];
82        let algorithm: Result<u8, SerialiseError> = self.algorithm.try_into();
83        match algorithm {
84            Err(error) => return Err(error),
85            Ok(algorithm) => bytes.push(algorithm),
86        }
87        bytes.extend_from_slice(self.bytes.get_bytes());
88        Ok(bytes)
89    }
90
91    /// Converts this hash to a `ByteVec` suitable for encoding.
92    ///
93    /// # Errors
94    /// Returns `SerialiseError` if the hash cannot be converted to bytes.
95    pub fn try_to_byte_vec(&self) -> Result<Arc<ByteVec>, SerialiseError> {
96        match self.try_as_bytes() {
97            Ok(bytes) => Ok(Arc::new(ByteVec::new(Arc::new(bytes)))),
98            Err(error) => Err(error),
99        }
100    }
101
102    fn try_from_bytes(bytes: &[u8]) -> Result<Self, SerialiseError> {
103        let algorithm = HashAlgorithm::try_from(bytes[0]);
104        match algorithm {
105            Err(error) => Err(error),
106            Ok(algorithm) => {
107                let bytes = bytes[1..].to_vec();
108                Ok(Self::new(algorithm, ByteVec::new(Arc::new(bytes))))
109            }
110        }
111    }
112    /// Computes a hash of the provided bytes using the given algorithm.
113    ///
114    /// # Errors
115    /// Returns `SerialiseError` if hashing fails.
116    pub fn try_hash(
117        byte_vec: Arc<ByteVec>,
118        algorithm: HashAlgorithm,
119    ) -> Result<Arc<Self>, SerialiseError> {
120        match algorithm {
121            HashAlgorithm::SHA256 => Sha256::try_hash(byte_vec),
122            HashAlgorithm::KECCAK256 => Keccak256::try_hash(byte_vec),
123            HashAlgorithm::KECCAK384 => Keccak384::try_hash(byte_vec),
124            HashAlgorithm::KECCAK512 => Keccak512::try_hash(byte_vec),
125            HashAlgorithm::RIPEMD160 => Ripemd160::try_hash(byte_vec),
126        }
127    }
128}
129
130impl TryFrom<Arc<ByteVec>> for Hash {
131    type Error = SerialiseError;
132    fn try_from(value: Arc<ByteVec>) -> Result<Self, Self::Error> {
133        match Self::try_from_bytes(value.get_bytes()) {
134            Ok(hash) => Ok(hash),
135            Err(err) => Err(err),
136        }
137    }
138}
139
140impl TryIntoByteVec for Hash {
141    fn try_into_byte_vec(value: Arc<Self>) -> Result<Arc<ByteVec>, SerialiseError> {
142        value.try_to_byte_vec()
143    }
144}
145
146impl Decodable for Hash {}
147
148#[cfg(test)]
149mod tests {
150
151    use super::*;
152
153    use base_xx::Encoding;
154
155    #[test]
156    fn test_hash() {
157        let bytes = Arc::new(ByteVec::new(Arc::new(vec![1, 2, 3])));
158        match Hash::try_hash(Arc::clone(&bytes), HashAlgorithm::SHA256) {
159            Ok(hash) => match hash.try_to_byte_vec() {
160                Ok(bytes) => match bytes.try_encode(Encoding::Base36) {
161                    Ok(hash_ss) => {
162                        let hash_str = hash_ss.get_string();
163                        slogger::debug!("hash: {hash_str}");
164                        slogger::debug!("hash debug: {hash:#?}");
165                        assert_eq!(
166                            hash_str,
167                            "hwis74tcngndmvw8t0jaf8baow2455synbsyr8u6vfvfvi6mgld"
168                        );
169                    }
170                    Err(error) => slogger::debug!("serialstring error: {error:?}"),
171                },
172                Err(error) => slogger::debug!("serialstring error: {error:?}"),
173            },
174            Err(error) => slogger::debug!("hash error: {error:?}"),
175        }
176
177        /*
178        let hash_str: SerialString = Base36::try_from(Bytes::try_from(&hash).unwrap())
179            .unwrap()
180            .into();
181        let hash_str = hash_str.get_string();
182        slogger::debug!("hash: {hash_str}");
183        slogger::debug!("hash debug: {hash:?}");
184
185        let hash: Hash = Keccak384::from_bytes(&bytes).into();
186
187        let hash_str: SerialString = Base36::try_from(Bytes::try_from(&hash).unwrap())
188            .unwrap()
189            .into();
190        let hash_str = hash_str.get_string();
191        slogger::debug!("hash: {hash_str}");
192        slogger::debug!("hash debug: {hash:?}");
193        */
194    }
195}