use std::sync::Arc;
use crate::Keccak256;
use crate::Keccak384;
use crate::Keccak512;
use crate::Ripemd160;
use crate::Sha256;
use crate::hasher::Hasher;
use base_xx::ByteVec;
use base_xx::SerialiseError;
use base_xx::byte_vec::TryIntoByteVec;
use base_xx::encoded_string::Decodable;
use crate::HashAlgorithm;
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct Hash {
algorithm: HashAlgorithm,
bytes: ByteVec,
}
impl Hash {
#[must_use]
pub const fn new(algorithm: HashAlgorithm, bytes: ByteVec) -> Self {
Self { algorithm, bytes }
}
#[must_use]
pub const fn get_bytes(&self) -> &ByteVec {
&self.bytes
}
#[must_use]
pub const fn get_algorithm(&self) -> HashAlgorithm {
self.algorithm
}
#[must_use]
pub fn verify(&self, bytes: Arc<ByteVec>) -> bool {
match self.algorithm {
HashAlgorithm::SHA256 => {
Sha256::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
}
HashAlgorithm::KECCAK512 => {
Keccak512::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
}
HashAlgorithm::KECCAK256 => {
Keccak256::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
}
HashAlgorithm::KECCAK384 => {
Keccak384::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
}
HashAlgorithm::RIPEMD160 => {
Ripemd160::try_hash(bytes).is_ok_and(|hash| hash.get_bytes() == self.get_bytes())
}
}
}
fn try_as_bytes(&self) -> Result<Vec<u8>, SerialiseError> {
let mut bytes = vec![];
let algorithm: Result<u8, SerialiseError> = self.algorithm.try_into();
match algorithm {
Err(error) => return Err(error),
Ok(algorithm) => bytes.push(algorithm),
}
bytes.extend_from_slice(self.bytes.get_bytes());
Ok(bytes)
}
pub fn try_to_byte_vec(&self) -> Result<Arc<ByteVec>, SerialiseError> {
match self.try_as_bytes() {
Ok(bytes) => Ok(Arc::new(ByteVec::new(Arc::new(bytes)))),
Err(error) => Err(error),
}
}
fn try_from_bytes(bytes: &[u8]) -> Result<Self, SerialiseError> {
let algorithm = HashAlgorithm::try_from(bytes[0]);
match algorithm {
Err(error) => Err(error),
Ok(algorithm) => {
let bytes = bytes[1..].to_vec();
Ok(Self::new(algorithm, ByteVec::new(Arc::new(bytes))))
}
}
}
pub fn try_hash(
byte_vec: Arc<ByteVec>,
algorithm: HashAlgorithm,
) -> Result<Arc<Self>, SerialiseError> {
match algorithm {
HashAlgorithm::SHA256 => Sha256::try_hash(byte_vec),
HashAlgorithm::KECCAK256 => Keccak256::try_hash(byte_vec),
HashAlgorithm::KECCAK384 => Keccak384::try_hash(byte_vec),
HashAlgorithm::KECCAK512 => Keccak512::try_hash(byte_vec),
HashAlgorithm::RIPEMD160 => Ripemd160::try_hash(byte_vec),
}
}
}
impl TryFrom<Arc<ByteVec>> for Hash {
type Error = SerialiseError;
fn try_from(value: Arc<ByteVec>) -> Result<Self, Self::Error> {
match Self::try_from_bytes(value.get_bytes()) {
Ok(hash) => Ok(hash),
Err(err) => Err(err),
}
}
}
impl TryIntoByteVec for Hash {
fn try_into_byte_vec(value: Arc<Self>) -> Result<Arc<ByteVec>, SerialiseError> {
value.try_to_byte_vec()
}
}
impl Decodable for Hash {}
#[cfg(test)]
mod tests {
use super::*;
use base_xx::Encoding;
#[test]
fn test_hash() {
let bytes = Arc::new(ByteVec::new(Arc::new(vec![1, 2, 3])));
match Hash::try_hash(Arc::clone(&bytes), HashAlgorithm::SHA256) {
Ok(hash) => match hash.try_to_byte_vec() {
Ok(bytes) => match bytes.try_encode(Encoding::Base36) {
Ok(hash_ss) => {
let hash_str = hash_ss.get_string();
slogger::debug!("hash: {hash_str}");
slogger::debug!("hash debug: {hash:#?}");
assert_eq!(
hash_str,
"hwis74tcngndmvw8t0jaf8baow2455synbsyr8u6vfvfvi6mgld"
);
}
Err(error) => slogger::debug!("serialstring error: {error:?}"),
},
Err(error) => slogger::debug!("serialstring error: {error:?}"),
},
Err(error) => slogger::debug!("hash error: {error:?}"),
}
}
}