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#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
22pub struct Hash {
23 algorithm: HashAlgorithm,
25 bytes: ByteVec,
27}
28
29impl Hash {
30 #[must_use]
36 pub const fn new(algorithm: HashAlgorithm, bytes: ByteVec) -> Self {
37 Self { algorithm, bytes }
38 }
39
40 #[must_use]
42 pub const fn get_bytes(&self) -> &ByteVec {
43 &self.bytes
44 }
45
46 #[must_use]
48 pub const fn get_algorithm(&self) -> HashAlgorithm {
49 self.algorithm
50 }
51
52 #[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 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 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 }
195}