133d722a9Sopenharmony_ci// Vendored from libstd: 233d722a9Sopenharmony_ci// https://github.com/rust-lang/rust/blob/1.57.0/library/core/src/hash/sip.rs 333d722a9Sopenharmony_ci// 433d722a9Sopenharmony_ci// TODO: maybe depend on a hasher from crates.io if this becomes annoying to 533d722a9Sopenharmony_ci// maintain, or change this to a simpler one. 633d722a9Sopenharmony_ci 733d722a9Sopenharmony_ci#![cfg(not(feature = "std"))] 833d722a9Sopenharmony_ci 933d722a9Sopenharmony_ciuse core::cmp; 1033d722a9Sopenharmony_ciuse core::hash::Hasher; 1133d722a9Sopenharmony_ciuse core::mem; 1233d722a9Sopenharmony_ciuse core::ptr; 1333d722a9Sopenharmony_ci 1433d722a9Sopenharmony_ci/// An implementation of SipHash 1-3. 1533d722a9Sopenharmony_ci/// 1633d722a9Sopenharmony_ci/// This is currently the default hashing function used by standard library 1733d722a9Sopenharmony_ci/// (e.g., `collections::HashMap` uses it by default). 1833d722a9Sopenharmony_ci/// 1933d722a9Sopenharmony_ci/// See: <https://131002.net/siphash> 2033d722a9Sopenharmony_cipub struct SipHasher13 { 2133d722a9Sopenharmony_ci k0: u64, 2233d722a9Sopenharmony_ci k1: u64, 2333d722a9Sopenharmony_ci length: usize, // how many bytes we've processed 2433d722a9Sopenharmony_ci state: State, // hash State 2533d722a9Sopenharmony_ci tail: u64, // unprocessed bytes le 2633d722a9Sopenharmony_ci ntail: usize, // how many bytes in tail are valid 2733d722a9Sopenharmony_ci} 2833d722a9Sopenharmony_ci 2933d722a9Sopenharmony_ci#[derive(Clone, Copy)] 3033d722a9Sopenharmony_ci#[repr(C)] 3133d722a9Sopenharmony_cistruct State { 3233d722a9Sopenharmony_ci // v0, v2 and v1, v3 show up in pairs in the algorithm, 3333d722a9Sopenharmony_ci // and simd implementations of SipHash will use vectors 3433d722a9Sopenharmony_ci // of v02 and v13. By placing them in this order in the struct, 3533d722a9Sopenharmony_ci // the compiler can pick up on just a few simd optimizations by itself. 3633d722a9Sopenharmony_ci v0: u64, 3733d722a9Sopenharmony_ci v2: u64, 3833d722a9Sopenharmony_ci v1: u64, 3933d722a9Sopenharmony_ci v3: u64, 4033d722a9Sopenharmony_ci} 4133d722a9Sopenharmony_ci 4233d722a9Sopenharmony_cimacro_rules! compress { 4333d722a9Sopenharmony_ci ($state:expr) => { 4433d722a9Sopenharmony_ci compress!($state.v0, $state.v1, $state.v2, $state.v3) 4533d722a9Sopenharmony_ci }; 4633d722a9Sopenharmony_ci ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => { 4733d722a9Sopenharmony_ci $v0 = $v0.wrapping_add($v1); 4833d722a9Sopenharmony_ci $v1 = $v1.rotate_left(13); 4933d722a9Sopenharmony_ci $v1 ^= $v0; 5033d722a9Sopenharmony_ci $v0 = $v0.rotate_left(32); 5133d722a9Sopenharmony_ci $v2 = $v2.wrapping_add($v3); 5233d722a9Sopenharmony_ci $v3 = $v3.rotate_left(16); 5333d722a9Sopenharmony_ci $v3 ^= $v2; 5433d722a9Sopenharmony_ci $v0 = $v0.wrapping_add($v3); 5533d722a9Sopenharmony_ci $v3 = $v3.rotate_left(21); 5633d722a9Sopenharmony_ci $v3 ^= $v0; 5733d722a9Sopenharmony_ci $v2 = $v2.wrapping_add($v1); 5833d722a9Sopenharmony_ci $v1 = $v1.rotate_left(17); 5933d722a9Sopenharmony_ci $v1 ^= $v2; 6033d722a9Sopenharmony_ci $v2 = $v2.rotate_left(32); 6133d722a9Sopenharmony_ci }; 6233d722a9Sopenharmony_ci} 6333d722a9Sopenharmony_ci 6433d722a9Sopenharmony_ci/// Loads an integer of the desired type from a byte stream, in LE order. Uses 6533d722a9Sopenharmony_ci/// `copy_nonoverlapping` to let the compiler generate the most efficient way 6633d722a9Sopenharmony_ci/// to load it from a possibly unaligned address. 6733d722a9Sopenharmony_ci/// 6833d722a9Sopenharmony_ci/// Unsafe because: unchecked indexing at i..i+size_of(int_ty) 6933d722a9Sopenharmony_cimacro_rules! load_int_le { 7033d722a9Sopenharmony_ci ($buf:expr, $i:expr, $int_ty:ident) => {{ 7133d722a9Sopenharmony_ci debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len()); 7233d722a9Sopenharmony_ci let mut data = 0 as $int_ty; 7333d722a9Sopenharmony_ci ptr::copy_nonoverlapping( 7433d722a9Sopenharmony_ci $buf.as_ptr().add($i), 7533d722a9Sopenharmony_ci &mut data as *mut _ as *mut u8, 7633d722a9Sopenharmony_ci mem::size_of::<$int_ty>(), 7733d722a9Sopenharmony_ci ); 7833d722a9Sopenharmony_ci data.to_le() 7933d722a9Sopenharmony_ci }}; 8033d722a9Sopenharmony_ci} 8133d722a9Sopenharmony_ci 8233d722a9Sopenharmony_ci/// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the 8333d722a9Sopenharmony_ci/// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed 8433d722a9Sopenharmony_ci/// sizes and avoid calling `memcpy`, which is good for speed. 8533d722a9Sopenharmony_ci/// 8633d722a9Sopenharmony_ci/// Unsafe because: unchecked indexing at start..start+len 8733d722a9Sopenharmony_ciunsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { 8833d722a9Sopenharmony_ci debug_assert!(len < 8); 8933d722a9Sopenharmony_ci let mut i = 0; // current byte index (from LSB) in the output u64 9033d722a9Sopenharmony_ci let mut out = 0; 9133d722a9Sopenharmony_ci if i + 3 < len { 9233d722a9Sopenharmony_ci // SAFETY: `i` cannot be greater than `len`, and the caller must guarantee 9333d722a9Sopenharmony_ci // that the index start..start+len is in bounds. 9433d722a9Sopenharmony_ci out = unsafe { load_int_le!(buf, start + i, u32) } as u64; 9533d722a9Sopenharmony_ci i += 4; 9633d722a9Sopenharmony_ci } 9733d722a9Sopenharmony_ci if i + 1 < len { 9833d722a9Sopenharmony_ci // SAFETY: same as above. 9933d722a9Sopenharmony_ci out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << (i * 8); 10033d722a9Sopenharmony_ci i += 2 10133d722a9Sopenharmony_ci } 10233d722a9Sopenharmony_ci if i < len { 10333d722a9Sopenharmony_ci // SAFETY: same as above. 10433d722a9Sopenharmony_ci out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8); 10533d722a9Sopenharmony_ci i += 1; 10633d722a9Sopenharmony_ci } 10733d722a9Sopenharmony_ci debug_assert_eq!(i, len); 10833d722a9Sopenharmony_ci out 10933d722a9Sopenharmony_ci} 11033d722a9Sopenharmony_ci 11133d722a9Sopenharmony_ciimpl SipHasher13 { 11233d722a9Sopenharmony_ci /// Creates a new `SipHasher13` with the two initial keys set to 0. 11333d722a9Sopenharmony_ci pub fn new() -> Self { 11433d722a9Sopenharmony_ci Self::new_with_keys(0, 0) 11533d722a9Sopenharmony_ci } 11633d722a9Sopenharmony_ci 11733d722a9Sopenharmony_ci /// Creates a `SipHasher13` that is keyed off the provided keys. 11833d722a9Sopenharmony_ci fn new_with_keys(key0: u64, key1: u64) -> Self { 11933d722a9Sopenharmony_ci let mut state = SipHasher13 { 12033d722a9Sopenharmony_ci k0: key0, 12133d722a9Sopenharmony_ci k1: key1, 12233d722a9Sopenharmony_ci length: 0, 12333d722a9Sopenharmony_ci state: State { 12433d722a9Sopenharmony_ci v0: 0, 12533d722a9Sopenharmony_ci v1: 0, 12633d722a9Sopenharmony_ci v2: 0, 12733d722a9Sopenharmony_ci v3: 0, 12833d722a9Sopenharmony_ci }, 12933d722a9Sopenharmony_ci tail: 0, 13033d722a9Sopenharmony_ci ntail: 0, 13133d722a9Sopenharmony_ci }; 13233d722a9Sopenharmony_ci state.reset(); 13333d722a9Sopenharmony_ci state 13433d722a9Sopenharmony_ci } 13533d722a9Sopenharmony_ci 13633d722a9Sopenharmony_ci fn reset(&mut self) { 13733d722a9Sopenharmony_ci self.length = 0; 13833d722a9Sopenharmony_ci self.state.v0 = self.k0 ^ 0x736f6d6570736575; 13933d722a9Sopenharmony_ci self.state.v1 = self.k1 ^ 0x646f72616e646f6d; 14033d722a9Sopenharmony_ci self.state.v2 = self.k0 ^ 0x6c7967656e657261; 14133d722a9Sopenharmony_ci self.state.v3 = self.k1 ^ 0x7465646279746573; 14233d722a9Sopenharmony_ci self.ntail = 0; 14333d722a9Sopenharmony_ci } 14433d722a9Sopenharmony_ci} 14533d722a9Sopenharmony_ci 14633d722a9Sopenharmony_ciimpl Hasher for SipHasher13 { 14733d722a9Sopenharmony_ci // Note: no integer hashing methods (`write_u*`, `write_i*`) are defined 14833d722a9Sopenharmony_ci // for this type. We could add them, copy the `short_write` implementation 14933d722a9Sopenharmony_ci // in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*` 15033d722a9Sopenharmony_ci // methods to `SipHasher`, `SipHasher13`, and `DefaultHasher`. This would 15133d722a9Sopenharmony_ci // greatly speed up integer hashing by those hashers, at the cost of 15233d722a9Sopenharmony_ci // slightly slowing down compile speeds on some benchmarks. See #69152 for 15333d722a9Sopenharmony_ci // details. 15433d722a9Sopenharmony_ci fn write(&mut self, msg: &[u8]) { 15533d722a9Sopenharmony_ci let length = msg.len(); 15633d722a9Sopenharmony_ci self.length += length; 15733d722a9Sopenharmony_ci 15833d722a9Sopenharmony_ci let mut needed = 0; 15933d722a9Sopenharmony_ci 16033d722a9Sopenharmony_ci if self.ntail != 0 { 16133d722a9Sopenharmony_ci needed = 8 - self.ntail; 16233d722a9Sopenharmony_ci // SAFETY: `cmp::min(length, needed)` is guaranteed to not be over `length` 16333d722a9Sopenharmony_ci self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); 16433d722a9Sopenharmony_ci if length < needed { 16533d722a9Sopenharmony_ci self.ntail += length; 16633d722a9Sopenharmony_ci return; 16733d722a9Sopenharmony_ci } else { 16833d722a9Sopenharmony_ci self.state.v3 ^= self.tail; 16933d722a9Sopenharmony_ci Sip13Rounds::c_rounds(&mut self.state); 17033d722a9Sopenharmony_ci self.state.v0 ^= self.tail; 17133d722a9Sopenharmony_ci self.ntail = 0; 17233d722a9Sopenharmony_ci } 17333d722a9Sopenharmony_ci } 17433d722a9Sopenharmony_ci 17533d722a9Sopenharmony_ci // Buffered tail is now flushed, process new input. 17633d722a9Sopenharmony_ci let len = length - needed; 17733d722a9Sopenharmony_ci let left = len & 0x7; // len % 8 17833d722a9Sopenharmony_ci 17933d722a9Sopenharmony_ci let mut i = needed; 18033d722a9Sopenharmony_ci while i < len - left { 18133d722a9Sopenharmony_ci // SAFETY: because `len - left` is the biggest multiple of 8 under 18233d722a9Sopenharmony_ci // `len`, and because `i` starts at `needed` where `len` is `length - needed`, 18333d722a9Sopenharmony_ci // `i + 8` is guaranteed to be less than or equal to `length`. 18433d722a9Sopenharmony_ci let mi = unsafe { load_int_le!(msg, i, u64) }; 18533d722a9Sopenharmony_ci 18633d722a9Sopenharmony_ci self.state.v3 ^= mi; 18733d722a9Sopenharmony_ci Sip13Rounds::c_rounds(&mut self.state); 18833d722a9Sopenharmony_ci self.state.v0 ^= mi; 18933d722a9Sopenharmony_ci 19033d722a9Sopenharmony_ci i += 8; 19133d722a9Sopenharmony_ci } 19233d722a9Sopenharmony_ci 19333d722a9Sopenharmony_ci // SAFETY: `i` is now `needed + len.div_euclid(8) * 8`, 19433d722a9Sopenharmony_ci // so `i + left` = `needed + len` = `length`, which is by 19533d722a9Sopenharmony_ci // definition equal to `msg.len()`. 19633d722a9Sopenharmony_ci self.tail = unsafe { u8to64_le(msg, i, left) }; 19733d722a9Sopenharmony_ci self.ntail = left; 19833d722a9Sopenharmony_ci } 19933d722a9Sopenharmony_ci 20033d722a9Sopenharmony_ci fn finish(&self) -> u64 { 20133d722a9Sopenharmony_ci let mut state = self.state; 20233d722a9Sopenharmony_ci 20333d722a9Sopenharmony_ci let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; 20433d722a9Sopenharmony_ci 20533d722a9Sopenharmony_ci state.v3 ^= b; 20633d722a9Sopenharmony_ci Sip13Rounds::c_rounds(&mut state); 20733d722a9Sopenharmony_ci state.v0 ^= b; 20833d722a9Sopenharmony_ci 20933d722a9Sopenharmony_ci state.v2 ^= 0xff; 21033d722a9Sopenharmony_ci Sip13Rounds::d_rounds(&mut state); 21133d722a9Sopenharmony_ci 21233d722a9Sopenharmony_ci state.v0 ^ state.v1 ^ state.v2 ^ state.v3 21333d722a9Sopenharmony_ci } 21433d722a9Sopenharmony_ci} 21533d722a9Sopenharmony_ci 21633d722a9Sopenharmony_cistruct Sip13Rounds; 21733d722a9Sopenharmony_ci 21833d722a9Sopenharmony_ciimpl Sip13Rounds { 21933d722a9Sopenharmony_ci fn c_rounds(state: &mut State) { 22033d722a9Sopenharmony_ci compress!(state); 22133d722a9Sopenharmony_ci } 22233d722a9Sopenharmony_ci 22333d722a9Sopenharmony_ci fn d_rounds(state: &mut State) { 22433d722a9Sopenharmony_ci compress!(state); 22533d722a9Sopenharmony_ci compress!(state); 22633d722a9Sopenharmony_ci compress!(state); 22733d722a9Sopenharmony_ci } 22833d722a9Sopenharmony_ci} 229