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.
This commit is contained in:
Palmer Cox 2013-06-23 19:03:59 -04:00
parent e1b8c67580
commit 89eef0b139
4 changed files with 119 additions and 37 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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 {