From 89eef0b139f0d16844155429a65fc1ac2ea4cd9f Mon Sep 17 00:00:00 2001
From: Palmer Cox
Date: Sun, 23 Jun 2013 19:03:59 -0400
Subject: [PATCH] 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.
---
src/libextra/crypto/digest.rs | 88 +++++++++++++++++++++++++++++++++++
src/libextra/crypto/sha1.rs | 53 +++++++++------------
src/libextra/std.rc | 2 +
src/libextra/workcache.rs | 13 +++---
4 files changed, 119 insertions(+), 37 deletions(-)
create mode 100644 src/libextra/crypto/digest.rs
diff --git a/src/libextra/crypto/digest.rs b/src/libextra/crypto/digest.rs
new file mode 100644
index 000000000000..8fd44bfc9abc
--- /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 or the MIT license
+// , 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 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 01e210803cf3..5a67e08c1900 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 98305e2766a0..dbc3095ae275 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 2ebf00c485ef..ed675bf99e9d 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>(s: &str) -> T {
}
fn digest>(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 {