1use std::ops::{BitXor, BitAnd};
6
7use crypto_bigint::{U512,U256};
8use crate::conversions;
9use crate::constants::{Constants, Sha256, Sha224};
10
11
12pub fn sha_256(m:Vec<U512>) -> U256 {
14 sha256_internal::<Sha256>(m)
15}
16
17pub fn sha_224(m:Vec<U512>) -> [u32;7] {
20 let hash = sha256_internal::<Sha224>(m);
21 let words = conversions::to_u32_words(hash);
22 let mut truncated_words = [0u32; 7];
23 for i in 0..7 {
24 truncated_words[i] = words[i];
25 }
26 return truncated_words;
27}
28
29
30pub fn sha256_internal<C:Constants<64,u32>>(msg:Vec<U512>) -> U256 {
33 let mut hash = C::initial_hash();
34 for block in msg {
35 let registers = sha256_compression::<C>(&hash, block);
36 for i in 0..8 {
37 hash[i] = hash[i].wrapping_add(registers[i]);
38 }
39 }
40 conversions::from_u32_words(&hash.to_vec())
41
42}
43
44fn sha256_compression<C:Constants<64,u32>>(intermediate_hash:&[u32;8], msg:U512) -> [u32;8] {
45 let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = intermediate_hash.clone();
46 let constants_k = C::constant_words();
47 let expanded_blocks = sha256_message_schedule(msg);
48
49 for j in 0..64 {
50 let T1 = wrapping_sum(vec![
51 h, sigma_l1(e), ch(e,f,g), constants_k[j], expanded_blocks[j]
52 ]);
53 let T2 = sigma_l0(a).wrapping_add(maj(a,b,c));
54
55 h = g;
56 g = f;
57 f = e;
58 e = d.wrapping_add(T1);
59 d = c;
60 c = b;
61 b = a;
62 a = T1.wrapping_add(T2);
63 }
64
65 [a, b, c, d, e, f, g, h]
66}
67
68fn ch(x:u32, y:u32, z:u32) -> u32 {
71 let x_and_y = x.bitand(y);
72 let x_and_z = inv(x).bitand(z);
73 return x_and_y.bitxor(x_and_z);
74}
75
76fn maj(x:u32, y:u32, z:u32) -> u32 {
77 let x_and_y = x.bitand(y);
78 let y_and_z = y.bitand(z);
79 let x_and_z = x.bitand(z);
80 return x_and_y.bitxor(y_and_z).bitxor(x_and_z);
81}
82
83fn sigma_l0(x:u32) -> u32 {
84 let s2 = x.rotate_right(2);
85 let s13 = x.rotate_right(13);
86 let s22 = x.rotate_right(22);
87 return s2.bitxor(s13).bitxor(s22);
88}
89
90fn sigma_l1(x:u32) -> u32 {
91 let s6 = x.rotate_right(6);
92 let s11 = x.rotate_right(11);
93 let s25 = x.rotate_right(25);
94 return s6.bitxor(s11).bitxor(s25);
95
96}
97
98fn sigma_s0(x:u32) -> u32 {
99 let s7 = x.rotate_right(7);
100 let s18 = x.rotate_right(18);
101 let r3 = x >> 3;
102 return s7.bitxor(s18).bitxor(r3);
103}
104
105fn sigma_s1(x:u32) -> u32 {
106 let s17 = x.rotate_right(17);
107 let s19 = x.rotate_right(19);
108 let r10 = x >> 10;
109 return s17.bitxor(s19).bitxor(r10);
110}
111
112fn inv(x:u32) -> u32 {
114 x.bitxor(u32::MAX)
115}
116
117fn xor_sum(v:Vec<u32>) -> u32 {
118 let mut res = 0u32;
119 for u in v {
120 res = res.bitxor(u);
121 }
122 return res;
123}
124
125fn wrapping_sum(v:Vec<u32>) -> u32 {
126 let mut res = 0u32;
127 for u in v {
128 res = res.wrapping_add(u);
129 }
130 return res;
131}
132
133
134fn sha256_message_schedule(m:U512) -> [u32;64] {
137 let m = conversions::to_u32_words(m);
139 let mut w = [0u32; 64];
140 for i in 0..16 {
141 w[i] = m[i];
142 }
143
144 for i in 16..64 {
145 let mut w_i = sigma_s1(w[i - 2]);
146 w_i = w_i.wrapping_add(w[i - 7]);
147 w_i = w_i.wrapping_add(sigma_s0(w[i - 15]));
148 w_i = w_i.wrapping_add(w[i - 16]);
149 w[i] = w_i;
150 }
151
152 return w;
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 #[test]
159 fn simple_sigma_s0() {
160 let y = sigma_s0(1);
161 let expected = (1 << 25) + (1 << 14);
162 assert_eq!(y, expected);
163 }
164
165 #[test]
166 fn simple_sigma_s1() {
167 let y = sigma_s1(1 << 31);
168 let expected = 0b00000000_00100000_01010000_00000000;
169 assert_eq!(y,expected);
170 }
171}