hash_lib/
hash.rs

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}