309 lines
10 KiB
Rust
309 lines
10 KiB
Rust
mod blake256;
|
|
|
|
mod blake3;
|
|
mod blake512;
|
|
mod crc32;
|
|
pub use crc32::CRC32TYPE;
|
|
mod md5;
|
|
mod null_hash;
|
|
mod sha1;
|
|
mod sha256;
|
|
mod sha3_256;
|
|
|
|
use std::sync::Arc;
|
|
|
|
type BITS512 = [u8; 64];
|
|
|
|
type BITS256 = [u8; 32];
|
|
type BITS160 = [u8; 20];
|
|
|
|
type BITS128 = [u8; 16];
|
|
|
|
type BITS32 = u32;
|
|
|
|
type ArcU8 = Arc<[u8]>;
|
|
|
|
macro_rules! arc_u8_sized {
|
|
($size: literal) => {
|
|
Arc::new([0u8, $size])
|
|
};
|
|
}
|
|
|
|
fn arc_u8_empty() -> ArcU8 {
|
|
arc_u8_sized!(0)
|
|
}
|
|
|
|
fn bits512_default() -> BITS512 {
|
|
[0; 64]
|
|
}
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum HashReturn {
|
|
CRC32(BITS32, crc32::CRC32TYPE),
|
|
SHA256(BITS256),
|
|
SHA3_256(BITS256),
|
|
BLAKE256(BITS256),
|
|
BLAKE512(BITS512),
|
|
BLAKE3(BITS256),
|
|
SHA1(BITS160),
|
|
MD5(BITS128),
|
|
RAW(ArcU8),
|
|
}
|
|
|
|
impl HashReturn {
|
|
pub fn into_bytes(self) -> Arc<[u8]> {
|
|
match self {
|
|
HashReturn::CRC32(inner, _) => Arc::new(inner.to_be_bytes()),
|
|
HashReturn::SHA256(inner) => Arc::new(inner),
|
|
HashReturn::SHA3_256(inner) => Arc::new(inner),
|
|
HashReturn::BLAKE256(inner) => Arc::new(inner),
|
|
HashReturn::BLAKE512(inner) => Arc::new(inner),
|
|
HashReturn::BLAKE3(inner) => Arc::new(inner),
|
|
HashReturn::SHA1(inner) => Arc::new(inner),
|
|
HashReturn::MD5(inner) => Arc::new(inner),
|
|
HashReturn::RAW(inner) => inner,
|
|
}
|
|
}
|
|
|
|
pub fn as_hex(self) -> String {
|
|
crate::u8_array_to_lower_hex_string(&self.into_bytes()).unwrap()
|
|
}
|
|
|
|
pub fn serialize(self) -> String {
|
|
match self {
|
|
HashReturn::CRC32(_, t) => {
|
|
format!("crc32_{t:?}: {}", self.as_hex())
|
|
}
|
|
HashReturn::SHA256(_) => {
|
|
format!("sha256: {}", self.as_hex())
|
|
}
|
|
HashReturn::SHA3_256(_) => {
|
|
format!("sha3_256: {}", self.as_hex())
|
|
}
|
|
HashReturn::BLAKE256(_) => {
|
|
format!("blake256: {}", self.as_hex())
|
|
}
|
|
HashReturn::BLAKE512(_) => {
|
|
format!("blake512: {}", self.as_hex())
|
|
}
|
|
HashReturn::BLAKE3(_) => {
|
|
format!("blake3: {}", self.as_hex())
|
|
}
|
|
HashReturn::SHA1(_) => {
|
|
format!("sha1: {}", self.as_hex())
|
|
}
|
|
HashReturn::MD5(_) => {
|
|
format!("md5: {}", self.as_hex())
|
|
}
|
|
HashReturn::RAW(_) => {
|
|
format!("raw: {}", self.as_hex())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
trait Hasher {
|
|
fn new() -> Self;
|
|
fn digest(&mut self, bytes: impl AsRef<[u8]>);
|
|
fn complete(self) -> HashReturn;
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub enum HashType {
|
|
CRC32(crc32::CRC32TYPE),
|
|
SHA256,
|
|
SHA3_256,
|
|
BLAKE256,
|
|
BLAKE512,
|
|
BLAKE3,
|
|
SHA1,
|
|
MD5,
|
|
Null,
|
|
}
|
|
|
|
// Why? because static dispatch is why!
|
|
// TODO: Make the concrete types return this too
|
|
// Maybe even a macro that does the below boilerplate? idk
|
|
enum HasherHolder {
|
|
CRC32(crc32::CRC32),
|
|
SHA256(sha256::SHA256),
|
|
SHA3_256(sha3_256::SHA3_256),
|
|
BLAKE256(blake256::BLAKE256),
|
|
BLAKE512(blake512::BLAKE512),
|
|
BLAKE3(blake3::BLAKE3),
|
|
SHA1(sha1::SHA1),
|
|
MD5(md5::MD5),
|
|
NULL(null_hash::NullHash),
|
|
}
|
|
|
|
pub struct Hashes {
|
|
hashers: Vec<HasherHolder>,
|
|
}
|
|
|
|
impl Hashes {
|
|
pub fn new(types: &[HashType]) -> Self {
|
|
let mut hashers = Vec::with_capacity(types.len());
|
|
for t in types {
|
|
match t {
|
|
HashType::CRC32(t) => match t {
|
|
crc32::CRC32TYPE::ISO => hashers.push(HasherHolder::CRC32(crc32::crc32_iso())),
|
|
crc32::CRC32TYPE::CKSUM => {
|
|
hashers.push(HasherHolder::CRC32(crc32::crc32_cksum()))
|
|
}
|
|
crc32::CRC32TYPE::XFER => {
|
|
hashers.push(HasherHolder::CRC32(crc32::crc32_xfer()))
|
|
}
|
|
},
|
|
HashType::SHA256 => hashers.push(HasherHolder::SHA256(sha256::SHA256::new())),
|
|
HashType::SHA3_256 => {
|
|
hashers.push(HasherHolder::SHA3_256(sha3_256::SHA3_256::new()))
|
|
}
|
|
HashType::BLAKE256 => {
|
|
hashers.push(HasherHolder::BLAKE256(blake256::BLAKE256::new()))
|
|
}
|
|
HashType::BLAKE512 => {
|
|
hashers.push(HasherHolder::BLAKE512(blake512::BLAKE512::new()))
|
|
}
|
|
HashType::BLAKE3 => hashers.push(HasherHolder::BLAKE3(blake3::BLAKE3::new())),
|
|
HashType::SHA1 => hashers.push(HasherHolder::SHA1(sha1::SHA1::new())),
|
|
HashType::MD5 => hashers.push(HasherHolder::MD5(md5::MD5::new())),
|
|
HashType::Null => hashers.push(HasherHolder::NULL(null_hash::NullHash::new())),
|
|
}
|
|
}
|
|
|
|
Hashes { hashers }
|
|
}
|
|
|
|
pub fn digest(&mut self, bytes: impl AsRef<[u8]>) {
|
|
for hasher in &mut self.hashers {
|
|
match hasher {
|
|
HasherHolder::CRC32(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::SHA256(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::SHA3_256(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::BLAKE256(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::BLAKE512(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::BLAKE3(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::SHA1(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::MD5(hasher) => hasher.digest(&bytes),
|
|
HasherHolder::NULL(hasher) => hasher.digest(&bytes),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn complete(mut self) -> Vec<HashReturn> {
|
|
let mut ret = Vec::with_capacity(self.hashers.len());
|
|
|
|
for hasher in self.hashers {
|
|
match hasher {
|
|
HasherHolder::CRC32(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::SHA256(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::SHA3_256(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::BLAKE256(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::BLAKE512(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::BLAKE3(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::SHA1(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::MD5(hasher) => ret.push(hasher.complete()),
|
|
HasherHolder::NULL(hasher) => ret.push(hasher.complete()),
|
|
}
|
|
}
|
|
|
|
ret
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use crate::hashes::crc32::CRC32TYPE;
|
|
use crate::hashes::{HashReturn, HashType, Hashes};
|
|
|
|
#[test]
|
|
fn test_multi_hash() {
|
|
let hash_types = [
|
|
HashType::CRC32(CRC32TYPE::CKSUM),
|
|
HashType::CRC32(CRC32TYPE::ISO),
|
|
HashType::CRC32(CRC32TYPE::XFER),
|
|
HashType::SHA256,
|
|
HashType::SHA3_256,
|
|
HashType::BLAKE256,
|
|
HashType::BLAKE512,
|
|
HashType::BLAKE3,
|
|
HashType::SHA1,
|
|
HashType::MD5,
|
|
//HashType::Null,
|
|
];
|
|
let mut hashes = Hashes::new(&hash_types);
|
|
|
|
hashes.digest("HashStream2025");
|
|
|
|
let ret = hashes.complete();
|
|
|
|
// Not using .into_bytes() to properly check each hash type
|
|
for hash in ret {
|
|
match hash {
|
|
HashReturn::CRC32(hash, t) => {
|
|
let hash_out =
|
|
crate::hex_table::u8_array_to_lower_hex_string(&hash.to_be_bytes())
|
|
.unwrap();
|
|
match t {
|
|
CRC32TYPE::CKSUM => {
|
|
assert_eq!(hash_out, "5f4f456d");
|
|
}
|
|
CRC32TYPE::XFER => {
|
|
assert_eq!(hash_out, "99e560da");
|
|
}
|
|
CRC32TYPE::ISO => {
|
|
assert_eq!(hash_out, "66eac774");
|
|
}
|
|
}
|
|
}
|
|
HashReturn::SHA256(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(
|
|
hash_out,
|
|
"9975cc7fe9ae0c307eae57ac62a099f07749d0d7d01362e92435941ca18a635e"
|
|
);
|
|
}
|
|
HashReturn::SHA3_256(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(
|
|
hash_out,
|
|
"47eec6a5beaf06f0bf5f0ee06f0cae374fd46b968849d2b65de2d8623e907e16"
|
|
);
|
|
}
|
|
HashReturn::BLAKE256(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(
|
|
hash_out,
|
|
"850e58e95935ccde7320cc41ff99c41877b4e8956f6c5c09d0a5afd40c659519"
|
|
);
|
|
}
|
|
HashReturn::BLAKE512(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(
|
|
hash_out,
|
|
"29f9c9c6f598e570fa6d036f68bc9e22d34cab2359a1dcf738d9a32a98721a5f0b7de34f20429c814529d3fac96e68a2d37460aeea355a3712e30f601ea3e607"
|
|
);
|
|
}
|
|
HashReturn::BLAKE3(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(
|
|
hash_out,
|
|
"6323d7085cd64ef68d16b2b53ec50de2b65f0f6e9d6fc44833de8925790eb3e6"
|
|
);
|
|
}
|
|
HashReturn::SHA1(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(hash_out, "d07e867570b94d81178a644e4b0359dc354872f1");
|
|
}
|
|
HashReturn::MD5(hash) => {
|
|
let hash_out = crate::hex_table::u8_array_to_lower_hex_string(&hash).unwrap();
|
|
assert_eq!(hash_out, "e001d16d3d95cf04ec4a86ecb4c5ab6a");
|
|
}
|
|
HashReturn::RAW(_) => {
|
|
todo!("Shouldn't be here for this test...")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|