]> git.proxmox.com Git - rustc.git/blame - src/librustc_back/sha2.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc_back / sha2.rs
CommitLineData
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
15use std::slice::bytes::{MutableByteVector, copy_memory};
16use 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.
20fn 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.
28fn 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.
37fn 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
46trait 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
52impl 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 60fn 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.
78trait 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.
109struct FixedBuffer64 {
110 buffer: [u8; 64],
c34b1796 111 buffer_idx: usize,
1a4d82fc
JJ
112}
113
114impl 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
124impl 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.
198trait 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
206impl <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.
223pub 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
271struct 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
282impl 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
409static 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.
430struct Engine256 {
431 length_bits: u64,
432 buffer: FixedBuffer64,
433 state: Engine256State,
434 finished: bool,
435}
436
437impl 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
478pub struct Sha256 {
479 engine: Engine256
480}
481
482impl 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
492impl 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
517static H256: [u32; 8] = [
518 0x6a09e667,
519 0xbb67ae85,
520 0x3c6ef372,
521 0xa54ff53a,
522 0x510e527f,
523 0x9b05688c,
524 0x1f83d9ab,
525 0x5be0cd19
526];
527
528#[cfg(test)]
529mod 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)]
651mod 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}