-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Implement the 64-bit variant of xxHash. #17656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
That post doesn't go into any in-depth cryptanalysis. Security against DoS attacks requires a lot more than just good results on statistical tests and avalanche effect resistance. |
Oh well. At least it's fast :) |
Can this replace the FNV implementation that's currently used in rustc? |
@thestinger: If used with large enough chunks (>32b), it can beat anything. With small chunks, it degrades the same way SipHash does, but I think that's inevitable with a decent hash. |
state.digest() | ||
} | ||
|
||
pub struct XXState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think the convention is XxState
This implementation has quite a bit of unsafe code. SipHash's doesn't have any. Have you checked the C implementation's speed? I think it should be faster than FNV for 8-byte or larger chunks when inlined. I've measured my implementation:
What makes you think a hash can't be fast? Xxhash has two parts at its core.
For 8 byte chunks, it does only the following: let total_len = 8;
let mut h64 = self.seed + PRIME5 + total_len;
let mut k1: u64 = source * PRIME2;
k1 = rotl64(k1, 31);
k1 *= PRIME1;
h64 ^= k1;
h64 = rotl64(h64, 27) * PRIME1 + PRIME4;
h64 ^= h64 >> 33;
h64 *= PRIME2;
h64 ^= h64 >> 29;
h64 *= PRIME3;
h64 ^= h64 >> 32;
return h64; However, the finalizer alone is responsible for avalanche properties and can be used with chunks that have exactly 8 bytes: let mut hash = source;
hash ^= hash >> 33;
hash *= PRIME2;
hash ^= hash >> 29;
hash *= PRIME3;
hash ^= hash >> 32;
return hash; |
|
||
impl XXHasher { | ||
pub fn new() -> XXHasher { #![inline] | ||
XXHasher::new_with_seed(18446744073709551557u64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where did this seed come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a large prime. This should be #[cfg(test)]
I think, but I wanted to be consistent with SipHash
which has new_with_keys(0, 0)
here.
For real uses, the seeds should be randomized, which is done with RandomSipHasher
in libstd
.
@pczarn: It's not the hash that's slow, but Rust's handling of them. |
I expressed this concern a couple of times already. I think we're taking security too far in the hashmap implementations. The majority of programming languages are using a per process seed (either for sip hash or others). Rust has a seed per hash map AND a slow overly-secure hash as the default. |
This is a better default than an insecure and fast hash. If you care about performance and not about security, you can opt in. If you don't care about performance, you should use the secure version. |
Did you guys see http://discuss.rust-lang.org/t/unstable-hash-architecture/578 ? It's something worth discussing. |
Unfortunately deleting the source repository causes bors to get stuck, @Jurily would you mind reopening? Thanks! |
fix: Allow flyimport to import primitive shadowing modules Fixes rust-lang/rust-analyzer#16371
fix: Allow flyimport to import primitive shadowing modules Fixes rust-lang/rust-analyzer#16371
Matches C in speed, but it looks like SipHash was not the only bottleneck for #11783.
Tests include the official data and the relevant ones from SipHash.