1use crate::Hasher;
19
20pub(crate) const H0_512: [u64; 8] = [
21 0x6a09e667f3bcc908,
22 0xbb67ae8584caa73b,
23 0x3c6ef372fe94f82b,
24 0xa54ff53a5f1d36f1,
25 0x510e527fade682d1,
26 0x9b05688c2b3e6c1f,
27 0x1f83d9abfb41bd6b,
28 0x5be0cd19137e2179,
29];
30
31const K: [u64; 80] = [
32 0x428a2f98d728ae22,
33 0x7137449123ef65cd,
34 0xb5c0fbcfec4d3b2f,
35 0xe9b5dba58189dbbc,
36 0x3956c25bf348b538,
37 0x59f111f1b605d019,
38 0x923f82a4af194f9b,
39 0xab1c5ed5da6d8118,
40 0xd807aa98a3030242,
41 0x12835b0145706fbe,
42 0x243185be4ee4b28c,
43 0x550c7dc3d5ffb4e2,
44 0x72be5d74f27b896f,
45 0x80deb1fe3b1696b1,
46 0x9bdc06a725c71235,
47 0xc19bf174cf692694,
48 0xe49b69c19ef14ad2,
49 0xefbe4786384f25e3,
50 0x0fc19dc68b8cd5b5,
51 0x240ca1cc77ac9c65,
52 0x2de92c6f592b0275,
53 0x4a7484aa6ea6e483,
54 0x5cb0a9dcbd41fbd4,
55 0x76f988da831153b5,
56 0x983e5152ee66dfab,
57 0xa831c66d2db43210,
58 0xb00327c898fb213f,
59 0xbf597fc7beef0ee4,
60 0xc6e00bf33da88fc2,
61 0xd5a79147930aa725,
62 0x06ca6351e003826f,
63 0x142929670a0e6e70,
64 0x27b70a8546d22ffc,
65 0x2e1b21385c26c926,
66 0x4d2c6dfc5ac42aed,
67 0x53380d139d95b3df,
68 0x650a73548baf63de,
69 0x766a0abb3c77b2a8,
70 0x81c2c92e47edaee6,
71 0x92722c851482353b,
72 0xa2bfe8a14cf10364,
73 0xa81a664bbc423001,
74 0xc24b8b70d0f89791,
75 0xc76c51a30654be30,
76 0xd192e819d6ef5218,
77 0xd69906245565a910,
78 0xf40e35855771202a,
79 0x106aa07032bbd1b8,
80 0x19a4c116b8d2d0c8,
81 0x1e376c085141ab53,
82 0x2748774cdf8eeb99,
83 0x34b0bcb5e19b48a8,
84 0x391c0cb3c5c95a63,
85 0x4ed8aa4ae3418acb,
86 0x5b9cca4f7763e373,
87 0x682e6ff3d6b2b8a3,
88 0x748f82ee5defb2fc,
89 0x78a5636f43172f60,
90 0x84c87814a1f0ab72,
91 0x8cc702081a6439ec,
92 0x90befffa23631e28,
93 0xa4506cebde82bde9,
94 0xbef9a3f7b2c67915,
95 0xc67178f2e372532b,
96 0xca273eceea26619c,
97 0xd186b8c721c0c207,
98 0xeada7dd6cde0eb1e,
99 0xf57d4f7fee6ed178,
100 0x06f067aa72176fba,
101 0x0a637dc5a2c898a6,
102 0x113f9804bef90dae,
103 0x1b710b35131c471b,
104 0x28db77f523047d84,
105 0x32caab7b40c72493,
106 0x3c9ebe0a15c9bebc,
107 0x431d67c49c100d4c,
108 0x4cc5d4becb3e42b6,
109 0x597f299cfc657e2a,
110 0x5fcb6fab3ad6faec,
111 0x6c44198c4a475817,
112];
113
114pub(crate) fn compress(state: &mut [u64; 8], block: &[u8]) {
115 let mut w = [0u64; 80];
116 for i in 0..16 {
117 w[i] = u64::from_be_bytes([
118 block[8 * i],
119 block[8 * i + 1],
120 block[8 * i + 2],
121 block[8 * i + 3],
122 block[8 * i + 4],
123 block[8 * i + 5],
124 block[8 * i + 6],
125 block[8 * i + 7],
126 ]);
127 }
128 for i in 16..80 {
129 let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
130 let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
131 w[i] = w[i - 16].wrapping_add(s0).wrapping_add(w[i - 7]).wrapping_add(s1);
132 }
133
134 let mut a = state[0];
135 let mut b = state[1];
136 let mut c = state[2];
137 let mut d = state[3];
138 let mut e = state[4];
139 let mut f = state[5];
140 let mut g = state[6];
141 let mut h = state[7];
142
143 for i in 0..80 {
144 let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
145 let ch = (e & f) ^ ((!e) & g);
146 let temp1 = h
147 .wrapping_add(s1)
148 .wrapping_add(ch)
149 .wrapping_add(K[i])
150 .wrapping_add(w[i]);
151 let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
152 let maj = (a & b) ^ (a & c) ^ (b & c);
153 let temp2 = s0.wrapping_add(maj);
154
155 h = g;
156 g = f;
157 f = e;
158 e = d.wrapping_add(temp1);
159 d = c;
160 c = b;
161 b = a;
162 a = temp1.wrapping_add(temp2);
163 }
164
165 state[0] = state[0].wrapping_add(a);
166 state[1] = state[1].wrapping_add(b);
167 state[2] = state[2].wrapping_add(c);
168 state[3] = state[3].wrapping_add(d);
169 state[4] = state[4].wrapping_add(e);
170 state[5] = state[5].wrapping_add(f);
171 state[6] = state[6].wrapping_add(g);
172 state[7] = state[7].wrapping_add(h);
173}
174
175#[derive(Clone)]
183pub struct Sha512 {
184 pub(crate) state: [u64; 8],
185 buf: [u8; 128],
186 buf_len: usize,
187 total_len: u128,
188}
189
190impl Sha512 {
191 pub(crate) fn new_with_iv(iv: [u64; 8]) -> Self {
192 Self {
193 state: iv,
194 buf: [0u8; 128],
195 buf_len: 0,
196 total_len: 0,
197 }
198 }
199}
200
201impl Hasher for Sha512 {
202 const OUTPUT_LEN: usize = 64;
203 const BLOCK_LEN: usize = 128;
204
205 fn new() -> Self {
206 Self::new_with_iv(H0_512)
207 }
208
209 fn update(&mut self, data: &[u8]) {
210 let mut pos = 0;
211 self.total_len += data.len() as u128;
212
213 if self.buf_len > 0 {
214 let need = 128 - self.buf_len;
215 let take = need.min(data.len());
216 self.buf[self.buf_len..self.buf_len + take].copy_from_slice(&data[..take]);
217 self.buf_len += take;
218 pos = take;
219 if self.buf_len == 128 {
220 let block = self.buf;
221 compress(&mut self.state, &block);
222 self.buf_len = 0;
223 }
224 }
225
226 while pos + 128 <= data.len() {
227 compress(&mut self.state, &data[pos..pos + 128]);
228 pos += 128;
229 }
230
231 if pos < data.len() {
232 let remaining = data.len() - pos;
233 self.buf[..remaining].copy_from_slice(&data[pos..]);
234 self.buf_len = remaining;
235 }
236 }
237
238 fn finalize(self) -> Vec<u8> {
239 let mut out = vec![0u8; 64];
240 self.finalize_into(&mut out);
241 out
242 }
243
244 fn finalize_into(mut self, out: &mut [u8]) {
245 let bit_len = self.total_len * 8;
246 let mut pad = [0u8; 136]; pad[0] = 0x80;
248 let pad_len = if self.buf_len < 112 {
249 112 - self.buf_len
250 } else {
251 240 - self.buf_len
252 };
253 self.update(&pad[..pad_len]);
254 self.update(&(bit_len as u128).to_be_bytes());
256
257 for (i, word) in self.state.iter().enumerate() {
258 let bytes = word.to_be_bytes();
259 let start = i * 8;
260 if start + 8 <= out.len() {
261 out[start..start + 8].copy_from_slice(&bytes);
262 } else if start < out.len() {
263 let end = out.len() - start;
264 out[start..].copy_from_slice(&bytes[..end]);
265 }
266 }
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use crate::Hasher;
274
275 #[test]
276 fn test_sha512_empty() {
277 let digest = Sha512::hash(b"");
278 let expected: [u8; 64] = [
279 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, 0xd6, 0x20,
280 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, 0x47, 0xd0, 0xd1, 0x3c,
281 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41,
282 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e,
283 ];
284 assert_eq!(&digest[..], &expected[..]);
285 }
286
287 #[test]
288 fn test_sha512_abc() {
289 let digest = Sha512::hash(b"abc");
290 let expected: [u8; 64] = [
291 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6,
292 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
293 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c,
294 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f,
295 ];
296 assert_eq!(&digest[..], &expected[..]);
297 }
298}