Meow Hash: A high-speed non-cryptographic hash function
mollyrocket.com
mollyrocket.com
I do want to comment for the wider audience why the details of this construction does not lend itself to small keys, and how you would fix that. I have an (unpublished, I'm lazy) AES-based hash function that is very fast for both bulk hashing and small keys, which required a mostly performance neutral (likely fits in an unused ALU execution port) tweak to the bulk hashing loop.
Large key performance is entirely in the bulk loop algorithm (an AES round in this case) and small key performance is entirely in the mixer/finalizer algorithm. If you have a very wide bulk loops with no mixing of the individual lanes then it usually requires a deep mixing stage that makes small keys very expensive since that is a fixed overhead. The question then becomes, how do you cheaply "bank" dispersal of bits across lanes in the bulk loop to shorten the mixing stage without creating an operation dependency between lanes that will massively reduce throughput.
As an important observation, vectorizing the AES lanes makes it difficult to disperse bits because there are no good, cheap operations that move bits between lanes. However, the CPU will happily run multiple AES operations and other 128-bit operations concurrently across ALU ports if they are in independent registers. This allows you to trivially create a "mixing" lane that solely exists to aid bit dispersal because you no longer are trying to do sideways operations on a vector. So what does a mixing lane look like that doesn't create dependencies on your hashing lanes? It is so simple it is embarrassing: XOR the input data lanes. The mixing lane is worthless as a hash but it only exists to represent all the bits from all the lanes.
At the mixing stage, you simply fold the mixing lane into each of the hashing lanes by running it through a round of AES -- one concurrent operation. This allows you to avoid the deep mixing stage altogether, which means small keys can be hashed very quickly since almost all of the computation is in the finalizer. Using this technique, I've been able to hash small keys in <30 cycles with concurrent AES lanes.
If the length is not part of the initialization vector, then the padding vector for partial blocks should vary as a function of partial data length. Otherwise it is trivial to create collisions by having partial blocks of different sizes that mimic the padding vector. Fixing this can be as easy as using _mm_set1_epi8(partial_length) as your padding vector.
Although Meow Hash is described as non-cryptographic, so the described attack is likely not applicable
Any chance you're thinking about releasing the program for generating new (good) Metrohash constants + shifts?
This sounds deeply fascinating, but I'm way out of my depth. Can you suggest any reading that would help me appreciate the "architecture" of hash functions?
This is an important passage that could be explained in more detail. I can look up a list of non-cryptographic hash functions, nine of which support 128-bit output:
https://en.wikipedia.org/wiki/List_of_hash_functions#Non-cry...
Given that the claim is that Meow Hash is fast, where's the benchmarking to prove it's faster than the alternatives?
For comparison, xxhash is the closest thing to this that I'm aware of and clocks in at around 1.7 bytes per cycle using the official implementation.
xxHash is also very simple, and can be written easily in high or low level languages, which I like. Someone even implemented it in C++ templates I believe. I don't know how Meow Hash is but I imagine the default implementation heavily exploits AMD64 CPUs and based on the article probably makes use of AES acceleration.
Basically, if you do this, at least be sure you're not bottlenecked on I/O already :)
(Better than xxhash on x86, worse than Meowhash -- assuming the bytes/cycle numbers can be compared apples-to-apples, which is a big if.)
Of course, if you are running a lot of hashes in parallel, I bet things get more interesting. (Example: would AES-NI instructions scale in parallel as fast as ordinary bitwise/vector instructions?)
Short version, it's ~2x as fast as anything else on my machine for data > 4k, maybe down to 1k, all the way up to > cache (where various other algorithms also max out memory bandwidth). Other non-cryptographic hashes (for comparison) on my local machine: xxHash64 -> ~13G/s, Metrohash128 -> ~13G/s, Metrohash128_crc -> ~18G/s, t1ha_crc -> ~17.5G/s, etc., but Meow doesn't break the 1G/s barrier until 64-96 bytes (the others mentioned reach that speed at 8 bytes).
So yeah, faster for longer keys due to the fast aes mixing + parallel pipeline usage, but slower for shorter keys due to the final mixing dependency at the end.
Using a hacked-up version of Smhasher for wider range of hashing sizes (cache on this CPU is 20 megs):
--- Testing Meow1_64 "parallel aes internals"
[[[ Speed Tests ]]]
Bulk speed test - 67108864-byte keys
Average - 4.556 bytes/cycle - 14337.09 MiB/sec @ 3 ghz
Bulk speed test - 16777216-byte keys
Average - 7.882 bytes/cycle - 24805.52 MiB/sec @ 3 ghz
Bulk speed test - 4194304-byte keys
Average - 9.813 bytes/cycle - 30884.30 MiB/sec @ 3 ghz
Bulk speed test - 1048576-byte keys
Average - 9.657 bytes/cycle - 30390.48 MiB/sec @ 3 ghz
Bulk speed test - 262144-byte keys
Average - 10.642 bytes/cycle - 33490.19 MiB/sec @ 3 ghz
Bulk speed test - 65536-byte keys
Average - 11.871 bytes/cycle - 37360.76 MiB/sec @ 3 ghz
Bulk speed test - 16384-byte keys
Average - 11.336 bytes/cycle - 35675.98 MiB/sec @ 3 ghz
Bulk speed test - 4096-byte keys
Average - 8.241 bytes/cycle - 25936.55 MiB/sec @ 3 ghz
Bulk speed test - 1024-byte keys
Average - 4.056 bytes/cycle - 12765.26 MiB/sec @ 3 ghzhttps://github.com/cmuratori/meow_hash/issues/7#issuecomment...
FarmHash
CityHash
SMHasher
MetroHash
FNV1a_YT
Note that if you're just using it for a hash table, where you'll compare the full strings to resolve hash collisions, you don't actually need good randomness. FNV1A_VT is faster than most, has worse collision properties, yet provides a faster overall hash table, because the faster hash (every operation) outweighs the extra full string checks (rare).
Recently (this year) the MCUs I've asked for have hardware crc32 and sometimes even AES128 but the suits tell me to Remember the BOM, Luke, and those fancy periphs aren't available on common M0+ my hardware guy likes (NXP KE0xxx for ex). Left wondering how this one will work on a run of the mill ARM.
Meow does include implementation for smhasher, so benchmarking should be easy enough
https://github.com/cmuratori/meow_hash/blob/master/meow_smha...
I'm confused... don't you have to do at least one full string check for every table lookup on a hash table, to ensure the value you're returning is really the right key, and not just some other key that happens to collide?
In other words, if I have 32 buckets in my table and one value stored at table["hello"], and table["goodbye"] happens to hash to the same bucket, how do you know whether to return not-found for "goodbye" without a full string comparison? (Or for that matter, how do you know whether to return the stored value for "hello" without a comparison?)
GP was saying that in their experience, the less frequent extra string checks generally isn't worth the slower hashing speed of an algorithm with a better distribution.
(It's also worth noting that getting or setting elements which don't exist requires 0 string compares unless there's a collision, which might be relevant for certain workloads.)
Depending on the input, e.g. if lengths have more or less uniform distributions, full string checks might only be needed 10% of the time or so; store the string length in the bucket and you save the cache miss. Or you could store the first few bytes of the key in the bucket (but then in other cases, for example a hash table containing absolute filesystem paths, the first few bytes are always the same across keys).
SMHasher isn't a hash function? It's a test suite for hash functions.
CityHash's CRC modes are nominally 4.3-5.5 bytes/cycle.
The others are slower.
This article quotes 16 b/c for Meowhash.
-Austin, SMHasher author.
The second is that even with the intrinsics, this is (supposedly) faster. The SHA instructions only get you a few gigabytes a second (single digits). This purportedly gets tens of GB/s.
https://www.phoronix.com/scan.php?page=news_item&px=Linux-4....
https://en.wikipedia.org/wiki/Skylake_(microarchitecture) nor https://en.wikipedia.org/wiki/Kaby_Lake nor even Coffee Lake list SHA intrinsics. It starts showing up in https://en.wikipedia.org/wiki/Cascade_Lake_(microarchitectur... and Cannon Lake pages.
Mainstream support for SHA in Intel CPUs will come with Cannon Lake, or whatever the next microarchitecture revision they release ends up being.
* Yes, Cannon Lake is technically shipping as the i3-8121U, but that isn't really relevant to anyone here.
https://software.intel.com/sites/default/files/managed/c5/15...
Cannon Lake and later according to Intel.
However, I question "mainstream" since many Celeron and Pentium branded parts featured SHA-NI, and those are arguably mainstream, low-cost parts.
Also, in fairness to Phoronix, it looks like SHA-NI support may have been planned for Skylake, but didn't make it based on various posts I see online as early as 2014 and Intel's first postings about SHA-NI on Goldmont, etc. in 2013.
Do you have a source for this claim?
> Also, in fairness to Phoronix, it looks like SHA-NI support may have been planned for Skylake
Yeah, but on the other hand that article was published 4 months after the general availability of Skylake. It was possible for Larabel to verify the facts before publishing and he just didn't. Nor did he correct the mistake in any of the past three years.
Can I expect Meow Hash being faster than that on x86_64? What about on some other platforms such as common ARM chips? Which one is more collision resistant?
Also: the writer seems to be Casey Muratori, who is also the author of the Handmade Hero series! Kudos.
So, my initial assumption was wrong. I'll be trying Meow Hash and some others out!
Both are faster than xxHash on machines with AESNI and CRC intrinsics (~1.7B/cycle). The advantage of xxHash is that it is very fast on machines without these instrinsics.
Other hashes tend to be slower although I'm sure there are some other intrinsics-based hashes I don't have at the tip of my tongue.
What do AESRotate(foo,bar) and AESMerge(foo,bar) do?
[edit]
So it's a simple cyclic rotation preceded by A.Q0 = _mm512_aesdec_epi128(A.Q0, B.Q0)
From Googling, _mm512_aesdec_epi128 looks like an Intel processor built-in.
This seems like an important caveat that means it will only be used in specialized applications.
Still, it would be nice is to state that is is the zlib license, and to include the license in the repository.
I will admit that when I first saw the zlib license, I was similarly confused but it's actually a license that is about the same age as most other common licenses (and quite a large body of software is licensed under it).
But that's not really the point -- GGGP implied that the license was written from scratch ("yet-another-open-source-license") and that's obviously not true.
MeowHash is not cryptographic at all.
> Is MeowHash faster than MD5 or not?
Meowhash is advertised as 16 bytes per cycle. MD5 is around 5 cycles per byte[0] or 0.2 bytes per cycle.
Pre-existing fast non-cryptographic hashes apparently top out around 5.5 bytes per cycle (CityHashCRC256).