use serde::{Serialize, Deserialize}; use std::convert::TryInto; #[cfg(any(test, test_utilities))] use rand::Rng; /// An object that can be meaningfully hashed. pub trait Hashable { /// Hash the object using SHA256. fn hash(&self) -> H256; } /// A SHA256 hash. #[derive(Eq, PartialEq, Serialize, Deserialize, Clone, Hash, Default, Copy)] pub struct H256([u8; 32]); // big endian u256 impl Hashable for H256 { fn hash(&self) -> H256 { ring::digest::digest(&ring::digest::SHA256, &self.0).into() } } impl std::fmt::Display for H256 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let start = if let Some(precision) = f.precision() { if precision >= 64 { 0 } else { 32 - precision / 2 } } else { 0 }; for byte_idx in start..32 { write!(f, "{:>02x}", &self.0[byte_idx])?; } Ok(()) } } impl std::fmt::Debug for H256 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "{:>02x}{:>02x}..{:>02x}{:>02x}", &self.0[0], &self.0[1], &self.0[30], &self.0[31] ) } } impl std::convert::AsRef<[u8]> for H256 { fn as_ref(&self) -> &[u8] { &self.0 } } impl std::convert::From<&[u8; 32]> for H256 { fn from(input: &[u8; 32]) -> H256 { let mut buffer: [u8; 32] = [0; 32]; buffer[..].copy_from_slice(input); H256(buffer) } } impl std::convert::From<&H256> for [u8; 32] { fn from(input: &H256) -> [u8; 32] { let mut buffer: [u8; 32] = [0; 32]; buffer[..].copy_from_slice(&input.0); buffer } } impl std::convert::From<[u8; 32]> for H256 { fn from(input: [u8; 32]) -> H256 { H256(input) } } impl std::convert::From<H256> for [u8; 32] { fn from(input: H256) -> [u8; 32] { input.0 } } impl std::convert::From<ring::digest::Digest> for H256 { fn from(input: ring::digest::Digest) -> H256 { let mut raw_hash: [u8; 32] = [0; 32]; raw_hash[0..32].copy_from_slice(input.as_ref()); H256(raw_hash) } } impl Ord for H256 { fn cmp(&self, other: &H256) -> std::cmp::Ordering { let self_higher = u128::from_be_bytes(self.0[0..16].try_into().unwrap()); let self_lower = u128::from_be_bytes(self.0[16..32].try_into().unwrap()); let other_higher = u128::from_be_bytes(other.0[0..16].try_into().unwrap()); let other_lower = u128::from_be_bytes(other.0[16..32].try_into().unwrap()); let higher = self_higher.cmp(&other_higher); match higher { std::cmp::Ordering::Equal => self_lower.cmp(&other_lower), _ => higher, } } } impl PartialOrd for H256 { fn partial_cmp(&self, other: &H256) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) } } pub fn random_hash() -> H256 { let mut rng = rand::thread_rng(); let random_bytes: Vec<u8> = (0..32).map(|_| rand::random()).collect(); let mut raw_bytes = [0; 32]; raw_bytes.copy_from_slice(&random_bytes); (&raw_bytes).into() } #[cfg(any(test, test_utilities))] pub fn generate_random_hash() -> H256 { let mut rng = rand::thread_rng(); let random_bytes: Vec<u8> = (0..32).map(|_| rng.gen()).collect(); let mut raw_bytes = [0; 32]; raw_bytes.copy_from_slice(&random_bytes); (&raw_bytes).into() }