neo_crypto/
sha.rs

1mod sha_cfg;
2
3use crate::sha::sha_cfg::{
4    HASH224_INIT_VALUES, HASH256_INIT_VALUES, HASH384_INIT_VALUES, HASH512_INIT_VALUES, K_224_256,
5    K_384_512,
6};
7use std::{u128, usize};
8
9#[cfg(test)]
10mod sha_tests {
11    use super::{sha, ShaType};
12    #[test]
13    fn sha224() {
14        let message: String = String::from("SUNYSUNYSUNYSUNY");
15        let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA224);
16        let mut hash_hex_str: String = String::new();
17
18        for byte in hash_bytes {
19            hash_hex_str.push_str(&format!("{:02x}", byte))
20        }
21
22        assert_eq!(
23            hash_hex_str,
24            String::from("678669c52c658fba0da32398376f700f367d2adf82291a269308f168")
25        );
26    }
27
28    #[test]
29    fn sha256() {
30        let message: String = String::from("SUNYSUNYSUNYSUNY");
31        let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA256);
32        let mut hash_hex_str: String = String::new();
33
34        for byte in hash_bytes {
35            hash_hex_str.push_str(&format!("{:02x}", byte))
36        }
37
38        assert_eq!(
39            hash_hex_str,
40            String::from("142ea313267fe7670d878726214c30b6850a1e189edeff9cd4f769ba02371180")
41        );
42    }
43
44    #[test]
45    fn sha384() {
46        let message: String = String::from("SUNYSUNYSUNYSUNYSUNYSUNYSUNYSUNY");
47
48        let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA384);
49        let mut hash_hex_str: String = String::new();
50
51        for byte in hash_bytes {
52            hash_hex_str.push_str(&format!("{:02x}", byte))
53        }
54
55        assert_eq!(
56            hash_hex_str,
57            String::from("b206401fad03e08d606bce8eab03f5116e01963dc5af6c8162b4020bc2a98c1ed7417399a0d611d259c04a6e6868f0e4")
58        );
59    }
60    #[test]
61    fn sha512() {
62        let message: String = String::from("SUNYSUNYSUNYSUNYSUNYSUNYSUNYSUNY");
63        let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA512);
64        let mut hash_hex_str: String = String::new();
65
66        for byte in hash_bytes {
67            hash_hex_str.push_str(&format!("{:02x}", byte))
68        }
69
70        assert_eq!(
71            hash_hex_str,
72            String::from("e8d877cad3ada1877203bec43cad9fe6fba800b91afcf874069d0c5559ac4efd3645009564fe7490c0f13c6aa4c069e0d3aed4ea2dc36af77696008602ff459e")
73        );
74    }
75}
76pub enum ShaType {
77    SHA224,
78    SHA256,
79    SHA384,
80    SHA512,
81}
82
83pub fn sha(message: &str, sha_type: ShaType) -> Vec<u8> {
84    let mut message_padding: Vec<u8> = Vec::from(message);
85
86    // padding msg regardless of whether length of msg meet with expectation
87    padding(&mut message_padding, &sha_type);
88
89    let mut res: Vec<u8> = Vec::new();
90
91    match sha_type {
92        ShaType::SHA224 => {
93            let hash: [u32; 8] = iteration_64(&message_padding, &HASH224_INIT_VALUES, &K_224_256);
94            for word in hash.into_iter().take(7) {
95                res.append(&mut word.to_be_bytes().to_vec());
96            }
97        }
98        ShaType::SHA256 => {
99            let hash: [u32; 8] = iteration_64(&message_padding, &HASH256_INIT_VALUES, &K_224_256);
100            for word in hash {
101                res.append(&mut word.to_be_bytes().to_vec());
102            }
103        }
104        ShaType::SHA384 => {
105            let hash: [u64; 8] = iteration_80(&message_padding, &HASH384_INIT_VALUES, &K_384_512);
106            for word in hash.into_iter().take(6) {
107                res.append(&mut word.to_be_bytes().to_vec());
108            }
109        }
110        ShaType::SHA512 => {
111            let hash: [u64; 8] = iteration_80(&message_padding, &HASH512_INIT_VALUES, &K_384_512);
112            for word in hash {
113                res.append(&mut word.to_be_bytes().to_vec());
114            }
115        }
116    };
117
118    res
119}
120
121fn padding(message: &mut Vec<u8>, sha_type: &ShaType) {
122    let alignment: u32;
123    let remainer_expect: u32;
124    let message_bits = (message.len() as u32) * u8::BITS;
125    let mut message_length: Vec<u8>;
126
127    match sha_type {
128        ShaType::SHA224 | ShaType::SHA256 => {
129            alignment = 512;
130            remainer_expect = alignment - u64::BITS;
131            message_length = Vec::from((message_bits as u64).to_be_bytes());
132        }
133        ShaType::SHA384 | ShaType::SHA512 => {
134            alignment = 1024;
135            remainer_expect = alignment - u128::BITS;
136            message_length = Vec::from((message_bits as u128).to_be_bytes());
137        }
138    };
139
140    let remainer = message_bits % alignment;
141
142    let bits_padding = if remainer == remainer_expect {
143        alignment
144    } else {
145        if remainer > remainer_expect {
146            alignment + remainer_expect - remainer
147        } else {
148            remainer_expect - remainer
149        }
150    };
151
152    // push fixed byte 0x80
153    message.push(0x80);
154
155    // push padding value 0x00
156    for _ in 1..(bits_padding as u32) / u8::BITS {
157        message.push(0x00);
158    }
159
160    // append length of big endian msg
161    message.append(&mut message_length);
162}
163
164fn iteration_64(message_padding: &[u8], hash_init_values: &[u32; 8], k: &[u32; 64]) -> [u32; 8] {
165    let mut w: [u32; 64] = [0; 64];
166    let mut m: Vec<u32> = Vec::new();
167    let mut hash: [u32; 8] = hash_init_values.clone();
168
169    // break msg into word (32 bits)
170    for chunk in message_padding.chunks((u32::BITS / u8::BITS) as usize) {
171        m.push(u32::from_be_bytes(
172            chunk.try_into().expect("Convert bytes to u32 failed!"),
173        ));
174    }
175
176    let msg_total_bits: usize = m.len() * u32::BITS as usize;
177    let msg_blocks_num: usize = msg_total_bits / 512;
178
179    // main loop
180    for mi in 0..msg_blocks_num {
181        for i in 0..16 {
182            w[i] = m[(mi * 16)..(mi * 16 + 16)][i];
183        }
184
185        for i in 16..64 {
186            let s0: u32 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
187            let s1: u32 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
188            w[i] = s1 + w[i - 7] + s0 + w[i - 16];
189        }
190
191        let mut a: u32 = hash[0];
192        let mut b: u32 = hash[1];
193        let mut c: u32 = hash[2];
194        let mut d: u32 = hash[3];
195        let mut e: u32 = hash[4];
196        let mut f: u32 = hash[5];
197        let mut g: u32 = hash[6];
198        let mut h: u32 = hash[7];
199
200        for i in 0..64 {
201            let s0: u32 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
202            let s1: u32 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
203            let maj: u32 = (a & b) ^ (a & c) ^ (b & c);
204            let ch: u32 = (e & f) ^ ((!e) & g);
205            let t1: u32 = h + s1 + ch + k[i] + w[i];
206            let t2: u32 = s0 + maj;
207
208            h = g;
209            g = f;
210            f = e;
211            e = d + t1;
212            d = c;
213            c = b;
214            b = a;
215            a = t1 + t2;
216        }
217
218        hash[0] += a;
219        hash[1] += b;
220        hash[2] += c;
221        hash[3] += d;
222        hash[4] += e;
223        hash[5] += f;
224        hash[6] += g;
225        hash[7] += h;
226    }
227    hash
228}
229
230fn iteration_80(message_padding: &[u8], hash_init_values: &[u64; 8], k: &[u64; 80]) -> [u64; 8] {
231    let mut w: [u64; 80] = [0; 80];
232    let mut m: Vec<u64> = Vec::new();
233    let mut hash = hash_init_values.clone();
234
235    // break msg into double word (64 bits)
236    for chunk in message_padding.chunks((u64::BITS / u8::BITS) as usize) {
237        m.push(u64::from_be_bytes(
238            chunk.try_into().expect("Convert bytes to u64 failed!"),
239        ));
240    }
241
242    let msg_total_bits: usize = m.len() * u64::BITS as usize;
243    let msg_blocks_num: usize = msg_total_bits / 1024;
244
245    // main loop
246    for mi in 0..msg_blocks_num {
247        for i in 0..16 {
248            w[i] = m[(mi * 16)..(mi * 16 + 16)][i];
249        }
250
251        for i in 16..80 {
252            let s0: u64 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
253            let s1: u64 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
254            w[i] = s1 + w[i - 16] + s0 + w[i - 7];
255        }
256
257        let mut a: u64 = hash[0];
258        let mut b: u64 = hash[1];
259        let mut c: u64 = hash[2];
260        let mut d: u64 = hash[3];
261        let mut e: u64 = hash[4];
262        let mut f: u64 = hash[5];
263        let mut g: u64 = hash[6];
264        let mut h: u64 = hash[7];
265
266        for i in 0..80 {
267            let s0: u64 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
268            let s1: u64 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
269            let maj: u64 = (a & b) ^ (a & c) ^ (b & c);
270            let ch: u64 = (e & f) ^ ((!e) & g);
271            let t1: u64 = h + s1 + ch + k[i] + w[i];
272            let t2: u64 = s0 + maj;
273
274            h = g;
275            g = f;
276            f = e;
277            e = d + t1;
278            d = c;
279            c = b;
280            b = a;
281            a = t1 + t2;
282        }
283
284        hash[0] += a;
285        hash[1] += b;
286        hash[2] += c;
287        hash[3] += d;
288        hash[4] += e;
289        hash[5] += f;
290        hash[6] += g;
291        hash[7] += h;
292    }
293
294    hash
295}