sha_rs/
lib.rs

1pub trait Sha {
2    fn new() -> Self;
3    fn digest(&self, input: &[u8]) -> String;
4}
5
6pub struct Sha1 {}
7
8impl Sha1 {
9    // Initial hash values
10    const H: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
11
12    // Round constants for SHA-1
13    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); // Padding the input to the required block size
22
23        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            // Prepare message schedule
33            for i in 0..16 {
34                w[i] = u32::from_be_bytes(chunk[i * 4..(i + 1) * 4].try_into().unwrap());
35            }
36
37            // Extend the message schedule
38            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            // Update the hash values
69            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        // Convert final hash values to bytes
77        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) // Convert the bytes to a hex string
85    }
86}
87
88pub struct Sha256 {}
89
90impl Sha256 {
91    // Initial hash values
92    const H: [u32; 8] = [
93        0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
94        0x5be0cd19,
95    ];
96
97    // Round constants for SHA-256
98    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); // Padding the input to the required block size
118
119        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            // Prepare message schedule
132            for i in 0..16 {
133                w[i] = u32::from_be_bytes(chunk[i * 4..(i + 1) * 4].try_into().unwrap());
134            }
135
136            // Extend the message schedule
137            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            // Update the hash values
166            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        // Convert final hash values to bytes
177        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) // Convert the bytes to a hex string
188    }
189}
190
191pub struct Sha512 {}
192
193impl Sha512 {
194    // Initial hash values
195    const H: [u64; 8] = [
196        0x6a09e667f3bcc908,
197        0xbb67ae8584caa73b,
198        0x3c6ef372fe94f82b,
199        0xa54ff53a5f1d36f1,
200        0x510e527fade682d1,
201        0x9b05688c2b3e6c1f,
202        0x1f83d9abfb41bd6b,
203        0x5be0cd19137e2179,
204    ];
205
206    // Round constants for SHA-512
207    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            // Prepare message schedule
311            for i in 0..16 {
312                w[i] = u64::from_be_bytes(chunk[i * 8..(i + 1) * 8].try_into().unwrap());
313            }
314
315            // Extend the message schedule
316            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            // Update the hash values
345            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        // Convert final hash values to bytes
356        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) // Convert the bytes to a hex string
367    }
368}
369
370// UTILITY FUNCTIONS
371
372fn 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// TESTS are from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA_All.pdf
473
474#[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}