//! SHA256d, a.k.a., double SHA2, a.k.a., 2 SHA 2 Furious use std::{fmt, io::prelude::*}; use sha2::{Digest, Sha256}; /// An `io::Write` instance that produces a SHA256d output. #[derive(Default)] pub struct Writer { hash: Sha256, } impl Writer { /// Consume the Writer and produce the hash result. pub fn finish(self) -> [u8; 32] { let result1 = self.hash.finalize(); let result2 = Sha256::digest(&result1); let mut buffer = [0u8; 32]; buffer[0..32].copy_from_slice(&result2[0..32]); buffer } } impl Write for Writer { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.hash.update(buf); Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } /// A 4-byte checksum using truncated double-SHA256 (two rounds of SHA256). #[derive(Copy, Clone, Eq, PartialEq)] pub struct Checksum(pub [u8; 4]); impl<'a> From<&'a [u8]> for Checksum { fn from(bytes: &'a [u8]) -> Self { let hash1 = Sha256::digest(bytes); let hash2 = Sha256::digest(&hash1); let mut checksum = [0u8; 4]; checksum[0..4].copy_from_slice(&hash2[0..4]); Self(checksum) } } impl fmt::Debug for Checksum { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Sha256dChecksum") .field(&hex::encode(&self.0)) .finish() } } #[cfg(test)] mod tests { use super::*; #[test] fn sha256d_checksum() { // https://en.bitcoin.it/wiki/Protocol_documentation#Hashes let input = b"hello"; let checksum = Checksum::from(&input[..]); let expected = Checksum([0x95, 0x95, 0xc9, 0xdf]); assert_eq!(checksum, expected); } #[test] fn sha256d_checksum_debug() { let input = b"hello"; let checksum = Checksum::from(&input[..]); assert_eq!(format!("{:?}", checksum), "Sha256dChecksum(\"9595c9df\")"); } }