about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPalmer Cox <p@lmercox.com>2013-06-23 19:03:59 -0400
committerPalmer Cox <p@lmercox.com>2013-06-24 00:04:00 -0400
commit89eef0b139f0d16844155429a65fc1ac2ea4cd9f (patch)
treefacda9cc65eac8682c58e92dfdf484ef80862436
parente1b8c6758099b634ea9033f97ddcd3fa88b5abeb (diff)
downloadrust-89eef0b139f0d16844155429a65fc1ac2ea4cd9f.tar.gz
rust-89eef0b139f0d16844155429a65fc1ac2ea4cd9f.zip
Create a Digest trait for common methods on digests and convert the SHA-1 implementation to use it.
The DigestUtil trait was created for helper methods since default methods still have issues.
-rw-r--r--src/libextra/crypto/digest.rs88
-rw-r--r--src/libextra/crypto/sha1.rs53
-rw-r--r--src/libextra/std.rc2
-rw-r--r--src/libextra/workcache.rs13
4 files changed, 119 insertions, 37 deletions
diff --git a/src/libextra/crypto/digest.rs b/src/libextra/crypto/digest.rs
new file mode 100644
index 00000000000..8fd44bfc9ab
--- /dev/null
+++ b/src/libextra/crypto/digest.rs
@@ -0,0 +1,88 @@
+// 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 core::prelude::*;
+
+use core::uint;
+use core::vec;
+
+/**
+ * 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.
+     */
+    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;
+}
+
+fn to_hex(rr: &[u8]) -> ~str {
+    let mut s = ~"";
+    for rr.iter().advance() |b| {
+        let hex = uint::to_str_radix(*b as uint, 16u);
+        if hex.len() == 1 {
+            s += "0";
+        }
+        s += hex;
+    }
+    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, in: &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, in: &str) {
+        self.input(in.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);
+    }
+}
diff --git a/src/libextra/crypto/sha1.rs b/src/libextra/crypto/sha1.rs
index 01e210803cf..5a67e08c190 100644
--- a/src/libextra/crypto/sha1.rs
+++ b/src/libextra/crypto/sha1.rs
@@ -24,7 +24,7 @@
 
 use core::prelude::*;
 
-use core::uint;
+use digest::Digest;
 
 /*
  * A SHA-1 implementation derived from Paul E. Jones's reference
@@ -148,18 +148,17 @@ fn circular_shift(bits: u32, word: u32) -> u32 {
     return word << bits | word >> 32u32 - bits;
 }
 
-fn mk_result(st: &mut Sha1) -> ~[u8] {
+fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
     if !st.computed { pad_msg(st); st.computed = true; }
-    let mut rs: ~[u8] = ~[];
+    let mut i = 0;
     for st.h.mut_iter().advance |ptr_hpart| {
         let hpart = *ptr_hpart;
-        let a = (hpart >> 24u32 & 0xFFu32) as u8;
-        let b = (hpart >> 16u32 & 0xFFu32) as u8;
-        let c = (hpart >> 8u32 & 0xFFu32) as u8;
-        let d = (hpart & 0xFFu32) as u8;
-        rs = vec::append(copy rs, [a, b, c, d]);
+        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;
     }
-    return rs;
 }
 
 /*
@@ -221,6 +220,9 @@ impl Sha1 {
         st.reset();
         return st;
     }
+}
+
+impl Digest for Sha1 {
     pub fn reset(&mut self) {
         self.len_low = 0;
         self.len_high = 0;
@@ -233,28 +235,15 @@ impl Sha1 {
         self.computed = false;
     }
     pub fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
-    pub fn input_str(&mut self, msg: &str) {
-        add_input(self, msg.as_bytes());
-    }
-    pub fn result(&mut self) -> ~[u8] { return mk_result(self); }
-    pub fn result_str(&mut self) -> ~str {
-        let rr = mk_result(self);
-        let mut s = ~"";
-        for rr.iter().advance() |b| {
-            let hex = uint::to_str_radix(*b as uint, 16u);
-            if hex.len() == 1 {
-                s += "0";
-            }
-            s += hex;
-        }
-        return s;
-    }
+    pub fn result(&mut self, out: &mut [u8]) { return mk_result(self, out); }
+    pub fn output_bits(&self) -> uint { 160 }
 }
 
 #[cfg(test)]
 mod tests {
     use core::vec;
 
+    use digest::{Digest, DigestUtil};
     use sha1::Sha1;
 
     #[test]
@@ -343,13 +332,15 @@ mod tests {
 
         // Test that it works when accepting the message all at once
 
+        let mut out = [0u8, ..20];
+
         let mut sh = ~Sha1::new();
         for tests.iter().advance |t| {
-            sh.input_str(t.input);
-            let out = sh.result();
+            (*sh).input_str(t.input);
+            sh.result(out);
             assert!(vec::eq(t.output, out));
 
-            let out_str = sh.result_str();
+            let out_str = (*sh).result_str();
             assert_eq!(out_str.len(), 40);
             assert!(out_str == t.output_str);
 
@@ -363,13 +354,13 @@ mod tests {
             let mut left = len;
             while left > 0u {
                 let take = (left + 1u) / 2u;
-                sh.input_str(t.input.slice(len - left, take + len - left));
+                (*sh).input_str(t.input.slice(len - left, take + len - left));
                 left = left - take;
             }
-            let out = sh.result();
+            sh.result(out);
             assert!(vec::eq(t.output, out));
 
-            let out_str = sh.result_str();
+            let out_str = (*sh).result_str();
             assert_eq!(out_str.len(), 40);
             assert!(out_str == t.output_str);
 
diff --git a/src/libextra/std.rc b/src/libextra/std.rc
index 98305e2766a..dbc3095ae27 100644
--- a/src/libextra/std.rc
+++ b/src/libextra/std.rc
@@ -87,6 +87,8 @@ pub mod dlist;
 pub mod treemap;
 
 // Crypto
+#[path="crypto/digest.rs"]
+pub mod digest;
 #[path="crypto/sha1.rs"]
 pub mod sha1;
 
diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs
index 2ebf00c485e..ed675bf99e9 100644
--- a/src/libextra/workcache.rs
+++ b/src/libextra/workcache.rs
@@ -12,6 +12,7 @@
 
 use core::prelude::*;
 
+use digest::DigestUtil;
 use json;
 use sha1::Sha1;
 use serialize::{Encoder, Encodable, Decoder, Decodable};
@@ -248,16 +249,16 @@ fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
 }
 
 fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str {
-    let mut sha = Sha1::new();
-    sha.input_str(json_encode(t));
-    sha.result_str()
+    let mut sha = ~Sha1::new();
+    (*sha).input_str(json_encode(t));
+    (*sha).result_str()
 }
 
 fn digest_file(path: &Path) -> ~str {
-    let mut sha = Sha1::new();
+    let mut sha = ~Sha1::new();
     let s = io::read_whole_file_str(path);
-    sha.input_str(*s.get_ref());
-    sha.result_str()
+    (*sha).input_str(*s.get_ref());
+    (*sha).result_str()
 }
 
 impl Context {