auto merge of #8174 : DaGenix/rust/digest-improvements, r=brson

Same content as #8097, but bors had an issue with that pull request. Opening a new one.
This commit is contained in:
bors
2013-08-02 19:29:00 -07:00
6 changed files with 952 additions and 890 deletions
+327
View File
@@ -0,0 +1,327 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::num::One;
use std::vec::bytes::{MutableByteVector, copy_memory};
/// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian
/// format.
pub fn write_u64_be(dst: &mut[u8], input: u64) {
use std::cast::transmute;
use std::unstable::intrinsics::to_be64;
assert!(dst.len() == 8);
unsafe {
let x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
*x = to_be64(input as i64);
}
}
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
/// format.
pub fn write_u32_be(dst: &mut[u8], input: u32) {
use std::cast::transmute;
use std::unstable::intrinsics::to_be32;
assert!(dst.len() == 4);
unsafe {
let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
*x = to_be32(input as i32);
}
}
/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
use std::cast::transmute;
use std::unstable::intrinsics::to_be64;
assert!(dst.len() * 8 == input.len());
unsafe {
let mut x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
let mut y: *i64 = transmute(input.unsafe_ref(0));
do dst.len().times() {
*x = to_be64(*y);
x = x.offset(1);
y = y.offset(1);
}
}
}
/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
use std::cast::transmute;
use std::unstable::intrinsics::to_be32;
assert!(dst.len() * 4 == input.len());
unsafe {
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
let mut y: *i32 = transmute(input.unsafe_ref(0));
do dst.len().times() {
*x = to_be32(*y);
x = x.offset(1);
y = y.offset(1);
}
}
}
/// Returns true if adding the two parameters will result in integer overflow
pub fn will_add_overflow<T: Int + Unsigned>(x: T, y: T) -> bool {
// This doesn't handle negative values! Don't copy this code elsewhere without considering if
// negative values are important to you!
let max: T = Bounded::max_value();
return x > max - y;
}
/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
/// integer overflow.
pub fn shift_add_check_overflow<T: Int + Unsigned + Clone>(x: T, mut y: T, shift: T) -> T {
if y.leading_zeros() < shift {
fail!("Could not add values - integer overflow.");
}
y = y << shift;
if will_add_overflow(x.clone(), y.clone()) {
fail!("Could not add values - integer overflow.");
}
return x + y;
}
/// Shifts the second parameter and then adds it to the first, which is a tuple where the first
/// element is the high order value. fails!() if there would be unsigned integer overflow.
pub fn shift_add_check_overflow_tuple
<T: Int + Unsigned + Clone>
(x: (T, T), mut y: T, shift: T) -> (T, T) {
if y.leading_zeros() < shift {
fail!("Could not add values - integer overflow.");
}
y = y << shift;
match x {
(hi, low) => {
let one: T = One::one();
if will_add_overflow(low.clone(), y.clone()) {
if will_add_overflow(hi.clone(), one.clone()) {
fail!("Could not add values - integer overflow.");
} else {
return (hi + one, low + y);
}
} else {
return (hi, low + y);
}
}
}
}
/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
/// must be processed. The input() method takes care of processing and then clearing the buffer
/// automatically. However, other methods do not and require the caller to process the buffer. Any
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
/// results in those bytes being marked as used by the buffer.
pub trait FixedBuffer {
/// Input a vector of bytes. If the buffer becomes full, proccess it with the provided
/// function and then clear the buffer.
fn input(&mut self, input: &[u8], func: &fn(&[u8]));
/// Reset the buffer.
fn reset(&mut self);
/// Zero the buffer up until the specified index. The buffer position currently must not be
/// greater than that index.
fn zero_until(&mut self, idx: uint);
/// Get a slice of the buffer of the specified size. There must be at least that many bytes
/// remaining in the buffer.
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];
/// Get the current buffer. The buffer must already be full. This clears the buffer as well.
fn full_buffer<'s>(&'s mut self) -> &'s [u8];
/// Get the current position of the buffer.
fn position(&self) -> uint;
/// Get the number of bytes remaining in the buffer until it is full.
fn remaining(&self) -> uint;
/// Get the size of the buffer
fn size(&self) -> uint;
}
macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => (
impl FixedBuffer for $name {
fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
let mut i = 0;
// FIXME: #6304 - This local variable shouldn't be necessary.
let size = $size;
// If there is already data in the buffer, copy as much as we can into it and process
// the data if the buffer becomes full.
if self.buffer_idx != 0 {
let buffer_remaining = size - self.buffer_idx;
if input.len() >= buffer_remaining {
copy_memory(
self.buffer.mut_slice(self.buffer_idx, size),
input.slice_to(buffer_remaining),
buffer_remaining);
self.buffer_idx = 0;
func(self.buffer);
i += buffer_remaining;
} else {
copy_memory(
self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
input,
input.len());
self.buffer_idx += input.len();
return;
}
}
// While we have at least a full buffer size chunks's worth of data, process that data
// without copying it into the buffer
while input.len() - i >= size {
func(input.slice(i, i + size));
i += size;
}
// Copy any input data into the buffer. At this point in the method, the ammount of
// data left in the input vector will be less than the buffer size and the buffer will
// be empty.
let input_remaining = input.len() - i;
copy_memory(
self.buffer.mut_slice(0, input_remaining),
input.slice_from(i),
input.len() - i);
self.buffer_idx += input_remaining;
}
fn reset(&mut self) {
self.buffer_idx = 0;
}
fn zero_until(&mut self, idx: uint) {
assert!(idx >= self.buffer_idx);
self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
self.buffer_idx = idx;
}
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
self.buffer_idx += len;
return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
}
fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
assert!(self.buffer_idx == $size);
self.buffer_idx = 0;
return self.buffer.slice_to($size);
}
fn position(&self) -> uint { self.buffer_idx }
fn remaining(&self) -> uint { $size - self.buffer_idx }
fn size(&self) -> uint { $size }
}
))
/// A fixed size buffer of 64 bytes useful for cryptographic operations.
pub struct FixedBuffer64 {
priv buffer: [u8, ..64],
priv buffer_idx: uint,
}
impl FixedBuffer64 {
/// Create a new buffer
pub fn new() -> FixedBuffer64 {
return FixedBuffer64 {
buffer: [0u8, ..64],
buffer_idx: 0
};
}
}
impl_fixed_buffer!(FixedBuffer64, 64)
/// A fixed size buffer of 128 bytes useful for cryptographic operations.
pub struct FixedBuffer128 {
priv buffer: [u8, ..128],
priv buffer_idx: uint,
}
impl FixedBuffer128 {
/// Create a new buffer
pub fn new() -> FixedBuffer128 {
return FixedBuffer128 {
buffer: [0u8, ..128],
buffer_idx: 0
};
}
}
impl_fixed_buffer!(FixedBuffer128, 128)
/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
/// struct.
pub trait StandardPadding {
/// Add standard padding to the buffer. The buffer must not be full when this method is called
/// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
/// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
/// filled with zeros again until only rem bytes are remaining.
fn standard_padding(&mut self, rem: uint, func: &fn(&[u8]));
}
impl <T: FixedBuffer> StandardPadding for T {
fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])) {
let size = self.size();
self.next(1)[0] = 128;
if self.remaining() < rem {
self.zero_until(size);
func(self.full_buffer());
}
self.zero_until(size - rem);
}
}
#[cfg(test)]
mod test {
use std::rand::IsaacRng;
use std::rand::RngUtil;
use std::vec;
use digest::Digest;
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
/// correct.
pub fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
let total_size = 1000000;
let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
let mut rng = IsaacRng::new_unseeded();
let mut count = 0;
digest.reset();
while count < total_size {
let next: uint = rng.gen_uint_range(0, 2 * blocksize + 1);
let remaining = total_size - count;
let size = if next > remaining { remaining } else { next };
digest.input(buffer.slice_to(size));
count += size;
}
let result_str = digest.result_str();
assert!(expected == result_str);
}
}
+26 -32
View File
@@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::uint;
use std::vec;
/**
* The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
* family of digest functions.
@@ -28,6 +28,10 @@ pub trait Digest {
/**
* Retrieve the digest result. This method may be called multiple times.
*
* # Arguments
*
* * out - the vector to hold the result. Must be large enough to contain output_bits().
*/
fn result(&mut self, out: &mut [u8]);
@@ -41,6 +45,27 @@ pub trait Digest {
* Get the output size in bits.
*/
fn output_bits(&self) -> uint;
/**
* Convenience functon that feeds a string into a digest
*
* # Arguments
*
* * in The string to feed into the digest
*/
fn input_str(&mut self, input: &str) {
self.input(input.as_bytes());
}
/**
* Convenience functon that retrieves the result of a digest as a
* ~str in hexadecimal format.
*/
fn result_str(&mut self) -> ~str {
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
self.result(buf);
return to_hex(buf);
}
}
fn to_hex(rr: &[u8]) -> ~str {
@@ -54,34 +79,3 @@ fn to_hex(rr: &[u8]) -> ~str {
}
return s;
}
/// Contains utility methods for Digests.
/// FIXME: #7339: Convert to default methods when issues with them are resolved.
pub trait DigestUtil {
/**
* Convenience functon that feeds a string into a digest
*
* # Arguments
*
* * in The string to feed into the digest
*/
fn input_str(&mut self, input: &str);
/**
* Convenience functon that retrieves the result of a digest as a
* ~str in hexadecimal format.
*/
fn result_str(&mut self) -> ~str;
}
impl<D: Digest> DigestUtil for D {
fn input_str(&mut self, input: &str) {
self.input(input.as_bytes());
}
fn result_str(&mut self) -> ~str {
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
self.result(buf);
return to_hex(buf);
}
}
+48 -123
View File
@@ -23,6 +23,8 @@
*/
use cryptoutil::{write_u32_be, read_u32v_be, shift_add_check_overflow, FixedBuffer, FixedBuffer64,
StandardPadding};
use digest::Digest;
/*
@@ -33,7 +35,6 @@
// Some unexported constants
static DIGEST_BUF_LEN: uint = 5u;
static MSG_BLOCK_LEN: uint = 64u;
static WORK_BUF_LEN: uint = 80u;
static K0: u32 = 0x5A827999u32;
static K1: u32 = 0x6ED9EBA1u32;
@@ -43,58 +44,38 @@
/// Structure representing the state of a Sha1 computation
pub struct Sha1 {
priv h: [u32, ..DIGEST_BUF_LEN],
priv len_low: u32,
priv len_high: u32,
priv msg_block: [u8, ..MSG_BLOCK_LEN],
priv msg_block_idx: uint,
priv length_bits: u64,
priv buffer: FixedBuffer64,
priv computed: bool,
priv work_buf: [u32, ..WORK_BUF_LEN]
}
fn add_input(st: &mut Sha1, msg: &[u8]) {
assert!((!st.computed));
foreach element in msg.iter() {
st.msg_block[st.msg_block_idx] = *element;
st.msg_block_idx += 1;
st.len_low += 8;
if st.len_low == 0 {
st.len_high += 1;
if st.len_high == 0 {
// FIXME: Need better failure mode (#2346)
fail!();
}
}
if st.msg_block_idx == MSG_BLOCK_LEN { process_msg_block(st); }
}
// Assumes that msg.len() can be converted to u64 without overflow
st.length_bits = shift_add_check_overflow(st.length_bits, msg.len() as u64, 3);
st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });
}
fn process_msg_block(st: &mut Sha1) {
fn process_msg_block(data: &[u8], h: &mut [u32, ..DIGEST_BUF_LEN]) {
let mut t: int; // Loop counter
let mut w = st.work_buf;
let mut w = [0u32, ..WORK_BUF_LEN];
// Initialize the first 16 words of the vector w
t = 0;
while t < 16 {
let mut tmp;
tmp = (st.msg_block[t * 4] as u32) << 24u32;
tmp = tmp | (st.msg_block[t * 4 + 1] as u32) << 16u32;
tmp = tmp | (st.msg_block[t * 4 + 2] as u32) << 8u32;
tmp = tmp | (st.msg_block[t * 4 + 3] as u32);
w[t] = tmp;
t += 1;
}
read_u32v_be(w.mut_slice(0, 16), data);
// Initialize the rest of vector w
t = 16;
while t < 80 {
let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
w[t] = circular_shift(1, val);
t += 1;
}
let mut a = st.h[0];
let mut b = st.h[1];
let mut c = st.h[2];
let mut d = st.h[3];
let mut e = st.h[4];
let mut a = h[0];
let mut b = h[1];
let mut c = h[2];
let mut d = h[3];
let mut e = h[4];
let mut temp: u32;
t = 0;
while t < 20 {
@@ -135,12 +116,11 @@ fn process_msg_block(st: &mut Sha1) {
a = temp;
t += 1;
}
st.h[0] = st.h[0] + a;
st.h[1] = st.h[1] + b;
st.h[2] = st.h[2] + c;
st.h[3] = st.h[3] + d;
st.h[4] = st.h[4] + e;
st.msg_block_idx = 0;
h[0] += a;
h[1] += b;
h[2] += c;
h[3] += d;
h[4] += e;
}
fn circular_shift(bits: u32, word: u32) -> u32 {
@@ -148,60 +128,20 @@ fn circular_shift(bits: u32, word: u32) -> u32 {
}
fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
if !st.computed { pad_msg(st); st.computed = true; }
let mut i = 0;
foreach ptr_hpart in st.h.mut_iter() {
let hpart = *ptr_hpart;
rs[i] = (hpart >> 24u32 & 0xFFu32) as u8;
rs[i+1] = (hpart >> 16u32 & 0xFFu32) as u8;
rs[i+2] = (hpart >> 8u32 & 0xFFu32) as u8;
rs[i+3] = (hpart & 0xFFu32) as u8;
i += 4;
}
}
if !st.computed {
st.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut st.h) });
write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
write_u32_be(st.buffer.next(4), st.length_bits as u32);
process_msg_block(st.buffer.full_buffer(), &mut st.h);
/*
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64 bits
* represent the length of the original message. All bits in between
* should be 0. This function will pad the message according to those
* rules by filling the msg_block vector accordingly. It will also
* call process_msg_block() appropriately. When it returns, it
* can be assumed that the message digest has been computed.
*/
fn pad_msg(st: &mut Sha1) {
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second block.
*/
if st.msg_block_idx > 55 {
st.msg_block[st.msg_block_idx] = 0x80;
st.msg_block_idx += 1;
while st.msg_block_idx < MSG_BLOCK_LEN {
st.msg_block[st.msg_block_idx] = 0;
st.msg_block_idx += 1;
}
process_msg_block(st);
} else {
st.msg_block[st.msg_block_idx] = 0x80;
st.msg_block_idx += 1;
}
while st.msg_block_idx < 56 {
st.msg_block[st.msg_block_idx] = 0u8;
st.msg_block_idx += 1;
st.computed = true;
}
// Store the message length as the last 8 octets
st.msg_block[56] = (st.len_high >> 24u32 & 0xFFu32) as u8;
st.msg_block[57] = (st.len_high >> 16u32 & 0xFFu32) as u8;
st.msg_block[58] = (st.len_high >> 8u32 & 0xFFu32) as u8;
st.msg_block[59] = (st.len_high & 0xFFu32) as u8;
st.msg_block[60] = (st.len_low >> 24u32 & 0xFFu32) as u8;
st.msg_block[61] = (st.len_low >> 16u32 & 0xFFu32) as u8;
st.msg_block[62] = (st.len_low >> 8u32 & 0xFFu32) as u8;
st.msg_block[63] = (st.len_low & 0xFFu32) as u8;
process_msg_block(st);
write_u32_be(rs.mut_slice(0, 4), st.h[0]);
write_u32_be(rs.mut_slice(4, 8), st.h[1]);
write_u32_be(rs.mut_slice(8, 12), st.h[2]);
write_u32_be(rs.mut_slice(12, 16), st.h[3]);
write_u32_be(rs.mut_slice(16, 20), st.h[4]);
}
impl Sha1 {
@@ -209,12 +149,9 @@ impl Sha1 {
pub fn new() -> Sha1 {
let mut st = Sha1 {
h: [0u32, ..DIGEST_BUF_LEN],
len_low: 0u32,
len_high: 0u32,
msg_block: [0u8, ..MSG_BLOCK_LEN],
msg_block_idx: 0,
length_bits: 0u64,
buffer: FixedBuffer64::new(),
computed: false,
work_buf: [0u32, ..WORK_BUF_LEN]
};
st.reset();
return st;
@@ -223,14 +160,13 @@ pub fn new() -> Sha1 {
impl Digest for Sha1 {
pub fn reset(&mut self) {
self.len_low = 0;
self.len_high = 0;
self.msg_block_idx = 0;
self.length_bits = 0;
self.h[0] = 0x67452301u32;
self.h[1] = 0xEFCDAB89u32;
self.h[2] = 0x98BADCFEu32;
self.h[3] = 0x10325476u32;
self.h[4] = 0xC3D2E1F0u32;
self.buffer.reset();
self.computed = false;
}
pub fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
@@ -240,8 +176,8 @@ pub fn output_bits(&self) -> uint { 160 }
#[cfg(test)]
mod tests {
use digest::{Digest, DigestUtil};
use cryptoutil::test::test_digest_1million_random;
use digest::Digest;
use sha1::Sha1;
#[deriving(Clone)]
@@ -253,15 +189,6 @@ struct Test {
#[test]
fn test() {
fn a_million_letter_a() -> ~str {
let mut i = 0;
let mut rs = ~"";
while i < 100000 {
rs.push_str("aaaaaaaaaa");
i += 1;
}
return rs;
}
// Test messages from FIPS 180-1
let fips_180_1_tests = ~[
@@ -289,17 +216,6 @@ fn a_million_letter_a() -> ~str {
],
output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1"
},
Test {
input: a_million_letter_a(),
output: ~[
0x34u8, 0xAAu8, 0x97u8, 0x3Cu8,
0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8,
0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8,
0xDBu8, 0xADu8, 0x27u8, 0x31u8,
0x65u8, 0x34u8, 0x01u8, 0x6Fu8,
],
output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f"
},
];
// Examples from wikipedia
@@ -366,6 +282,15 @@ fn a_million_letter_a() -> ~str {
sh.reset();
}
}
#[test]
fn test_1million_random_sha1() {
let mut sh = Sha1::new();
test_digest_1million_random(
&mut sh,
64,
"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
}
}
#[cfg(test)]
+548 -733
View File
@@ -8,47 +8,35 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::uint;
use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, shift_add_check_overflow,
shift_add_check_overflow_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
use digest::Digest;
// BitCounter is a specialized structure intended simply for counting the
// number of bits that have been processed by the SHA-2 512 family of functions.
// It does very little overflow checking since such checking is not necessary
// for how it is used. A more generic structure would have to do this checking.
// So, don't copy this structure and use it elsewhere!
struct BitCounter {
high_bit_count: u64,
low_byte_count: u64
}
impl BitCounter {
fn add_bytes(&mut self, bytes: uint) {
self.low_byte_count += bytes as u64;
if(self.low_byte_count > 0x1fffffffffffffffu64) {
self.high_bit_count += (self.low_byte_count >> 61);
self.low_byte_count &= 0x1fffffffffffffffu64;
// Sha-512 and Sha-256 use basically the same calculations which are implemented by these macros.
// Inlining the calculations seems to result in better generated code.
macro_rules! schedule_round( ($t:expr) => (
W[$t] = sigma1(W[$t - 2]) + W[$t - 7] + sigma0(W[$t - 15]) + W[$t - 16];
)
)
macro_rules! sha2_round(
($A:ident, $B:ident, $C:ident, $D:ident,
$E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
{
$H += sum1($E) + ch($E, $F, $G) + $K[$t] + W[$t];
$D += $H;
$H += sum0($A) + maj($A, $B, $C);
}
}
)
)
fn reset(&mut self) {
self.low_byte_count = 0;
self.high_bit_count = 0;
}
fn get_low_bit_count(&self) -> u64 {
self.low_byte_count << 3
}
fn get_high_bit_count(&self) -> u64 {
self.high_bit_count
}
}
// A structure that represents that state of a digest computation
// for the SHA-2 512 family of digest functions
struct Engine512 {
input_buffer: [u8, ..8],
input_buffer_idx: uint,
bit_counter: BitCounter,
// A structure that represents that state of a digest computation for the SHA-2 512 family of digest
// functions
struct Engine512State {
H0: u64,
H1: u64,
H2: u64,
@@ -57,91 +45,34 @@ struct Engine512 {
H5: u64,
H6: u64,
H7: u64,
W: [u64, ..80],
W_idx: uint,
finished: bool,
}
// Convert a [u8] to a u64 in big-endian format
fn to_u64(input: &[u8]) -> u64 {
(input[0] as u64) << 56 |
(input[1] as u64) << 48 |
(input[2] as u64) << 40 |
(input[3] as u64) << 32 |
(input[4] as u64) << 24 |
(input[5] as u64) << 16 |
(input[6] as u64) << 8 |
(input[7] as u64)
}
// Convert a u64 to a [u8] in big endian format
fn from_u64(input: u64, out: &mut [u8]) {
out[0] = (input >> 56) as u8;
out[1] = (input >> 48) as u8;
out[2] = (input >> 40) as u8;
out[3] = (input >> 32) as u8;
out[4] = (input >> 24) as u8;
out[5] = (input >> 16) as u8;
out[6] = (input >> 8) as u8;
out[7] = input as u8;
}
impl Engine512 {
fn input_byte(&mut self, input: u8) {
assert!(!self.finished)
self.input_buffer[self.input_buffer_idx] = input;
self.input_buffer_idx += 1;
if (self.input_buffer_idx == 8) {
self.input_buffer_idx = 0;
let w = to_u64(self.input_buffer);
self.process_word(w);
}
self.bit_counter.add_bytes(1);
impl Engine512State {
fn new(h: &[u64, ..8]) -> Engine512State {
return Engine512State {
H0: h[0],
H1: h[1],
H2: h[2],
H3: h[3],
H4: h[4],
H5: h[5],
H6: h[6],
H7: h[7]
};
}
fn input_vec(&mut self, input: &[u8]) {
assert!(!self.finished)
let mut i = 0;
while i < input.len() && self.input_buffer_idx != 0 {
self.input_byte(input[i]);
i += 1;
}
while input.len() - i >= 8 {
let w = to_u64(input.slice(i, i + 8));
self.process_word(w);
self.bit_counter.add_bytes(8);
i += 8;
}
while i < input.len() {
self.input_byte(input[i]);
i += 1;
}
fn reset(&mut self, h: &[u64, ..8]) {
self.H0 = h[0];
self.H1 = h[1];
self.H2 = h[2];
self.H3 = h[3];
self.H4 = h[4];
self.H5 = h[5];
self.H6 = h[6];
self.H7 = h[7];
}
fn reset(&mut self) {
self.bit_counter.reset();
self.finished = false;
self.input_buffer_idx = 0;
self.W_idx = 0;
}
fn process_word(&mut self, input: u64) {
self.W[self.W_idx] = input;
self.W_idx += 1;
if (self.W_idx == 16) {
self.W_idx = 0;
self.process_block();
}
}
fn process_block(&mut self) {
fn process_block(&mut self, data: &[u8]) {
fn ch(x: u64, y: u64, z: u64) -> u64 {
((x & y) ^ ((!x) & z))
}
@@ -166,11 +97,6 @@ fn sigma1(x: u64) -> u64 {
((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6)
}
foreach t in range(16u, 80) {
self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) +
self.W[t - 16];
}
let mut a = self.H0;
let mut b = self.H1;
let mut c = self.H2;
@@ -180,47 +106,41 @@ fn sigma1(x: u64) -> u64 {
let mut g = self.H6;
let mut h = self.H7;
let mut t = 0;
foreach _ in range(0u, 10) {
h += sum1(e) + ch(e, f, g) + K64[t] + self.W[t];
d += h;
h += sum0(a) + maj(a, b, c);
t += 1;
let mut W = [0u64, ..80];
g += sum1(d) + ch(d, e, f) + K64[t] + self.W[t];
c += g;
g += sum0(h) + maj(h, a, b);
t += 1;
read_u64v_be(W.mut_slice(0, 16), data);
f += sum1(c) + ch(c, d, e) + K64[t] + self.W[t];
b += f;
f += sum0(g) + maj(g, h, a);
t += 1;
// Putting the message schedule inside the same loop as the round calculations allows for
// the compiler to generate better code.
for uint::range_step(0, 64, 8) |t| {
schedule_round!(t + 16);
schedule_round!(t + 17);
schedule_round!(t + 18);
schedule_round!(t + 19);
schedule_round!(t + 20);
schedule_round!(t + 21);
schedule_round!(t + 22);
schedule_round!(t + 23);
e += sum1(b) + ch(b, c, d) + K64[t] + self.W[t];
a += e;
e += sum0(f) + maj(f, g, h);
t += 1;
sha2_round!(a, b, c, d, e, f, g, h, K64, t);
sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2);
sha2_round!(f, g, h, a, b, c, d, e, K64, t + 3);
sha2_round!(e, f, g, h, a, b, c, d, K64, t + 4);
sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
}
d += sum1(a) + ch(a, b, c) + K64[t] + self.W[t];
h += d;
d += sum0(e) + maj(e, f, g);
t += 1;
c += sum1(h) + ch(h, a, b) + K64[t] + self.W[t];
g += c;
c += sum0(d) + maj(d, e, f);
t += 1;
b += sum1(g) + ch(g, h, a) + K64[t] + self.W[t];
f += b;
b += sum0(c) + maj(c, d, e);
t += 1;
a += sum1(f) + ch(f, g, h) + K64[t] + self.W[t];
e += a;
a += sum0(b) + maj(b, c, d);
t += 1;
for uint::range_step(64, 80, 8) |t| {
sha2_round!(a, b, c, d, e, f, g, h, K64, t);
sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2);
sha2_round!(f, g, h, a, b, c, d, e, K64, t + 3);
sha2_round!(e, f, g, h, a, b, c, d, K64, t + 4);
sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
}
self.H0 += a;
@@ -232,113 +152,286 @@ fn sigma1(x: u64) -> u64 {
self.H6 += g;
self.H7 += h;
}
fn finish(&mut self) {
if (self.finished) {
return;
}
// must get message length before padding is added
let high_bit_count = self.bit_counter.get_high_bit_count();
let low_bit_count = self.bit_counter.get_low_bit_count();
// add padding
self.input_byte(128u8);
while self.input_buffer_idx != 0 {
self.input_byte(0u8);
}
// add length
if (self.W_idx > 14) {
foreach _ in range(self.W_idx, 16) {
self.process_word(0);
}
}
while self.W_idx < 14 {
self.process_word(0);
}
self.process_word(high_bit_count);
self.process_word(low_bit_count);
self.finished = true;
}
fn result_512(&mut self, out: &mut [u8]) {
self.finish();
from_u64(self.H0, out.mut_slice(0, 8));
from_u64(self.H1, out.mut_slice(8, 16));
from_u64(self.H2, out.mut_slice(16, 24));
from_u64(self.H3, out.mut_slice(24, 32));
from_u64(self.H4, out.mut_slice(32, 40));
from_u64(self.H5, out.mut_slice(40, 48));
from_u64(self.H6, out.mut_slice(48, 56));
from_u64(self.H7, out.mut_slice(56, 64));
}
fn result_384(&mut self, out: &mut [u8]) {
self.finish();
from_u64(self.H0, out.mut_slice(0, 8));
from_u64(self.H1, out.mut_slice(8, 16));
from_u64(self.H2, out.mut_slice(16, 24));
from_u64(self.H3, out.mut_slice(24, 32));
from_u64(self.H4, out.mut_slice(32, 40));
from_u64(self.H5, out.mut_slice(40, 48));
}
fn result_256(&mut self, out: &mut [u8]) {
self.finish();
from_u64(self.H0, out.mut_slice(0, 8));
from_u64(self.H1, out.mut_slice(8, 16));
from_u64(self.H2, out.mut_slice(16, 24));
from_u64(self.H3, out.mut_slice(24, 32));
}
fn result_224(&mut self, out: &mut [u8]) {
self.finish();
from_u64(self.H0, out.mut_slice(0, 8));
from_u64(self.H1, out.mut_slice(8, 16));
from_u64(self.H2, out.mut_slice(16, 24));
from_u32((self.H3 >> 32) as u32, out.mut_slice(24, 28));
}
}
// Constants necessary for SHA-2 512 family of digests.
static K64: [u64, ..80] = [
0x428a2f98d728ae22u64, 0x7137449123ef65cdu64, 0xb5c0fbcfec4d3b2fu64, 0xe9b5dba58189dbbcu64,
0x3956c25bf348b538u64, 0x59f111f1b605d019u64, 0x923f82a4af194f9bu64, 0xab1c5ed5da6d8118u64,
0xd807aa98a3030242u64, 0x12835b0145706fbeu64, 0x243185be4ee4b28cu64, 0x550c7dc3d5ffb4e2u64,
0x72be5d74f27b896fu64, 0x80deb1fe3b1696b1u64, 0x9bdc06a725c71235u64, 0xc19bf174cf692694u64,
0xe49b69c19ef14ad2u64, 0xefbe4786384f25e3u64, 0x0fc19dc68b8cd5b5u64, 0x240ca1cc77ac9c65u64,
0x2de92c6f592b0275u64, 0x4a7484aa6ea6e483u64, 0x5cb0a9dcbd41fbd4u64, 0x76f988da831153b5u64,
0x983e5152ee66dfabu64, 0xa831c66d2db43210u64, 0xb00327c898fb213fu64, 0xbf597fc7beef0ee4u64,
0xc6e00bf33da88fc2u64, 0xd5a79147930aa725u64, 0x06ca6351e003826fu64, 0x142929670a0e6e70u64,
0x27b70a8546d22ffcu64, 0x2e1b21385c26c926u64, 0x4d2c6dfc5ac42aedu64, 0x53380d139d95b3dfu64,
0x650a73548baf63deu64, 0x766a0abb3c77b2a8u64, 0x81c2c92e47edaee6u64, 0x92722c851482353bu64,
0xa2bfe8a14cf10364u64, 0xa81a664bbc423001u64, 0xc24b8b70d0f89791u64, 0xc76c51a30654be30u64,
0xd192e819d6ef5218u64, 0xd69906245565a910u64, 0xf40e35855771202au64, 0x106aa07032bbd1b8u64,
0x19a4c116b8d2d0c8u64, 0x1e376c085141ab53u64, 0x2748774cdf8eeb99u64, 0x34b0bcb5e19b48a8u64,
0x391c0cb3c5c95a63u64, 0x4ed8aa4ae3418acbu64, 0x5b9cca4f7763e373u64, 0x682e6ff3d6b2b8a3u64,
0x748f82ee5defb2fcu64, 0x78a5636f43172f60u64, 0x84c87814a1f0ab72u64, 0x8cc702081a6439ecu64,
0x90befffa23631e28u64, 0xa4506cebde82bde9u64, 0xbef9a3f7b2c67915u64, 0xc67178f2e372532bu64,
0xca273eceea26619cu64, 0xd186b8c721c0c207u64, 0xeada7dd6cde0eb1eu64, 0xf57d4f7fee6ed178u64,
0x06f067aa72176fbau64, 0x0a637dc5a2c898a6u64, 0x113f9804bef90daeu64, 0x1b710b35131c471bu64,
0x28db77f523047d84u64, 0x32caab7b40c72493u64, 0x3c9ebe0a15c9bebcu64, 0x431d67c49c100d4cu64,
0x4cc5d4becb3e42b6u64, 0x597f299cfc657e2au64, 0x5fcb6fab3ad6faecu64, 0x6c44198c4a475817u64
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
];
// A structure that represents that state of a digest computation
// for the SHA-2 256 family of digest functions
struct Engine256 {
input_buffer: [u8, ..4],
input_buffer_idx: uint,
length_bytes: u64,
// A structure that keeps track of the state of the Sha-512 operation and contains the logic
// necessary to perform the final calculations.
struct Engine512 {
length_bits: (u64, u64),
buffer: FixedBuffer128,
state: Engine512State,
finished: bool,
}
impl Engine512 {
fn new(h: &[u64, ..8]) -> Engine512 {
return Engine512 {
length_bits: (0, 0),
buffer: FixedBuffer128::new(),
state: Engine512State::new(h),
finished: false
}
}
fn reset(&mut self, h: &[u64, ..8]) {
self.length_bits = (0, 0);
self.buffer.reset();
self.state.reset(h);
self.finished = false;
}
fn input(&mut self, input: &[u8]) {
assert!(!self.finished)
// Assumes that input.len() can be converted to u64 without overflow
self.length_bits = shift_add_check_overflow_tuple(self.length_bits, input.len() as u64, 3);
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
}
fn finish(&mut self) {
if self.finished {
return;
}
self.buffer.standard_padding(16, |input: &[u8]| { self.state.process_block(input) });
match self.length_bits {
(hi, low) => {
write_u64_be(self.buffer.next(8), hi);
write_u64_be(self.buffer.next(8), low);
}
}
self.state.process_block(self.buffer.full_buffer());
self.finished = true;
}
}
struct Sha512 {
priv engine: Engine512
}
impl Sha512 {
/**
* Construct an new instance of a SHA-512 digest.
*/
pub fn new() -> Sha512 {
return Sha512 {
engine: Engine512::new(&H512)
};
}
}
impl Digest for Sha512 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
write_u64_be(out.mut_slice(32, 40), self.engine.state.H4);
write_u64_be(out.mut_slice(40, 48), self.engine.state.H5);
write_u64_be(out.mut_slice(48, 56), self.engine.state.H6);
write_u64_be(out.mut_slice(56, 64), self.engine.state.H7);
}
fn reset(&mut self) {
self.engine.reset(&H512);
}
fn output_bits(&self) -> uint { 512 }
}
static H512: [u64, ..8] = [
0x6a09e667f3bcc908,
0xbb67ae8584caa73b,
0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1,
0x510e527fade682d1,
0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b,
0x5be0cd19137e2179
];
struct Sha384 {
priv engine: Engine512
}
impl Sha384 {
/**
* Construct an new instance of a SHA-384 digest.
*/
pub fn new() -> Sha384 {
Sha384 {
engine: Engine512::new(&H384)
}
}
}
impl Digest for Sha384 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
write_u64_be(out.mut_slice(32, 40), self.engine.state.H4);
write_u64_be(out.mut_slice(40, 48), self.engine.state.H5);
}
fn reset(&mut self) {
self.engine.reset(&H384);
}
fn output_bits(&self) -> uint { 384 }
}
static H384: [u64, ..8] = [
0xcbbb9d5dc1059ed8,
0x629a292a367cd507,
0x9159015a3070dd17,
0x152fecd8f70e5939,
0x67332667ffc00b31,
0x8eb44a8768581511,
0xdb0c2e0d64f98fa7,
0x47b5481dbefa4fa4
];
struct Sha512Trunc256 {
priv engine: Engine512
}
impl Sha512Trunc256 {
/**
* Construct an new instance of a SHA-512/256 digest.
*/
pub fn new() -> Sha512Trunc256 {
Sha512Trunc256 {
engine: Engine512::new(&H512_TRUNC_256)
}
}
}
impl Digest for Sha512Trunc256 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
}
fn reset(&mut self) {
self.engine.reset(&H512_TRUNC_256);
}
fn output_bits(&self) -> uint { 256 }
}
static H512_TRUNC_256: [u64, ..8] = [
0x22312194fc2bf72c,
0x9f555fa3c84c64c2,
0x2393b86b6f53b151,
0x963877195940eabd,
0x96283ee2a88effe3,
0xbe5e1e2553863992,
0x2b0199fc2c85b8aa,
0x0eb72ddc81c52ca2
];
struct Sha512Trunc224 {
priv engine: Engine512
}
impl Sha512Trunc224 {
/**
* Construct an new instance of a SHA-512/224 digest.
*/
pub fn new() -> Sha512Trunc224 {
Sha512Trunc224 {
engine: Engine512::new(&H512_TRUNC_224)
}
}
}
impl Digest for Sha512Trunc224 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
write_u32_be(out.mut_slice(24, 28), (self.engine.state.H3 >> 32) as u32);
}
fn reset(&mut self) {
self.engine.reset(&H512_TRUNC_224);
}
fn output_bits(&self) -> uint { 224 }
}
static H512_TRUNC_224: [u64, ..8] = [
0x8c3d37c819544da2,
0x73e1996689dcd4d6,
0x1dfab7ae32ff9c82,
0x679dd514582f9fcf,
0x0f6d2b697bd44da8,
0x77e36f7304c48942,
0x3f9d85a86a1d36c8,
0x1112e6ad91d692a1,
];
// A structure that represents that state of a digest computation for the SHA-2 512 family of digest
// functions
struct Engine256State {
H0: u32,
H1: u32,
H2: u32,
@@ -347,84 +440,34 @@ struct Engine256 {
H5: u32,
H6: u32,
H7: u32,
W: [u32, ..64],
W_idx: uint,
finished: bool
}
// Convert a [u8] to a u32 in big endian format
fn to_u32(input: &[u8]) -> u32 {
(input[0] as u32) << 24 |
(input[1] as u32) << 16 |
(input[2] as u32) << 8 |
(input[3] as u32)
}
// Convert a u32 to a [u8] in big endian format
fn from_u32(input: u32, out: &mut [u8]) {
out[0] = (input >> 24) as u8;
out[1] = (input >> 16) as u8;
out[2] = (input >> 8) as u8;
out[3] = input as u8;
}
impl Engine256 {
fn input_byte(&mut self, input: u8) {
assert!(!self.finished)
self.input_buffer[self.input_buffer_idx] = input;
self.input_buffer_idx += 1;
if (self.input_buffer_idx == 4) {
self.input_buffer_idx = 0;
let w = to_u32(self.input_buffer);
self.process_word(w);
}
self.length_bytes += 1;
impl Engine256State {
fn new(h: &[u32, ..8]) -> Engine256State {
return Engine256State {
H0: h[0],
H1: h[1],
H2: h[2],
H3: h[3],
H4: h[4],
H5: h[5],
H6: h[6],
H7: h[7]
};
}
fn input_vec(&mut self, input: &[u8]) {
assert!(!self.finished)
let mut i = 0;
while i < input.len() && self.input_buffer_idx != 0 {
self.input_byte(input[i]);
i += 1;
}
while input.len() - i >= 4 {
let w = to_u32(input.slice(i, i + 4));
self.process_word(w);
self.length_bytes += 4;
i += 4;
}
while i < input.len() {
self.input_byte(input[i]);
i += 1;
}
fn reset(&mut self, h: &[u32, ..8]) {
self.H0 = h[0];
self.H1 = h[1];
self.H2 = h[2];
self.H3 = h[3];
self.H4 = h[4];
self.H5 = h[5];
self.H6 = h[6];
self.H7 = h[7];
}
fn reset(&mut self) {
self.length_bytes = 0;
self.finished = false;
self.input_buffer_idx = 0;
self.W_idx = 0;
}
fn process_word(&mut self, input: u32) {
self.W[self.W_idx] = input;
self.W_idx += 1;
if (self.W_idx == 16) {
self.W_idx = 0;
self.process_block();
}
}
fn process_block(&mut self) {
fn process_block(&mut self, data: &[u8]) {
fn ch(x: u32, y: u32, z: u32) -> u32 {
((x & y) ^ ((!x) & z))
}
@@ -449,11 +492,6 @@ fn sigma1(x: u32) -> u32 {
((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10)
}
foreach t in range(16u, 64) {
self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) +
self.W[t - 16];
}
let mut a = self.H0;
let mut b = self.H1;
let mut c = self.H2;
@@ -463,47 +501,41 @@ fn sigma1(x: u32) -> u32 {
let mut g = self.H6;
let mut h = self.H7;
let mut t = 0;
foreach _ in range(0u, 8) {
h += sum1(e) + ch(e, f, g) + K32[t] + self.W[t];
d += h;
h += sum0(a) + maj(a, b, c);
t += 1;
let mut W = [0u32, ..64];
g += sum1(d) + ch(d, e, f) + K32[t] + self.W[t];
c += g;
g += sum0(h) + maj(h, a, b);
t += 1;
read_u32v_be(W.mut_slice(0, 16), data);
f += sum1(c) + ch(c, d, e) + K32[t] + self.W[t];
b += f;
f += sum0(g) + maj(g, h, a);
t += 1;
// Putting the message schedule inside the same loop as the round calculations allows for
// the compiler to generate better code.
for uint::range_step(0, 48, 8) |t| {
schedule_round!(t + 16);
schedule_round!(t + 17);
schedule_round!(t + 18);
schedule_round!(t + 19);
schedule_round!(t + 20);
schedule_round!(t + 21);
schedule_round!(t + 22);
schedule_round!(t + 23);
e += sum1(b) + ch(b, c, d) + K32[t] + self.W[t];
a += e;
e += sum0(f) + maj(f, g, h);
t += 1;
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3);
sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4);
sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
}
d += sum1(a) + ch(a, b, c) + K32[t] + self.W[t];
h += d;
d += sum0(e) + maj(e, f, g);
t += 1;
c += sum1(h) + ch(h, a, b) + K32[t] + self.W[t];
g += c;
c += sum0(d) + maj(d, e, f);
t += 1;
b += sum1(g) + ch(g, h, a) + K32[t] + self.W[t];
f += b;
b += sum0(c) + maj(c, d, e);
t += 1;
a += sum1(f) + ch(f, g, h) + K32[t] + self.W[t];
e += a;
a += sum0(b) + maj(b, c, d);
t += 1;
for uint::range_step(48, 64, 8) |t| {
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3);
sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4);
sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
}
self.H0 += a;
@@ -515,418 +547,182 @@ fn sigma1(x: u32) -> u32 {
self.H6 += g;
self.H7 += h;
}
fn finish(&mut self) {
if (self.finished) {
return;
}
// must get length before adding padding
let bit_length = self.length_bytes << 3;
// add padding
self.input_byte(128u8);
while self.input_buffer_idx != 0 {
self.input_byte(0u8);
}
// add length
if (self.W_idx > 14) {
foreach _ in range(self.W_idx, 16) {
self.process_word(0);
}
}
while self.W_idx < 14 {
self.process_word(0);
}
self.process_word((bit_length >> 32) as u32);
self.process_word(bit_length as u32);
self.finished = true;
}
fn result_256(&mut self, out: &mut [u8]) {
self.finish();
from_u32(self.H0, out.mut_slice(0, 4));
from_u32(self.H1, out.mut_slice(4, 8));
from_u32(self.H2, out.mut_slice(8, 12));
from_u32(self.H3, out.mut_slice(12, 16));
from_u32(self.H4, out.mut_slice(16, 20));
from_u32(self.H5, out.mut_slice(20, 24));
from_u32(self.H6, out.mut_slice(24, 28));
from_u32(self.H7, out.mut_slice(28, 32));
}
fn result_224(&mut self, out: &mut [u8]) {
self.finish();
from_u32(self.H0, out.mut_slice(0, 4));
from_u32(self.H1, out.mut_slice(4, 8));
from_u32(self.H2, out.mut_slice(8, 12));
from_u32(self.H3, out.mut_slice(12, 16));
from_u32(self.H4, out.mut_slice(16, 20));
from_u32(self.H5, out.mut_slice(20, 24));
from_u32(self.H6, out.mut_slice(24, 28));
}
}
static K32: [u32, ..64] = [
0x428a2f98u32, 0x71374491u32, 0xb5c0fbcfu32, 0xe9b5dba5u32,
0x3956c25bu32, 0x59f111f1u32, 0x923f82a4u32, 0xab1c5ed5u32,
0xd807aa98u32, 0x12835b01u32, 0x243185beu32, 0x550c7dc3u32,
0x72be5d74u32, 0x80deb1feu32, 0x9bdc06a7u32, 0xc19bf174u32,
0xe49b69c1u32, 0xefbe4786u32, 0x0fc19dc6u32, 0x240ca1ccu32,
0x2de92c6fu32, 0x4a7484aau32, 0x5cb0a9dcu32, 0x76f988dau32,
0x983e5152u32, 0xa831c66du32, 0xb00327c8u32, 0xbf597fc7u32,
0xc6e00bf3u32, 0xd5a79147u32, 0x06ca6351u32, 0x14292967u32,
0x27b70a85u32, 0x2e1b2138u32, 0x4d2c6dfcu32, 0x53380d13u32,
0x650a7354u32, 0x766a0abbu32, 0x81c2c92eu32, 0x92722c85u32,
0xa2bfe8a1u32, 0xa81a664bu32, 0xc24b8b70u32, 0xc76c51a3u32,
0xd192e819u32, 0xd6990624u32, 0xf40e3585u32, 0x106aa070u32,
0x19a4c116u32, 0x1e376c08u32, 0x2748774cu32, 0x34b0bcb5u32,
0x391c0cb3u32, 0x4ed8aa4au32, 0x5b9cca4fu32, 0x682e6ff3u32,
0x748f82eeu32, 0x78a5636fu32, 0x84c87814u32, 0x8cc70208u32,
0x90befffau32, 0xa4506cebu32, 0xbef9a3f7u32, 0xc67178f2u32
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
struct Sha512 {
priv engine: Engine512
// A structure that keeps track of the state of the Sha-256 operation and contains the logic
// necessary to perform the final calculations.
struct Engine256 {
length_bits: u64,
buffer: FixedBuffer64,
state: Engine256State,
finished: bool,
}
struct Sha384 {
priv engine: Engine512
impl Engine256 {
fn new(h: &[u32, ..8]) -> Engine256 {
return Engine256 {
length_bits: 0,
buffer: FixedBuffer64::new(),
state: Engine256State::new(h),
finished: false
}
}
fn reset(&mut self, h: &[u32, ..8]) {
self.length_bits = 0;
self.buffer.reset();
self.state.reset(h);
self.finished = false;
}
fn input(&mut self, input: &[u8]) {
assert!(!self.finished)
// Assumes that input.len() can be converted to u64 without overflow
self.length_bits = shift_add_check_overflow(self.length_bits, input.len() as u64, 3);
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
}
fn finish(&mut self) {
if self.finished {
return;
}
self.buffer.standard_padding(8, |input: &[u8]| { self.state.process_block(input) });
write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 );
write_u32_be(self.buffer.next(4), self.length_bits as u32);
self.state.process_block(self.buffer.full_buffer());
self.finished = true;
}
}
struct Sha512Trunc256 {
priv engine: Engine512
}
struct Sha512Trunc224 {
priv engine: Engine512
}
struct Sha256 {
priv engine: Engine256
}
struct Sha224 {
priv engine: Engine256
}
impl Sha512 {
/**
* Construct an new instance of a SHA-512 digest.
*/
pub fn new() -> Sha512 {
Sha512 {
engine: Engine512 {
input_buffer: [0u8, ..8],
input_buffer_idx: 0,
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
H0: 0x6a09e667f3bcc908u64,
H1: 0xbb67ae8584caa73bu64,
H2: 0x3c6ef372fe94f82bu64,
H3: 0xa54ff53a5f1d36f1u64,
H4: 0x510e527fade682d1u64,
H5: 0x9b05688c2b3e6c1fu64,
H6: 0x1f83d9abfb41bd6bu64,
H7: 0x5be0cd19137e2179u64,
W: [0u64, ..80],
W_idx: 0,
finished: false,
}
}
}
}
impl Sha384 {
/**
* Construct an new instance of a SHA-384 digest.
*/
pub fn new() -> Sha384 {
Sha384 {
engine: Engine512 {
input_buffer: [0u8, ..8],
input_buffer_idx: 0,
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
H0: 0xcbbb9d5dc1059ed8u64,
H1: 0x629a292a367cd507u64,
H2: 0x9159015a3070dd17u64,
H3: 0x152fecd8f70e5939u64,
H4: 0x67332667ffc00b31u64,
H5: 0x8eb44a8768581511u64,
H6: 0xdb0c2e0d64f98fa7u64,
H7: 0x47b5481dbefa4fa4u64,
W: [0u64, ..80],
W_idx: 0,
finished: false,
}
}
}
}
impl Sha512Trunc256 {
/**
* Construct an new instance of a SHA-512/256 digest.
*/
pub fn new() -> Sha512Trunc256 {
Sha512Trunc256 {
engine: Engine512 {
input_buffer: [0u8, ..8],
input_buffer_idx: 0,
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
H0: 0x22312194fc2bf72cu64,
H1: 0x9f555fa3c84c64c2u64,
H2: 0x2393b86b6f53b151u64,
H3: 0x963877195940eabdu64,
H4: 0x96283ee2a88effe3u64,
H5: 0xbe5e1e2553863992u64,
H6: 0x2b0199fc2c85b8aau64,
H7: 0x0eb72ddc81c52ca2u64,
W: [0u64, ..80],
W_idx: 0,
finished: false,
}
}
}
}
impl Sha512Trunc224 {
/**
* Construct an new instance of a SHA-512/224 digest.
*/
pub fn new() -> Sha512Trunc224 {
Sha512Trunc224 {
engine: Engine512 {
input_buffer: [0u8, ..8],
input_buffer_idx: 0,
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
H0: 0x8c3d37c819544da2u64,
H1: 0x73e1996689dcd4d6u64,
H2: 0x1dfab7ae32ff9c82u64,
H3: 0x679dd514582f9fcfu64,
H4: 0x0f6d2b697bd44da8u64,
H5: 0x77e36f7304c48942u64,
H6: 0x3f9d85a86a1d36c8u64,
H7: 0x1112e6ad91d692a1u64,
W: [0u64, ..80],
W_idx: 0,
finished: false,
}
}
}
}
impl Sha256 {
/**
* Construct an new instance of a SHA-256 digest.
*/
pub fn new() -> Sha256 {
Sha256 {
engine: Engine256 {
input_buffer: [0u8, ..4],
input_buffer_idx: 0,
length_bytes: 0,
H0: 0x6a09e667u32,
H1: 0xbb67ae85u32,
H2: 0x3c6ef372u32,
H3: 0xa54ff53au32,
H4: 0x510e527fu32,
H5: 0x9b05688cu32,
H6: 0x1f83d9abu32,
H7: 0x5be0cd19u32,
W: [0u32, ..64],
W_idx: 0,
finished: false,
}
engine: Engine256::new(&H256)
}
}
}
impl Digest for Sha256 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u32_be(out.mut_slice(0, 4), self.engine.state.H0);
write_u32_be(out.mut_slice(4, 8), self.engine.state.H1);
write_u32_be(out.mut_slice(8, 12), self.engine.state.H2);
write_u32_be(out.mut_slice(12, 16), self.engine.state.H3);
write_u32_be(out.mut_slice(16, 20), self.engine.state.H4);
write_u32_be(out.mut_slice(20, 24), self.engine.state.H5);
write_u32_be(out.mut_slice(24, 28), self.engine.state.H6);
write_u32_be(out.mut_slice(28, 32), self.engine.state.H7);
}
fn reset(&mut self) {
self.engine.reset(&H256);
}
fn output_bits(&self) -> uint { 256 }
}
static H256: [u32, ..8] = [
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19
];
struct Sha224 {
priv engine: Engine256
}
impl Sha224 {
/**
* Construct an new instance of a SHA-224 digest.
*/
pub fn new() -> Sha224 {
Sha224 {
engine: Engine256 {
input_buffer: [0u8, ..4],
input_buffer_idx: 0,
length_bytes: 0,
H0: 0xc1059ed8u32,
H1: 0x367cd507u32,
H2: 0x3070dd17u32,
H3: 0xf70e5939u32,
H4: 0xffc00b31u32,
H5: 0x68581511u32,
H6: 0x64f98fa7u32,
H7: 0xbefa4fa4u32,
W: [0u32, ..64],
W_idx: 0,
finished: false,
}
engine: Engine256::new(&H224)
}
}
}
impl Digest for Sha512 {
fn input(&mut self, d: &[u8]) {
self.engine.input_vec(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.result_512(out)
}
fn reset(&mut self) {
self.engine.reset();
self.engine.H0 = 0x6a09e667f3bcc908u64;
self.engine.H1 = 0xbb67ae8584caa73bu64;
self.engine.H2 = 0x3c6ef372fe94f82bu64;
self.engine.H3 = 0xa54ff53a5f1d36f1u64;
self.engine.H4 = 0x510e527fade682d1u64;
self.engine.H5 = 0x9b05688c2b3e6c1fu64;
self.engine.H6 = 0x1f83d9abfb41bd6bu64;
self.engine.H7 = 0x5be0cd19137e2179u64;
}
fn output_bits(&self) -> uint { 512 }
}
impl Digest for Sha384 {
fn input(&mut self, d: &[u8]) {
self.engine.input_vec(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.result_384(out)
}
fn reset(&mut self) {
self.engine.reset();
self.engine.H0 = 0xcbbb9d5dc1059ed8u64;
self.engine.H1 = 0x629a292a367cd507u64;
self.engine.H2 = 0x9159015a3070dd17u64;
self.engine.H3 = 0x152fecd8f70e5939u64;
self.engine.H4 = 0x67332667ffc00b31u64;
self.engine.H5 = 0x8eb44a8768581511u64;
self.engine.H6 = 0xdb0c2e0d64f98fa7u64;
self.engine.H7 = 0x47b5481dbefa4fa4u64;
}
fn output_bits(&self) -> uint { 384 }
}
impl Digest for Sha512Trunc256 {
fn input(&mut self, d: &[u8]) {
self.engine.input_vec(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.result_256(out)
}
fn reset(&mut self) {
self.engine.reset();
self.engine.H0 = 0x22312194fc2bf72cu64;
self.engine.H1 = 0x9f555fa3c84c64c2u64;
self.engine.H2 = 0x2393b86b6f53b151u64;
self.engine.H3 = 0x963877195940eabdu64;
self.engine.H4 = 0x96283ee2a88effe3u64;
self.engine.H5 = 0xbe5e1e2553863992u64;
self.engine.H6 = 0x2b0199fc2c85b8aau64;
self.engine.H7 = 0x0eb72ddc81c52ca2u64;
}
fn output_bits(&self) -> uint { 256 }
}
impl Digest for Sha512Trunc224 {
fn input(&mut self, d: &[u8]) {
self.engine.input_vec(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.result_224(out)
}
fn reset(&mut self) {
self.engine.reset();
self.engine.H0 = 0x8c3d37c819544da2u64;
self.engine.H1 = 0x73e1996689dcd4d6u64;
self.engine.H2 = 0x1dfab7ae32ff9c82u64;
self.engine.H3 = 0x679dd514582f9fcfu64;
self.engine.H4 = 0x0f6d2b697bd44da8u64;
self.engine.H5 = 0x77e36f7304c48942u64;
self.engine.H6 = 0x3f9d85a86a1d36c8u64;
self.engine.H7 = 0x1112e6ad91d692a1u64;
}
fn output_bits(&self) -> uint { 224 }
}
impl Digest for Sha256 {
fn input(&mut self, d: &[u8]) {
self.engine.input_vec(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.result_256(out)
}
fn reset(&mut self) {
self.engine.reset();
self.engine.H0 = 0x6a09e667u32;
self.engine.H1 = 0xbb67ae85u32;
self.engine.H2 = 0x3c6ef372u32;
self.engine.H3 = 0xa54ff53au32;
self.engine.H4 = 0x510e527fu32;
self.engine.H5 = 0x9b05688cu32;
self.engine.H6 = 0x1f83d9abu32;
self.engine.H7 = 0x5be0cd19u32;
}
fn output_bits(&self) -> uint { 256 }
}
impl Digest for Sha224 {
fn input(&mut self, d: &[u8]) {
self.engine.input_vec(d);
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.result_224(out)
self.engine.finish();
write_u32_be(out.mut_slice(0, 4), self.engine.state.H0);
write_u32_be(out.mut_slice(4, 8), self.engine.state.H1);
write_u32_be(out.mut_slice(8, 12), self.engine.state.H2);
write_u32_be(out.mut_slice(12, 16), self.engine.state.H3);
write_u32_be(out.mut_slice(16, 20), self.engine.state.H4);
write_u32_be(out.mut_slice(20, 24), self.engine.state.H5);
write_u32_be(out.mut_slice(24, 28), self.engine.state.H6);
}
fn reset(&mut self) {
self.engine.reset();
self.engine.H0 = 0xc1059ed8u32;
self.engine.H1 = 0x367cd507u32;
self.engine.H2 = 0x3070dd17u32;
self.engine.H3 = 0xf70e5939u32;
self.engine.H4 = 0xffc00b31u32;
self.engine.H5 = 0x68581511u32;
self.engine.H6 = 0x64f98fa7u32;
self.engine.H7 = 0xbefa4fa4u32;
self.engine.reset(&H224);
}
fn output_bits(&self) -> uint { 224 }
}
static H224: [u32, ..8] = [
0xc1059ed8,
0x367cd507,
0x3070dd17,
0xf70e5939,
0xffc00b31,
0x68581511,
0x64f98fa7,
0xbefa4fa4
];
#[cfg(test)]
mod tests {
use digest::{Digest, DigestUtil};
use cryptoutil::test::test_digest_1million_random;
use digest::Digest;
use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224};
struct Test {
@@ -1117,6 +913,25 @@ fn test_sha224() {
test_hash(sh, tests);
}
#[test]
fn test_1million_random_sha512() {
let mut sh = Sha512::new();
test_digest_1million_random(
&mut sh,
128,
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" +
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
}
#[test]
fn test_1million_random_sha256() {
let mut sh = Sha256::new();
test_digest_1million_random(
&mut sh,
64,
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
}
}
+2
View File
@@ -67,6 +67,8 @@
pub mod treemap;
// Crypto
#[path="crypto/cryptoutil.rs"]
mod cryptoutil;
#[path="crypto/digest.rs"]
pub mod digest;
#[path="crypto/sha1.rs"]
+1 -2
View File
@@ -10,8 +10,7 @@
#[allow(missing_doc)];
use digest::DigestUtil;
use digest::Digest;
use json;
use sha1::Sha1;
use serialize::{Encoder, Encodable, Decoder, Decodable};