bitcoin_hashes/
sha512.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA512 implementation.
4//!
5
6use core::ops::Index;
7use core::slice::SliceIndex;
8use core::{cmp, str};
9
10use crate::{FromSliceError, HashEngine as _};
11
12crate::internal_macros::hash_type! {
13    512,
14    false,
15    "Output of the SHA512 hash function."
16}
17
18#[cfg(not(hashes_fuzz))]
19pub(crate) fn from_engine(mut e: HashEngine) -> Hash {
20    // pad buffer with a single 1-bit then all 0s, until there are exactly 16 bytes remaining
21    let data_len = e.length as u64;
22
23    let zeroes = [0; BLOCK_SIZE - 16];
24    e.input(&[0x80]);
25    if e.length % BLOCK_SIZE > zeroes.len() {
26        e.input(&zeroes);
27    }
28    let pad_length = zeroes.len() - (e.length % BLOCK_SIZE);
29    e.input(&zeroes[..pad_length]);
30    debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len());
31
32    e.input(&[0; 8]);
33    e.input(&(8 * data_len).to_be_bytes());
34    debug_assert_eq!(e.length % BLOCK_SIZE, 0);
35
36    Hash(e.midstate())
37}
38
39#[cfg(hashes_fuzz)]
40pub(crate) fn from_engine(e: HashEngine) -> Hash {
41    let mut hash = e.midstate();
42    hash[0] ^= 0xff; // Make this distinct from SHA-256
43    Hash(hash)
44}
45
46pub(crate) const BLOCK_SIZE: usize = 128;
47
48/// Engine to compute SHA512 hash function.
49#[derive(Clone)]
50pub struct HashEngine {
51    h: [u64; 8],
52    length: usize,
53    buffer: [u8; BLOCK_SIZE],
54}
55
56impl Default for HashEngine {
57    #[rustfmt::skip]
58    fn default() -> Self {
59        HashEngine {
60            h: [
61                0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
62                0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
63            ],
64            length: 0,
65            buffer: [0; BLOCK_SIZE],
66        }
67    }
68}
69
70impl HashEngine {
71    /// Constructs a hash engine suitable for use inside the default `sha512_256::HashEngine`.
72    #[rustfmt::skip]
73    pub(crate) fn sha512_256() -> Self {
74        HashEngine {
75            h: [
76                0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd,
77                0x96283ee2a88effe3, 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2,
78            ],
79            length: 0,
80            buffer: [0; BLOCK_SIZE],
81        }
82    }
83
84    /// Constructs a hash engine suitable for use inside the default `sha384::HashEngine`.
85    #[rustfmt::skip]
86    pub(crate) fn sha384() -> Self {
87        HashEngine {
88            h: [
89                0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939,
90                0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
91            ],
92            length: 0,
93            buffer: [0; BLOCK_SIZE],
94        }
95    }
96}
97
98impl crate::HashEngine for HashEngine {
99    type MidState = [u8; 64];
100
101    #[cfg(not(hashes_fuzz))]
102    fn midstate(&self) -> [u8; 64] {
103        let mut ret = [0; 64];
104        for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(8)) {
105            ret_bytes.copy_from_slice(&val.to_be_bytes());
106        }
107        ret
108    }
109
110    #[cfg(hashes_fuzz)]
111    fn midstate(&self) -> [u8; 64] {
112        let mut ret = [0; 64];
113        ret.copy_from_slice(&self.buffer[..64]);
114        ret
115    }
116
117    const BLOCK_SIZE: usize = 128;
118
119    fn n_bytes_hashed(&self) -> usize { self.length }
120
121    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        let _ = w[15]; // silence "unnecessary assignment" lint in macro
295
296        self.h[0] = self.h[0].wrapping_add(a);
297        self.h[1] = self.h[1].wrapping_add(b);
298        self.h[2] = self.h[2].wrapping_add(c);
299        self.h[3] = self.h[3].wrapping_add(d);
300        self.h[4] = self.h[4].wrapping_add(e);
301        self.h[5] = self.h[5].wrapping_add(f);
302        self.h[6] = self.h[6].wrapping_add(g);
303        self.h[7] = self.h[7].wrapping_add(h);
304    }
305}
306
307#[cfg(test)]
308mod tests {
309    #[test]
310    #[cfg(feature = "alloc")]
311    fn test() {
312        use crate::{sha512, Hash, HashEngine};
313
314        #[derive(Clone)]
315        struct Test {
316            input: &'static str,
317            output: Vec<u8>,
318            output_str: &'static str,
319        }
320
321        #[rustfmt::skip]
322        let tests = vec![
323            // Test vectors computed with `sha512sum`
324            Test {
325                input: "",
326                output: vec![
327                    0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
328                    0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
329                    0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
330                    0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
331                    0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
332                    0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
333                    0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
334                    0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e,
335                ],
336                output_str: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
337            },
338            Test {
339                input: "The quick brown fox jumps over the lazy dog",
340                output: vec![
341                    0x07, 0xe5, 0x47, 0xd9, 0x58, 0x6f, 0x6a, 0x73,
342                    0xf7, 0x3f, 0xba, 0xc0, 0x43, 0x5e, 0xd7, 0x69,
343                    0x51, 0x21, 0x8f, 0xb7, 0xd0, 0xc8, 0xd7, 0x88,
344                    0xa3, 0x09, 0xd7, 0x85, 0x43, 0x6b, 0xbb, 0x64,
345                    0x2e, 0x93, 0xa2, 0x52, 0xa9, 0x54, 0xf2, 0x39,
346                    0x12, 0x54, 0x7d, 0x1e, 0x8a, 0x3b, 0x5e, 0xd6,
347                    0xe1, 0xbf, 0xd7, 0x09, 0x78, 0x21, 0x23, 0x3f,
348                    0xa0, 0x53, 0x8f, 0x3d, 0xb8, 0x54, 0xfe, 0xe6,
349                ],
350                output_str: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
351            },
352            Test {
353                input: "The quick brown fox jumps over the lazy dog.",
354                output: vec![
355                    0x91, 0xea, 0x12, 0x45, 0xf2, 0x0d, 0x46, 0xae,
356                    0x9a, 0x03, 0x7a, 0x98, 0x9f, 0x54, 0xf1, 0xf7,
357                    0x90, 0xf0, 0xa4, 0x76, 0x07, 0xee, 0xb8, 0xa1,
358                    0x4d, 0x12, 0x89, 0x0c, 0xea, 0x77, 0xa1, 0xbb,
359                    0xc6, 0xc7, 0xed, 0x9c, 0xf2, 0x05, 0xe6, 0x7b,
360                    0x7f, 0x2b, 0x8f, 0xd4, 0xc7, 0xdf, 0xd3, 0xa7,
361                    0xa8, 0x61, 0x7e, 0x45, 0xf3, 0xc4, 0x63, 0xd4,
362                    0x81, 0xc7, 0xe5, 0x86, 0xc3, 0x9a, 0xc1, 0xed,
363                ],
364                output_str: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed",
365            },
366        ];
367
368        for test in tests {
369            // Hash through high-level API, check hex encoding/decoding
370            let hash = sha512::Hash::hash(test.input.as_bytes());
371            assert_eq!(hash, test.output_str.parse::<sha512::Hash>().expect("parse hex"));
372            assert_eq!(&hash[..], &test.output[..]);
373            assert_eq!(&hash.to_string(), &test.output_str);
374
375            // Hash through engine, checking that we can input byte by byte
376            let mut engine = sha512::Hash::engine();
377            for ch in test.input.as_bytes() {
378                engine.input(&[*ch]);
379            }
380            let manual_hash = sha512::Hash::from_engine(engine);
381            assert_eq!(hash, manual_hash);
382            assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice());
383        }
384    }
385
386    #[cfg(feature = "serde")]
387    #[test]
388    fn sha512_serde() {
389        use serde_test::{assert_tokens, Configure, Token};
390
391        use crate::{sha512, Hash};
392
393        #[rustfmt::skip]
394        static HASH_BYTES: [u8; 64] = [
395            0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
396            0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
397            0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
398            0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
399            0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
400            0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
401            0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
402            0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
403        ];
404
405        let hash = sha512::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
406        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
407        assert_tokens(
408            &hash.readable(),
409            &[Token::Str(
410                "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
411                 fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
412            )],
413        );
414    }
415}
416
417#[cfg(bench)]
418mod benches {
419    use test::Bencher;
420
421    use crate::{sha512, Hash, HashEngine};
422
423    #[bench]
424    pub fn sha512_10(bh: &mut Bencher) {
425        let mut engine = sha512::Hash::engine();
426        let bytes = [1u8; 10];
427        bh.iter(|| {
428            engine.input(&bytes);
429        });
430        bh.bytes = bytes.len() as u64;
431    }
432
433    #[bench]
434    pub fn sha512_1k(bh: &mut Bencher) {
435        let mut engine = sha512::Hash::engine();
436        let bytes = [1u8; 1024];
437        bh.iter(|| {
438            engine.input(&bytes);
439        });
440        bh.bytes = bytes.len() as u64;
441    }
442
443    #[bench]
444    pub fn sha512_64k(bh: &mut Bencher) {
445        let mut engine = sha512::Hash::engine();
446        let bytes = [1u8; 65536];
447        bh.iter(|| {
448            engine.input(&bytes);
449        });
450        bh.bytes = bytes.len() as u64;
451    }
452}