bitcoin_hashes/
sha512.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA512 implementation.
4
5use core::cmp;
6
7use crate::{incomplete_block_len, HashEngine as _};
8
9crate::internal_macros::general_hash_type! {
10    512,
11    false,
12    "Output of the SHA512 hash function."
13}
14
15#[cfg(not(hashes_fuzz))]
16pub(crate) fn from_engine(mut e: HashEngine) -> Hash {
17    // pad buffer with a single 1-bit then all 0s, until there are exactly 16 bytes remaining
18    let n_bytes_hashed = e.bytes_hashed;
19
20    let zeroes = [0; BLOCK_SIZE - 16];
21    e.input(&[0x80]);
22    if incomplete_block_len(&e) > zeroes.len() {
23        e.input(&zeroes);
24    }
25    let pad_length = zeroes.len() - incomplete_block_len(&e);
26    e.input(&zeroes[..pad_length]);
27    debug_assert_eq!(incomplete_block_len(&e), zeroes.len());
28
29    e.input(&[0; 8]);
30    e.input(&(8 * n_bytes_hashed).to_be_bytes());
31    debug_assert_eq!(incomplete_block_len(&e), 0);
32
33    Hash(e.midstate())
34}
35
36#[cfg(hashes_fuzz)]
37pub(crate) fn from_engine(e: HashEngine) -> Hash {
38    let mut hash = e.midstate();
39    hash[0] ^= 0xff; // Make this distinct from SHA-256
40    Hash(hash)
41}
42
43pub(crate) const BLOCK_SIZE: usize = 128;
44
45/// Engine to compute SHA512 hash function.
46#[derive(Clone)]
47pub struct HashEngine {
48    h: [u64; 8],
49    bytes_hashed: u64,
50    buffer: [u8; BLOCK_SIZE],
51}
52
53impl HashEngine {
54    /// Constructs a new SHA512 hash engine.
55    #[rustfmt::skip]
56    pub const fn new() -> Self {
57        Self {
58            h: [
59                0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
60                0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
61            ],
62            bytes_hashed: 0,
63            buffer: [0; BLOCK_SIZE],
64        }
65    }
66}
67
68impl Default for HashEngine {
69    fn default() -> Self { Self::new() }
70}
71
72impl HashEngine {
73    #[cfg(not(hashes_fuzz))]
74    pub(crate) fn midstate(&self) -> [u8; 64] {
75        let mut ret = [0; 64];
76        for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(8)) {
77            ret_bytes.copy_from_slice(&val.to_be_bytes());
78        }
79        ret
80    }
81
82    #[cfg(hashes_fuzz)]
83    pub(crate) fn midstate(&self) -> [u8; 64] {
84        let mut ret = [0; 64];
85        ret.copy_from_slice(&self.buffer[..64]);
86        ret
87    }
88
89    /// Constructs a new hash engine suitable for use constructing a `sha512_256::HashEngine`.
90    #[rustfmt::skip]
91    pub(crate) const fn sha512_256() -> Self {
92        HashEngine {
93            h: [
94                0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd,
95                0x96283ee2a88effe3, 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2,
96            ],
97            bytes_hashed: 0,
98            buffer: [0; BLOCK_SIZE],
99        }
100    }
101
102    /// Constructs a new hash engine suitable for constructing a `sha384::HashEngine`.
103    #[rustfmt::skip]
104    pub(crate) const fn sha384() -> Self {
105        HashEngine {
106            h: [
107                0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939,
108                0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
109            ],
110            bytes_hashed: 0,
111            buffer: [0; BLOCK_SIZE],
112        }
113    }
114}
115
116impl crate::HashEngine for HashEngine {
117    const BLOCK_SIZE: usize = 128;
118
119    fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
120
121    crate::internal_macros::engine_input_impl!();
122}
123
124#[allow(non_snake_case)]
125fn Ch(x: u64, y: u64, z: u64) -> u64 { z ^ (x & (y ^ z)) }
126#[allow(non_snake_case)]
127fn Maj(x: u64, y: u64, z: u64) -> u64 { (x & y) | (z & (x | y)) }
128#[allow(non_snake_case)]
129fn Sigma0(x: u64) -> u64 { x.rotate_left(36) ^ x.rotate_left(30) ^ x.rotate_left(25) }
130#[allow(non_snake_case)]
131fn Sigma1(x: u64) -> u64 { x.rotate_left(50) ^ x.rotate_left(46) ^ x.rotate_left(23) }
132fn sigma0(x: u64) -> u64 { x.rotate_left(63) ^ x.rotate_left(56) ^ (x >> 7) }
133fn sigma1(x: u64) -> u64 { x.rotate_left(45) ^ x.rotate_left(3) ^ (x >> 6) }
134
135#[cfg(feature = "small-hash")]
136#[macro_use]
137mod small_hash {
138    use super::*;
139
140    #[rustfmt::skip]
141    pub(super) fn round(a: u64, b: u64, c: u64, d: &mut u64, e: u64,
142                        f: u64, g: u64, h: &mut u64, k: u64, w: u64,
143    ) {
144        let t1 =
145            h.wrapping_add(Sigma1(e)).wrapping_add(Ch(e, f, g)).wrapping_add(k).wrapping_add(w);
146        let t2 = Sigma0(a).wrapping_add(Maj(a, b, c));
147        *d = d.wrapping_add(t1);
148        *h = t1.wrapping_add(t2);
149    }
150    #[rustfmt::skip]
151    pub(super) fn later_round(a: u64, b: u64, c: u64, d: &mut u64, e: u64,
152                              f: u64, g: u64, h: &mut u64, k: u64, w: u64,
153                              w1: u64, w2: u64, w3: u64,
154    ) -> u64 {
155        let w = w.wrapping_add(sigma1(w1)).wrapping_add(w2).wrapping_add(sigma0(w3));
156        round(a, b, c, d, e, f, g, h, k, w);
157        w
158    }
159
160    macro_rules! round(
161        // first round
162        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
163            small_hash::round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w)
164        );
165        // later rounds we reassign $w before doing the first-round computation
166        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
167            $w = small_hash::later_round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w, $w1, $w2, $w3)
168        )
169    );
170}
171
172#[cfg(not(feature = "small-hash"))]
173#[macro_use]
174mod fast_hash {
175    macro_rules! round(
176        // first round
177        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
178            let t1 = $h.wrapping_add(Sigma1($e)).wrapping_add(Ch($e, $f, $g)).wrapping_add($k).wrapping_add($w);
179            let t2 = Sigma0($a).wrapping_add(Maj($a, $b, $c));
180            $d = $d.wrapping_add(t1);
181            $h = t1.wrapping_add(t2);
182        );
183        // later rounds we reassign $w before doing the first-round computation
184        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
185            $w = $w.wrapping_add(sigma1($w1)).wrapping_add($w2).wrapping_add(sigma0($w3));
186            round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w);
187        )
188    );
189}
190
191impl HashEngine {
192    // Algorithm copied from libsecp256k1
193    pub(crate) fn process_block(&mut self) {
194        debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
195
196        let mut w = [0u64; 16];
197        for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(8)) {
198            *w_val = u64::from_be_bytes(buff_bytes.try_into().expect("8 byte slice"));
199        }
200
201        let mut a = self.h[0];
202        let mut b = self.h[1];
203        let mut c = self.h[2];
204        let mut d = self.h[3];
205        let mut e = self.h[4];
206        let mut f = self.h[5];
207        let mut g = self.h[6];
208        let mut h = self.h[7];
209
210        round!(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22, w[0]);
211        round!(h, a, b, c, d, e, f, g, 0x7137449123ef65cd, w[1]);
212        round!(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2f, w[2]);
213        round!(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbc, w[3]);
214        round!(e, f, g, h, a, b, c, d, 0x3956c25bf348b538, w[4]);
215        round!(d, e, f, g, h, a, b, c, 0x59f111f1b605d019, w[5]);
216        round!(c, d, e, f, g, h, a, b, 0x923f82a4af194f9b, w[6]);
217        round!(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118, w[7]);
218        round!(a, b, c, d, e, f, g, h, 0xd807aa98a3030242, w[8]);
219        round!(h, a, b, c, d, e, f, g, 0x12835b0145706fbe, w[9]);
220        round!(g, h, a, b, c, d, e, f, 0x243185be4ee4b28c, w[10]);
221        round!(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2, w[11]);
222        round!(e, f, g, h, a, b, c, d, 0x72be5d74f27b896f, w[12]);
223        round!(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1, w[13]);
224        round!(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235, w[14]);
225        round!(b, c, d, e, f, g, h, a, 0xc19bf174cf692694, w[15]);
226
227        round!(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2, w[0], w[14], w[9], w[1]);
228        round!(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3, w[1], w[15], w[10], w[2]);
229        round!(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5, w[2], w[0], w[11], w[3]);
230        round!(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65, w[3], w[1], w[12], w[4]);
231        round!(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275, w[4], w[2], w[13], w[5]);
232        round!(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483, w[5], w[3], w[14], w[6]);
233        round!(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4, w[6], w[4], w[15], w[7]);
234        round!(b, c, d, e, f, g, h, a, 0x76f988da831153b5, w[7], w[5], w[0], w[8]);
235        round!(a, b, c, d, e, f, g, h, 0x983e5152ee66dfab, w[8], w[6], w[1], w[9]);
236        round!(h, a, b, c, d, e, f, g, 0xa831c66d2db43210, w[9], w[7], w[2], w[10]);
237        round!(g, h, a, b, c, d, e, f, 0xb00327c898fb213f, w[10], w[8], w[3], w[11]);
238        round!(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4, w[11], w[9], w[4], w[12]);
239        round!(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2, w[12], w[10], w[5], w[13]);
240        round!(d, e, f, g, h, a, b, c, 0xd5a79147930aa725, w[13], w[11], w[6], w[14]);
241        round!(c, d, e, f, g, h, a, b, 0x06ca6351e003826f, w[14], w[12], w[7], w[15]);
242        round!(b, c, d, e, f, g, h, a, 0x142929670a0e6e70, w[15], w[13], w[8], w[0]);
243
244        round!(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffc, w[0], w[14], w[9], w[1]);
245        round!(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926, w[1], w[15], w[10], w[2]);
246        round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aed, w[2], w[0], w[11], w[3]);
247        round!(f, g, h, a, b, c, d, e, 0x53380d139d95b3df, w[3], w[1], w[12], w[4]);
248        round!(e, f, g, h, a, b, c, d, 0x650a73548baf63de, w[4], w[2], w[13], w[5]);
249        round!(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8, w[5], w[3], w[14], w[6]);
250        round!(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6, w[6], w[4], w[15], w[7]);
251        round!(b, c, d, e, f, g, h, a, 0x92722c851482353b, w[7], w[5], w[0], w[8]);
252        round!(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364, w[8], w[6], w[1], w[9]);
253        round!(h, a, b, c, d, e, f, g, 0xa81a664bbc423001, w[9], w[7], w[2], w[10]);
254        round!(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791, w[10], w[8], w[3], w[11]);
255        round!(f, g, h, a, b, c, d, e, 0xc76c51a30654be30, w[11], w[9], w[4], w[12]);
256        round!(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218, w[12], w[10], w[5], w[13]);
257        round!(d, e, f, g, h, a, b, c, 0xd69906245565a910, w[13], w[11], w[6], w[14]);
258        round!(c, d, e, f, g, h, a, b, 0xf40e35855771202a, w[14], w[12], w[7], w[15]);
259        round!(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8, w[15], w[13], w[8], w[0]);
260
261        round!(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8, w[0], w[14], w[9], w[1]);
262        round!(h, a, b, c, d, e, f, g, 0x1e376c085141ab53, w[1], w[15], w[10], w[2]);
263        round!(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99, w[2], w[0], w[11], w[3]);
264        round!(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8, w[3], w[1], w[12], w[4]);
265        round!(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63, w[4], w[2], w[13], w[5]);
266        round!(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acb, w[5], w[3], w[14], w[6]);
267        round!(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373, w[6], w[4], w[15], w[7]);
268        round!(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3, w[7], w[5], w[0], w[8]);
269        round!(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fc, w[8], w[6], w[1], w[9]);
270        round!(h, a, b, c, d, e, f, g, 0x78a5636f43172f60, w[9], w[7], w[2], w[10]);
271        round!(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72, w[10], w[8], w[3], w[11]);
272        round!(f, g, h, a, b, c, d, e, 0x8cc702081a6439ec, w[11], w[9], w[4], w[12]);
273        round!(e, f, g, h, a, b, c, d, 0x90befffa23631e28, w[12], w[10], w[5], w[13]);
274        round!(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9, w[13], w[11], w[6], w[14]);
275        round!(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915, w[14], w[12], w[7], w[15]);
276        round!(b, c, d, e, f, g, h, a, 0xc67178f2e372532b, w[15], w[13], w[8], w[0]);
277
278        round!(a, b, c, d, e, f, g, h, 0xca273eceea26619c, w[0], w[14], w[9], w[1]);
279        round!(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207, w[1], w[15], w[10], w[2]);
280        round!(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1e, w[2], w[0], w[11], w[3]);
281        round!(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178, w[3], w[1], w[12], w[4]);
282        round!(e, f, g, h, a, b, c, d, 0x06f067aa72176fba, w[4], w[2], w[13], w[5]);
283        round!(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6, w[5], w[3], w[14], w[6]);
284        round!(c, d, e, f, g, h, a, b, 0x113f9804bef90dae, w[6], w[4], w[15], w[7]);
285        round!(b, c, d, e, f, g, h, a, 0x1b710b35131c471b, w[7], w[5], w[0], w[8]);
286        round!(a, b, c, d, e, f, g, h, 0x28db77f523047d84, w[8], w[6], w[1], w[9]);
287        round!(h, a, b, c, d, e, f, g, 0x32caab7b40c72493, w[9], w[7], w[2], w[10]);
288        round!(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebc, w[10], w[8], w[3], w[11]);
289        round!(f, g, h, a, b, c, d, e, 0x431d67c49c100d4c, w[11], w[9], w[4], w[12]);
290        round!(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6, w[12], w[10], w[5], w[13]);
291        round!(d, e, f, g, h, a, b, c, 0x597f299cfc657e2a, w[13], w[11], w[6], w[14]);
292        round!(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faec, w[14], w[12], w[7], w[15]);
293        round!(b, c, d, e, f, g, h, a, 0x6c44198c4a475817, w[15], w[13], w[8], w[0]);
294
295        self.h[0] = self.h[0].wrapping_add(a);
296        self.h[1] = self.h[1].wrapping_add(b);
297        self.h[2] = self.h[2].wrapping_add(c);
298        self.h[3] = self.h[3].wrapping_add(d);
299        self.h[4] = self.h[4].wrapping_add(e);
300        self.h[5] = self.h[5].wrapping_add(f);
301        self.h[6] = self.h[6].wrapping_add(g);
302        self.h[7] = self.h[7].wrapping_add(h);
303    }
304}
305
306#[cfg(test)]
307mod tests {
308    #[test]
309    #[cfg(feature = "alloc")]
310    fn test() {
311        use alloc::string::ToString;
312
313        use crate::{sha512, HashEngine};
314
315        #[derive(Clone)]
316        struct Test {
317            input: &'static str,
318            output: [u8; 64],
319            output_str: &'static str,
320        }
321
322        #[rustfmt::skip]
323        let tests = [
324            // Test vectors computed with `sha512sum`
325            Test {
326                input: "",
327                output: [
328                    0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
329                    0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
330                    0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
331                    0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
332                    0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
333                    0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
334                    0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
335                    0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e,
336                ],
337                output_str: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
338            },
339            Test {
340                input: "The quick brown fox jumps over the lazy dog",
341                output: [
342                    0x07, 0xe5, 0x47, 0xd9, 0x58, 0x6f, 0x6a, 0x73,
343                    0xf7, 0x3f, 0xba, 0xc0, 0x43, 0x5e, 0xd7, 0x69,
344                    0x51, 0x21, 0x8f, 0xb7, 0xd0, 0xc8, 0xd7, 0x88,
345                    0xa3, 0x09, 0xd7, 0x85, 0x43, 0x6b, 0xbb, 0x64,
346                    0x2e, 0x93, 0xa2, 0x52, 0xa9, 0x54, 0xf2, 0x39,
347                    0x12, 0x54, 0x7d, 0x1e, 0x8a, 0x3b, 0x5e, 0xd6,
348                    0xe1, 0xbf, 0xd7, 0x09, 0x78, 0x21, 0x23, 0x3f,
349                    0xa0, 0x53, 0x8f, 0x3d, 0xb8, 0x54, 0xfe, 0xe6,
350                ],
351                output_str: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
352            },
353            Test {
354                input: "The quick brown fox jumps over the lazy dog.",
355                output: [
356                    0x91, 0xea, 0x12, 0x45, 0xf2, 0x0d, 0x46, 0xae,
357                    0x9a, 0x03, 0x7a, 0x98, 0x9f, 0x54, 0xf1, 0xf7,
358                    0x90, 0xf0, 0xa4, 0x76, 0x07, 0xee, 0xb8, 0xa1,
359                    0x4d, 0x12, 0x89, 0x0c, 0xea, 0x77, 0xa1, 0xbb,
360                    0xc6, 0xc7, 0xed, 0x9c, 0xf2, 0x05, 0xe6, 0x7b,
361                    0x7f, 0x2b, 0x8f, 0xd4, 0xc7, 0xdf, 0xd3, 0xa7,
362                    0xa8, 0x61, 0x7e, 0x45, 0xf3, 0xc4, 0x63, 0xd4,
363                    0x81, 0xc7, 0xe5, 0x86, 0xc3, 0x9a, 0xc1, 0xed,
364                ],
365                output_str: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed",
366            },
367        ];
368
369        for test in tests {
370            // Hash through high-level API, check hex encoding/decoding
371            let hash = sha512::Hash::hash(test.input.as_bytes());
372            assert_eq!(hash, test.output_str.parse::<sha512::Hash>().expect("parse hex"));
373            assert_eq!(hash.as_byte_array(), &test.output);
374            assert_eq!(hash.to_string(), test.output_str);
375
376            // Hash through engine, checking that we can input byte by byte
377            let mut engine = sha512::Hash::engine();
378            for ch in test.input.as_bytes() {
379                engine.input(&[*ch]);
380            }
381            let manual_hash = sha512::Hash::from_engine(engine);
382            assert_eq!(hash, manual_hash);
383            assert_eq!(hash.to_byte_array(), test.output);
384        }
385    }
386
387    #[test]
388    #[cfg(feature = "serde")]
389    fn sha512_serde() {
390        use serde_test::{assert_tokens, Configure, Token};
391
392        use crate::sha512;
393
394        #[rustfmt::skip]
395        static HASH_BYTES: [u8; 64] = [
396            0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
397            0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
398            0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
399            0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
400            0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
401            0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
402            0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
403            0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
404        ];
405
406        let hash = sha512::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
407        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
408        assert_tokens(
409            &hash.readable(),
410            &[Token::Str(
411                "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
412                 fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
413            )],
414        );
415    }
416}
417
418#[cfg(bench)]
419mod benches {
420    use test::Bencher;
421
422    use crate::{sha512, Hash, HashEngine};
423
424    #[bench]
425    pub fn sha512_10(bh: &mut Bencher) {
426        let mut engine = sha512::Hash::engine();
427        let bytes = [1u8; 10];
428        bh.iter(|| {
429            engine.input(&bytes);
430        });
431        bh.bytes = bytes.len() as u64;
432    }
433
434    #[bench]
435    pub fn sha512_1k(bh: &mut Bencher) {
436        let mut engine = sha512::Hash::engine();
437        let bytes = [1u8; 1024];
438        bh.iter(|| {
439            engine.input(&bytes);
440        });
441        bh.bytes = bytes.len() as u64;
442    }
443
444    #[bench]
445    pub fn sha512_64k(bh: &mut Bencher) {
446        let mut engine = sha512::Hash::engine();
447        let bytes = [1u8; 65536];
448        bh.iter(|| {
449            engine.input(&bytes);
450        });
451        bh.bytes = bytes.len() as u64;
452    }
453}