zebra_chain/serialization/
sha256d.rs

1//! SHA256d, a.k.a., double SHA2, a.k.a., 2 SHA 2 Furious
2
3use std::{fmt, io::prelude::*};
4
5use sha2::{Digest, Sha256};
6
7/// An `io::Write` instance that produces a SHA256d output.
8#[derive(Default)]
9pub struct Writer {
10    hash: Sha256,
11}
12
13impl Writer {
14    /// Consume the Writer and produce the hash result.
15    pub fn finish(self) -> [u8; 32] {
16        let result1 = self.hash.finalize();
17        let result2 = Sha256::digest(result1);
18        let mut buffer = [0u8; 32];
19        buffer[0..32].copy_from_slice(&result2[0..32]);
20        buffer
21    }
22}
23
24impl Write for Writer {
25    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
26        self.hash.update(buf);
27        Ok(buf.len())
28    }
29
30    fn flush(&mut self) -> std::io::Result<()> {
31        Ok(())
32    }
33}
34
35/// A 4-byte checksum using truncated double-SHA256 (two rounds of SHA256).
36#[derive(Copy, Clone, Eq, PartialEq)]
37pub struct Checksum(pub [u8; 4]);
38
39impl<'a> From<&'a [u8]> for Checksum {
40    fn from(bytes: &'a [u8]) -> Self {
41        let hash1 = Sha256::digest(bytes);
42        let hash2 = Sha256::digest(hash1);
43        let mut checksum = [0u8; 4];
44        checksum[0..4].copy_from_slice(&hash2[0..4]);
45        Self(checksum)
46    }
47}
48
49impl fmt::Debug for Checksum {
50    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51        f.debug_tuple("Sha256dChecksum")
52            .field(&hex::encode(self.0))
53            .finish()
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn sha256d_checksum() {
63        let _init_guard = zebra_test::init();
64
65        // https://en.bitcoin.it/wiki/Protocol_documentation#Hashes
66        let input = b"hello";
67        let checksum = Checksum::from(&input[..]);
68        let expected = Checksum([0x95, 0x95, 0xc9, 0xdf]);
69        assert_eq!(checksum, expected);
70    }
71
72    #[test]
73    fn sha256d_checksum_debug() {
74        let _init_guard = zebra_test::init();
75
76        let input = b"hello";
77        let checksum = Checksum::from(&input[..]);
78
79        assert_eq!(format!("{checksum:?}"), "Sha256dChecksum(\"9595c9df\")");
80    }
81}