#[macro_use]
extern crate mopa;
#[cfg(any(feature = "sha3", feature = "doc"))]
extern crate sha3 as lib_sha3;
#[cfg(any(feature = "sha3", feature = "doc"))]
pub mod sha3;
#[cfg(any(feature = "sha2", feature = "doc"))]
extern crate sha2 as lib_sha2;
#[cfg(any(feature = "sha2", feature = "doc"))]
pub mod sha2;
use std::fmt;
use std::io::Error as IoError;
#[derive(Debug)]
pub enum HashError {
IncorrectSize,
}
pub trait HashType {
fn as_string(&self) -> &'static str;
fn new_with_content(&self, f: &[u8]) -> Result<Box<Hash>, HashError>;
fn len(&self) -> usize;
}
impl fmt::Debug for HashType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "HashType<{}>", self.as_string())
}
}
pub trait Hash: mopa::Any + std::fmt::Debug + std::fmt::LowerHex + std::fmt::UpperHex {
fn hash_type(&self) -> &'static HashType
where
Self: Sized;
fn as_slice(&self) -> &[u8];
}
mopafy!(Hash);
pub trait Hasher {
type HasherOutput: Hash;
fn output_type() -> &'static HashType;
fn new() -> Self;
fn input(&mut self, buf: &[u8]) -> Result<(), IoError>;
fn result(self) -> Box<Self::HasherOutput>;
}
#[macro_export]
macro_rules! new_hash {
( $hname:ident, $tname:ident, $len:expr, $str:expr ) => {
#[allow(non_camel_case_types)]
pub struct $tname;
impl HashType for $tname {
fn as_string(&self) -> &'static str {
$str
}
fn len(&self) -> usize {
$len
}
fn new_with_content(&self, c: &[u8]) -> Result<Box<Hash>, HashError> {
if c.len() != self.len() {
Err(self::HashError::IncorrectSize)
} else {
let mut arr: Box<$hname> = Box::new($hname([0; $len]));
arr.0.copy_from_slice(c);
Ok(arr as Box<Hash>)
}
}
}
#[allow(non_camel_case_types)]
pub struct $hname(pub [u8; $len]);
impl Hash for $hname {
fn hash_type(&self) -> &'static HashType {
&$tname as &HashType
}
fn as_slice(&self) -> &[u8] {
&self.0
}
}
impl std::fmt::LowerHex for $hname {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for &b in self.as_slice().iter() {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
impl std::fmt::UpperHex for $hname {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for &b in self.as_slice().iter() {
write!(f, "{:02X}", b)?;
}
Ok(())
}
}
impl std::fmt::Debug for $hname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Hash<{}, {:#02x}>", self.hash_type().as_string(), self)
}
}
};
}
#[test]
fn test_struct_sizes() {
assert!(std::mem::size_of::<sha2::HashType_Sha2_512>() == 0);
assert!(std::mem::size_of::<sha3::HashType_Sha3_512>() == 0);
assert!(std::mem::size_of::<sha2::Hash_Sha2_256>() == 32);
assert!(std::mem::size_of::<sha3::Hash_Sha3_512>() == 64);
}
#[test]
fn test_downcast() {
let sha3_hash: Box<dyn Hash> = Box::new(sha3::Hash_Sha3_512([0xAF as u8; 64]));
let _sha3_hash: Box<sha3::Hash_Sha3_512> = sha3_hash.downcast().unwrap();
let sha2_hash: Box<dyn Hash> = Box::new(sha2::Hash_Sha2_256([0xFA as u8; 32]));
let maybe_sha3_hash: Result<Box<sha3::Hash_Sha3_256>, Box<dyn Hash>> = sha2_hash.downcast();
maybe_sha3_hash.unwrap_err();
}