Skip to content

Commit 89eef0b

Browse files
author
Palmer Cox
committed
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.
1 parent e1b8c67 commit 89eef0b

File tree

4 files changed

+119
-37
lines changed

4 files changed

+119
-37
lines changed

src/libextra/crypto/digest.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use core::prelude::*;
12+
13+
use core::uint;
14+
use core::vec;
15+
16+
/**
17+
* The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
18+
* family of digest functions.
19+
*/
20+
pub trait Digest {
21+
/**
22+
* Provide message data.
23+
*
24+
* # Arguments
25+
*
26+
* * input - A vector of message data
27+
*/
28+
fn input(&mut self, input: &[u8]);
29+
30+
/**
31+
* Retrieve the digest result. This method may be called multiple times.
32+
*/
33+
fn result(&mut self, out: &mut [u8]);
34+
35+
/**
36+
* Reset the digest. This method must be called after result() and before supplying more
37+
* data.
38+
*/
39+
fn reset(&mut self);
40+
41+
/**
42+
* Get the output size in bits.
43+
*/
44+
fn output_bits(&self) -> uint;
45+
}
46+
47+
fn to_hex(rr: &[u8]) -> ~str {
48+
let mut s = ~"";
49+
for rr.iter().advance() |b| {
50+
let hex = uint::to_str_radix(*b as uint, 16u);
51+
if hex.len() == 1 {
52+
s += "0";
53+
}
54+
s += hex;
55+
}
56+
return s;
57+
}
58+
59+
/// Contains utility methods for Digests.
60+
/// FIXME: #7339: Convert to default methods when issues with them are resolved.
61+
pub trait DigestUtil {
62+
/**
63+
* Convenience functon that feeds a string into a digest
64+
*
65+
* # Arguments
66+
*
67+
* * in The string to feed into the digest
68+
*/
69+
fn input_str(&mut self, in: &str);
70+
71+
/**
72+
* Convenience functon that retrieves the result of a digest as a
73+
* ~str in hexadecimal format.
74+
*/
75+
fn result_str(&mut self) -> ~str;
76+
}
77+
78+
impl<D: Digest> DigestUtil for D {
79+
fn input_str(&mut self, in: &str) {
80+
self.input(in.as_bytes());
81+
}
82+
83+
fn result_str(&mut self) -> ~str {
84+
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
85+
self.result(buf);
86+
return to_hex(buf);
87+
}
88+
}

src/libextra/crypto/sha1.rs

+22-31
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
use core::prelude::*;
2626

27-
use core::uint;
27+
use digest::Digest;
2828

