lhash/
sha512.rs

1const BLOCK_SIZE: usize = 128;
2const RESULT_SIZE: usize = 64;
3const STATE_SIZE: usize = 8;
4const INIT_STATE: [u64; STATE_SIZE] = [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179];
5const K512: [u64; 80] = [
6	0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
7	0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
8	0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
9	0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
10	0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
11	0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
12	0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
13	0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
14	0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
15	0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
16	0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
17	0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
18	0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
19	0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
20	0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
21	0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
22	0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
23	0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
24	0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
25	0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
26];
27
28const fn sha512_transform(state: [u64; STATE_SIZE], cursor: usize, input: &[u8]) -> [u64; STATE_SIZE] {
29    let mut a = state[0];
30    let mut b = state[1];
31    let mut c = state[2];
32    let mut d = state[3];
33    let mut e = state[4];
34    let mut f = state[5];
35    let mut g = state[6];
36    let mut h = state[7];
37
38    macro_rules! S0 {
39        ($in:expr) => {
40            (($in.rotate_right(5) ^ $in).rotate_right(6) ^ $in).rotate_right(28)
41        }
42    }
43
44    macro_rules! S1 {
45        ($in:expr) => {
46            (($in.rotate_right(23) ^ $in).rotate_right(4) ^ $in).rotate_right(14)
47        }
48    }
49
50    macro_rules! s0 {
51        ($in:expr) => {
52            ($in.rotate_right(7) ^ $in).rotate_right(1) ^ $in.wrapping_shr(7)
53        }
54    }
55
56    macro_rules! s1 {
57        ($in:expr) => {
58            ($in.rotate_right(42) ^ $in).rotate_right(19) ^ $in.wrapping_shr(6)
59        }
60    }
61
62    macro_rules! Ch {
63        ($x:expr, $y:expr, $z:expr) => {
64            (($z) ^ (($x) & (($y) ^ ($z))))
65        }
66    }
67
68    macro_rules! Ma {
69        ($x:expr, $y:expr, $z:expr) => {
70            ((($x) & ($y)) | (($z) & (($x) | ($y))))
71        }
72    }
73
74    const fn read_u64(input: &[u8], cursor: usize) -> u64 {
75        u64::from_be_bytes([input[cursor], input[cursor + 1], input[cursor + 2], input[cursor + 3], input[cursor + 4], input[cursor + 5], input[cursor + 6], input[cursor + 7]])
76    }
77
78    let mut x = [0u64; 80];
79    let mut idx = 0;
80    while idx < 16 {
81        x[idx] = read_u64(input, cursor + idx * 8);
82        idx += 1;
83    }
84
85    while idx < x.len() {
86        x[idx] = s1!(x[idx - 2]).wrapping_add(x[idx - 7]).wrapping_add(s0!(x[idx - 15])).wrapping_add(x[idx - 16]);
87        idx += 1;
88    }
89
90    macro_rules! R {
91        ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr) => {
92            $h = $h.wrapping_add(S1!($e).wrapping_add(Ch!($e, $f, $g)).wrapping_add(K512[$i]).wrapping_add(x[$i]));
93            $d = $d.wrapping_add($h);
94            $h = $h.wrapping_add(S0!($a).wrapping_add(Ma!($a, $b, $c)));
95        }
96    }
97
98    idx = 0;
99    while idx < 80 {
100        R!(a, b, c, d, e, f, g, h, idx);
101        R!(h, a, b, c, d, e, f, g, idx+1);
102        R!(g, h, a, b, c, d, e, f, idx+2);
103        R!(f, g, h, a, b, c, d, e, idx+3);
104        R!(e, f, g, h, a, b, c, d, idx+4);
105        R!(d, e, f, g, h, a, b, c, idx+5);
106        R!(c, d, e, f, g, h, a, b, idx+6);
107        R!(b, c, d, e, f, g, h, a, idx+7);
108
109        idx += 8;
110    }
111
112    [
113        state[0].wrapping_add(a),
114        state[1].wrapping_add(b),
115        state[2].wrapping_add(c),
116        state[3].wrapping_add(d),
117        state[4].wrapping_add(e),
118        state[5].wrapping_add(f),
119        state[6].wrapping_add(g),
120        state[7].wrapping_add(h),
121    ]
122}
123
124#[inline]
125///const `SHA512` algorithm implementation
126pub const fn sha512(input: &[u8]) -> [u8; RESULT_SIZE] {
127    let mut state = INIT_STATE;
128    let mut cursor = 0;
129
130    while cursor + BLOCK_SIZE <= input.len() {
131        state = sha512_transform(state, cursor, input);
132        cursor += BLOCK_SIZE;
133    }
134
135    let mut pos = 0;
136    let mut buffer = [0; BLOCK_SIZE];
137
138    while pos < input.len() - cursor {
139        buffer[pos] = input[cursor + pos];
140        pos += 1;
141    }
142    buffer[pos] = 0x80;
143    pos += 1;
144
145    while pos != (BLOCK_SIZE - (2 * core::mem::size_of::<u64>())) {
146        pos &= BLOCK_SIZE - 1;
147
148        if pos == 0 {
149            state = sha512_transform(state, 0, &buffer);
150        }
151
152        buffer[pos] = 0;
153        pos += 1;
154    }
155
156    let input_len = input.len() as u64;
157    let len_lo = input_len.wrapping_shl(3).to_be_bytes();
158    let len_hi = input_len.wrapping_shr(64 - 3).to_be_bytes();
159    buffer[pos] = len_hi[0];
160    buffer[pos + 1] = len_hi[1];
161    buffer[pos + 2] = len_hi[2];
162    buffer[pos + 3] = len_hi[3];
163    buffer[pos + 4] = len_hi[4];
164    buffer[pos + 5] = len_hi[5];
165    buffer[pos + 6] = len_hi[6];
166    buffer[pos + 7] = len_hi[7];
167
168    buffer[pos + 8] = len_lo[0];
169    buffer[pos + 9] = len_lo[1];
170    buffer[pos + 10] = len_lo[2];
171    buffer[pos + 11] = len_lo[3];
172    buffer[pos + 12] = len_lo[4];
173    buffer[pos + 13] = len_lo[5];
174    buffer[pos + 14] = len_lo[6];
175    buffer[pos + 15] = len_lo[7];
176
177    state = sha512_transform(state, 0, &buffer);
178
179    let a = state[0].to_be_bytes();
180    let b = state[1].to_be_bytes();
181    let c = state[2].to_be_bytes();
182    let d = state[3].to_be_bytes();
183    let e = state[4].to_be_bytes();
184    let f = state[5].to_be_bytes();
185    let g = state[6].to_be_bytes();
186    let h = state[7].to_be_bytes();
187    [
188        a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
189        b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
190        c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
191        d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
192        e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7],
193        f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7],
194        g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7],
195        h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7],
196    ]
197}
198
199///`Sha512` algorithm implementation
200pub struct Sha512 {
201    state: [u64; STATE_SIZE],
202    len: u64,
203    buffer: [u8; BLOCK_SIZE],
204}
205
206
207impl Sha512 {
208    ///Creates new instance
209    pub const fn new() -> Self {
210        Self {
211            state: INIT_STATE,
212            len: 0,
213            buffer: [0; BLOCK_SIZE]
214        }
215    }
216
217    ///Resets algorithm's state.
218    pub fn reset(&mut self) {
219        *self = Self::new();
220    }
221
222    ///Hashes input
223    pub const fn const_update(mut self, input: &[u8]) -> Self {
224        let num = (self.len & (BLOCK_SIZE as u64 - 1)) as usize;
225        self.len += input.len() as u64;
226
227        let mut cursor = 0;
228
229        if num > 0 {
230            let block_num = BLOCK_SIZE - num;
231
232            if input.len() < block_num {
233                let mut idx = 0;
234                while idx < input.len() {
235                    self.buffer[num + idx] = input[idx];
236                    idx += 1;
237                }
238                return self;
239            }
240
241            let mut idx = 0;
242            while idx < block_num {
243                self.buffer[num + idx] = input[idx];
244                idx += 1;
245            }
246            self.state = sha512_transform(self.state, 0, &self.buffer);
247            cursor += block_num
248        }
249
250        while input.len() - cursor >= BLOCK_SIZE {
251            self.state = sha512_transform(self.state, cursor, input);
252            cursor += BLOCK_SIZE;
253        }
254
255        let remains = input.len() - cursor;
256        let mut idx = 0;
257        while idx < remains {
258            self.buffer[idx] = input[cursor + idx];
259            idx += 1;
260        }
261
262        self
263    }
264
265    ///Hashes input
266    pub fn update(&mut self, input: &[u8]) {
267        let mut num = (self.len & (BLOCK_SIZE as u64 - 1)) as usize;
268        self.len += input.len() as u64;
269
270        let mut cursor = 0;
271
272        if num > 0 {
273            let buffer = &mut self.buffer[num..];
274            num = BLOCK_SIZE - num;
275
276            if input.len() < num {
277                buffer[..input.len()].copy_from_slice(input);
278                return;
279            }
280
281            buffer.copy_from_slice(&input[..num]);
282            self.state = sha512_transform(self.state, 0, &self.buffer);
283            cursor += num;
284        }
285
286        while input.len() - cursor >= BLOCK_SIZE {
287            self.state = sha512_transform(self.state, cursor, input);
288            cursor += BLOCK_SIZE;
289        }
290
291        let remains = input.len() - cursor;
292        if remains > 0 {
293            self.buffer[..remains].copy_from_slice(&input[cursor..]);
294        }
295    }
296
297    ///Finalizes algorithm, returning the hash.
298    pub const fn const_result(mut self) -> [u8; RESULT_SIZE] {
299        let mut pos = (self.len & (BLOCK_SIZE as u64 - 1)) as usize;
300
301        self.buffer[pos] = 0x80;
302        pos += 1;
303
304        while pos != (BLOCK_SIZE - (2 * core::mem::size_of::<u64>())) {
305            pos &= BLOCK_SIZE - 1;
306
307            if pos == 0 {
308                self.state = sha512_transform(self.state, 0, &self.buffer);
309            }
310
311            self.buffer[pos] = 0;
312            pos += 1;
313        }
314
315        let len_lo = self.len.wrapping_shl(3).to_be_bytes();
316        let len_hi = self.len.wrapping_shr(64 - 3).to_be_bytes();
317
318        self.buffer[pos] = len_hi[0];
319        self.buffer[pos + 1] = len_hi[1];
320        self.buffer[pos + 2] = len_hi[2];
321        self.buffer[pos + 3] = len_hi[3];
322        self.buffer[pos + 4] = len_hi[4];
323        self.buffer[pos + 5] = len_hi[5];
324        self.buffer[pos + 6] = len_hi[6];
325        self.buffer[pos + 7] = len_hi[7];
326
327        self.buffer[pos + 8] = len_lo[0];
328        self.buffer[pos + 9] = len_lo[1];
329        self.buffer[pos + 10] = len_lo[2];
330        self.buffer[pos + 11] = len_lo[3];
331        self.buffer[pos + 12] = len_lo[4];
332        self.buffer[pos + 13] = len_lo[5];
333        self.buffer[pos + 14] = len_lo[6];
334        self.buffer[pos + 15] = len_lo[7];
335
336        self.state = sha512_transform(self.state, 0, &self.buffer);
337
338        let a = self.state[0].to_be_bytes();
339        let b = self.state[1].to_be_bytes();
340        let c = self.state[2].to_be_bytes();
341        let d = self.state[3].to_be_bytes();
342        let e = self.state[4].to_be_bytes();
343        let f = self.state[5].to_be_bytes();
344        let g = self.state[6].to_be_bytes();
345        let h = self.state[7].to_be_bytes();
346        [
347            a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
348            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
349            c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
350            d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
351            e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7],
352            f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7],
353            g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7],
354            h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7],
355        ]
356    }
357
358    ///Finalizes algorithm, returning the hash.
359    pub fn result(&mut self) -> [u8; RESULT_SIZE] {
360        let mut pos = (self.len & (BLOCK_SIZE as u64 - 1)) as usize;
361
362        self.buffer[pos] = 0x80;
363        pos += 1;
364
365        while pos != (BLOCK_SIZE - (2 * core::mem::size_of::<u64>())) {
366            pos &= BLOCK_SIZE - 1;
367
368            if pos == 0 {
369                self.state = sha512_transform(self.state, 0, &self.buffer);
370            }
371
372            self.buffer[pos] = 0;
373            pos += 1;
374        }
375
376        let len_lo = self.len.wrapping_shl(3).to_be_bytes();
377        let len_hi = self.len.wrapping_shr(64 - 3).to_be_bytes();
378
379        self.buffer[pos] = len_hi[0];
380        self.buffer[pos + 1] = len_hi[1];
381        self.buffer[pos + 2] = len_hi[2];
382        self.buffer[pos + 3] = len_hi[3];
383        self.buffer[pos + 4] = len_hi[4];
384        self.buffer[pos + 5] = len_hi[5];
385        self.buffer[pos + 6] = len_hi[6];
386        self.buffer[pos + 7] = len_hi[7];
387
388        self.buffer[pos + 8] = len_lo[0];
389        self.buffer[pos + 9] = len_lo[1];
390        self.buffer[pos + 10] = len_lo[2];
391        self.buffer[pos + 11] = len_lo[3];
392        self.buffer[pos + 12] = len_lo[4];
393        self.buffer[pos + 13] = len_lo[5];
394        self.buffer[pos + 14] = len_lo[6];
395        self.buffer[pos + 15] = len_lo[7];
396
397        self.state = sha512_transform(self.state, 0, &self.buffer);
398
399        let a = self.state[0].to_be_bytes();
400        let b = self.state[1].to_be_bytes();
401        let c = self.state[2].to_be_bytes();
402        let d = self.state[3].to_be_bytes();
403        let e = self.state[4].to_be_bytes();
404        let f = self.state[5].to_be_bytes();
405        let g = self.state[6].to_be_bytes();
406        let h = self.state[7].to_be_bytes();
407        [
408            a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
409            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
410            c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
411            d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
412            e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7],
413            f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7],
414            g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7],
415            h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7],
416        ]
417    }
418}
419
420impl super::Digest for Sha512 {
421    type OutputType = [u8; RESULT_SIZE];
422    type BlockType = [u8; BLOCK_SIZE];
423
424    #[inline(always)]
425    fn new() -> Self {
426        Self::new()
427    }
428
429    #[inline(always)]
430    fn reset(&mut self) {
431        self.reset();
432    }
433
434    #[inline(always)]
435    fn update(&mut self, input: &[u8]) {
436        self.update(input);
437    }
438
439    #[inline(always)]
440    fn result(&mut self) -> Self::OutputType {
441        self.result()
442    }
443}