sha1_smol-1.0.0/.cargo_vcs_info.json0000644000000001360000000000100127200ustar { "git": { "sha1": "73d6f6ad063113845688e6b9226d3798186606ed" }, "path_in_vcs": "" }sha1_smol-1.0.0/.github/FUNDING.yml000064400000000000000000000000240072674642500147110ustar 00000000000000github: [mitsuhiko] sha1_smol-1.0.0/.github/workflows/clippy.yml000064400000000000000000000005170072674642500171630ustar 00000000000000name: Clippy on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal components: clippy, rustfmt override: true - name: Run clippy run: cargo clippy sha1_smol-1.0.0/.github/workflows/rustfmt.yml000064400000000000000000000005260072674642500173670ustar 00000000000000name: Rustfmt on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal components: clippy, rustfmt override: true - name: Run rustfmt run: cargo fmt --check sha1_smol-1.0.0/.github/workflows/tests.yml000064400000000000000000000011440072674642500170220ustar 00000000000000name: Tests on: [push] jobs: test-latest: name: Test on Latest runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal override: true - name: Test run: cargo test build-stable: name: Build on 1.31.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: toolchain: 1.31.0 profile: minimal override: true - name: Build run: cargo check sha1_smol-1.0.0/.gitignore000064400000000000000000000000240072674642500135240ustar 00000000000000/target /Cargo.lock sha1_smol-1.0.0/Cargo.toml0000644000000017670000000000100107310ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "sha1_smol" version = "1.0.0" authors = ["Armin Ronacher "] description = "Minimal dependency free implementation of SHA1 for Rust." keywords = ["sha1"] license = "BSD-3-Clause" repository = "https://github.com/mitsuhiko/sha1-smol" [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_smol-1.0.0/Cargo.toml.orig000064400000000000000000000007560072674642500144370ustar 00000000000000[package] name = "sha1_smol" version = "1.0.0" authors = ["Armin Ronacher "] keywords = ["sha1"] description = "Minimal dependency free implementation of SHA1 for Rust." license = "BSD-3-Clause" repository = "https://github.com/mitsuhiko/sha1-smol" edition = "2018" [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_smol-1.0.0/LICENSE000064400000000000000000000027660072674642500125600ustar 00000000000000Copyright (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_smol-1.0.0/Makefile000064400000000000000000000003460072674642500132030ustar 00000000000000build: @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 .PHONY: build test docs sha1_smol-1.0.0/README.md000064400000000000000000000031650072674642500130240ustar 00000000000000# sha1-smol [![Build Status](https://github.com/mitsuhiko/sha1-smol/workflows/Tests/badge.svg?branch=master)](https://github.com/mitsuhiko/sha1-smol/actions?query=workflow%3ATests) [![Crates.io](https://img.shields.io/crates/d/sha1-smol.svg)](https://crates.io/crates/sha1-smol) [![License](https://img.shields.io/github/license/mitsuhiko/sha1-smol)](https://github.com/mitsuhiko/sha1-smol/blob/master/LICENSE) [![rustc 1.31.0](https://img.shields.io/badge/rust-1.31%2B-orange.svg)](https://img.shields.io/badge/rust-1.31%2B-orange.svg) [![Documentation](https://docs.rs/sha1-smol/badge.svg)](https://docs.rs/sha1-smol) Minimal and dependency free implementation of SHA1 for Rust. SHA1 is not exactly a good choice for crypto hashes these days but unfortunately SHA1 continues to be needed for a handful of situations due to legacy functionality. If you have the need for a SHA1 implementation that does not pull in large dependency chains you might want to consider this crate. In all other cases use the new [`sha1`](https://crates.io/crates/sha1) crate by the RustCrypto project instead. ## sha1 crate This crate used to be published as `sha1` but in recent years a large ecosystem of hash libraries was built around [`RustCrypto`](https://github.com/RustCrypto) so the crate name was given to that project instead. Versions newer than `0.6` of `sha1`. This is largely based on the hash code in crypto-rs by Koka El Kiwi. ## License and Links - [Documentation](https://docs.rs/sha1-smol/) - [Issue Tracker](https://github.com/mitsuhiko/sha1-smol/issues) - License: [3 Clause BSD](https://github.com/mitsuhiko/sha1-smol/blob/master/LICENSE) sha1_smol-1.0.0/src/lib.rs000064400000000000000000000551100072674642500134450ustar 00000000000000//! 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. //! //! ## Example //! //! ```rust //! # fn main() { //! //! let mut m = sha1_smol::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 (requires std): //! //! ``` //! # trait X { fn hexdigest(&self) -> &'static str { "2ef7bde608ce5404e97d5f042f95f89f1c232871" }} //! # impl X for sha1_smol::Sha1 {} //! # fn main() { //! assert_eq!(sha1_smol::Sha1::from("Hello World!").hexdigest(), //! "2ef7bde608ce5404e97d5f042f95f89f1c232871"); //! # } //! ``` #![no_std] #![deny(missing_docs)] #![allow(deprecated)] #![allow(clippy::double_parens)] #![allow(clippy::identity_op)] use core::cmp; use core::fmt; use core::hash; use core::str; mod simd; use crate::simd::*; #[cfg(feature = "std")] extern crate std; /// 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] = &*(input.as_ptr() as *const [u8; 64]); 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, word) in words.iter_mut().enumerate() { let off = i * 4; *word = (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] = r#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() { r#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) } } #[rustfmt::skip] #[cfg(test)] mod tests { extern crate std; extern crate rand; extern crate openssl; use self::std::prelude::v1::*; use crate::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 crate::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"); } } #[rustfmt::skip] #[cfg(all(test, feature="serde"))] mod serde_tests { extern crate std; extern crate serde_json; use self::std::prelude::v1::*; use crate::{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_smol-1.0.0/src/simd.rs000064400000000000000000000106060072674642500136340ustar 00000000000000// 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)) } } }