bitcoin_hashes/sha256d/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA256d implementation (double SHA256).
4
5use crate::sha256;
6
7crate::internal_macros::general_hash_type! {
8    256,
9    true,
10    "Output of the SHA256d hash function."
11}
12
13impl Hash {
14    /// Finalize a hash engine to produce a hash.
15    pub fn from_engine(e: HashEngine) -> Self {
16        let sha2 = sha256::Hash::from_engine(e.0);
17        let sha2d = sha256::Hash::hash(sha2.as_byte_array());
18
19        let mut ret = [0; 32];
20        ret.copy_from_slice(sha2d.as_byte_array());
21        Self(ret)
22    }
23}
24
25/// Engine to compute SHA256d hash function.
26#[derive(Debug, Clone)]
27pub struct HashEngine(sha256::HashEngine);
28
29impl HashEngine {
30    /// Constructs a new SHA256d hash engine.
31    pub const fn new() -> Self { Self(sha256::HashEngine::new()) }
32}
33
34impl Default for HashEngine {
35    fn default() -> Self { Self::new() }
36}
37
38impl crate::HashEngine for HashEngine {
39    type Hash = Hash;
40    type Bytes = [u8; 32];
41    const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
42
43    fn input(&mut self, data: &[u8]) { self.0.input(data) }
44    fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
45    fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
46}
47
48#[cfg(test)]
49mod tests {
50    #[allow(unused_imports)] // whether this is used depends on features
51    use crate::sha256d;
52
53    #[test]
54    #[cfg(feature = "alloc")]
55    #[cfg(feature = "hex")]
56    fn test() {
57        use alloc::string::ToString;
58
59        use crate::{sha256, HashEngine};
60
61        #[derive(Clone)]
62        struct Test {
63            input: &'static str,
64            output: [u8; 32],
65            output_str: &'static str,
66        }
67
68        #[rustfmt::skip]
69        let tests = [
70            // Test vector copied out of rust-bitcoin
71            Test {
72                input: "",
73                output: [
74                    0x5d, 0xf6, 0xe0, 0xe2, 0x76, 0x13, 0x59, 0xd3,
75                    0x0a, 0x82, 0x75, 0x05, 0x8e, 0x29, 0x9f, 0xcc,
76                    0x03, 0x81, 0x53, 0x45, 0x45, 0xf5, 0x5c, 0xf4,
77                    0x3e, 0x41, 0x98, 0x3f, 0x5d, 0x4c, 0x94, 0x56,
78                ],
79                output_str: "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d",
80            },
81        ];
82
83        for test in tests {
84            // Hash through high-level API, check hex encoding/decoding
85            let hash = sha256d::Hash::hash(test.input.as_bytes());
86            assert_eq!(hash, test.output_str.parse::<sha256d::Hash>().expect("parse hex"));
87            assert_eq!(hash.as_byte_array(), &test.output);
88            assert_eq!(hash.to_string(), test.output_str);
89
90            // Hash through engine, checking that we can input byte by byte
91            let mut engine = sha256d::Hash::engine();
92            for ch in test.input.as_bytes() {
93                engine.input(&[*ch]);
94            }
95            let manual_hash = sha256d::Hash::from_engine(engine);
96            assert_eq!(hash, manual_hash);
97
98            // Hash by computing a sha256 then `hash_again`ing it
99            let sha2_hash = sha256::Hash::hash(test.input.as_bytes());
100            let sha2d_hash = sha2_hash.hash_again();
101            assert_eq!(hash, sha2d_hash);
102
103            assert_eq!(hash.to_byte_array(), test.output);
104        }
105    }
106
107    #[test]
108    #[cfg(feature = "alloc")]
109    #[cfg(feature = "hex")]
110    fn fmt_roundtrips() {
111        use alloc::format;
112
113        let hash = sha256d::Hash::hash(b"some arbitrary bytes");
114        let hex = format!("{}", hash);
115        let rinsed = hex.parse::<sha256d::Hash>().expect("failed to parse hex");
116        assert_eq!(rinsed, hash)
117    }
118
119    #[test]
120    #[cfg(feature = "serde")]
121    fn sha256_serde() {
122        use serde_test::{assert_tokens, Configure, Token};
123
124        #[rustfmt::skip]
125        static HASH_BYTES: [u8; 32] = [
126            0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
127            0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
128            0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
129            0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
130        ];
131
132        let hash = sha256d::Hash::from_byte_array(HASH_BYTES);
133        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
134        assert_tokens(
135            &hash.readable(),
136            &[Token::Str("6cfb35868c4465b7c289d7d5641563aa973db6a929655282a7bf95c8257f53ef")],
137        );
138    }
139}