sha1-0.6.0/.gitignore01006000000765000002400000000024124336202450012545 0ustar0000000000000000/target /Cargo.lock sha1-0.6.0/Cargo.toml.orig01006440000765000002400000000710132401366440013460 0ustar0000000000000000[package] name = "sha1" version = "0.6.0" authors = ["Armin Ronacher "] keywords = ["sha1"] description = "Minimal implementation of SHA1 for Rust." license = "BSD-3-Clause" repository = "https://github.com/mitsuhiko/rust-sha1" [features] std = [] [dependencies] serde = { version = "1.0", optional = true } [dev-dependencies] openssl = "0.10" rand = "0.4" serde_json = "1.0" [package.metadata.docs.rs] all-features = true sha1-0.6.0/Cargo.toml0000644000000020120006703 0ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "sha1" version = "0.6.0" authors = ["Armin Ronacher "] description = "Minimal implementation of SHA1 for Rust." keywords = ["sha1"] license = "BSD-3-Clause" repository = "https://github.com/mitsuhiko/rust-sha1" [package.metadata.docs.rs] all-features = true [dependencies.serde] version = "1.0" optional = true [dev-dependencies.openssl] version = "0.10" [dev-dependencies.rand] version = "0.4" [dev-dependencies.serde_json] version = "1.0" [features] std = [] sha1-0.6.0/LICENSE01006440000765000002400000002766124336331120011606 0ustar0000000000000000Copyright (c) 2014 by Armin Ronacher. Copyright (c) 2013 Koka El Kiwi Some rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sha1-0.6.0/Makefile01006440000765000002400000000430132336200070012221 0ustar0000000000000000build: @cargo build watch: @cargo watch watch-docs: @cargo watch build "doc --no-deps" test: @cargo test --features=serde @cargo test --features=std @cargo test docs: build @cargo doc --no-deps upload-docs: docs @./upload-docs.sh .PHONY: build test docs upload-docs sha1-0.6.0/README.md01006440000765000002400000000407130361232640012050 0ustar0000000000000000# rust-sha1 Minimal implementation of SHA1 for Rust. Right now SHA1 is quite frequently used and many things want to have an implementation of it, that does not pull in too much other stuff. This is largely based on the hash code in crypto-rs by Koka El Kiwi. sha1-0.6.0/rustfmt.toml01006440000765000002400000000027130361230620013164 0ustar0000000000000000format_strings = false sha1-0.6.0/src/lib.rs01006440000765000002400000054613132401365170012506 0ustar0000000000000000//! A minimal implementation of SHA1 for rust. //! //! This implementation supports no_std which is the default mode. The //! following features are available and can be optionally enabled: //! //! * ``serde``: when enabled the `Digest` type can be serialized. //! * ``std``: when enabled errors from this library implement `std::error::Error` //! and the `hexdigest` shortcut becomes available. //! //! Simple Example: //! //! ```rust //! extern crate sha1; //! # fn main() { //! //! let mut m = sha1::Sha1::new(); //! m.update(b"Hello World!"); //! assert_eq!(m.digest().to_string(), //! "2ef7bde608ce5404e97d5f042f95f89f1c232871"); //! # } //! ``` //! //! The sha1 object can be updated multiple times. If you only need to use //! it once you can also use shortcuts: //! //! ``` //! extern crate sha1; //! # fn main() { //! assert_eq!(sha1::Sha1::from("Hello World!").hexdigest(), //! "2ef7bde608ce5404e97d5f042f95f89f1c232871"); //! # } //! ``` #![no_std] #![deny(missing_docs)] #[cfg(feature="serde")] extern crate serde; #[cfg(feature="std")] extern crate std; use core::cmp; use core::fmt; use core::mem; use core::hash; use core::str; mod simd; use simd::*; /// The length of a SHA1 digest in bytes pub const DIGEST_LENGTH: usize = 20; /// Represents a Sha1 hash object in memory. #[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct Sha1 { state: Sha1State, blocks: Blocks, len: u64, } struct Blocks { len: u32, block: [u8; 64], } #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] struct Sha1State { state: [u32; 5], } /// Digest generated from a `Sha1` instance. /// /// A digest can be formatted to view the digest as a hex string, or the bytes /// can be extracted for later processing. /// /// To retrieve a hex string result call `to_string` on it (requires that std /// is available). /// /// If the `serde` feature is enabled a digest can also be serialized and /// deserialized. Likewise a digest can be parsed from a hex string. #[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Default)] pub struct Digest { data: Sha1State, } const DEFAULT_STATE: Sha1State = Sha1State { state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0] }; #[inline(always)] fn as_block(input: &[u8]) -> &[u8; 64] { unsafe { assert!(input.len() == 64); let arr: &[u8; 64] = mem::transmute(input.as_ptr()); arr } } impl Default for Sha1 { fn default() -> Sha1 { Sha1::new() } } impl Sha1 { /// Creates an fresh sha1 hash object. /// /// This is equivalent to creating a hash with `Default::default`. pub fn new() -> Sha1 { Sha1 { state: DEFAULT_STATE, len: 0, blocks: Blocks { len: 0, block: [0; 64], }, } } /// Shortcut to create a sha1 from some bytes. /// /// This also lets you create a hash from a utf-8 string. This is equivalent /// to making a new Sha1 object and calling `update` on it once. pub fn from>(data: D) -> Sha1 { let mut rv = Sha1::new(); rv.update(data.as_ref()); rv } /// Resets the hash object to it's initial state. pub fn reset(&mut self) { self.state = DEFAULT_STATE; self.len = 0; self.blocks.len = 0; } /// Update hash with input data. pub fn update(&mut self, data: &[u8]) { let len = &mut self.len; let state = &mut self.state; self.blocks.input(data, |block| { *len += block.len() as u64; state.process(block); }) } /// Retrieve digest result. pub fn digest(&self) -> Digest { let mut state = self.state; let bits = (self.len + (self.blocks.len as u64)) * 8; let extra = [(bits >> 56) as u8, (bits >> 48) as u8, (bits >> 40) as u8, (bits >> 32) as u8, (bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, (bits >> 0) as u8]; let mut last = [0; 128]; let blocklen = self.blocks.len as usize; last[..blocklen].clone_from_slice(&self.blocks.block[..blocklen]); last[blocklen] = 0x80; if blocklen < 56 { last[56..64].clone_from_slice(&extra); state.process(as_block(&last[0..64])); } else { last[120..128].clone_from_slice(&extra); state.process(as_block(&last[0..64])); state.process(as_block(&last[64..128])); } Digest { data: state } } /// Retrieve the digest result as hex string directly. /// /// (The function is only available if the `std` feature is enabled) #[cfg(feature="std")] pub fn hexdigest(&self) -> std::string::String { use std::string::ToString; self.digest().to_string() } } impl Digest { /// Returns the 160 bit (20 byte) digest as a byte array. pub fn bytes(&self) -> [u8; DIGEST_LENGTH] { [(self.data.state[0] >> 24) as u8, (self.data.state[0] >> 16) as u8, (self.data.state[0] >> 8) as u8, (self.data.state[0] >> 0) as u8, (self.data.state[1] >> 24) as u8, (self.data.state[1] >> 16) as u8, (self.data.state[1] >> 8) as u8, (self.data.state[1] >> 0) as u8, (self.data.state[2] >> 24) as u8, (self.data.state[2] >> 16) as u8, (self.data.state[2] >> 8) as u8, (self.data.state[2] >> 0) as u8, (self.data.state[3] >> 24) as u8, (self.data.state[3] >> 16) as u8, (self.data.state[3] >> 8) as u8, (self.data.state[3] >> 0) as u8, (self.data.state[4] >> 24) as u8, (self.data.state[4] >> 16) as u8, (self.data.state[4] >> 8) as u8, (self.data.state[4] >> 0) as u8] } } impl Blocks { fn input(&mut self, mut input: &[u8], mut f: F) where F: FnMut(&[u8; 64]) { if self.len > 0 { let len = self.len as usize; let amt = cmp::min(input.len(), self.block.len() - len); self.block[len..len + amt].clone_from_slice(&input[..amt]); if len + amt == self.block.len() { f(&self.block); self.len = 0; input = &input[amt..]; } else { self.len += amt as u32; return; } } assert_eq!(self.len, 0); for chunk in input.chunks(64) { if chunk.len() == 64 { f(as_block(chunk)) } else { self.block[..chunk.len()].clone_from_slice(chunk); self.len = chunk.len() as u32; } } } } // Round key constants const K0: u32 = 0x5A827999u32; const K1: u32 = 0x6ED9EBA1u32; const K2: u32 = 0x8F1BBCDCu32; const K3: u32 = 0xCA62C1D6u32; /// Not an intrinsic, but gets the first element of a vector. #[inline] fn sha1_first(w0: u32x4) -> u32 { w0.0 } /// Not an intrinsic, but adds a word to the first element of a vector. #[inline] fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 { let u32x4(a, b, c, d) = w0; u32x4(e.wrapping_add(a), b, c, d) } /// Emulates `llvm.x86.sha1msg1` intrinsic. fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 { let u32x4(_, _, w2, w3) = a; let u32x4(w4, w5, _, _) = b; a ^ u32x4(w2, w3, w4, w5) } /// Emulates `llvm.x86.sha1msg2` intrinsic. fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 { let u32x4(x0, x1, x2, x3) = a; let u32x4(_, w13, w14, w15) = b; let w16 = (x0 ^ w13).rotate_left(1); let w17 = (x1 ^ w14).rotate_left(1); let w18 = (x2 ^ w15).rotate_left(1); let w19 = (x3 ^ w16).rotate_left(1); u32x4(w16, w17, w18, w19) } /// Emulates `llvm.x86.sha1nexte` intrinsic. #[inline] fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 { sha1_first_add(sha1_first(abcd).rotate_left(30), msg) } /// Emulates `llvm.x86.sha1rnds4` intrinsic. /// Performs 4 rounds of the message block digest. fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 { const K0V: u32x4 = u32x4(K0, K0, K0, K0); const K1V: u32x4 = u32x4(K1, K1, K1, K1); const K2V: u32x4 = u32x4(K2, K2, K2, K2); const K3V: u32x4 = u32x4(K3, K3, K3, K3); match i { 0 => sha1rnds4c(abcd, work + K0V), 1 => sha1rnds4p(abcd, work + K1V), 2 => sha1rnds4m(abcd, work + K2V), 3 => sha1rnds4p(abcd, work + K3V), _ => panic!("unknown icosaround index") } } /// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic. fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 { let u32x4(mut a, mut b, mut c, mut d) = abcd; let u32x4(t, u, v, w) = msg; let mut e = 0u32; macro_rules! bool3ary_202 { ($a:expr, $b:expr, $c:expr) => (($c ^ ($a & ($b ^ $c)))) } // Choose, MD5F, SHA1C e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_202!(b, c, d)).wrapping_add(t); b = b.rotate_left(30); d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_202!(a, b, c)).wrapping_add(u); a = a.rotate_left(30); c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_202!(e, a, b)).wrapping_add(v); e = e.rotate_left(30); b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_202!(d, e, a)).wrapping_add(w); d = d.rotate_left(30); u32x4(b, c, d, e) } /// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic. fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 { let u32x4(mut a, mut b, mut c, mut d) = abcd; let u32x4(t, u, v, w) = msg; let mut e = 0u32; macro_rules! bool3ary_150 { ($a:expr, $b:expr, $c:expr) => (($a ^ $b ^ $c)) } // Parity, XOR, MD5H, SHA1P e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_150!(b, c, d)).wrapping_add(t); b = b.rotate_left(30); d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_150!(a, b, c)).wrapping_add(u); a = a.rotate_left(30); c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_150!(e, a, b)).wrapping_add(v); e = e.rotate_left(30); b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_150!(d, e, a)).wrapping_add(w); d = d.rotate_left(30); u32x4(b, c, d, e) } /// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic. fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 { let u32x4(mut a, mut b, mut c, mut d) = abcd; let u32x4(t, u, v, w) = msg; let mut e = 0u32; macro_rules! bool3ary_232 { ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c)) } // Majority, SHA1M e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_232!(b, c, d)).wrapping_add(t); b = b.rotate_left(30); d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_232!(a, b, c)).wrapping_add(u); a = a.rotate_left(30); c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_232!(e, a, b)).wrapping_add(v); e = e.rotate_left(30); b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_232!(d, e, a)).wrapping_add(w); d = d.rotate_left(30); u32x4(b, c, d, e) } impl Sha1State { fn process(&mut self, block: &[u8; 64]) { let mut words = [0u32; 16]; for i in 0..16 { let off = i * 4; words[i] = (block[off + 3] as u32) | ((block[off + 2] as u32) << 8) | ((block[off + 1] as u32) << 16) | ((block[off] as u32) << 24); } macro_rules! schedule { ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => ( sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3) ) } macro_rules! rounds4 { ($h0:ident, $h1:ident, $wk:expr, $i:expr) => ( sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i) ) } // Rounds 0..20 let mut h0 = u32x4(self.state[0], self.state[1], self.state[2], self.state[3]); let mut w0 = u32x4(words[0], words[1], words[2], words[3]); let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(self.state[4], w0), 0); let mut w1 = u32x4(words[4], words[5], words[6], words[7]); h0 = rounds4!(h1, h0, w1, 0); let mut w2 = u32x4(words[8], words[9], words[10], words[11]); h1 = rounds4!(h0, h1, w2, 0); let mut w3 = u32x4(words[12], words[13], words[14], words[15]); h0 = rounds4!(h1, h0, w3, 0); let mut w4 = schedule!(w0, w1, w2, w3); h1 = rounds4!(h0, h1, w4, 0); // Rounds 20..40 w0 = schedule!(w1, w2, w3, w4); h0 = rounds4!(h1, h0, w0, 1); w1 = schedule!(w2, w3, w4, w0); h1 = rounds4!(h0, h1, w1, 1); w2 = schedule!(w3, w4, w0, w1); h0 = rounds4!(h1, h0, w2, 1); w3 = schedule!(w4, w0, w1, w2); h1 = rounds4!(h0, h1, w3, 1); w4 = schedule!(w0, w1, w2, w3); h0 = rounds4!(h1, h0, w4, 1); // Rounds 40..60 w0 = schedule!(w1, w2, w3, w4); h1 = rounds4!(h0, h1, w0, 2); w1 = schedule!(w2, w3, w4, w0); h0 = rounds4!(h1, h0, w1, 2); w2 = schedule!(w3, w4, w0, w1); h1 = rounds4!(h0, h1, w2, 2); w3 = schedule!(w4, w0, w1, w2); h0 = rounds4!(h1, h0, w3, 2); w4 = schedule!(w0, w1, w2, w3); h1 = rounds4!(h0, h1, w4, 2); // Rounds 60..80 w0 = schedule!(w1, w2, w3, w4); h0 = rounds4!(h1, h0, w0, 3); w1 = schedule!(w2, w3, w4, w0); h1 = rounds4!(h0, h1, w1, 3); w2 = schedule!(w3, w4, w0, w1); h0 = rounds4!(h1, h0, w2, 3); w3 = schedule!(w4, w0, w1, w2); h1 = rounds4!(h0, h1, w3, 3); w4 = schedule!(w0, w1, w2, w3); h0 = rounds4!(h1, h0, w4, 3); let e = sha1_first(h1).rotate_left(30); let u32x4(a, b, c, d) = h0; self.state[0] = self.state[0].wrapping_add(a); self.state[1] = self.state[1].wrapping_add(b); self.state[2] = self.state[2].wrapping_add(c); self.state[3] = self.state[3].wrapping_add(d); self.state[4] = self.state[4].wrapping_add(e); } } impl PartialEq for Blocks { fn eq(&self, other: &Blocks) -> bool { (self.len, &self.block[..]).eq(&(other.len, &other.block[..])) } } impl Ord for Blocks { fn cmp(&self, other: &Blocks) -> cmp::Ordering { (self.len, &self.block[..]).cmp(&(other.len, &other.block[..])) } } impl PartialOrd for Blocks { fn partial_cmp(&self, other: &Blocks) -> Option { Some(self.cmp(other)) } } impl Eq for Blocks {} impl hash::Hash for Blocks { fn hash(&self, state: &mut H) { self.len.hash(state); self.block.hash(state); } } impl Clone for Blocks { fn clone(&self) -> Blocks { Blocks { ..*self } } } /// Indicates that a digest couldn't be parsed. #[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)] pub struct DigestParseError(()); impl fmt::Display for DigestParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "not a valid sha1 hash") } } #[cfg(feature="std")] impl std::error::Error for DigestParseError { fn description(&self) -> &str { "not a valid sha1 hash" } } impl str::FromStr for Digest { type Err = DigestParseError; fn from_str(s: &str) -> Result { if s.len() != 40 { return Err(DigestParseError(())); } let mut rv: Digest = Default::default(); for idx in 0..5 { rv.data.state[idx] = try!(u32::from_str_radix(&s[idx * 8..idx * 8 + 8], 16) .map_err(|_| DigestParseError(()))); } Ok(rv) } } impl fmt::Display for Digest { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for i in self.data.state.iter() { try!(write!(f, "{:08x}", i)); } Ok(()) } } impl fmt::Debug for Digest { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Digest {{ \"{}\" }}", self) } } #[cfg(feature="serde")] impl serde::ser::Serialize for Digest { fn serialize(&self, serializer: S) -> Result where S: serde::ser::Serializer, { fn to_hex(num: u8) -> u8 { b"0123456789abcdef"[num as usize] } let mut hex_str = [0u8; 40]; let mut c = 0; for state in self.data.state.iter() { for off in 0..4 { let byte = (state >> (8 * (3 - off))) as u8; hex_str[c] = to_hex(byte >> 4); hex_str[c + 1] = to_hex(byte & 0xf); c += 2; } } serializer.serialize_str(unsafe { str::from_utf8_unchecked(&hex_str[..]) }) } } #[cfg(feature="serde")] impl<'de> serde::de::Deserialize<'de> for Digest { fn deserialize(deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { struct V; impl<'de> serde::de::Visitor<'de> for V { type Value = Digest; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("SHA-1 hash") } fn visit_str(self, value: &str) -> Result where E: serde::de::Error, { value .parse() .map_err(|_| serde::de::Error::invalid_value( serde::de::Unexpected::Str(value), &self)) } } deserializer.deserialize_str(V) } } #[cfg_attr(rustfmt, rustfmt_skip)] #[cfg(test)] mod tests { extern crate std; extern crate rand; extern crate openssl; use self::std::prelude::v1::*; use Sha1; #[test] fn test_simple() { let mut m = Sha1::new(); let tests = [ ("The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"), ("The quick brown fox jumps over the lazy cog", "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"), ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"), ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"), ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"), ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "4300320394f7ee239bcdce7d3b8bcee173a0cd5c"), ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "cef734ba81a024479e09eb5a75b6ddae62e6abf1"), ]; for &(s, ref h) in tests.iter() { let data = s.as_bytes(); m.reset(); m.update(data); let hh = m.digest().to_string(); assert_eq!(hh.len(), h.len()); assert_eq!(hh, *h); } } #[test] fn test_shortcuts() { let s = Sha1::from("The quick brown fox jumps over the lazy dog"); assert_eq!(s.digest().to_string(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"); let s = Sha1::from(&b"The quick brown fox jumps over the lazy dog"[..]); assert_eq!(s.digest().to_string(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"); #[cfg(feature="std")] { let s = Sha1::from("The quick brown fox jumps over the lazy dog"); assert_eq!(s.hexdigest(), "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"); } } #[test] fn test_multiple_updates() { let mut m = Sha1::new(); m.reset(); m.update("The quick brown ".as_bytes()); m.update("fox jumps over ".as_bytes()); m.update("the lazy dog".as_bytes()); let hh = m.digest().to_string(); let h = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"; assert_eq!(hh.len(), h.len()); assert_eq!(hh, &*h); } #[test] fn test_sha1_loop() { let mut m = Sha1::new(); let s = "The quick brown fox jumps over the lazy dog."; let n = 1000u64; for _ in 0..3 { m.reset(); for _ in 0..n { m.update(s.as_bytes()); } assert_eq!(m.digest().to_string(), "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2"); } } #[test] fn spray_and_pray() { use self::rand::Rng; let mut rng = rand::thread_rng(); let mut m = Sha1::new(); let mut bytes = [0; 512]; for _ in 0..20 { let ty = openssl::hash::MessageDigest::sha1(); let mut r = openssl::hash::Hasher::new(ty).unwrap(); m.reset(); for _ in 0..50 { let len = rng.gen::() % bytes.len(); rng.fill_bytes(&mut bytes[..len]); m.update(&bytes[..len]); r.update(&bytes[..len]).unwrap(); } assert_eq!(r.finish().unwrap().as_ref(), &m.digest().bytes()); } } #[test] #[cfg(feature="std")] fn test_parse() { use Digest; use std::error::Error; let y: Digest = "2ef7bde608ce5404e97d5f042f95f89f1c232871".parse().unwrap(); assert_eq!(y.to_string(), "2ef7bde608ce5404e97d5f042f95f89f1c232871"); assert!("asdfasdf".parse::().is_err()); assert_eq!("asdfasdf".parse::() .map_err(|x| x.description().to_string()).unwrap_err(), "not a valid sha1 hash"); } } #[cfg_attr(rustfmt, rustfmt_skip)] #[cfg(all(test, feature="serde"))] mod serde_tests { extern crate std; extern crate serde_json; use self::std::prelude::v1::*; use {Sha1, Digest}; #[test] fn test_to_json() { let mut s = Sha1::new(); s.update(b"Hello World!"); let x = s.digest(); let y = serde_json::to_vec(&x).unwrap(); assert_eq!(y, &b"\"2ef7bde608ce5404e97d5f042f95f89f1c232871\""[..]); } #[test] fn test_from_json() { let y: Digest = serde_json::from_str("\"2ef7bde608ce5404e97d5f042f95f89f1c232871\"").unwrap(); assert_eq!(y.to_string(), "2ef7bde608ce5404e97d5f042f95f89f1c232871"); } } sha1-0.6.0/src/simd.rs01006440000765000002400000007740132225134470012674 0ustar0000000000000000// Copyright (c) 2006-2009 Graydon Hoare // Copyright (c) 2009-2013 Mozilla Foundation // Permission is hereby granted, free of charge, to any // person obtaining a copy of this software and associated // documentation files (the "Software"), to deal in the // Software without restriction, including without // limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following // conditions: // The above copyright notice and this permission notice // shall be included in all copies or substantial portions // of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. pub use self::fake::*; pub trait SimdExt { fn simd_eq(self, rhs: Self) -> Self; } impl SimdExt for fake::u32x4 { fn simd_eq(self, rhs: Self) -> Self { if self == rhs { fake::u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff) } else { fake::u32x4(0, 0, 0, 0) } } } mod fake { use core::ops::{Add, BitAnd, BitOr, BitXor, Shl, Shr, Sub}; #[derive(Clone, Copy, PartialEq, Eq)] #[allow(non_camel_case_types)] pub struct u32x4(pub u32, pub u32, pub u32, pub u32); impl Add for u32x4 { type Output = u32x4; fn add(self, rhs: u32x4) -> u32x4 { u32x4( self.0.wrapping_add(rhs.0), self.1.wrapping_add(rhs.1), self.2.wrapping_add(rhs.2), self.3.wrapping_add(rhs.3)) } } impl Sub for u32x4 { type Output = u32x4; fn sub(self, rhs: u32x4) -> u32x4 { u32x4( self.0.wrapping_sub(rhs.0), self.1.wrapping_sub(rhs.1), self.2.wrapping_sub(rhs.2), self.3.wrapping_sub(rhs.3)) } } impl BitAnd for u32x4 { type Output = u32x4; fn bitand(self, rhs: u32x4) -> u32x4 { u32x4(self.0 & rhs.0, self.1 & rhs.1, self.2 & rhs.2, self.3 & rhs.3) } } impl BitOr for u32x4 { type Output = u32x4; fn bitor(self, rhs: u32x4) -> u32x4 { u32x4(self.0 | rhs.0, self.1 | rhs.1, self.2 | rhs.2, self.3 | rhs.3) } } impl BitXor for u32x4 { type Output = u32x4; fn bitxor(self, rhs: u32x4) -> u32x4 { u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3) } } impl Shl for u32x4 { type Output = u32x4; fn shl(self, amt: usize) -> u32x4 { u32x4(self.0 << amt, self.1 << amt, self.2 << amt, self.3 << amt) } } impl Shl for u32x4 { type Output = u32x4; fn shl(self, rhs: u32x4) -> u32x4 { u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3) } } impl Shr for u32x4 { type Output = u32x4; fn shr(self, amt: usize) -> u32x4 { u32x4(self.0 >> amt, self.1 >> amt, self.2 >> amt, self.3 >> amt) } } impl Shr for u32x4 { type Output = u32x4; fn shr(self, rhs: u32x4) -> u32x4 { u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3) } } #[derive(Clone, Copy)] #[allow(non_camel_case_types)] pub struct u64x2(pub u64, pub u64); impl Add for u64x2 { type Output = u64x2; fn add(self, rhs: u64x2) -> u64x2 { u64x2(self.0.wrapping_add(rhs.0), self.1.wrapping_add(rhs.1)) } } } sha1-0.6.0/upload-docs.sh01007550000765000002400000000777127414513650013364 0ustar0000000000000000#!/bin/bash # Make a new repo for the gh-pages branch rm -rf .gh-pages mkdir .gh-pages cd .gh-pages git init # Copy over the documentation cp -r ../target/doc/* . cat < index.html sha1 EOF # Add, commit and push files git add -f --all . git commit -m "Built documentation" git checkout -b gh-pages git remote add origin git@github.com:mitsuhiko/rust-sha1.git git push -qf origin gh-pages # Cleanup cd .. rm -rf .gh-pages