bitcoin_hashes/
sha256d.rs

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