sip.rs 5.8 KB
Newer Older
A
Akos Kiss 已提交
1
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9
// 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.
10 11
//
// ignore-lexer-test FIXME #15883
12

P
P1start 已提交
13
//! An implementation of SipHash 2-4.
14

15 16
use prelude::*;
use default::Default;
17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
use super::{Hasher, Writer};

/// An implementation of SipHash 2-4.
///
/// See: http://131002.net/siphash/
///
/// Consider this as a main "general-purpose" hash for all hashtables: it
/// runs at good speed (competitive with spooky and city) and permits
/// strong _keyed_ hashing. Key your hashtables from a strong RNG,
/// such as `rand::Rng`.
///
/// Although the SipHash algorithm is considered to be cryptographically
/// strong, this implementation has not been reviewed for such purposes.
/// As such, all cryptographic uses of this implementation are strongly
/// discouraged.
pub struct SipHasher {
34 35 36 37 38 39 40
    k0: u64,
    k1: u64,
    length: uint, // how many bytes we've processed
    v0: u64,      // hash state
    v1: u64,
    v2: u64,
    v3: u64,
S
Sean McArthur 已提交
41
    tail: u64, // unprocessed bytes le
42
    ntail: uint,  // how many bytes in tail are valid
43 44
}

45 46 47 48
// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.

49
macro_rules! u8to64_le {
50 51
    ($buf:expr, $i:expr) =>
    ($buf[0+$i] as u64 |
52 53 54 55 56 57 58
     ($buf[1+$i] as u64) << 8 |
     ($buf[2+$i] as u64) << 16 |
     ($buf[3+$i] as u64) << 24 |
     ($buf[4+$i] as u64) << 32 |
     ($buf[5+$i] as u64) << 40 |
     ($buf[6+$i] as u64) << 48 |
     ($buf[7+$i] as u64) << 56);
S
Sean McArthur 已提交
59 60 61 62 63
    ($buf:expr, $i:expr, $len:expr) =>
    ({
        let mut t = 0;
        let mut out = 0u64;
        while t < $len {
64
            out |= ($buf[t+$i] as u64) << t*8;
S
Sean McArthur 已提交
65 66 67 68
            t += 1;
        }
        out
    });
69
}
70

71
macro_rules! rotl {
72 73
    ($x:expr, $b:expr) =>
    (($x << $b) | ($x >> (64 - $b)))
74
}
75

76
macro_rules! compress {
77 78 79 80 81 82 83 84 85
    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
    ({
        $v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
        $v0 = rotl!($v0, 32);
        $v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
        $v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
        $v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
        $v2 = rotl!($v2, 32);
    })
86
}
87

88 89
impl SipHasher {
    /// Creates a new `SipHasher` with the two initial keys set to 0.
90
    #[inline]
91 92
    pub fn new() -> SipHasher {
        SipHasher::new_with_keys(0, 0)
93 94
    }

95
    /// Creates a `SipHasher` that is keyed off the provided keys.
96
    #[inline]
97 98
    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
        let mut state = SipHasher {
99 100 101 102 103 104 105
            k0: key0,
            k1: key1,
            length: 0,
            v0: 0,
            v1: 0,
            v2: 0,
            v3: 0,
S
Sean McArthur 已提交
106
            tail: 0,
107 108 109 110 111 112
            ntail: 0,
        };
        state.reset();
        state
    }

P
P1start 已提交
113
    /// Returns the computed hash.
114 115
    #[unstable(feature = "hash")]
    #[deprecated(since = "1.0.0", reason = "renamed to finish")]
116
    pub fn result(&self) -> u64 { self.finish() }
117
}
118

119
impl Writer for SipHasher {
120
    #[inline]
121
    fn write(&mut self, msg: &[u8]) {
122 123
        let length = msg.len();
        self.length += length;
124

125
        let mut needed = 0;
126

127 128
        if self.ntail != 0 {
            needed = 8 - self.ntail;
129
            if length < needed {
S
Sean McArthur 已提交
130
                self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
131
                self.ntail += length;
132
                return
133 134
            }

S
Sean McArthur 已提交
135
            let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;
136

137
            self.v3 ^= m;
P
Paul Stansifer 已提交
138 139
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
140
            self.v0 ^= m;
141

142
            self.ntail = 0;
143 144
        }

145
        // Buffered tail is now flushed, process new input.
146 147 148 149 150 151
        let len = length - needed;
        let end = len & (!0x7);
        let left = len & 0x7;

        let mut i = needed;
        while i < end {
P
Paul Stansifer 已提交
152
            let mi = u8to64_le!(msg, i);
153

154
            self.v3 ^= mi;
P
Paul Stansifer 已提交
155 156
            compress!(self.v0, self.v1, self.v2, self.v3);
            compress!(self.v0, self.v1, self.v2, self.v3);
157
            self.v0 ^= mi;
158 159 160 161

            i += 8;
        }

S
Sean McArthur 已提交
162
        self.tail = u8to64_le!(msg, i, left);
163
        self.ntail = left;
S
Sean McArthur 已提交
164
    }
165 166
}

167 168
impl Hasher for SipHasher {
    type Output = u64;
169

170 171 172 173 174 175 176
    fn reset(&mut self) {
        self.length = 0;
        self.v0 = self.k0 ^ 0x736f6d6570736575;
        self.v1 = self.k1 ^ 0x646f72616e646f6d;
        self.v2 = self.k0 ^ 0x6c7967656e657261;
        self.v3 = self.k1 ^ 0x7465646279746573;
        self.ntail = 0;
177 178
    }

179 180 181 182 183
    fn finish(&self) -> u64 {
        let mut v0 = self.v0;
        let mut v1 = self.v1;
        let mut v2 = self.v2;
        let mut v3 = self.v3;
184

185
        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
186

187 188 189 190 191 192 193 194 195 196 197 198
        v3 ^= b;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        v0 ^= b;

        v2 ^= 0xff;
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);
        compress!(v0, v1, v2, v3);

        v0 ^ v1 ^ v2 ^ v3
199
    }
200
}
201

202
impl Clone for SipHasher {
203
    #[inline]
204 205 206 207 208 209 210 211 212 213 214 215
    fn clone(&self) -> SipHasher {
        SipHasher {
            k0: self.k0,
            k1: self.k1,
            length: self.length,
            v0: self.v0,
            v1: self.v1,
            v2: self.v2,
            v3: self.v3,
            tail: self.tail,
            ntail: self.ntail,
        }
216
    }
217 218
}

219 220 221 222 223
impl Default for SipHasher {
    fn default() -> SipHasher {
        SipHasher::new()
    }
}