1#[derive(Clone)]
27pub struct Context {
28 buffer: [u8; 64],
29 count: [u32; 2],
30 state: [u32; 4],
31}
32
33const PADDING: [u8; 64] = [
34 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38];
39
40impl Context {
41 #[inline]
43 pub const fn new() -> Self {
44 #![allow(clippy::unreadable_literal)]
45 Self {
46 buffer: [0; 64],
47 count: [0, 0],
48 state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
49 }
50 }
51
52 pub fn consume(&mut self, data: &[u8]) {
53 let Self {
54 buffer,
55 count,
56 state,
57 } = self;
58 let mut input = [0_u32; 16];
59 let mut k = ((count[0] >> 3) & 0x3f) as usize;
60 let length = data.len() as u32;
61 count[0] = count[0].wrapping_add(length << 3);
62 if count[0] < length << 3 {
63 count[1] = count[1].wrapping_add(1);
64 }
65 count[1] = count[1].wrapping_add(length >> 29);
66 for &value in data {
67 buffer[k] = value;
68 k += 1;
69 if k == 0x40 {
70 let mut j = 0;
71 for i in &mut input {
72 *i = (u32::from(buffer[j + 3]) << 24)
73 | (u32::from(buffer[j + 2]) << 16)
74 | (u32::from(buffer[j + 1]) << 8)
75 | (u32::from(buffer[j]));
76 j += 4;
77 }
78 transform(state, &input);
79 k = 0;
80 }
81 }
82 }
83
84 pub fn compute(mut self) -> [u8; 16] {
86 let mut input = [0_u32; 16];
87 let k = ((self.count[0] >> 3) & 0x3f) as usize;
88 input[14] = self.count[0];
89 input[15] = self.count[1];
90 self.consume(&PADDING[..(if k < 56 { 56 - k } else { 120 - k })]);
91 let mut j = 0;
92 for i in input.iter_mut().take(14) {
93 *i = (u32::from(self.buffer[j + 3]) << 24)
94 | (u32::from(self.buffer[j + 2]) << 16)
95 | (u32::from(self.buffer[j + 1]) << 8)
96 | (u32::from(self.buffer[j]));
97 j += 4;
98 }
99 transform(&mut self.state, &input);
100 let mut digest = [0_u8; 16];
101 let mut j = 0;
102 for i in 0..4 {
103 digest[j] = ((self.state[i]) & 0xff) as u8;
104 digest[j + 1] = ((self.state[i] >> 8) & 0xff) as u8;
105 digest[j + 2] = ((self.state[i] >> 16) & 0xff) as u8;
106 digest[j + 3] = ((self.state[i] >> 24) & 0xff) as u8;
107 j += 4;
108 }
109 digest
110 }
111}
112
113#[inline]
115#[cfg(test)]
116pub fn compute<T: AsRef<[u8]>>(data: T) -> [u8; 16] {
117 let mut context = Context::new();
118 context.consume(data.as_ref());
119 context.compute()
120}
121
122#[cfg(test)]
123fn lower_hex(data: &[u8]) -> String {
124 use std::fmt::Write;
125 let mut buf = String::new();
126 for value in data {
127 write!(buf, "{value:02x}").unwrap();
128 }
130 buf
131}
132
133const fn transform(state: &mut [u32; 4], input: &[u32; 16]) {
134 #![allow(clippy::unreadable_literal)]
135 #![allow(clippy::tuple_array_conversions)]
136 let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
137 macro_rules! add(
138 ($a:expr, $b:expr) => ($a.wrapping_add($b));
139 );
140 macro_rules! rotate(
141 ($x:expr, $n:expr) => ($x.rotate_left($n));
143 );
144 {
145 macro_rules! F(
146 ($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z));
147 );
148 macro_rules! T(
149 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
150 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
151 $a = rotate!($a, $s);
152 $a = add!($a, $b);
153 });
154 );
155 const S1: u32 = 7;
156 const S2: u32 = 12;
157 const S3: u32 = 17;
158 const S4: u32 = 22;
159 T!(a, b, c, d, input[0], S1, 3614090360);
160 T!(d, a, b, c, input[1], S2, 3905402710);
161 T!(c, d, a, b, input[2], S3, 606105819);
162 T!(b, c, d, a, input[3], S4, 3250441966);
163 T!(a, b, c, d, input[4], S1, 4118548399);
164 T!(d, a, b, c, input[5], S2, 1200080426);
165 T!(c, d, a, b, input[6], S3, 2821735955);
166 T!(b, c, d, a, input[7], S4, 4249261313);
167 T!(a, b, c, d, input[8], S1, 1770035416);
168 T!(d, a, b, c, input[9], S2, 2336552879);
169 T!(c, d, a, b, input[10], S3, 4294925233);
170 T!(b, c, d, a, input[11], S4, 2304563134);
171 T!(a, b, c, d, input[12], S1, 1804603682);
172 T!(d, a, b, c, input[13], S2, 4254626195);
173 T!(c, d, a, b, input[14], S3, 2792965006);
174 T!(b, c, d, a, input[15], S4, 1236535329);
175 }
176 {
177 macro_rules! F(
178 ($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z));
179 );
180 macro_rules! T(
181 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
182 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
183 $a = rotate!($a, $s);
184 $a = add!($a, $b);
185 });
186 );
187 const S1: u32 = 5;
188 const S2: u32 = 9;
189 const S3: u32 = 14;
190 const S4: u32 = 20;
191 T!(a, b, c, d, input[1], S1, 4129170786);
192 T!(d, a, b, c, input[6], S2, 3225465664);
193 T!(c, d, a, b, input[11], S3, 643717713);
194 T!(b, c, d, a, input[0], S4, 3921069994);
195 T!(a, b, c, d, input[5], S1, 3593408605);
196 T!(d, a, b, c, input[10], S2, 38016083);
197 T!(c, d, a, b, input[15], S3, 3634488961);
198 T!(b, c, d, a, input[4], S4, 3889429448);
199 T!(a, b, c, d, input[9], S1, 568446438);
200 T!(d, a, b, c, input[14], S2, 3275163606);
201 T!(c, d, a, b, input[3], S3, 4107603335);
202 T!(b, c, d, a, input[8], S4, 1163531501);
203 T!(a, b, c, d, input[13], S1, 2850285829);
204 T!(d, a, b, c, input[2], S2, 4243563512);
205 T!(c, d, a, b, input[7], S3, 1735328473);
206 T!(b, c, d, a, input[12], S4, 2368359562);
207 }
208 {
209 macro_rules! F(
210 ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
211 );
212 macro_rules! T(
213 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
214 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
215 $a = rotate!($a, $s);
216 $a = add!($a, $b);
217 });
218 );
219 const S1: u32 = 4;
220 const S2: u32 = 11;
221 const S3: u32 = 16;
222 const S4: u32 = 23;
223 T!(a, b, c, d, input[5], S1, 4294588738);
224 T!(d, a, b, c, input[8], S2, 2272392833);
225 T!(c, d, a, b, input[11], S3, 1839030562);
226 T!(b, c, d, a, input[14], S4, 4259657740);
227 T!(a, b, c, d, input[1], S1, 2763975236);
228 T!(d, a, b, c, input[4], S2, 1272893353);
229 T!(c, d, a, b, input[7], S3, 4139469664);
230 T!(b, c, d, a, input[10], S4, 3200236656);
231 T!(a, b, c, d, input[13], S1, 681279174);
232 T!(d, a, b, c, input[0], S2, 3936430074);
233 T!(c, d, a, b, input[3], S3, 3572445317);
234 T!(b, c, d, a, input[6], S4, 76029189);
235 T!(a, b, c, d, input[9], S1, 3654602809);
236 T!(d, a, b, c, input[12], S2, 3873151461);
237 T!(c, d, a, b, input[15], S3, 530742520);
238 T!(b, c, d, a, input[2], S4, 3299628645);
239 }
240 {
241 macro_rules! F(
242 ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
243 );
244 macro_rules! T(
245 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
246 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
247 $a = rotate!($a, $s);
248 $a = add!($a, $b);
249 });
250 );
251 const S1: u32 = 6;
252 const S2: u32 = 10;
253 const S3: u32 = 15;
254 const S4: u32 = 21;
255 T!(a, b, c, d, input[0], S1, 4096336452);
256 T!(d, a, b, c, input[7], S2, 1126891415);
257 T!(c, d, a, b, input[14], S3, 2878612391);
258 T!(b, c, d, a, input[5], S4, 4237533241);
259 T!(a, b, c, d, input[12], S1, 1700485571);
260 T!(d, a, b, c, input[3], S2, 2399980690);
261 T!(c, d, a, b, input[10], S3, 4293915773);
262 T!(b, c, d, a, input[1], S4, 2240044497);
263 T!(a, b, c, d, input[8], S1, 1873313359);
264 T!(d, a, b, c, input[15], S2, 4264355552);
265 T!(c, d, a, b, input[6], S3, 2734768916);
266 T!(b, c, d, a, input[13], S4, 1309151649);
267 T!(a, b, c, d, input[4], S1, 4149444226);
268 T!(d, a, b, c, input[11], S2, 3174756917);
269 T!(c, d, a, b, input[2], S3, 718787259);
270 T!(b, c, d, a, input[9], S4, 3951481745);
271 }
272 state[0] = add!(state[0], a);
273 state[1] = add!(state[1], b);
274 state[2] = add!(state[2], c);
275 state[3] = add!(state[3], d);
276}
277
278#[cfg(test)]
279mod tests {
280 #[test]
281 fn compute() {
282 let inputs = [
283 "",
284 "a",
285 "abc",
286 "message digest",
287 "abcdefghijklmnopqrstuvwxyz",
288 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
289 "0123456789012345678901234567890123456789012345678901234567890123",
290 "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
291 ];
292 let outputs = [
293 "d41d8cd98f00b204e9800998ecf8427e",
294 "0cc175b9c0f1b6a831c399e269772661",
295 "900150983cd24fb0d6963f7d28e17f72",
296 "f96b697d7cb7938d525a2f31aaf161d0",
297 "c3fcd3d76192e4007dfb496cca67e13b",
298 "d174ab98d277d9f5a5611c2c9f419d9f",
299 "7f7bfd348709deeaace19e3f535f8c54",
300 "57edf4a22be3c955ac49da2e2107b67a",
301 ];
302 for (input, &output) in inputs.iter().zip(outputs.iter()) {
303 assert_eq!(super::lower_hex(&super::compute(input)), output);
304 }
305 }
306
307 #[test]
308 fn index() {
309 let mut digest = super::compute(b"abc");
310 assert_eq!(digest[0], 0x90);
311 assert_eq!(&digest[0], &0x90);
312 assert_eq!(&mut digest[0], &mut 0x90);
313 }
314
315 #[test]
316 fn overflow_count() {
317 let data = vec![0; 8 * 1024 * 1024];
318 let mut context = super::Context::new();
319 for _ in 0..64 {
320 context.consume(&data);
321 }
322 assert_eq!(
323 super::lower_hex(&context.compute()),
324 "aa559b4e3523a6c931f08f4df52d58f2"
325 );
326 }
327}