bitcoin_hashes/
sha512.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! SHA512 implementation.
4//!
5
6use core::convert::TryInto;
7use core::ops::Index;
8use core::slice::SliceIndex;
9use core::{cmp, str};
10
11use crate::{FromSliceError, HashEngine as _};
12
13crate::internal_macros::hash_trait_impls!(512, false);
14
15pub(crate) const BLOCK_SIZE: usize = 128;
16
17/// Engine to compute SHA512 hash function.
18#[derive(Clone)]
19pub struct HashEngine {
20    h: [u64; 8],
21    length: usize,
22    buffer: [u8; BLOCK_SIZE],
23}
24
25impl Default for HashEngine {
26    #[rustfmt::skip]
27    fn default() -> Self {
28        HashEngine {
29            h: [
30                0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
31                0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
32            ],
33            length: 0,
34            buffer: [0; BLOCK_SIZE],
35        }
36    }
37}
38
39impl HashEngine {
40    /// Constructs a hash engine suitable for use inside the default `sha512_256::HashEngine`.
41    #[rustfmt::skip]
42    pub(crate) fn sha512_256() -> Self {
43        HashEngine {
44            h: [
45                0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd,
46                0x96283ee2a88effe3, 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2,
47            ],
48            length: 0,
49            buffer: [0; BLOCK_SIZE],
50        }
51    }
52}
53
54impl crate::HashEngine for HashEngine {
55    type MidState = [u8; 64];
56
57    #[cfg(not(hashes_fuzz))]
58    fn midstate(&self) -> [u8; 64] {
59        let mut ret = [0; 64];
60        for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(8)) {
61            ret_bytes.copy_from_slice(&val.to_be_bytes());
62        }
63        ret
64    }
65
66    #[cfg(hashes_fuzz)]
67    fn midstate(&self) -> [u8; 64] {
68        let mut ret = [0; 64];
69        ret.copy_from_slice(&self.buffer[..64]);
70        ret
71    }
72
73    const BLOCK_SIZE: usize = 128;
74
75    fn n_bytes_hashed(&self) -> usize { self.length }
76
77    engine_input_impl!();
78}
79
80/// Output of the SHA512 hash function.
81#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
82#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
83#[repr(transparent)]
84pub struct Hash(
85    #[cfg_attr(
86        feature = "schemars",
87        schemars(schema_with = "crate::util::json_hex_string::len_64")
88    )]
89    [u8; 64],
90);
91
92impl Hash {
93    fn internal_new(arr: [u8; 64]) -> Self { Hash(arr) }
94
95    fn internal_engine() -> HashEngine { Default::default() }
96}
97
98#[cfg(not(hashes_fuzz))]
99pub(crate) fn from_engine(mut e: HashEngine) -> Hash {
100    // pad buffer with a single 1-bit then all 0s, until there are exactly 16 bytes remaining
101    let data_len = e.length as u64;
102
103    let zeroes = [0; BLOCK_SIZE - 16];
104    e.input(&[0x80]);
105    if e.length % BLOCK_SIZE > zeroes.len() {
106        e.input(&zeroes);
107    }
108    let pad_length = zeroes.len() - (e.length % BLOCK_SIZE);
109    e.input(&zeroes[..pad_length]);
110    debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len());
111
112    e.input(&[0; 8]);
113    e.input(&(8 * data_len).to_be_bytes());
114    debug_assert_eq!(e.length % BLOCK_SIZE, 0);
115
116    Hash(e.midstate())
117}
118
119#[cfg(hashes_fuzz)]
120pub(crate) fn from_engine(e: HashEngine) -> Hash {
121    let mut hash = e.midstate();
122    hash[0] ^= 0xff; // Make this distinct from SHA-256
123    Hash(hash)
124}
125
126#[allow(non_snake_case)]
127fn Ch(x: u64, y: u64, z: u64) -> u64 { z ^ (x & (y ^ z)) }
128#[allow(non_snake_case)]
129fn Maj(x: u64, y: u64, z: u64) -> u64 { (x & y) | (z & (x | y)) }
130#[allow(non_snake_case)]
131fn Sigma0(x: u64) -> u64 { x.rotate_left(36) ^ x.rotate_left(30) ^ x.rotate_left(25) }
132#[allow(non_snake_case)]
133fn Sigma1(x: u64) -> u64 { x.rotate_left(50) ^ x.rotate_left(46) ^ x.rotate_left(23) }
134fn sigma0(x: u64) -> u64 { x.rotate_left(63) ^ x.rotate_left(56) ^ (x >> 7) }
135fn sigma1(x: u64) -> u64 { x.rotate_left(45) ^ x.rotate_left(3) ^ (x >> 6) }
136
137#[cfg(feature = "small-hash")]
138#[macro_use]
139mod small_hash {
140    use super::*;
141
142    #[rustfmt::skip]
143    pub(super) fn round(a: u64, b: u64, c: u64, d: &mut u64, e: u64,
144                        f: u64, g: u64, h: &mut u64, k: u64, w: u64,
145    ) {
146        let t1 =
147            h.wrapping_add(Sigma1(e)).wrapping_add(Ch(e, f, g)).wrapping_add(k).wrapping_add(w);
148        let t2 = Sigma0(a).wrapping_add(Maj(a, b, c));
149        *d = d.wrapping_add(t1);
150        *h = t1.wrapping_add(t2);
151    }
152    #[rustfmt::skip]
153    pub(super) fn later_round(a: u64, b: u64, c: u64, d: &mut u64, e: u64,
154                              f: u64, g: u64, h: &mut u64, k: u64, w: u64,
155                              w1: u64, w2: u64, w3: u64,
156    ) -> u64 {
157        let w = w.wrapping_add(sigma1(w1)).wrapping_add(w2).wrapping_add(sigma0(w3));
158        round(a, b, c, d, e, f, g, h, k, w);
159        w
160    }
161
162    macro_rules! round(
163        // first round
164        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
165            small_hash::round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w)
166        );
167        // later rounds we reassign $w before doing the first-round computation
168        ($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) => (
169            $w = small_hash::later_round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w, $w1, $w2, $w3)
170        )
171    );
172}
173
174#[cfg(not(feature = "small-hash"))]
175#[macro_use]
176mod fast_hash {
177    macro_rules! round(
178        // first round
179        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
180            let t1 = $h.wrapping_add(Sigma1($e)).wrapping_add(Ch($e, $f, $g)).wrapping_add($k).wrapping_add($w);
181            let t2 = Sigma0($a).wrapping_add(Maj($a, $b, $c));
182            $d = $d.wrapping_add(t1);
183            $h = t1.wrapping_add(t2);
184        );
185        // later rounds we reassign $w before doing the first-round computation
186        ($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) => (
187            $w = $w.wrapping_add(sigma1($w1)).wrapping_add($w2).wrapping_add(sigma0($w3));
188            round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w);
189        )
190    );
191}
192
193impl HashEngine {
194    // Algorithm copied from libsecp256k1
195    pub(crate) fn process_block(&mut self) {
196        debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
197
198        let mut w = [0u64; 16];
199        for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(8)) {
200            *w_val = u64::from_be_bytes(buff_bytes.try_into().expect("8 byte slice"));
201        }
202
203        let mut a = self.h[0];
204        let mut b = self.h[1];
205        let mut c = self.h[2];
206        let mut d = self.h[3];
207        let mut e = self.h[4];
208        let mut f = self.h[5];
209        let mut g = self.h[6];
210        let mut h = self.h[7];
211
212        round!(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22, w[0]);
213        round!(h, a, b, c, d, e, f, g, 0x7137449123ef65cd, w[1]);
214        round!(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2f, w[2]);
215        round!(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbc, w[3]);
216        round!(e, f, g, h, a, b, c, d, 0x3956c25bf348b538, w[4]);
217        round!(d, e, f, g, h, a, b, c, 0x59f111f1b605d019, w[5]);
218        round!(c, d, e, f, g, h, a, b, 0x923f82a4af194f9b, w[6]);
219        round!(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118, w[7]);
220        round!(a, b, c, d, e, f, g, h, 0xd807aa98a3030242, w[8]);
221        round!(h, a, b, c, d, e, f, g, 0x12835b0145706fbe, w[9]);
222        round!(g, h, a, b, c, d, e, f, 0x243185be4ee4b28c, w[10]);
223        round!(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2, w[11]);
224        round!(e, f, g, h, a, b, c, d, 0x72be5d74f27b896f, w[12]);
225        round!(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1, w[13]);
226        round!(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235, w[14]);
227        round!(b, c, d, e, f, g, h, a, 0xc19bf174cf692694, w[15]);
228
229        round!(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2, w[0], w[14], w[9], w[1]);
230        round!(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3, w[1], w[15], w[10], w[2]);
231        round!(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5, w[2], w[0], w[11], w[3]);
232        round!(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65, w[3], w[1], w[12], w[4]);
233        round!(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275, w[4], w[2], w[13], w[5]);
234        round!(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483, w[5], w[3], w[14], w[6]);
235        round!(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4, w[6], w[4], w[15], w[7]);
236        round!(b, c, d, e, f, g, h, a, 0x76f988da831153b5, w[7], w[5], w[0], w[8]);
237        round!(a, b, c, d, e, f, g, h, 0x983e5152ee66dfab, w[8], w[6], w[1], w[9]);
238        round!(h, a, b, c, d, e, f, g, 0xa831c66d2db43210, w[9], w[7], w[2], w[10]);
239        round!(g, h, a, b, c, d, e, f, 0xb00327c898fb213f, w[10], w[8], w[3], w[11]);
240        round!(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4, w[11], w[9], w[4], w[12]);
241        round!(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2, w[12], w[10], w[5], w[13]);
242        round!(d, e, f, g, h, a, b, c, 0xd5a79147930aa725, w[13], w[11], w[6], w[14]);
243        round!(c, d, e, f, g, h, a, b, 0x06ca6351e003826f, w[14], w[12], w[7], w[15]);
244        round!(b, c, d, e, f, g, h, a, 0x142929670a0e6e70, w[15], w[13], w[8], w[0]);
245
246        round!(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffc, w[0], w[14], w[9], w[1]);
247        round!(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926, w[1], w[15], w[10], w[2]);
248        round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aed, w[2], w[0], w[11], w[3]);
249        round!(f, g, h, a, b, c, d, e, 0x53380d139d95b3df, w[3], w[1], w[12], w[4]);
250        round!(e, f, g, h, a, b, c, d, 0x650a73548baf63de, w[4], w[2], w[13], w[5]);
251        round!(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8, w[5], w[3], w[14], w[6]);
252        round!(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6, w[6], w[4], w[15], w[7]);
253        round!(b, c, d, e, f, g, h, a, 0x92722c851482353b, w[7], w[5], w[0], w[8]);
254        round!(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364, w[8], w[6], w[1], w[9]);
255        round!(h, a, b, c, d, e, f, g, 0xa81a664bbc423001, w[9], w[7], w[2], w[10]);
256        round!(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791, w[10], w[8], w[3], w[11]);
257        round!(f, g, h, a, b, c, d, e, 0xc76c51a30654be30, w[11], w[9], w[4], w[12]);
258        round!(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218, w[12], w[10], w[5], w[13]);
259        round!(d, e, f, g, h, a, b, c, 0xd69906245565a910, w[13], w[11], w[6], w[14]);
260        round!(c, d, e, f, g, h, a, b, 0xf40e35855771202a, w[14], w[12], w[7], w[15]);
261        round!(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8, w[15], w[13], w[8], w[0]);
262
263        round!(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8, w[0], w[14], w[9], w[1]);
264        round!(h, a, b, c, d, e, f, g, 0x1e376c085141ab53, w[1], w[15], w[10], w[2]);
265        round!(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99, w[2], w[0], w[11], w[3]);
266        round!(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8, w[3], w[1], w[12], w[4]);
267        round!(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63, w[4], w[2], w[13], w[5]);
268        round!(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acb, w[5], w[3], w[14], w[6]);
269        round!(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373, w[6], w[4], w[15], w[7]);
270        round!(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3, w[7], w[5], w[0], w[8]);
271        round!(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fc, w[8], w[6], w[1], w[9]);
272        round!(h, a, b, c, d, e, f, g, 0x78a5636f43172f60, w[9], w[7], w[2], w[10]);
273        round!(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72, w[10], w[8], w[3], w[11]);
274        round!(f, g, h, a, b, c, d, e, 0x8cc702081a6439ec, w[11], w[9], w[4], w[12]);
275        round!(e, f, g, h, a, b, c, d, 0x90befffa23631e28, w[12], w[10], w[5], w[13]);
276        round!(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9, w[13], w[11], w[6], w[14]);
277        round!(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915, w[14], w[12], w[7], w[15]);
278        round!(b, c, d, e, f, g, h, a, 0xc67178f2e372532b, w[15], w[13], w[8], w[0]);
279
280        round!(a, b, c, d, e, f, g, h, 0xca273eceea26619c, w[0], w[14], w[9], w[1]);
281        round!(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207, w[1], w[15], w[10], w[2]);
282        round!(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1e, w[2], w[0], w[11], w[3]);
283        round!(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178, w[3], w[1], w[12], w[4]);
284        round!(e, f, g, h, a, b, c, d, 0x06f067aa72176fba, w[4], w[2], w[13], w[5]);
285        round!(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6, w[5], w[3], w[14], w[6]);
286        round!(c, d, e, f, g, h, a, b, 0x113f9804bef90dae, w[6], w[4], w[15], w[7]);
287        round!(b, c, d, e, f, g, h, a, 0x1b710b35131c471b, w[7], w[5], w[0], w[8]);
288        round!(a, b, c, d, e, f, g, h, 0x28db77f523047d84, w[8], w[6], w[1], w[9]);
289        round!(h, a, b, c, d, e, f, g, 0x32caab7b40c72493, w[9], w[7], w[2], w[10]);
290        round!(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebc, w[10], w[8], w[3], w[11]);
291        round!(f, g, h, a, b, c, d, e, 0x431d67c49c100d4c, w[11], w[9], w[4], w[12]);
292        round!(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6, w[12], w[10], w[5], w[13]);
293        round!(d, e, f, g, h, a, b, c, 0x597f299cfc657e2a, w[13], w[11], w[6], w[14]);
294        round!(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faec, w[14], w[12], w[7], w[15]);
295        round!(b, c, d, e, f, g, h, a, 0x6c44198c4a475817, w[15], w[13], w[8], w[0]);
296
297        self.h[0] = self.h[0].wrapping_add(a);
298        self.h[1] = self.h[1].wrapping_add(b);
299        self.h[2] = self.h[2].wrapping_add(c);
300        self.h[3] = self.h[3].wrapping_add(d);
301        self.h[4] = self.h[4].wrapping_add(e);
302        self.h[5] = self.h[5].wrapping_add(f);
303        self.h[6] = self.h[6].wrapping_add(g);
304        self.h[7] = self.h[7].wrapping_add(h);
305    }
306}
307
308#[cfg(test)]
309mod tests {
310    #[test]
311    #[cfg(feature = "alloc")]
312    fn test() {
313        use crate::{sha512, Hash, HashEngine};
314
315        #[derive(Clone)]
316        struct Test {
317            input: &'static str,
318            output: Vec<u8>,
319            output_str: &'static str,
320        }
321
322        #[rustfmt::skip]
323        let tests = vec![
324            // Test vectors computed with `sha512sum`
325            Test {
326                input: "",
327                output: vec![
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: vec![
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: vec![
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[..], &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()[..].as_ref(), test.output.as_slice());
384        }
385    }
386
387    #[cfg(feature = "serde")]
388    #[test]
389    fn sha512_serde() {
390        use serde_test::{assert_tokens, Configure, Token};
391
392        use crate::{sha512, Hash};
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}