#![warn(unused_assignments)]
#![warn(unreachable_patterns)]
use crypto::digest::Digest;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum HashKind {
SASHA = 0,
MD5,
SHA1,
SHA256,
SHA512,
BLAKE2B,
BLAKE2S,
BLAKE3,
RIPEMD160,
WHIRLPOOL,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hash {
pub hash_type: HashKind,
}
trait SubStr {
fn sub_strings(&self, length: usize) -> Vec<&str>;
}
impl SubStr for str {
fn sub_strings(&self, sub_len: usize) -> Vec<&str> {
let mut subs = Vec::with_capacity(self.len() / sub_len);
let mut iter = self.chars();
let mut pos = 0;
while pos < self.len() {
let mut len = 0;
for ch in iter.by_ref().take(sub_len) {
len += ch.len_utf8();
}
subs.push(&self[pos..pos + len]);
pos += len;
}
subs
}
}
impl HashKind {
pub fn length(&self) -> u16 {
match self {
HashKind::SASHA => 240,
HashKind::MD5 => 32,
HashKind::SHA1 => 40,
HashKind::SHA256 => 64,
HashKind::SHA512 => 128,
HashKind::BLAKE2B => 128,
HashKind::BLAKE2S => 64,
HashKind::BLAKE3 => 64,
HashKind::RIPEMD160 => 40,
HashKind::WHIRLPOOL => 128,
}
}
}
pub trait U8ToHashKind {
fn to_hash_kind(&self) -> HashKind;
}
impl U8ToHashKind for u8 {
fn to_hash_kind(&self) -> HashKind {
match self {
0 => HashKind::SASHA,
1 => HashKind::MD5,
2 => HashKind::SHA1,
3 => HashKind::SHA256,
4 => HashKind::SHA512,
5 => HashKind::BLAKE2B,
6 => HashKind::BLAKE2B,
7 => HashKind::BLAKE3,
8 => HashKind::RIPEMD160,
9 => HashKind::WHIRLPOOL,
_ => HashKind::SASHA,
}
}
}
impl Hash {
pub fn calculate(hash_type: HashKind, hash_data: &str) -> String {
match hash_type {
HashKind::SASHA => {
let blake2b_temp_result = Self::calculate(HashKind::BLAKE2B, hash_data);
let split_blake2b = &blake2b_temp_result.sub_strings(16);
let md5_temp_result = Self::calculate(HashKind::MD5, hash_data);
let split_md5 = &md5_temp_result.sub_strings(4);
let sha1_temp_result = Self::calculate(HashKind::SHA1, hash_data);
let split_sha1 = &sha1_temp_result.sub_strings(5);
let ripemd160_temp_result = Self::calculate(HashKind::RIPEMD160, hash_data);
let split_ripemd160 = &ripemd160_temp_result.sub_strings(5);
let mut result_val = String::new();
for x in 0..8 {
if x < 4 {
result_val = result_val
+ split_blake2b[x]
+ split_md5[x]
+ split_sha1[x]
+ split_ripemd160[x];
} else {
result_val = result_val
+ split_ripemd160[x]
+ split_sha1[x]
+ split_md5[x]
+ split_blake2b[x];
}
}
return result_val;
}
HashKind::MD5 => {
let mut hash_obj = crypto::md5::Md5::new();
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::SHA1 => {
let mut hash_obj = crypto::sha1::Sha1::new();
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::SHA256 => {
let mut hash_obj = crypto::sha2::Sha256::new();
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::SHA512 => {
let mut hash_obj = crypto::sha2::Sha512::new();
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::BLAKE2B => {
let mut hash_obj = crypto::blake2b::Blake2b::new(64);
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::RIPEMD160 => {
let mut hash_obj = crypto::ripemd160::Ripemd160::new();
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::WHIRLPOOL => {
let mut hash_obj = crypto::whirlpool::Whirlpool::new();
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::BLAKE2S => {
let mut hash_obj = crypto::blake2s::Blake2s::new(32);
hash_obj.input_str(hash_data);
return hash_obj.result_str();
}
HashKind::BLAKE3 => {
return blake3::hash(hash_data.as_bytes()).to_string();
}
}
}
pub fn wallet_calculation(in_data: &str) -> String {
const DEFAULT_HEX_ALPHABET_STRING: &str = "0123456789abcdef";
const SIMPLE_HASH_ALPHABET_FOR_HEX_RESULT: &str = "fedcba9876543210";
Self::replace_char(
Self::calculate(HashKind::SASHA, &in_data.chars().rev().collect::<String>()),
DEFAULT_HEX_ALPHABET_STRING.to_string(),
SIMPLE_HASH_ALPHABET_FOR_HEX_RESULT.to_string(),
)
}
fn replace_char(source_text: String, from_text: String, to_text: String) -> String {
let mut input = source_text.chars().collect::<Vec<char>>();
let mut replaced: Vec<bool> = Vec::with_capacity(input.len());
for _ in 0..input.len() {
replaced.push(false);
}
for i in 0..from_text.len() {
for j in 0..input.len() {
if replaced[j] == false && input[j] == from_text.chars().nth(i).unwrap() {
input[j] = to_text.chars().nth(i).unwrap();
replaced[j] = true;
}
}
}
input.iter().collect::<String>()
}
}
#[test]
fn md5_short_hash_test() {
assert_eq!(
"d8578edf8458ce06fbc5bb76a58c5ca4",
Hash::calculate(HashKind::MD5, "qwerty")
);
}
#[test]
fn md5_long_hash_test() {
assert_eq!(
"65be673803a67c8f37e9ec51dfb66bc0",
Hash::calculate(HashKind::MD5, &"qwert".repeat(10))
);
}
#[test]
fn sha1_short_hash_test() {
assert_eq!(
"b1b3773a05c0ed0176787a4f1574ff0075f7521e",
Hash::calculate(HashKind::SHA1, "qwerty")
);
}
#[test]
fn sha1_long_hash_test() {
assert_eq!(
"8ce2bfdafe27ef4c3d1fae9db2a2c428cd5c063a",
Hash::calculate(HashKind::SHA1, &"qwert".repeat(10))
);
}
#[test]
fn sha256_short_hash_test() {
assert_eq!(
"65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5",
Hash::calculate(HashKind::SHA256, "qwerty")
);
}
#[test]
fn sha256_long_hash_test() {
assert_eq!(
"a69a351e7de07f954b1ca107a1f38592fc35afe6ed625b80959311c8ce831d2b",
Hash::calculate(HashKind::SHA256, &"qwert".repeat(20))
);
}
#[test]
fn sha512_short_hash_test() {
assert_eq!(
"0dd3e512642c97ca3f747f9a76e374fbda73f9292823c0313be9d78add7cdd8f72235af0c553dd26797e78e1854edee0ae002f8aba074b066dfce1af114e32f8",
Hash::calculate(HashKind::SHA512, "qwerty")
);
}
#[test]
fn sha512_long_hash_test() {
assert_eq!(
"409b286f9e9be0eb9ffc6a89a96742c1d4e56bcc49441cc2e67f7c1aa3ab829bc48680bda8125cca10f18eea1d046420064fb69f82b6b1265581a0467c4d9318",
Hash::calculate(HashKind::SHA512, &"qwert".repeat(40))
);
}
#[test]
fn blake2b_short_hash_test() {
assert_eq!(
"9548a146e860a65a1aae6c7a9ee6143c52cf0fcd65db45e1773a4fa785bcb158c5827ec6f7fad3188409a4401a71c32a792fce997048684f77b598831eb81e21",
Hash::calculate(HashKind::BLAKE2B, "qwerty")
);
}
#[test]
fn blake2b_long_hash_test() {
assert_eq!(
"80472ae0730951dd5daccc2608ac4db554ee37609a205ec05124549d097b96b24138965329dfaa97c62bdd20b5a059b031c96070640744c3a0f6f5bc31167e5c",
Hash::calculate(HashKind::BLAKE2B, &"qwert".repeat(40))
);
}
#[test]
fn blake2s_short_hash_test() {
assert_eq!(
"4bb6d05aebc19ab25a7abfc3d283fc66b738f9295065fc684c23b16db775b662",
Hash::calculate(HashKind::BLAKE2S, "qwerty")
);
}
#[test]
fn blake2s_long_hash_test() {
assert_eq!(
"72b57e7bae1e4ff79940f04098cbb744908b35edf1caff494eaee3344488090d",
Hash::calculate(HashKind::BLAKE2S, &"qwert".repeat(20))
);
}
#[test]
fn blake3_short_hash_test() {
assert_eq!(
"305ff248441f66cdfe5f44be6ad896d366f32910748ed71d0d18f5467b817ce7",
Hash::calculate(HashKind::BLAKE3, "qwerty")
);
}
#[test]
fn blake3_long_hash_test() {
assert_eq!(
"2c0989aead13089f1272210c9f58c452f8e6f9c398e7b46ae819d082d01183f7",
Hash::calculate(HashKind::BLAKE3, &"qwert".repeat(20))
);
}
#[test]
fn ripemd160_short_hash_test() {
assert_eq!(
"3a0ede1791358f307ae1f211d3fc4acf677644d8",
Hash::calculate(HashKind::RIPEMD160, "qwerty")
);
}
#[test]
fn ripemd160_long_hash_test() {
assert_eq!(
"3c46f1b916f88d714395432743e2955d0f2743f2",
Hash::calculate(HashKind::RIPEMD160, &"qwert".repeat(20))
);
}
#[test]
fn whirlpool_short_hash_test() {
assert_eq!(
"4925da7da7a56260baf1c37925a8fa24e46ad8b107dcd21f44e39e4751bae1304fc70de7acb847ffa96126bb372de005f5320f1ede6f9df07c7d53f9c160f022",
Hash::calculate(HashKind::WHIRLPOOL, "qwerty")
);
}
#[test]
fn whirlpool_long_hash_test() {
assert_eq!(
"e95a46ff079e3a37e6c099db9bc332a3473839a6139958f6d1ea08a37ab902709fe8fb02db4d68818a3c44ae78e60f785cb69f808af6a52b82e120465e2da8df",
Hash::calculate(HashKind::WHIRLPOOL, &"qwert".repeat(100))
);
}
#[test]
fn sasha_short_hash_test() {
assert_eq!(
"9548a146e860a65ad857b1b373a0ed1aae6c7a9ee6143c8edf73a05e179152cf0fcd65db45e18458c0ed0358f3773a4fa785bcb158ce061767807ae1f211d7a4f1fbc5c5827ec6f7fad3183fc4a574ffbb768409a4401a71c32acf6770075fa58c792fce997048684f644d87521e5ca477b598831eb81e21",
Hash::calculate(HashKind::SASHA, "qwerty")
);
}
#[test]
fn sasha_long_hash_test() {
assert_eq!(
"d370806299e4294a701aaaf6b573b0e1eb34a44cda3a09148e22f4972557a7a1e8ade94b2482398ac63ac6e664e91155a1cba034ca9bd592d07b88aeea27f2406502945ff5837608871d10cfd0de932b094d94c9700b145d920378be4b385548b1a4425a1849068c4abf70145a8641d4648dd2fed2943d73",
Hash::calculate(HashKind::SASHA, &"qwert".repeat(100))
);
}