about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPalmer Cox <p@lmercox.com>2013-10-26 16:49:51 -0400
committerPalmer Cox <p@lmercox.com>2013-10-27 21:25:19 -0400
commit2d5cb5d99a68d9b603675b1c4284dbe37333332c (patch)
treec5bcb630d21739824839e9d0cfd71405c5aa8979
parentff9e573a6752cde4760fafdb94f7337c9e133905 (diff)
downloadrust-2d5cb5d99a68d9b603675b1c4284dbe37333332c.tar.gz
rust-2d5cb5d99a68d9b603675b1c4284dbe37333332c.zip
Integrate the code in the digest and cryptoutil modules directly into the sha1 module.
-rw-r--r--src/librustpkg/cryptoutil.rs271
-rw-r--r--src/librustpkg/digest.rs81
-rw-r--r--src/librustpkg/rustpkg.rs2
-rw-r--r--src/librustpkg/sha1.rs323
-rw-r--r--src/librustpkg/workcache_support.rs3
5 files changed, 315 insertions, 365 deletions
diff --git a/src/librustpkg/cryptoutil.rs b/src/librustpkg/cryptoutil.rs
deleted file mode 100644
index 55199b1f2cc..00000000000
--- a/src/librustpkg/cryptoutil.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-// 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::{Zero, CheckedAdd};
-use std::vec::bytes::{MutableByteVector, copy_memory};
-
-
-/// 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 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);
-        }
-    }
-}
-
-
-trait ToBits {
-    /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
-    /// high-order value and the 2nd item is the low order value.
-    fn to_bits(self) -> (Self, Self);
-}
-
-impl ToBits for u64 {
-    fn to_bits(self) -> (u64, u64) {
-        return (self >> 61, self << 3);
-    }
-}
-
-/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
-/// overflow.
-pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
-    let (new_high_bits, new_low_bits) = bytes.to_bits();
-
-    if new_high_bits > Zero::zero() {
-        fail!("Numeric overflow occured.")
-    }
-
-    match bits.checked_add(&new_low_bits) {
-        Some(x) => return x,
-        None => fail!("Numeric overflow occured.")
-    }
-}
-
-
-/// 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, process 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;
-}
-
-
-/// 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 FixedBuffer for FixedBuffer64 {
-    fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
-        let mut i = 0;
-
-        // FIXME: #6304 - This local variable shouldn't be necessary.
-        let size = 64;
-
-        // 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 == 64);
-        self.buffer_idx = 0;
-        return self.buffer.slice_to(64);
-    }
-
-    fn position(&self) -> uint { self.buffer_idx }
-
-    fn remaining(&self) -> uint { 64 - self.buffer_idx }
-
-    fn size(&self) -> uint { 64 }
-}
-
-
-/// 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)]
-pub mod test {
-    use std::rand::{IsaacRng, Rng};
-    use std::vec;
-    use extra::hex::FromHex;
-
-    use cryptoutil::add_bytes_to_bits;
-    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_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();
-        let result_bytes = digest.result_bytes();
-
-        assert_eq!(expected, result_str.as_slice());
-        assert_eq!(expected.from_hex().unwrap(), result_bytes);
-    }
-
-    // A normal addition - no overflow occurs
-    #[test]
-    fn test_add_bytes_to_bits_ok() {
-        assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
-    }
-
-    // A simple failure case - adding 1 to the max value
-    #[test]
-    #[should_fail]
-    fn test_add_bytes_to_bits_overflow() {
-        add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
-    }
-}
diff --git a/src/librustpkg/digest.rs b/src/librustpkg/digest.rs
deleted file mode 100644
index f0dccf7c2e2..00000000000
--- a/src/librustpkg/digest.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.
-
-//! Common functionality related to cryptographic digest functions
-
-use std::vec;
-
-use extra::hex::ToHex;
-
-
-/**
- * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
- * family of digest functions.
- */
-pub trait Digest {
-    /**
-     * Provide message data.
-     *
-     * # Arguments
-     *
-     * * input - A vector of message data
-     */
-    fn input(&mut self, input: &[u8]);
-
-    /**
-     * 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]);
-
-    /**
-     * Reset the digest. This method must be called after result() and before supplying more
-     * data.
-     */
-    fn reset(&mut self);
-
-    /**
-     * Get the output size in bits.
-     */
-    fn output_bits(&self) -> uint;
-
-    /**
-     * Convenience function that feeds a string into a digest.
-     *
-     * # Arguments
-     *
-     * * `input` The string to feed into the digest
-     */
-    fn input_str(&mut self, input: &str) {
-        self.input(input.as_bytes());
-    }
-
-    /**
-     * Convenience function that retrieves the result of a digest as a
-     * newly allocated vec of bytes.
-     */
-    fn result_bytes(&mut self) -> ~[u8] {
-        let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
-        self.result(buf);
-        buf
-    }
-
-    /**
-     * Convenience function that retrieves the result of a digest as a
-     * ~str in hexadecimal format.
-     */
-    fn result_str(&mut self) -> ~str {
-        self.result_bytes().to_hex()
-    }
-}
-
diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs
index 229eecffbea..95a2c5b1702 100644
--- a/src/librustpkg/rustpkg.rs
+++ b/src/librustpkg/rustpkg.rs
@@ -55,8 +55,6 @@ pub mod api;
 mod conditions;
 pub mod context;
 mod crate;
