use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; #[derive(Clone, Debug, PartialOrd, Ord, Deserialize, Serialize, Eq, Hash, PartialEq)] pub struct Sha256(#[serde(serialize_with = "as_hex", deserialize_with = "from_hex")] pub [u8; 32]); fn hash_to_hex_string(hash: &[u8; 32]) -> String { use std::fmt::*; let mut hex_string = String::with_capacity(64); for digit in hash.iter() { write!(hex_string, "{:02X}", digit).unwrap(); } hex_string } impl Sha256 { pub fn as_hex_string(&self) -> String { hash_to_hex_string(&self.0) } pub fn from_data(data: &[u8]) -> Self { use sha2::Digest; let mut hasher = sha2::Sha256::new(); hasher.input(data); let hash_result = hasher.result(); let mut hash_arr = [0u8; 32]; for i in 0..32 { hash_arr[i] = hash_result[i]; } Sha256(hash_arr) } pub fn from_hex(hex_str: &str) -> Option { if hex_str.len() != 32 * 2 { return None; // String has wrong length } let mut out = [0u8; 32]; for (i, byte) in out.iter_mut().enumerate() { let string_index = i * 2; *byte = u8::from_str_radix(&hex_str[string_index..=string_index + 1], 16).ok()?; } Some(Sha256(out)) } } impl fmt::Display for Sha256 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for digit in self.0.iter() { write!(f, "{:02X}", digit)? } Ok(()) } } fn as_hex(hash: &[u8; 32], serializer: S) -> Result where S: Serializer, { serializer.serialize_str(&hash_to_hex_string(hash)) } fn from_hex<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> where D: Deserializer<'de>, { use serde::de::Error; String::deserialize(deserializer).and_then(|string| { Ok(Sha256::from_hex(&string) .ok_or_else(|| Error::custom("Invalid HEX String!".to_string()))? .0) }) } #[cfg(test)] mod tests { use super::*; use serde_json; const HASH_BYTES: [u8; 32] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ]; const HASH_STRING: &'static str = r#""000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F""#; #[test] fn serialize() { let hash = serde_json::to_string_pretty(&Sha256(HASH_BYTES)).unwrap(); assert_eq!(&hash, HASH_STRING); } #[test] fn deserialize() { let hash: Sha256 = serde_json::from_str(HASH_STRING).unwrap(); assert_eq!(hash, Sha256(HASH_BYTES)) } #[test] fn fail_deserialize() { // too short. assert_eq!( serde_json::from_str::<'_, Sha256>(r#""0102013""#).is_err(), true ); // wrong radix assert_eq!( serde_json::from_str::<'_, Sha256>(r#""Hallo Welt""#).is_err(), true ); // too long. assert_eq!( serde_json::from_str::<'_, Sha256>( r#""000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F""#).is_err(), true ); } }