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