hsieh_hash/
lib.rs

1// The "SuperFastHash" byte sequence hash function
2// Copyright (C) 2003  Paul Hsieh
3// Copyright (C) 2019  Xiphoseer
4//
5// This library is free software; you can redistribute it and/or
6// modify it under the terms of the GNU Lesser General Public
7// License as published by the Free Software Foundation; either
8// version 2.1 of the License, or (at your option) any later version.
9//
10// This library is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13// Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public
16// License along with this library; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
19//! This crate contains the `Hsieh Hash` or `SuperFastHash` function
20//! created by Paul Hsieh and presented at <http://www.azillionmonkeys.com/qed/hash.html>
21//!
22//! ```rust
23//! use hsieh_hash::digest;
24//!
25//! let hash = digest("Hello World!".as_bytes());
26//! assert_eq!(hash, 1774740540);
27//! ```
28//!
29//! The hash value is initialized with the lenght of the input, so
30//! the algorithm cannot be used incrementally.
31
32use core::num::Wrapping;
33
34/// Calculate the Hash of a byte slice
35pub fn digest(mut data: &[u8]) -> u32 {
36    let len: u32 = data.len() as u32;
37    let mut hash: Wrapping<u32> = Wrapping(len);
38
39    if len == 0 {
40        return 0;
41    }
42
43    let remainder = len & 3;
44    let block_count = len >> 2;
45
46    /* Main loop */
47    for _i in 0..block_count {
48        hash += Wrapping(u16::from_le_bytes([data[0], data[1]]) as u32);
49        let temp = Wrapping(u16::from_le_bytes([data[2], data[3]]) as u32) << 11 ^ hash;
50        hash = hash << 16 ^ temp;
51        data = &data[4..];
52        hash += hash >> 11;
53    }
54
55    /* Handle end cases */
56    match remainder {
57        0 => {
58            // Do nothing
59        }
60        1 => {
61            hash += Wrapping(data[0] as u32);
62            hash ^= hash << 10;
63            hash += hash >> 1;
64        },
65        2 => {
66            hash += Wrapping(u16::from_le_bytes([data[0], data[1]]) as u32);
67            hash ^= hash << 11;
68            hash += hash >> 17;
69        },
70        3 => {
71            hash += Wrapping(u16::from_le_bytes([data[0], data[1]]) as u32);
72            hash ^= hash << 16;
73            hash ^= Wrapping(data[2] as u32) << 18;
74            hash += hash >> 11;
75        },
76        _ => {
77            panic!("Please investigate");
78        }
79    }
80
81    /* Force "avalanching" of final 127 bits */
82    hash ^= hash << 3;
83    hash += hash >> 5;
84    hash ^= hash << 4;
85    hash += hash >> 17;
86    hash ^= hash << 25;
87    hash += hash >> 6;
88
89    return hash.0;
90}
91
92#[cfg(test)]
93mod hiesh_tests {
94    use super::digest;
95
96    #[test]
97    fn test_digest() {
98        assert_eq!(digest("Hello World!".as_bytes()), 1774740540);
99        assert_eq!(digest("Hsieh Hash".as_bytes()), 1552477933);
100        assert_eq!(digest("SuperFastHash".as_bytes()), 2245601745);
101        assert_eq!(digest("pirateDay".as_bytes()), 2774317235);
102    }
103}