bitcoin_hashes/
sha512_256.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA512_256 implementation.
4//!
5//! SHA512/256 is a hash function that uses the sha512 algorithm but it truncates
6//! the output to 256 bits. It has different initial constants than sha512 so it
7//! produces an entirely different hash compared to sha512. More information at
8//! <https://eprint.iacr.org/2010/548.pdf>.
9
10use core::ops::Index;
11use core::slice::SliceIndex;
12use core::str;
13
14use crate::{sha512, FromSliceError};
15
16crate::internal_macros::hash_type! {
17    256,
18    false,
19    "Output of the SHA512/256 hash function.\n\nSHA512/256 is a hash function that uses the sha512 algorithm but it truncates the output to 256 bits. It has different initial constants than sha512 so it produces an entirely different hash compared to sha512. More information at <https://eprint.iacr.org/2010/548.pdf>."
20}
21
22fn from_engine(e: HashEngine) -> Hash {
23    let mut ret = [0; 32];
24    ret.copy_from_slice(&sha512::from_engine(e.0)[..32]);
25    Hash(ret)
26}
27
28/// Engine to compute SHA512/256 hash function.
29///
30/// SHA512/256 is a hash function that uses the sha512 algorithm but it truncates
31/// the output to 256 bits. It has different initial constants than sha512 so it
32/// produces an entirely different hash compared to sha512. More information at
33/// <https://eprint.iacr.org/2010/548.pdf>.
34#[derive(Clone)]
35pub struct HashEngine(sha512::HashEngine);
36
37impl Default for HashEngine {
38    #[rustfmt::skip]
39    fn default() -> Self {
40        HashEngine(sha512::HashEngine::sha512_256())
41    }
42}
43
44impl crate::HashEngine for HashEngine {
45    type MidState = [u8; 64];
46
47    fn midstate(&self) -> [u8; 64] { self.0.midstate() }
48
49    const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
50
51    fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() }
52
53    fn input(&mut self, inp: &[u8]) { self.0.input(inp); }
54}
55
56#[cfg(test)]
57mod tests {
58    #[test]
59    #[cfg(feature = "alloc")]
60    fn test() {
61        use crate::{sha512_256, Hash, HashEngine};
62
63        #[derive(Clone)]
64        struct Test {
65            input: &'static str,
66            output: Vec<u8>,
67            output_str: &'static str,
68        }
69
70        #[rustfmt::skip]
71        let tests = vec![
72            // Examples from go sha512/256 tests.
73            Test {
74                input: "",
75                output: vec![
76                    0xc6, 0x72, 0xb8, 0xd1, 0xef, 0x56, 0xed, 0x28,
77                    0xab, 0x87, 0xc3, 0x62, 0x2c, 0x51, 0x14, 0x06,
78                    0x9b, 0xdd, 0x3a, 0xd7, 0xb8, 0xf9, 0x73, 0x74,
79                    0x98, 0xd0, 0xc0, 0x1e, 0xce, 0xf0, 0x96, 0x7a,
80                ],
81                output_str: "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"
82            },
83            Test {
84                input: "abcdef",
85                output: vec![
86                    0xe4, 0xfd, 0xcb, 0x11, 0xd1, 0xac, 0x14, 0xe6,
87                    0x98, 0x74, 0x3a, 0xcd, 0x88, 0x05, 0x17, 0x4c,
88                    0xea, 0x5d, 0xdc, 0x0d, 0x31, 0x2e, 0x3e, 0x47,
89                    0xf6, 0x37, 0x20, 0x32, 0x57, 0x1b, 0xad, 0x84,
90                ],
91                output_str: "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84",
92            },
93            Test {
94                input: "Discard medicine more than two years old.",
95                output: vec![
96                    0x69, 0x0c, 0x8a, 0xd3, 0x91, 0x6c, 0xef, 0xd3,
97                    0xad, 0x29, 0x22, 0x6d, 0x98, 0x75, 0x96, 0x5e,
98                    0x3e, 0xe9, 0xec, 0x0d, 0x44, 0x82, 0xea, 0xcc,
99                    0x24, 0x8f, 0x2f, 0xf4, 0xaa, 0x0d, 0x8e, 0x5b,
100                ],
101                output_str: "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b",
102            },
103            Test {
104                input: "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
105                output: vec![
106                    0xb5, 0xba, 0xf7, 0x47, 0xc3, 0x07, 0xf9, 0x88,
107                    0x49, 0xec, 0x88, 0x1c, 0xf0, 0xd4, 0x86, 0x05,
108                    0xae, 0x4e, 0xdd, 0x38, 0x63, 0x72, 0xae, 0xa9,
109                    0xb2, 0x6e, 0x71, 0xdb, 0x51, 0x7e, 0x65, 0x0b,
110                ],
111                output_str: "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b",
112            },
113            Test {
114                input: "The major problem is with sendmail.  -Mark Horton",
115                output: vec![
116                    0x53, 0xed, 0x5f, 0x9b, 0x5c, 0x0b, 0x67, 0x4a,
117                    0xc0, 0xf3, 0x42, 0x5d, 0x9f, 0x9a, 0x5d, 0x46,
118                    0x26, 0x55, 0xb0, 0x7c, 0xc9, 0x0f, 0x5d, 0x0f,
119                    0x69, 0x2e, 0xec, 0x09, 0x38, 0x84, 0xa6, 0x07,
120                ],
121                output_str: "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607",
122            },
123        ];
124
125        for test in tests {
126            // Hash through high-level API, check hex encoding/decoding
127            let hash = sha512_256::Hash::hash(test.input.as_bytes());
128            assert_eq!(hash, test.output_str.parse::<sha512_256::Hash>().expect("parse hex"));
129            assert_eq!(&hash[..], &test.output[..]);
130            assert_eq!(&hash.to_string(), &test.output_str);
131
132            // Hash through engine, checking that we can input byte by byte
133            let mut engine = sha512_256::Hash::engine();
134            for ch in test.input.as_bytes() {
135                engine.0.input(&[*ch]);
136            }
137            let manual_hash = sha512_256::Hash::from_engine(engine);
138            assert_eq!(hash, manual_hash);
139            assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice());
140        }
141    }
142}
143
144#[cfg(bench)]
145mod benches {
146    use test::Bencher;
147
148    use crate::{sha512_256, Hash, HashEngine};
149
150    #[bench]
151    pub fn sha512_256_10(bh: &mut Bencher) {
152        let mut engine = sha512_256::Hash::engine();
153        let bytes = [1u8; 10];
154        bh.iter(|| {
155            engine.input(&bytes);
156        });
157        bh.bytes = bytes.len() as u64;
158    }
159
160    #[bench]
161    pub fn sha512_256_1k(bh: &mut Bencher) {
162        let mut engine = sha512_256::Hash::engine();
163        let bytes = [1u8; 1024];
164        bh.iter(|| {
165            engine.input(&bytes);
166        });
167        bh.bytes = bytes.len() as u64;
168    }
169
170    #[bench]
171    pub fn sha512_256_64k(bh: &mut Bencher) {
172        let mut engine = sha512_256::Hash::engine();
173        let bytes = [1u8; 65536];
174        bh.iter(|| {
175            engine.input(&bytes);
176        });
177        bh.bytes = bytes.len() as u64;
178    }
179}