-mod cryptoutil;
-mod digest;
 pub mod exit_codes;
 mod installed_packages;
 mod messages;
diff --git a/src/librustpkg/sha1.rs b/src/librustpkg/sha1.rs
index 04efbfffe15..d955fd1aa97 100644
--- a/src/librustpkg/sha1.rs
+++ b/src/librustpkg/sha1.rs
@@ -26,10 +26,278 @@
  * discouraged.
  */
 
+use std::num::Zero;
+use std::vec;
+use std::vec::bytes::{MutableByteVector, copy_memory};
+use extra::hex::ToHex;
+
+/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
+/// format.
+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 u32s. The values are read in big-endian format.
+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);
+        }
+    }
+}
+
+trait ToBits {
+    /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
+    /// high-order value and the 2nd item is the low order value.
+    fn to_bits(self) -> (Self, Self);
+}
+
+impl ToBits for u64 {
+    fn to_bits(self) -> (u64, u64) {
+        return (self >> 61, self << 3);
+    }
+}
+
+/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
+/// overflow.
+fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
+    let (new_high_bits, new_low_bits) = bytes.to_bits();
+
+    if new_high_bits > Zero::zero() {
+        fail!("Numeric overflow occured.")
+    }
+
+    match bits.checked_add(&new_low_bits) {
+        Some(x) => return x,
+        None => fail!("Numeric overflow occured.")
+    }
+}
+
+/// 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.
+trait FixedBuffer {
+    /// Input a vector of bytes. If the buffer becomes full, process 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];
 
-use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64,
-    StandardPadding};
-use digest::Digest;
+    /// 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;
+}
+
+/// A fixed size buffer of 64 bytes useful for cryptographic operations.
+struct FixedBuffer64 {
+    priv buffer: [u8, ..64],
+    priv buffer_idx: uint,
+}
+
+impl FixedBuffer64 {
+    /// Create a new buffer
+    fn new() -> FixedBuffer64 {
+        return FixedBuffer64 {
+            buffer: [0u8, ..64],
+            buffer_idx: 0
+        };
+    }
+}
+
+impl FixedBuffer for FixedBuffer64 {
+    fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
+        let mut i = 0;
+
+        let size = 64;
+
+        // 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 == 64);
+        self.buffer_idx = 0;
+        return self.buffer.slice_to(64);
+    }
+
+    fn position(&self) -> uint { self.buffer_idx }
+
+    fn remaining(&self) -> uint { 64 - self.buffer_idx }
+
+    fn size(&self) -> uint { 64 }
+}
+
+/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
+/// struct.
+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);
+    }
+}
+
+/**
+ * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
+ * family of digest functions.
+ */
+pub trait Digest {
+    /**
+     * Provide message data.
+     *
+     * # Arguments
+     *
+     * * input - A vector of message data
+     */
+    fn input(&mut self, input: &[u8]);
+
+    /**
+     * 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]);
+
+    /**
+     * Reset the digest. This method must be called after result() and before supplying more
+     * data.
+     */
+    fn reset(&mut self);
+
+    /**
+     * Get the output size in bits.
+     */
+    fn output_bits(&self) -> uint;
+
+    /**
+     * Convenience function that feeds a string into a digest.
+     *
+     * # Arguments
+     *
+     * * `input` The string to feed into the digest
+     */
+    fn input_str(&mut self, input: &str) {
+        self.input(input.as_bytes());
+    }
+
+    /**
+     * Convenience function that retrieves the result of a digest as a
+     * newly allocated vec of bytes.
+     */
+    fn result_bytes(&mut self) -> ~[u8] {
+        let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
+        self.result(buf);
+        buf
+    }
+
+    /**
+     * Convenience function that retrieves the result of a digest as a
+     * ~str in hexadecimal format.
+     */
+    fn result_str(&mut self) -> ~str {
+        self.result_bytes().to_hex()
+    }
+}
 
 /*
  * A SHA-1 implementation derived from Paul E. Jones's reference
@@ -180,9 +448,10 @@ impl Digest for Sha1 {
 
 #[cfg(test)]
 mod tests {
-    use cryptoutil::test::test_digest_1million_random;
-    use digest::Digest;
-    use sha1::Sha1;
+    use std::rand::{IsaacRng, Rng};
+    use std::vec;
+    use extra::hex::FromHex;
+    use super::{Digest, Sha1, add_bytes_to_bits};
 
     #[deriving(Clone)]
     struct Test {
@@ -287,6 +556,31 @@ mod tests {
         }
     }
 
+    /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
+    /// correct.
+    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_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();
+        let result_bytes = digest.result_bytes();
+
+        assert_eq!(expected, result_str.as_slice());
+        assert_eq!(expected.from_hex().unwrap(), result_bytes);
+    }
+
     #[test]
     fn test_1million_random_sha1() {
         let mut sh = Sha1::new();
@@ -295,13 +589,25 @@ mod tests {
             64,
             "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
     }
+
+    // A normal addition - no overflow occurs
+    #[test]
+    fn test_add_bytes_to_bits_ok() {
+        assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
+    }
+
+    // A simple failure case - adding 1 to the max value
+    #[test]
+    #[should_fail]
+    fn test_add_bytes_to_bits_overflow() {
+        add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
+    }
 }
 
 #[cfg(test)]
 mod bench {
     use extra::test::BenchHarness;
-
-    use sha1::Sha1;
+    use super::Sha1;
 
     #[bench]
     pub fn sha1_10(bh: & mut BenchHarness) {
@@ -332,5 +638,4 @@ mod bench {
         }
         bh.bytes = bytes.len() as u64;
     }
-
 }
diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs
index 1cdaefd592b..3adb33ec2f4 100644
--- a/src/librustpkg/workcache_support.rs
+++ b/src/librustpkg/workcache_support.rs
@@ -12,8 +12,7 @@ use std::rt::io;
 use std::rt::io::extensions::ReaderUtil;
 use std::rt::io::file::FileInfo;
 use extra::workcache;
-use sha1::Sha1;
-use digest::Digest;
+use sha1::{Digest, Sha1};
 
 /// Hashes the file contents along with the last-modified time
 pub fn digest_file_with_date(path: &Path) -> ~str {