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
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 crate::{sha512, Hash, HashEngine};
312
313        #[derive(Clone)]
314        struct Test {
315            input: &'static str,
316            output: Vec<u8>,
317            output_str: &'static str,
318        }
319
320        #[rustfmt::skip]
321        let tests = vec![
322            // Test vectors computed with `sha512sum`
323            Test {
324                input: "",
325                output: vec![
326                    0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
327                    0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
328                    0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
329                    0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
330                    0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
331                    0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
332                    0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
333                    0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e,
334                ],
335                output_str: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
336            },
337            Test {
338                input: "The quick brown fox jumps over the lazy dog",
339                output: vec![
340                    0x07, 0xe5, 0x47, 0xd9, 0x58, 0x6f, 0x6a, 0x73,
341                    0xf7, 0x3f, 0xba, 0xc0, 0x43, 0x5e, 0xd7, 0x69,
342                    0x51, 0x21, 0x8f, 0xb7, 0xd0, 0xc8, 0xd7, 0x88,
343                    0xa3, 0x09, 0xd7, 0x85, 0x43, 0x6b, 0xbb, 0x64,
344                    0x2e, 0x93, 0xa2, 0x52, 0xa9, 0x54, 0xf2, 0x39,
345                    0x12, 0x54, 0x7d, 0x1e, 0x8a, 0x3b, 0x5e, 0xd6,
346                    0xe1, 0xbf, 0xd7, 0x09, 0x78, 0x21, 0x23, 0x3f,
347                    0xa0, 0x53, 0x8f, 0x3d, 0xb8, 0x54, 0xfe, 0xe6,
348                ],
349                output_str: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
350            },
351            Test {
352                input: "The quick brown fox jumps over the lazy dog.",
353                output: vec![
354                    0x91, 0xea, 0x12, 0x45, 0xf2, 0x0d, 0x46, 0xae,
355                    0x9a, 0x03, 0x7a, 0x98, 0x9f, 0x54, 0xf1, 0xf7,
356                    0x90, 0xf0, 0xa4, 0x76, 0x07, 0xee, 0xb8, 0xa1,
357                    0x4d, 0x12, 0x89, 0x0c, 0xea, 0x77, 0xa1, 0xbb,
358                    0xc6, 0xc7, 0xed, 0x9c, 0xf2, 0x05, 0xe6, 0x7b,
359                    0x7f, 0x2b, 0x8f, 0xd4, 0xc7, 0xdf, 0xd3, 0xa7,
360                    0xa8, 0x61, 0x7e, 0x45, 0xf3, 0xc4, 0x63, 0xd4,
361                    0x81, 0xc7, 0xe5, 0x86, 0xc3, 0x9a, 0xc1, 0xed,
362                ],
363                output_str: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed",
364            },
365        ];
366
367        for test in tests {
368            // Hash through high-level API, check hex encoding/decoding
369            let hash = sha512::Hash::hash(test.input.as_bytes());
370            assert_eq!(hash, test.output_str.parse::<sha512::Hash>().expect("parse hex"));
371            assert_eq!(&hash[..], &test.output[..]);
372            assert_eq!(&hash.to_string(), &test.output_str);
373
374            // Hash through engine, checking that we can input byte by byte
375            let mut engine = sha512::Hash::engine();
376            for ch in test.input.as_bytes() {
377                engine.input(&[*ch]);
378            }
379            let manual_hash = sha512::Hash::from_engine(engine);
380            assert_eq!(hash, manual_hash);
381            assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice());
382        }
383    }
384
385    #[cfg(feature = "serde")]
386    #[test]
387    fn sha512_serde() {
388        use serde_test::{assert_tokens, Configure, Token};
389
390        use crate::{sha512, Hash};
391
392        #[rustfmt::skip]
393        static HASH_BYTES: [u8; 64] = [
394            0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
395            0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
396            0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
397            0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
398            0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
399            0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
400            0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
401            0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
402        ];
403
404        let hash = sha512::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
405        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
406        assert_tokens(
407            &hash.readable(),
408            &[Token::Str(
409                "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
410                 fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
411            )],
412        );
413    }
414}
415
416#[cfg(bench)]
417mod benches {
418    use test::Bencher;
419
420    use crate::{sha512, Hash, HashEngine};
421
422    #[bench]
423    pub fn sha512_10(bh: &mut Bencher) {
424        let mut engine = sha512::Hash::engine();
425        let bytes = [1u8; 10];
426        bh.iter(|| {
427            engine.input(&bytes);
428        });
429        bh.bytes = bytes.len() as u64;
430    }
431
432    #[bench]
433    pub fn sha512_1k(bh: &mut Bencher) {
434        let mut engine = sha512::Hash::engine();
435        let bytes = [1u8; 1024];
436        bh.iter(|| {
437            engine.input(&bytes);
438        });
439        bh.bytes = bytes.len() as u64;
440    }
441
442    #[bench]
443    pub fn sha512_64k(bh: &mut Bencher) {
444        let mut engine = sha512::Hash::engine();
445        let bytes = [1u8; 65536];
446        bh.iter(|| {
447            engine.input(&bytes);
448        });
449        bh.bytes = bytes.len() as u64;
450    }
451}