1use crypto::digest::Digest;
2
3#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
4pub enum HashKind {
5 NONE,
6
7 SASHA,
8
9 MD5,
10
11 SHA1,
12 SHA256,
13 SHA512,
14
15 BLAKE2B,
16 BLAKE2S,
17 BLAKE3,
18
19 RIPEMD160,
20 WHIRLPOOL,
21}
22#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
23pub struct Hash {
24 pub hash_type: HashKind,
25}
26
27trait SubStr {
28 fn sub_strings(&self, length: usize) -> Vec<&str>;
29}
30
31impl SubStr for str {
32 fn sub_strings(&self, sub_len: usize) -> Vec<&str> {
33 let mut subs = Vec::with_capacity(self.len() / sub_len);
34 let mut iter = self.chars();
35 let mut pos = 0;
36
37 while pos < self.len() {
38 let mut len = 0;
39 for ch in iter.by_ref().take(sub_len) {
40 len += ch.len_utf8();
41 }
42 subs.push(&self[pos..pos + len]);
43 pos += len;
44 }
45 subs
46 }
47}
48
49impl HashKind {
50 pub fn length(&self) -> u16 {
51 match self {
52 HashKind::SASHA => 240,
53 HashKind::MD5 => 32,
54
55 HashKind::SHA1 => 40,
56 HashKind::SHA256 => 64,
57 HashKind::SHA512 => 128,
58
59 HashKind::BLAKE2B => 128,
60 HashKind::BLAKE2S => 64,
61 HashKind::BLAKE3 => 64,
62
63 HashKind::RIPEMD160 => 40,
64 HashKind::WHIRLPOOL => 128,
65 _ => 0,
66 }
67 }
68}
69
70pub trait U8ToHashKind {
71 fn to_hash_kind(&self) -> HashKind;
72}
73
74impl U8ToHashKind for u8 {
75 fn to_hash_kind(&self) -> HashKind {
76 match self {
77 0 => HashKind::NONE,
78 1 => HashKind::SASHA,
79 2 => HashKind::MD5,
80 3 => HashKind::SHA1,
81 4 => HashKind::SHA256,
82 5 => HashKind::SHA512,
83 6 => HashKind::BLAKE2B,
84 7 => HashKind::BLAKE2S,
85 8 => HashKind::BLAKE3,
86 9 => HashKind::RIPEMD160,
87 10 => HashKind::WHIRLPOOL,
88 _ => HashKind::NONE,
89 }
90 }
91}
92
93impl Hash {
94 pub fn calculate(hash_type: HashKind, hash_data: &str) -> String {
95 let mut result = String::from("-");
96 match hash_type {
97 HashKind::SASHA => {
98 let blake2b_temp_result = Self::calculate(HashKind::BLAKE2B, hash_data);
99 let split_blake2b = &blake2b_temp_result.sub_strings(16);
100
101 let md5_temp_result = Self::calculate(HashKind::MD5, hash_data);
102 let split_md5 = &md5_temp_result.sub_strings(4);
103
104 let sha1_temp_result = Self::calculate(HashKind::SHA1, hash_data);
105 let split_sha1 = &sha1_temp_result.sub_strings(5);
106
107 let ripemd160_temp_result = Self::calculate(HashKind::RIPEMD160, hash_data);
108 let split_ripemd160 = &ripemd160_temp_result.sub_strings(5);
109
110 let mut result_val = String::new();
111 for x in 0..8 {
112 if x < 4 {
113 result_val = result_val
114 + split_blake2b[x]
115 + split_md5[x]
116 + split_sha1[x]
117 + split_ripemd160[x];
118 } else {
119 result_val = result_val
120 + split_ripemd160[x]
121 + split_sha1[x]
122 + split_md5[x]
123 + split_blake2b[x];
124 }
125 }
126 result = result_val;
127 }
128 HashKind::MD5 => {
129 let mut hash_obj = crypto::md5::Md5::new();
130 hash_obj.input_str(hash_data);
131 result = hash_obj.result_str();
132 }
133 HashKind::SHA1 => {
134 let mut hash_obj = crypto::sha1::Sha1::new();
135 hash_obj.input_str(hash_data);
136 result = hash_obj.result_str();
137 }
138 HashKind::SHA256 => {
139 let mut hash_obj = crypto::sha2::Sha256::new();
140 hash_obj.input_str(hash_data);
141 result = hash_obj.result_str();
142 }
143 HashKind::SHA512 => {
144 let mut hash_obj = crypto::sha2::Sha512::new();
145 hash_obj.input_str(hash_data);
146 result = hash_obj.result_str();
147 }
148 HashKind::BLAKE2B => {
149 let mut hash_obj = crypto::blake2b::Blake2b::new(64);
150 hash_obj.input_str(hash_data);
151 result = hash_obj.result_str();
152 }
153 HashKind::RIPEMD160 => {
154 let mut hash_obj = crypto::ripemd160::Ripemd160::new();
155 hash_obj.input_str(hash_data);
156 result = hash_obj.result_str();
157 }
158 HashKind::WHIRLPOOL => {
159 let mut hash_obj = crypto::whirlpool::Whirlpool::new();
160 hash_obj.input_str(hash_data);
161 result = hash_obj.result_str();
162 }
163 HashKind::BLAKE2S => {
164 let mut hash_obj = crypto::blake2s::Blake2s::new(32);
165 hash_obj.input_str(hash_data);
166 result = hash_obj.result_str();
167 }
168 HashKind::BLAKE3 => {
169 let hash_obj = blake3::hash(hash_data.as_bytes());
170 result = hash_obj.to_string();
171 }
172 _ => println!("Unknown Hash Type"),
173 }
174 result
175 }
176
177 pub fn wallet_calculation(in_data: &str) -> String {
178
179 const DEFAULT_HEX_ALPHABET_STRING: &str = "0123456789abcdef";
180 const SIMPLE_HASH_ALPHABET_FOR_HEX_RESULT: &str = "fedcba9876543210";
181
182 Self::replace_char(
183 Self::calculate(HashKind::SASHA, &in_data.chars().rev().collect::<String>()),
184 DEFAULT_HEX_ALPHABET_STRING.to_string(),
185 SIMPLE_HASH_ALPHABET_FOR_HEX_RESULT.to_string(),
186 )
187 }
188
189 fn replace_char(source_text: String, from_text: String, to_text: String) -> String {
190 let mut input = source_text.chars().collect::<Vec<char>>();
191 let mut replaced: Vec<bool> = Vec::with_capacity(input.len());
192 for _ in 0..input.len() {
193 replaced.push(false);
194 }
195 for i in 0..from_text.len() {
196 for j in 0..input.len() {
197 if replaced[j] == false && input[j] == from_text.chars().nth(i).unwrap() {
198 input[j] = to_text.chars().nth(i).unwrap();
199 replaced[j] = true;
200 }
201 }
202 }
203 input.iter().collect::<String>()
204 }
205}
206
207#[test]
208fn md5_short_hash_test() {
209 assert_eq!(
210 "d8578edf8458ce06fbc5bb76a58c5ca4",
211 Hash::calculate(HashKind::MD5, "qwerty")
212 );
213}
214#[test]
215fn md5_long_hash_test() {
216 assert_eq!(
217 "65be673803a67c8f37e9ec51dfb66bc0",
218 Hash::calculate(HashKind::MD5, &"qwert".repeat(10))
219 );
220}
221#[test]
222fn sha1_short_hash_test() {
223 assert_eq!(
224 "b1b3773a05c0ed0176787a4f1574ff0075f7521e",
225 Hash::calculate(HashKind::SHA1, "qwerty")
226 );
227}
228#[test]
229fn sha1_long_hash_test() {
230 assert_eq!(
231 "8ce2bfdafe27ef4c3d1fae9db2a2c428cd5c063a",
232 Hash::calculate(HashKind::SHA1, &"qwert".repeat(10))
233 );
234}
235#[test]
236fn sha256_short_hash_test() {
237 assert_eq!(
238 "65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5",
239 Hash::calculate(HashKind::SHA256, "qwerty")
240 );
241}
242#[test]
243fn sha256_long_hash_test() {
244 assert_eq!(
245 "a69a351e7de07f954b1ca107a1f38592fc35afe6ed625b80959311c8ce831d2b",
246 Hash::calculate(HashKind::SHA256, &"qwert".repeat(20))
247 );
248}
249#[test]
250fn sha512_short_hash_test() {
251 assert_eq!(
252 "0dd3e512642c97ca3f747f9a76e374fbda73f9292823c0313be9d78add7cdd8f72235af0c553dd26797e78e1854edee0ae002f8aba074b066dfce1af114e32f8",
253 Hash::calculate(HashKind::SHA512, "qwerty")
254 );
255}
256#[test]
257fn sha512_long_hash_test() {
258 assert_eq!(
259 "409b286f9e9be0eb9ffc6a89a96742c1d4e56bcc49441cc2e67f7c1aa3ab829bc48680bda8125cca10f18eea1d046420064fb69f82b6b1265581a0467c4d9318",
260 Hash::calculate(HashKind::SHA512, &"qwert".repeat(40))
261 );
262}
263#[test]
264fn blake2b_short_hash_test() {
265 assert_eq!(
266 "9548a146e860a65a1aae6c7a9ee6143c52cf0fcd65db45e1773a4fa785bcb158c5827ec6f7fad3188409a4401a71c32a792fce997048684f77b598831eb81e21",
267 Hash::calculate(HashKind::BLAKE2B, "qwerty")
268 );
269}
270#[test]
271fn blake2b_long_hash_test() {
272 assert_eq!(
273 "80472ae0730951dd5daccc2608ac4db554ee37609a205ec05124549d097b96b24138965329dfaa97c62bdd20b5a059b031c96070640744c3a0f6f5bc31167e5c",
274 Hash::calculate(HashKind::BLAKE2B, &"qwert".repeat(40))
275 );
276}
277#[test]
278fn blake2s_short_hash_test() {
279 assert_eq!(
280 "4bb6d05aebc19ab25a7abfc3d283fc66b738f9295065fc684c23b16db775b662",
281 Hash::calculate(HashKind::BLAKE2S, "qwerty")
282 );
283}
284#[test]
285fn blake2s_long_hash_test() {
286 assert_eq!(
287 "72b57e7bae1e4ff79940f04098cbb744908b35edf1caff494eaee3344488090d",
288 Hash::calculate(HashKind::BLAKE2S, &"qwert".repeat(20))
289 );
290}
291#[test]
292fn blake3_short_hash_test() {
293 assert_eq!(
294 "305ff248441f66cdfe5f44be6ad896d366f32910748ed71d0d18f5467b817ce7",
295 Hash::calculate(HashKind::BLAKE3, "qwerty")
296 );
297}
298#[test]
299fn blake3_long_hash_test() {
300 assert_eq!(
301 "2c0989aead13089f1272210c9f58c452f8e6f9c398e7b46ae819d082d01183f7",
302 Hash::calculate(HashKind::BLAKE3, &"qwert".repeat(20))
303 );
304}
305#[test]
306fn ripemd160_short_hash_test() {
307 assert_eq!(
308 "3a0ede1791358f307ae1f211d3fc4acf677644d8",
309 Hash::calculate(HashKind::RIPEMD160, "qwerty")
310 );
311}
312#[test]
313fn ripemd160_long_hash_test() {
314 assert_eq!(
315 "3c46f1b916f88d714395432743e2955d0f2743f2",
316 Hash::calculate(HashKind::RIPEMD160, &"qwert".repeat(20))
317 );
318}
319#[test]
320fn whirlpool_short_hash_test() {
321 assert_eq!(
322 "4925da7da7a56260baf1c37925a8fa24e46ad8b107dcd21f44e39e4751bae1304fc70de7acb847ffa96126bb372de005f5320f1ede6f9df07c7d53f9c160f022",
323 Hash::calculate(HashKind::WHIRLPOOL, "qwerty")
324 );
325}
326#[test]
327fn whirlpool_long_hash_test() {
328 assert_eq!(
329 "e95a46ff079e3a37e6c099db9bc332a3473839a6139958f6d1ea08a37ab902709fe8fb02db4d68818a3c44ae78e60f785cb69f808af6a52b82e120465e2da8df",
330 Hash::calculate(HashKind::WHIRLPOOL, &"qwert".repeat(100))
331 );
332}
333#[test]
334fn sasha_short_hash_test() {
335 assert_eq!(
336 "9548a146e860a65ad857b1b373a0ed1aae6c7a9ee6143c8edf73a05e179152cf0fcd65db45e18458c0ed0358f3773a4fa785bcb158ce061767807ae1f211d7a4f1fbc5c5827ec6f7fad3183fc4a574ffbb768409a4401a71c32acf6770075fa58c792fce997048684f644d87521e5ca477b598831eb81e21",
337 Hash::calculate(HashKind::SASHA, "qwerty")
338 );
339}
340#[test]
341fn sasha_long_hash_test() {
342 assert_eq!(
343 "d370806299e4294a701aaaf6b573b0e1eb34a44cda3a09148e22f4972557a7a1e8ade94b2482398ac63ac6e664e91155a1cba034ca9bd592d07b88aeea27f2406502945ff5837608871d10cfd0de932b094d94c9700b145d920378be4b385548b1a4425a1849068c4abf70145a8641d4648dd2fed2943d73",
344 Hash::calculate(HashKind::SASHA, &"qwert".repeat(100))
345 );
346}