2929
/*
3030
* A SHA-1 implementation derived from Paul E. Jones's reference
@@ -148,18 +148,17 @@ fn circular_shift(bits: u32, word: u32) -> u32 {
148148
return word << bits | word >> 32u32 - bits;
149149
}
150150

151-
fn mk_result(st: &mut Sha1) -> ~[u8] {
151+
fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
152152
if !st.computed { pad_msg(st); st.computed = true; }
153-
let mut rs: ~[u8] = ~[];
153+
let mut i = 0;
154154
for st.h.mut_iter().advance |ptr_hpart| {
155155
let hpart = *ptr_hpart;
156-
let a = (hpart >> 24u32 & 0xFFu32) as u8;
157-
let b = (hpart >> 16u32 & 0xFFu32) as u8;
158-
let c = (hpart >> 8u32 & 0xFFu32) as u8;
159-
let d = (hpart & 0xFFu32) as u8;
160-
rs = vec::append(copy rs, [a, b, c, d]);
156+
rs[i] = (hpart >> 24u32 & 0xFFu32) as u8;
157+
rs[i+1] = (hpart >> 16u32 & 0xFFu32) as u8;
158+
rs[i+2] = (hpart >> 8u32 & 0xFFu32) as u8;
159+
rs[i+3] = (hpart & 0xFFu32) as u8;
160+
i += 4;
161161
}
162-
return rs;
163162
}
164163

165164
/*
@@ -221,6 +220,9 @@ impl Sha1 {
221220
st.reset();
222221
return st;
223222
}
223+
}
224+
225+
impl Digest for Sha1 {
224226
pub fn reset(&mut self) {
225227
self.len_low = 0;
226228
self.len_high = 0;
@@ -233,28 +235,15 @@ impl Sha1 {
233235
self.computed = false;
234236
}
235237
pub fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
236-
pub fn input_str(&mut self, msg: &str) {
237-
add_input(self, msg.as_bytes());
238-
}
239-
pub fn result(&mut self) -> ~[u8] { return mk_result(self); }
240-
pub fn result_str(&mut self) -> ~str {
241-
let rr = mk_result(self);
242-
let mut s = ~"";
243-
for rr.iter().advance() |b| {
244-
let hex = uint::to_str_radix(*b as uint, 16u);
245-
if hex.len() == 1 {
246-
s += "0";
247-
}
248-
s += hex;
249-
}
250-
return s;
251-
}
238+
pub fn result(&mut self, out: &mut [u8]) { return mk_result(self, out); }
239+
pub fn output_bits(&self) -> uint { 160 }
252240
}
253241

254242
#[cfg(test)]
255243
mod tests {
256244
use core::vec;
257245

246+
use digest::{Digest, DigestUtil};
258247
use sha1::Sha1;
259248

260249
#[test]
@@ -343,13 +332,15 @@ mod tests {
343332

344333
// Test that it works when accepting the message all at once
345334

335+
let mut out = [0u8, ..20];
336+
346337
let mut sh = ~Sha1::new();
347338
for tests.iter().advance |t| {
348-
sh.input_str(t.input);
349-
let out = sh.result();
339+
(*sh).input_str(t.input);
340+
sh.result(out);
350341
assert!(vec::eq(t.output, out));
351342

352-
let out_str = sh.result_str();
343+
let out_str = (*sh).result_str();
353344
assert_eq!(out_str.len(), 40);
354345
assert!(out_str == t.output_str);
355346

@@ -363,13 +354,13 @@ mod tests {
363354
let mut left = len;
364355
while left > 0u {
365356
let take = (left + 1u) / 2u;
366-
sh.input_str(t.input.slice(len - left, take + len - left));
357+
(*sh).input_str(t.input.slice(len - left, take + len - left));
367358
left = left - take;
368359
}
369-
let out = sh.result();
360+
sh.result(out);
370361
assert!(vec::eq(t.output, out));
371362

372-
let out_str = sh.result_str();
363+
let out_str = (*sh).result_str();
373364
assert_eq!(out_str.len(), 40);
374365
assert!(out_str == t.output_str);
375366

src/libextra/std.rc

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ pub mod dlist;
8787
pub mod treemap;
8888

8989
// Crypto
90+
#[path="crypto/digest.rs"]
91+
pub mod digest;
9092
#[path="crypto/sha1.rs"]
9193
pub mod sha1;
9294

src/libextra/workcache.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use core::prelude::*;
1414

15+
use digest::DigestUtil;
1516
use json;
1617
use sha1::Sha1;
1718
use serialize::{Encoder, Encodable, Decoder, Decodable};
@@ -248,16 +249,16 @@ fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
248249
}
249250
250251
fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str {
251-
let mut sha = Sha1::new();
252-
sha.input_str(json_encode(t));
253-
sha.result_str()
252+
let mut sha = ~Sha1::new();
253+
(*sha).input_str(json_encode(t));
254+
(*sha).result_str()
254255
}
255256
256257
fn digest_file(path: &Path) -> ~str {
257-
let mut sha = Sha1::new();
258+
let mut sha = ~Sha1::new();
258259
let s = io::read_whole_file_str(path);
259-
sha.input_str(*s.get_ref());
260-
sha.result_str()
260+
(*sha).input_str(*s.get_ref());
261+
(*sha).result_str()
261262
}
262263
263264
impl Context {

0 commit comments

Comments
 (0)