1pub trait Sha {
2 fn new() -> Self;
3 fn digest(&self, input: &[u8]) -> String;
4}
5
6pub struct Sha1 {}
7
8impl Sha1 {
9 const H: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
11
12 const K: [u32; 4] = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6];
14}
15
16impl Sha for Sha1 {
17 fn new() -> Self {
18 Self {}
19 }
20 fn digest(&self, input: &[u8]) -> String {
21 let padded = pad_512(input); let mut h0 = Self::H[0];
24 let mut h1 = Self::H[1];
25 let mut h2 = Self::H[2];
26 let mut h3 = Self::H[3];
27 let mut h4 = Self::H[4];
28
29 for chunk in padded.chunks(64) {
30 let mut w = [0u32; 80];
31
32 for i in 0..16 {
34 w[i] = u32::from_be_bytes(chunk[i * 4..(i + 1) * 4].try_into().unwrap());
35 }
36
37 for i in 16..80 {
39 w[i] = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
40 w[i] = rotl_32(w[i], 1);
41 }
42
43 let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4);
44
45 for i in 0..80 {
46 let (f, k) = if i < 20 {
47 (ch_32(b, c, d), Self::K[0])
48 } else if i < 40 {
49 (parity_32(b, c, d), Self::K[1])
50 } else if i < 60 {
51 (maj_32(b, c, d), Self::K[2])
52 } else {
53 (parity_32(b, c, d), Self::K[3])
54 };
55
56 let temp = rotl_32(a, 5)
57 .wrapping_add(f)
58 .wrapping_add(e)
59 .wrapping_add(k)
60 .wrapping_add(w[i]);
61 e = d;
62 d = c;
63 c = rotl_32(b, 30);
64 b = a;
65 a = temp;
66 }
67
68 h0 = h0.wrapping_add(a);
70 h1 = h1.wrapping_add(b);
71 h2 = h2.wrapping_add(c);
72 h3 = h3.wrapping_add(d);
73 h4 = h4.wrapping_add(e);
74 }
75
76 let mut hash = [0u8; 20];
78 hash[..4].copy_from_slice(&h0.to_be_bytes());
79 hash[4..8].copy_from_slice(&h1.to_be_bytes());
80 hash[8..12].copy_from_slice(&h2.to_be_bytes());
81 hash[12..16].copy_from_slice(&h3.to_be_bytes());
82 hash[16..20].copy_from_slice(&h4.to_be_bytes());
83
84 hex::encode(hash) }
86}
87
88pub struct Sha256 {}
89
90impl Sha256 {
91 const H: [u32; 8] = [
93 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
94 0x5be0cd19,
95 ];
96
97 const K: [u32; 64] = [
99 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
100 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
101 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
102 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
103 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
104 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
105 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
106 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
107 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
108 0xc67178f2,
109 ];
110}
111
112impl Sha for Sha256 {
113 fn new() -> Self {
114 Self {}
115 }
116 fn digest(&self, input: &[u8]) -> String {
117 let padded = pad_512(input); let mut h0 = Self::H[0];
120 let mut h1 = Self::H[1];
121 let mut h2 = Self::H[2];
122 let mut h3 = Self::H[3];
123 let mut h4 = Self::H[4];
124 let mut h5 = Self::H[5];
125 let mut h6 = Self::H[6];
126 let mut h7 = Self::H[7];
127
128 for chunk in padded.chunks(64) {
129 let mut w = [0u32; 64];
130
131 for i in 0..16 {
133 w[i] = u32::from_be_bytes(chunk[i * 4..(i + 1) * 4].try_into().unwrap());
134 }
135
136 for i in 16..64 {
138 w[i] = delta1_32(w[i - 2])
139 .wrapping_add(w[i - 7])
140 .wrapping_add(delta0_32(w[i - 15]))
141 .wrapping_add(w[i - 16]);
142 }
143
144 let (mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h) =
145 (h0, h1, h2, h3, h4, h5, h6, h7);
146
147 for i in 0..64 {
148 let t1 = h
149 .wrapping_add(sigma1_32(e))
150 .wrapping_add(ch_32(e, f, g))
151 .wrapping_add(Self::K[i])
152 .wrapping_add(w[i]);
153 let t2 = sigma0_32(a).wrapping_add(maj_32(a, b, c));
154
155 h = g;
156 g = f;
157 f = e;
158 e = d.wrapping_add(t1);
159 d = c;
160 c = b;
161 b = a;
162 a = t1.wrapping_add(t2);
163 }
164
165 h0 = h0.wrapping_add(a);
167 h1 = h1.wrapping_add(b);
168 h2 = h2.wrapping_add(c);
169 h3 = h3.wrapping_add(d);
170 h4 = h4.wrapping_add(e);
171 h5 = h5.wrapping_add(f);
172 h6 = h6.wrapping_add(g);
173 h7 = h7.wrapping_add(h);
174 }
175
176 let mut hash = [0u8; 32];
178 hash[..4].copy_from_slice(&h0.to_be_bytes());
179 hash[4..8].copy_from_slice(&h1.to_be_bytes());
180 hash[8..12].copy_from_slice(&h2.to_be_bytes());
181 hash[12..16].copy_from_slice(&h3.to_be_bytes());
182 hash[16..20].copy_from_slice(&h4.to_be_bytes());
183 hash[20..24].copy_from_slice(&h5.to_be_bytes());
184 hash[24..28].copy_from_slice(&h6.to_be_bytes());
185 hash[28..32].copy_from_slice(&h7.to_be_bytes());
186
187 hex::encode(hash) }
189}
190
191pub struct Sha512 {}
192
193impl Sha512 {
194 const H: [u64; 8] = [
196 0x6a09e667f3bcc908,
197 0xbb67ae8584caa73b,
198 0x3c6ef372fe94f82b,
199 0xa54ff53a5f1d36f1,
200 0x510e527fade682d1,
201 0x9b05688c2b3e6c1f,
202 0x1f83d9abfb41bd6b,
203 0x5be0cd19137e2179,
204 ];
205
206 const K: [u64; 80] = [
208 0x428a2f98d728ae22,
209 0x7137449123ef65cd,
210 0xb5c0fbcfec4d3b2f,
211 0xe9b5dba58189dbbc,
212 0x3956c25bf348b538,
213 0x59f111f1b605d019,
214 0x923f82a4af194f9b,
215 0xab1c5ed5da6d8118,
216 0xd807aa98a3030242,
217 0x12835b0145706fbe,
218 0x243185be4ee4b28c,
219 0x550c7dc3d5ffb4e2,
220 0x72be5d74f27b896f,
221 0x80deb1fe3b1696b1,
222 0x9bdc06a725c71235,
223 0xc19bf174cf692694,
224 0xe49b69c19ef14ad2,
225 0xefbe4786384f25e3,
226 0x0fc19dc68b8cd5b5,
227 0x240ca1cc77ac9c65,
228 0x2de92c6f592b0275,
229 0x4a7484aa6ea6e483,
230 0x5cb0a9dcbd41fbd4,
231 0x76f988da831153b5,
232 0x983e5152ee66dfab,
233 0xa831c66d2db43210,
234 0xb00327c898fb213f,
235 0xbf597fc7beef0ee4,
236 0xc6e00bf33da88fc2,
237 0xd5a79147930aa725,
238 0x06ca6351e003826f,
239 0x142929670a0e6e70,
240 0x27b70a8546d22ffc,
241 0x2e1b21385c26c926,
242 0x4d2c6dfc5ac42aed,
243 0x53380d139d95b3df,
244 0x650a73548baf63de,
245 0x766a0abb3c77b2a8,
246 0x81c2c92e47edaee6,
247 0x92722c851482353b,
248 0xa2bfe8a14cf10364,
249 0xa81a664bbc423001,
250 0xc24b8b70d0f89791,
251 0xc76c51a30654be30,
252 0xd192e819d6ef5218,
253 0xd69906245565a910,
254 0xf40e35855771202a,
255 0x106aa07032bbd1b8,
256 0x19a4c116b8d2d0c8,
257 0x1e376c085141ab53,
258 0x2748774cdf8eeb99,
259 0x34b0bcb5e19b48a8,
260 0x391c0cb3c5c95a63,
261 0x4ed8aa4ae3418acb,
262 0x5b9cca4f7763e373,
263 0x682e6ff3d6b2b8a3,
264 0x748f82ee5defb2fc,
265 0x78a5636f43172f60,
266 0x84c87814a1f0ab72,
267 0x8cc702081a6439ec,
268 0x90befffa23631e28,
269 0xa4506cebde82bde9,
270 0xbef9a3f7b2c67915,
271 0xc67178f2e372532b,
272 0xca273eceea26619c,
273 0xd186b8c721c0c207,
274 0xeada7dd6cde0eb1e,
275 0xf57d4f7fee6ed178,
276 0x06f067aa72176fba,
277 0x0a637dc5a2c898a6,
278 0x113f9804bef90dae,
279 0x1b710b35131c471b,
280 0x28db77f523047d84,
281 0x32caab7b40c72493,
282 0x3c9ebe0a15c9bebc,
283 0x431d67c49c100d4c,
284 0x4cc5d4becb3e42b6,
285 0x597f299cfc657e2a,
286 0x5fcb6fab3ad6faec,
287 0x6c44198c4a475817,
288 ];
289}
290
291impl Sha for Sha512 {
292 fn new() -> Self {
293 Self {}
294 }
295 fn digest(&self, input: &[u8]) -> String {
296 let padded = pad_1024(input);
297
298 let mut h0 = Self::H[0];
299 let mut h1 = Self::H[1];
300 let mut h2 = Self::H[2];
301 let mut h3 = Self::H[3];
302 let mut h4 = Self::H[4];
303 let mut h5 = Self::H[5];
304 let mut h6 = Self::H[6];
305 let mut h7 = Self::H[7];
306
307 for chunk in padded.chunks(128) {
308 let mut w = [0u64; 80];
309
310 for i in 0..16 {
312 w[i] = u64::from_be_bytes(chunk[i * 8..(i + 1) * 8].try_into().unwrap());
313 }
314
315 for i in 16..80 {
317 w[i] = delta1_64(w[i - 2])
318 .wrapping_add(w[i - 7])
319 .wrapping_add(delta0_64(w[i - 15]))
320 .wrapping_add(w[i - 16]);
321 }
322
323 let (mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h) =
324 (h0, h1, h2, h3, h4, h5, h6, h7);
325
326 for i in 0..80 {
327 let t1 = h
328 .wrapping_add(sigma1_64(e))
329 .wrapping_add(ch_64(e, f, g))
330 .wrapping_add(Self::K[i])
331 .wrapping_add(w[i]);
332 let t2 = sigma0_64(a).wrapping_add(maj_64(a, b, c));
333
334 h = g;
335 g = f;
336 f = e;
337 e = d.wrapping_add(t1);
338 d = c;
339 c = b;
340 b = a;
341 a = t1.wrapping_add(t2);
342 }
343
344 h0 = h0.wrapping_add(a);
346 h1 = h1.wrapping_add(b);
347 h2 = h2.wrapping_add(c);
348 h3 = h3.wrapping_add(d);
349 h4 = h4.wrapping_add(e);
350 h5 = h5.wrapping_add(f);
351 h6 = h6.wrapping_add(g);
352 h7 = h7.wrapping_add(h);
353 }
354
355 let mut hash = [0u8; 64];
357 hash[..8].copy_from_slice(&h0.to_be_bytes());
358 hash[8..16].copy_from_slice(&h1.to_be_bytes());
359 hash[16..24].copy_from_slice(&h2.to_be_bytes());
360 hash[24..32].copy_from_slice(&h3.to_be_bytes());
361 hash[32..40].copy_from_slice(&h4.to_be_bytes());
362 hash[40..48].copy_from_slice(&h5.to_be_bytes());
363 hash[48..56].copy_from_slice(&h6.to_be_bytes());
364 hash[56..64].copy_from_slice(&h7.to_be_bytes());
365
366 hex::encode(hash) }
368}
369
370fn ch_32(x: u32, y: u32, z: u32) -> u32 {
373 (x & y) ^ (!x & z)
374}
375
376fn maj_32(x: u32, y: u32, z: u32) -> u32 {
377 (x & y) ^ (x & z) ^ (y & z)
378}
379
380fn parity_32(x: u32, y: u32, z: u32) -> u32 {
381 x ^ y ^ z
382}
383
384fn rotr_32(x: u32, n: u32) -> u32 {
385 (x >> n) | (x << (32 - n))
386}
387
388fn rotl_32(x: u32, n: u32) -> u32 {
389 (x << n) | (x >> (32 - n))
390}
391
392fn sigma0_32(x: u32) -> u32 {
393 rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22)
394}
395
396fn sigma1_32(x: u32) -> u32 {
397 rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25)
398}
399
400fn delta0_32(x: u32) -> u32 {
401 rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3)
402}
403
404fn delta1_32(x: u32) -> u32 {
405 rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10)
406}
407
408fn shr_32(x: u32, n: u32) -> u32 {
409 x >> n
410}
411
412fn ch_64(x: u64, y: u64, z: u64) -> u64 {
413 (x & y) ^ (!x & z)
414}
415
416fn maj_64(x: u64, y: u64, z: u64) -> u64 {
417 (x & y) ^ (x & z) ^ (y & z)
418}
419
420fn rotr_64(x: u64, n: u64) -> u64 {
421 (x >> n) | (x << (64 - n))
422}
423
424fn sigma0_64(x: u64) -> u64 {
425 rotr_64(x, 28) ^ rotr_64(x, 34) ^ rotr_64(x, 39)
426}
427
428fn sigma1_64(x: u64) -> u64 {
429 rotr_64(x, 14) ^ rotr_64(x, 18) ^ rotr_64(x, 41)
430}
431
432fn delta0_64(x: u64) -> u64 {
433 rotr_64(x, 1) ^ rotr_64(x, 8) ^ shr_64(x, 7)
434}
435
436fn delta1_64(x: u64) -> u64 {
437 rotr_64(x, 19) ^ rotr_64(x, 61) ^ shr_64(x, 6)
438}
439
440fn shr_64(x: u64, n: u64) -> u64 {
441 x >> n
442}
443
444fn pad_512(input: &[u8]) -> Vec<u8> {
445 let mut padded = input.to_vec();
446 padded.push(0x80);
447
448 while (padded.len() * 8) % 512 != 448 {
449 padded.push(0);
450 }
451
452 let bit_len = (input.len() as u64) * 8;
453 padded.extend_from_slice(&bit_len.to_be_bytes());
454
455 padded
456}
457
458fn pad_1024(input: &[u8]) -> Vec<u8> {
459 let mut padded = input.to_vec();
460 padded.push(0x80);
461
462 while (padded.len() * 8) % 1024 != 896 {
463 padded.push(0);
464 }
465
466 let bit_len = (input.len() as u128) * 8;
467 padded.extend_from_slice(&bit_len.to_be_bytes());
468
469 padded
470}
471
472#[cfg(test)]
475mod tests {
476 use super::*;
477
478 #[test]
479 fn test_sha1() {
480 let sha1 = Sha1::new();
481 let input1 = b"abc";
482 let input2 = b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
483 let expected_hash1 = "a9993e364706816aba3e25717850c26c9cd0d89d";
484 let expected_hash2 = "84983e441c3bd26ebaae4aa1f95129e5e54670f1";
485 let hash1 = sha1.digest(input1);
486 let hash2 = sha1.digest(input2);
487
488 assert_eq!(expected_hash1, hash1);
489 assert_eq!(expected_hash2, hash2);
490 }
491
492 #[test]
493 fn test_sha256() {
494 let sha256 = Sha256::new();
495 let input1 = b"abc";
496 let input2 = b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
497 let expected_hash1 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
498 let expected_hash2 = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1";
499 let hash1 = sha256.digest(input1);
500 let hash2 = sha256.digest(input2);
501
502 assert_eq!(expected_hash1, hash1);
503 assert_eq!(expected_hash2, hash2);
504 }
505
506 #[test]
507 fn test_sha512() {
508 let sha512 = Sha512::new();
509 let input1 = b"abc";
510 let input2 = b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
511 let expected_hash1 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
512 let expected_hash2 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909";
513 let hash1 = sha512.digest(input1);
514 let hash2 = sha512.digest(input2);
515
516 assert_eq!(expected_hash1, hash1);
517 assert_eq!(expected_hash2, hash2);
518 }
519}