]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! This module implements only the Sha256 function since that is all that is needed for internal | |
12 | //! use. This implementation is not intended for external use or for any use where security is | |
13 | //! important. | |
14 | ||
1a4d82fc JJ |
15 | use std::slice::bytes::{MutableByteVector, copy_memory}; |
16 | use serialize::hex::ToHex; | |
17 | ||
18 | /// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian | |
19 | /// format. | |
20 | fn write_u32_be(dst: &mut[u8], input: u32) { | |
21 | dst[0] = (input >> 24) as u8; | |
22 | dst[1] = (input >> 16) as u8; | |
23 | dst[2] = (input >> 8) as u8; | |
24 | dst[3] = input as u8; | |
25 | } | |
26 | ||
27 | /// Read the value of a vector of bytes as a u32 value in big-endian format. | |
28 | fn read_u32_be(input: &[u8]) -> u32 { | |
29 | return | |
30 | (input[0] as u32) << 24 | | |
31 | (input[1] as u32) << 16 | | |
32 | (input[2] as u32) << 8 | | |
33 | (input[3] as u32); | |
34 | } | |
35 | ||
36 | /// Read a vector of bytes into a vector of u32s. The values are read in big-endian format. | |
37 | fn read_u32v_be(dst: &mut[u32], input: &[u8]) { | |
38 | assert!(dst.len() * 4 == input.len()); | |
85aaf69f | 39 | let mut pos = 0; |
1a4d82fc JJ |
40 | for chunk in input.chunks(4) { |
41 | dst[pos] = read_u32_be(chunk); | |
42 | pos += 1; | |
43 | } | |
44 | } | |
45 | ||
46 | trait ToBits { | |
47 | /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the | |
48 | /// high-order value and the 2nd item is the low order value. | |
49 | fn to_bits(self) -> (Self, Self); | |
50 | } | |
51 | ||
52 | impl ToBits for u64 { | |
53 | fn to_bits(self) -> (u64, u64) { | |
54 | return (self >> 61, self << 3); | |
55 | } | |
56 | } | |
57 | ||
58 | /// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric | |
59 | /// overflow. | |
9346a6ac | 60 | fn add_bytes_to_bits(bits: u64, bytes: u64) -> u64 { |
1a4d82fc JJ |
61 | let (new_high_bits, new_low_bits) = bytes.to_bits(); |
62 | ||
9346a6ac | 63 | if new_high_bits > 0 { |
1a4d82fc JJ |
64 | panic!("numeric overflow occurred.") |
65 | } | |
66 | ||
67 | match bits.checked_add(new_low_bits) { | |
68 | Some(x) => return x, | |
69 | None => panic!("numeric overflow occurred.") | |
70 | } | |
71 | } | |
72 | ||
73 | /// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it | |
74 | /// must be processed. The input() method takes care of processing and then clearing the buffer | |
75 | /// automatically. However, other methods do not and require the caller to process the buffer. Any | |
76 | /// method that modifies the buffer directory or provides the caller with bytes that can be modified | |
77 | /// results in those bytes being marked as used by the buffer. | |
78 | trait FixedBuffer { | |
79 | /// Input a vector of bytes. If the buffer becomes full, process it with the provided | |
80 | /// function and then clear the buffer. | |
81 | fn input<F>(&mut self, input: &[u8], func: F) where | |
82 | F: FnMut(&[u8]); | |
83 | ||
84 | /// Reset the buffer. | |
85 | fn reset(&mut self); | |
86 | ||
87 | /// Zero the buffer up until the specified index. The buffer position currently must not be | |
88 | /// greater than that index. | |
c34b1796 | 89 | fn zero_until(&mut self, idx: usize); |
1a4d82fc JJ |
90 | |
91 | /// Get a slice of the buffer of the specified size. There must be at least that many bytes | |
92 | /// remaining in the buffer. | |
c34b1796 | 93 | fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8]; |
1a4d82fc JJ |
94 | |
95 | /// Get the current buffer. The buffer must already be full. This clears the buffer as well. | |
96 | fn full_buffer<'s>(&'s mut self) -> &'s [u8]; | |
97 | ||
98 | /// Get the current position of the buffer. | |
c34b1796 | 99 | fn position(&self) -> usize; |
1a4d82fc JJ |
100 | |
101 | /// Get the number of bytes remaining in the buffer until it is full. | |
c34b1796 | 102 | fn remaining(&self) -> usize; |
1a4d82fc JJ |
103 | |
104 | /// Get the size of the buffer | |
c34b1796 | 105 | fn size(&self) -> usize; |
1a4d82fc JJ |
106 | } |
107 | ||
108 | /// A FixedBuffer of 64 bytes useful for implementing Sha256 which has a 64 byte blocksize. | |
109 | struct FixedBuffer64 { | |
110 | buffer: [u8; 64], | |
c34b1796 | 111 | buffer_idx: usize, |
1a4d82fc JJ |
112 | } |
113 | ||
114 | impl FixedBuffer64 { | |
115 | /// Create a new FixedBuffer64 | |
116 | fn new() -> FixedBuffer64 { | |
117 | return FixedBuffer64 { | |
c34b1796 | 118 | buffer: [0; 64], |
1a4d82fc JJ |
119 | buffer_idx: 0 |
120 | }; | |
121 | } | |
122 | } | |
123 | ||
124 | impl FixedBuffer for FixedBuffer64 { | |
125 | fn input<F>(&mut self, input: &[u8], mut func: F) where | |
126 | F: FnMut(&[u8]), | |
127 | { | |
128 | let mut i = 0; | |
129 | ||
130 | let size = self.size(); | |
131 | ||
132 | // If there is already data in the buffer, copy as much as we can into it and process | |
133 | // the data if the buffer becomes full. | |
134 | if self.buffer_idx != 0 { | |
135 | let buffer_remaining = size - self.buffer_idx; | |
136 | if input.len() >= buffer_remaining { | |
137 | copy_memory( | |
c34b1796 AL |
138 | &input[..buffer_remaining], |
139 | &mut self.buffer[self.buffer_idx..size]); | |
1a4d82fc JJ |
140 | self.buffer_idx = 0; |
141 | func(&self.buffer); | |
142 | i += buffer_remaining; | |
143 | } else { | |
144 | copy_memory( | |
c34b1796 AL |
145 | input, |
146 | &mut self.buffer[self.buffer_idx..self.buffer_idx + input.len()]); | |
1a4d82fc JJ |
147 | self.buffer_idx += input.len(); |
148 | return; | |
149 | } | |
150 | } | |
151 | ||
152 | // While we have at least a full buffer size chunk's worth of data, process that data | |
153 | // without copying it into the buffer | |
154 | while input.len() - i >= size { | |
85aaf69f | 155 | func(&input[i..i + size]); |
1a4d82fc JJ |
156 | i += size; |
157 | } | |
158 | ||
159 | // Copy any input data into the buffer. At this point in the method, the amount of | |
160 | // data left in the input vector will be less than the buffer size and the buffer will | |
161 | // be empty. | |
162 | let input_remaining = input.len() - i; | |
163 | copy_memory( | |
c34b1796 AL |
164 | &input[i..], |
165 | &mut self.buffer[..input_remaining]); | |
1a4d82fc JJ |
166 | self.buffer_idx += input_remaining; |
167 | } | |
168 | ||
169 | fn reset(&mut self) { | |
170 | self.buffer_idx = 0; | |
171 | } | |
172 | ||
c34b1796 | 173 | fn zero_until(&mut self, idx: usize) { |
1a4d82fc | 174 | assert!(idx >= self.buffer_idx); |
85aaf69f | 175 | self.buffer[self.buffer_idx..idx].set_memory(0); |
1a4d82fc JJ |
176 | self.buffer_idx = idx; |
177 | } | |
178 | ||
c34b1796 | 179 | fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8] { |
1a4d82fc | 180 | self.buffer_idx += len; |
85aaf69f | 181 | return &mut self.buffer[self.buffer_idx - len..self.buffer_idx]; |
1a4d82fc JJ |
182 | } |
183 | ||
184 | fn full_buffer<'s>(&'s mut self) -> &'s [u8] { | |
185 | assert!(self.buffer_idx == 64); | |
186 | self.buffer_idx = 0; | |
85aaf69f | 187 | return &self.buffer[..64]; |
1a4d82fc JJ |
188 | } |
189 | ||
c34b1796 | 190 | fn position(&self) -> usize { self.buffer_idx } |
1a4d82fc | 191 | |
c34b1796 | 192 | fn remaining(&self) -> usize { 64 - self.buffer_idx } |
1a4d82fc | 193 | |
c34b1796 | 194 | fn size(&self) -> usize { 64 } |
1a4d82fc JJ |
195 | } |
196 | ||
197 | /// The StandardPadding trait adds a method useful for Sha256 to a FixedBuffer struct. | |
198 | trait StandardPadding { | |
199 | /// Add padding to the buffer. The buffer must not be full when this method is called and is | |
200 | /// guaranteed to have exactly rem remaining bytes when it returns. If there are not at least | |
201 | /// rem bytes available, the buffer will be zero padded, processed, cleared, and then filled | |
202 | /// with zeros again until only rem bytes are remaining. | |
c34b1796 | 203 | fn standard_padding<F>(&mut self, rem: usize, func: F) where F: FnMut(&[u8]); |
1a4d82fc JJ |
204 | } |
205 | ||
206 | impl <T: FixedBuffer> StandardPadding for T { | |
c34b1796 | 207 | fn standard_padding<F>(&mut self, rem: usize, mut func: F) where F: FnMut(&[u8]) { |
1a4d82fc JJ |
208 | let size = self.size(); |
209 | ||
210 | self.next(1)[0] = 128; | |
211 | ||
212 | if self.remaining() < rem { | |
213 | self.zero_until(size); | |
214 | func(self.full_buffer()); | |
215 | } | |
216 | ||
217 | self.zero_until(size - rem); | |
218 | } | |
219 | } | |
220 | ||
221 | /// The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2 | |
222 | /// family of digest functions. | |
223 | pub trait Digest { | |
224 | /// Provide message data. | |
225 | /// | |
226 | /// # Arguments | |
227 | /// | |
228 | /// * input - A vector of message data | |
229 | fn input(&mut self, input: &[u8]); | |
230 | ||
231 | /// Retrieve the digest result. This method may be called multiple times. | |
232 | /// | |
233 | /// # Arguments | |
234 | /// | |
235 | /// * out - the vector to hold the result. Must be large enough to contain output_bits(). | |
236 | fn result(&mut self, out: &mut [u8]); | |
237 | ||
238 | /// Reset the digest. This method must be called after result() and before supplying more | |
239 | /// data. | |
240 | fn reset(&mut self); | |
241 | ||
242 | /// Get the output size in bits. | |
c34b1796 | 243 | fn output_bits(&self) -> usize; |
1a4d82fc JJ |
244 | |
245 | /// Convenience function that feeds a string into a digest. | |
246 | /// | |
247 | /// # Arguments | |
248 | /// | |
249 | /// * `input` The string to feed into the digest | |
250 | fn input_str(&mut self, input: &str) { | |
251 | self.input(input.as_bytes()); | |
252 | } | |
253 | ||
254 | /// Convenience function that retrieves the result of a digest as a | |
255 | /// newly allocated vec of bytes. | |
256 | fn result_bytes(&mut self) -> Vec<u8> { | |
c1a9b12d | 257 | let mut buf = vec![0; (self.output_bits()+7)/8]; |
85aaf69f | 258 | self.result(&mut buf); |
1a4d82fc JJ |
259 | buf |
260 | } | |
261 | ||
262 | /// Convenience function that retrieves the result of a digest as a | |
263 | /// String in hexadecimal format. | |
264 | fn result_str(&mut self) -> String { | |
265 | self.result_bytes().to_hex().to_string() | |
266 | } | |
267 | } | |
268 | ||
269 | // A structure that represents that state of a digest computation for the SHA-2 512 family of digest | |
270 | // functions | |
271 | struct Engine256State { | |
272 | h0: u32, | |
273 | h1: u32, | |
274 | h2: u32, | |
275 | h3: u32, | |
276 | h4: u32, | |
277 | h5: u32, | |
278 | h6: u32, | |
279 | h7: u32, | |
280 | } | |
281 | ||
282 | impl Engine256State { | |
283 | fn new(h: &[u32; 8]) -> Engine256State { | |
284 | return Engine256State { | |
285 | h0: h[0], | |
286 | h1: h[1], | |
287 | h2: h[2], | |
288 | h3: h[3], | |
289 | h4: h[4], | |
290 | h5: h[5], | |
291 | h6: h[6], | |
292 | h7: h[7] | |
293 | }; | |
294 | } | |
295 | ||
296 | fn reset(&mut self, h: &[u32; 8]) { | |
297 | self.h0 = h[0]; | |
298 | self.h1 = h[1]; | |
299 | self.h2 = h[2]; | |
300 | self.h3 = h[3]; | |
301 | self.h4 = h[4]; | |
302 | self.h5 = h[5]; | |
303 | self.h6 = h[6]; | |
304 | self.h7 = h[7]; | |
305 | } | |
306 | ||
307 | fn process_block(&mut self, data: &[u8]) { | |
308 | fn ch(x: u32, y: u32, z: u32) -> u32 { | |
309 | ((x & y) ^ ((!x) & z)) | |
310 | } | |
311 | ||
312 | fn maj(x: u32, y: u32, z: u32) -> u32 { | |
313 | ((x & y) ^ (x & z) ^ (y & z)) | |
314 | } | |
315 | ||
316 | fn sum0(x: u32) -> u32 { | |
317 | ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) | |
318 | } | |
319 | ||
320 | fn sum1(x: u32) -> u32 { | |
321 | ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) | |
322 | } | |
323 | ||
324 | fn sigma0(x: u32) -> u32 { | |
325 | ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3) | |
326 | } | |
327 | ||
328 | fn sigma1(x: u32) -> u32 { | |
329 | ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10) | |
330 | } | |
331 | ||
332 | let mut a = self.h0; | |
333 | let mut b = self.h1; | |
334 | let mut c = self.h2; | |
335 | let mut d = self.h3; | |
336 | let mut e = self.h4; | |
337 | let mut f = self.h5; | |
338 | let mut g = self.h6; | |
339 | let mut h = self.h7; | |
340 | ||
c34b1796 | 341 | let mut w = [0; 64]; |
1a4d82fc JJ |
342 | |
343 | // Sha-512 and Sha-256 use basically the same calculations which are implemented | |
344 | // by these macros. Inlining the calculations seems to result in better generated code. | |
345 | macro_rules! schedule_round { ($t:expr) => ( | |
c34b1796 AL |
346 | w[$t] = sigma1(w[$t - 2]).wrapping_add(w[$t - 7]) |
347 | .wrapping_add(sigma0(w[$t - 15])).wrapping_add(w[$t - 16]); | |
348 | ) | |
1a4d82fc JJ |
349 | } |
350 | ||
351 | macro_rules! sha2_round { | |
352 | ($A:ident, $B:ident, $C:ident, $D:ident, | |
353 | $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => ( | |
354 | { | |
c34b1796 AL |
355 | $H = $H.wrapping_add(sum1($E)).wrapping_add(ch($E, $F, $G)) |
356 | .wrapping_add($K[$t]).wrapping_add(w[$t]); | |
357 | $D = $D.wrapping_add($H); | |
358 | $H = $H.wrapping_add(sum0($A)).wrapping_add(maj($A, $B, $C)); | |
1a4d82fc JJ |
359 | } |
360 | ) | |
361 | } | |
362 | ||
85aaf69f | 363 | read_u32v_be(&mut w[0..16], data); |
1a4d82fc JJ |
364 | |
365 | // Putting the message schedule inside the same loop as the round calculations allows for | |
366 | // the compiler to generate better code. | |
c34b1796 | 367 | for t in (0..48).step_by(8) { |
1a4d82fc JJ |
368 | schedule_round!(t + 16); |
369 | schedule_round!(t + 17); | |
370 | schedule_round!(t + 18); | |
371 | schedule_round!(t + 19); | |
372 | schedule_round!(t + 20); | |
373 | schedule_round!(t + 21); | |
374 | schedule_round!(t + 22); | |
375 | schedule_round!(t + 23); | |
376 | ||
377 | sha2_round!(a, b, c, d, e, f, g, h, K32, t); | |
378 | sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1); | |
379 | sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2); | |
380 | sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3); | |
381 | sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4); | |
382 | sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5); | |
383 | sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6); | |
384 | sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7); | |
385 | } | |
386 | ||
c34b1796 | 387 | for t in (48..64).step_by(8) { |
1a4d82fc JJ |
388 | sha2_round!(a, b, c, d, e, f, g, h, K32, t); |
389 | sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1); | |
390 | sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2); | |
391 | sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3); | |
392 | sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4); | |
393 | sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5); | |
394 | sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6); | |
395 | sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7); | |
396 | } | |
397 | ||
c34b1796 AL |
398 | self.h0 = self.h0.wrapping_add(a); |
399 | self.h1 = self.h1.wrapping_add(b); | |
400 | self.h2 = self.h2.wrapping_add(c); | |
401 | self.h3 = self.h3.wrapping_add(d); | |
402 | self.h4 = self.h4.wrapping_add(e); | |
403 | self.h5 = self.h5.wrapping_add(f); | |
404 | self.h6 = self.h6.wrapping_add(g); | |
405 | self.h7 = self.h7.wrapping_add(h); | |
1a4d82fc JJ |
406 | } |
407 | } | |
408 | ||
409 | static K32: [u32; 64] = [ | |
410 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, | |
411 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, | |
412 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, | |
413 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, | |
414 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, | |
415 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | |
416 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, | |
417 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, | |
418 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, | |
419 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, | |
420 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, | |
421 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | |
422 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, | |
423 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, | |
424 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, | |
425 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 | |
426 | ]; | |
427 | ||
428 | // A structure that keeps track of the state of the Sha-256 operation and contains the logic | |
429 | // necessary to perform the final calculations. | |
430 | struct Engine256 { | |
431 | length_bits: u64, | |
432 | buffer: FixedBuffer64, | |
433 | state: Engine256State, | |
434 | finished: bool, | |
435 | } | |
436 | ||
437 | impl Engine256 { | |
438 | fn new(h: &[u32; 8]) -> Engine256 { | |
439 | return Engine256 { | |
440 | length_bits: 0, | |
441 | buffer: FixedBuffer64::new(), | |
442 | state: Engine256State::new(h), | |
443 | finished: false | |
444 | } | |
445 | } | |
446 | ||
447 | fn reset(&mut self, h: &[u32; 8]) { | |
448 | self.length_bits = 0; | |
449 | self.buffer.reset(); | |
450 | self.state.reset(h); | |
451 | self.finished = false; | |
452 | } | |
453 | ||
454 | fn input(&mut self, input: &[u8]) { | |
455 | assert!(!self.finished); | |
456 | // Assumes that input.len() can be converted to u64 without overflow | |
457 | self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64); | |
458 | let self_state = &mut self.state; | |
459 | self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) }); | |
460 | } | |
461 | ||
462 | fn finish(&mut self) { | |
463 | if self.finished { | |
464 | return; | |
465 | } | |
466 | ||
467 | let self_state = &mut self.state; | |
468 | self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) }); | |
469 | write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 ); | |
470 | write_u32_be(self.buffer.next(4), self.length_bits as u32); | |
471 | self_state.process_block(self.buffer.full_buffer()); | |
472 | ||
473 | self.finished = true; | |
474 | } | |
475 | } | |
476 | ||
477 | /// The SHA-256 hash algorithm | |
478 | pub struct Sha256 { | |
479 | engine: Engine256 | |
480 | } | |
481 | ||
482 | impl Sha256 { | |
483 | /// Construct a new instance of a SHA-256 digest. | |
62682a34 | 484 | /// Do not – under any circumstances – use this where timing attacks might be possible! |
1a4d82fc JJ |
485 | pub fn new() -> Sha256 { |
486 | Sha256 { | |
487 | engine: Engine256::new(&H256) | |
488 | } | |
489 | } | |
490 | } | |
491 | ||
492 | impl Digest for Sha256 { | |
493 | fn input(&mut self, d: &[u8]) { | |
494 | self.engine.input(d); | |
495 | } | |
496 | ||
497 | fn result(&mut self, out: &mut [u8]) { | |
498 | self.engine.finish(); | |
499 | ||
85aaf69f SL |
500 | write_u32_be(&mut out[0..4], self.engine.state.h0); |
501 | write_u32_be(&mut out[4..8], self.engine.state.h1); | |
502 | write_u32_be(&mut out[8..12], self.engine.state.h2); | |
503 | write_u32_be(&mut out[12..16], self.engine.state.h3); | |
504 | write_u32_be(&mut out[16..20], self.engine.state.h4); | |
505 | write_u32_be(&mut out[20..24], self.engine.state.h5); | |
506 | write_u32_be(&mut out[24..28], self.engine.state.h6); | |
507 | write_u32_be(&mut out[28..32], self.engine.state.h7); | |
1a4d82fc JJ |
508 | } |
509 | ||
510 | fn reset(&mut self) { | |
511 | self.engine.reset(&H256); | |
512 | } | |
513 | ||
c34b1796 | 514 | fn output_bits(&self) -> usize { 256 } |
1a4d82fc JJ |
515 | } |
516 | ||
517 | static H256: [u32; 8] = [ | |
518 | 0x6a09e667, | |
519 | 0xbb67ae85, | |
520 | 0x3c6ef372, | |
521 | 0xa54ff53a, | |
522 | 0x510e527f, | |
523 | 0x9b05688c, | |
524 | 0x1f83d9ab, | |
525 | 0x5be0cd19 | |
526 | ]; | |
527 | ||
528 | #[cfg(test)] | |
529 | mod tests { | |
85aaf69f | 530 | #![allow(deprecated)] |
1a4d82fc JJ |
531 | extern crate rand; |
532 | ||
533 | use self::rand::Rng; | |
534 | use self::rand::isaac::IsaacRng; | |
535 | use serialize::hex::FromHex; | |
c34b1796 | 536 | use std::u64; |
1a4d82fc JJ |
537 | use super::{Digest, Sha256, FixedBuffer}; |
538 | ||
539 | // A normal addition - no overflow occurs | |
540 | #[test] | |
541 | fn test_add_bytes_to_bits_ok() { | |
9346a6ac | 542 | assert!(super::add_bytes_to_bits(100, 10) == 180); |
1a4d82fc JJ |
543 | } |
544 | ||
545 | // A simple failure case - adding 1 to the max value | |
546 | #[test] | |
c34b1796 | 547 | #[should_panic] |
1a4d82fc | 548 | fn test_add_bytes_to_bits_overflow() { |
9346a6ac | 549 | super::add_bytes_to_bits(u64::MAX, 1); |
1a4d82fc JJ |
550 | } |
551 | ||
552 | struct Test { | |
553 | input: String, | |
554 | output_str: String, | |
555 | } | |
556 | ||
557 | fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) { | |
558 | // Test that it works when accepting the message all at once | |
85aaf69f | 559 | for t in tests { |
1a4d82fc | 560 | sh.reset(); |
85aaf69f | 561 | sh.input_str(&t.input); |
1a4d82fc JJ |
562 | let out_str = sh.result_str(); |
563 | assert!(out_str == t.output_str); | |
564 | } | |
565 | ||
566 | // Test that it works when accepting the message in pieces | |
85aaf69f | 567 | for t in tests { |
1a4d82fc JJ |
568 | sh.reset(); |
569 | let len = t.input.len(); | |
570 | let mut left = len; | |
85aaf69f SL |
571 | while left > 0 { |
572 | let take = (left + 1) / 2; | |
573 | sh.input_str(&t.input[len - left..take + len - left]); | |
1a4d82fc JJ |
574 | left = left - take; |
575 | } | |
576 | let out_str = sh.result_str(); | |
577 | assert!(out_str == t.output_str); | |
578 | } | |
579 | } | |
580 | ||
581 | #[test] | |
582 | fn test_sha256() { | |
583 | // Examples from wikipedia | |
584 | let wikipedia_tests = vec!( | |
585 | Test { | |
586 | input: "".to_string(), | |
587 | output_str: "e3b0c44298fc1c149afb\ | |
588 | f4c8996fb92427ae41e4649b934ca495991b7852b855".to_string() | |
589 | }, | |
590 | Test { | |
591 | input: "The quick brown fox jumps over the lazy \ | |
592 | dog".to_string(), | |
593 | output_str: "d7a8fbb307d7809469ca\ | |
594 | 9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592".to_string() | |
595 | }, | |
596 | Test { | |
597 | input: "The quick brown fox jumps over the lazy \ | |
598 | dog.".to_string(), | |
599 | output_str: "ef537f25c895bfa78252\ | |
600 | 6529a9b63d97aa631564d5d789c2b765448c8635fb6c".to_string() | |
601 | }); | |
602 | ||
603 | let tests = wikipedia_tests; | |
604 | ||
c34b1796 | 605 | let mut sh: Box<_> = box Sha256::new(); |
1a4d82fc | 606 | |
85aaf69f | 607 | test_hash(&mut *sh, &tests); |
1a4d82fc JJ |
608 | } |
609 | ||
610 | /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is | |
611 | /// correct. | |
c34b1796 | 612 | fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: usize, expected: &str) { |
1a4d82fc | 613 | let total_size = 1000000; |
c1a9b12d | 614 | let buffer = vec![b'a'; blocksize * 2]; |
1a4d82fc JJ |
615 | let mut rng = IsaacRng::new_unseeded(); |
616 | let mut count = 0; | |
617 | ||
618 | digest.reset(); | |
619 | ||
620 | while count < total_size { | |
c34b1796 | 621 | let next: usize = rng.gen_range(0, 2 * blocksize + 1); |
1a4d82fc JJ |
622 | let remaining = total_size - count; |
623 | let size = if next > remaining { remaining } else { next }; | |
85aaf69f | 624 | digest.input(&buffer[..size]); |
1a4d82fc JJ |
625 | count += size; |
626 | } | |
627 | ||
628 | let result_str = digest.result_str(); | |
629 | let result_bytes = digest.result_bytes(); | |
630 | ||
85aaf69f | 631 | assert_eq!(expected, result_str); |
1a4d82fc JJ |
632 | |
633 | let expected_vec: Vec<u8> = expected.from_hex() | |
634 | .unwrap() | |
635 | .into_iter() | |
636 | .collect(); | |
637 | assert_eq!(expected_vec, result_bytes); | |
638 | } | |
639 | ||
640 | #[test] | |
641 | fn test_1million_random_sha256() { | |
642 | let mut sh = Sha256::new(); | |
643 | test_digest_1million_random( | |
644 | &mut sh, | |
645 | 64, | |
646 | "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); | |
647 | } | |
648 | } | |
649 | ||
650 | #[cfg(test)] | |
651 | mod bench { | |
652 | extern crate test; | |
653 | use self::test::Bencher; | |
654 | use super::{Sha256, FixedBuffer, Digest}; | |
655 | ||
656 | #[bench] | |
657 | pub fn sha256_10(b: &mut Bencher) { | |
658 | let mut sh = Sha256::new(); | |
c34b1796 | 659 | let bytes = [1; 10]; |
1a4d82fc JJ |
660 | b.iter(|| { |
661 | sh.input(&bytes); | |
662 | }); | |
663 | b.bytes = bytes.len() as u64; | |
664 | } | |
665 | ||
666 | #[bench] | |
667 | pub fn sha256_1k(b: &mut Bencher) { | |
668 | let mut sh = Sha256::new(); | |
c34b1796 | 669 | let bytes = [1; 1024]; |
1a4d82fc JJ |
670 | b.iter(|| { |
671 | sh.input(&bytes); | |
672 | }); | |
673 | b.bytes = bytes.len() as u64; | |
674 | } | |
675 | ||
676 | #[bench] | |
677 | pub fn sha256_64k(b: &mut Bencher) { | |
678 | let mut sh = Sha256::new(); | |
c34b1796 | 679 | let bytes = [1; 65536]; |
1a4d82fc JJ |
680 | b.iter(|| { |
681 | sh.input(&bytes); | |
682 | }); | |
683 | b.bytes = bytes.len() as u64; | |
684 | } | |
685 | } |