HighwayHash: Strong hashing at 0.3 clock cycles per byte
github.com
github.com
nate@skylake:~/git/highwayhash$ bazel build :all -c opt --copt=-mavx2
.....
ERROR: /home/nate/git/highwayhash/BUILD:3:1: unexpected
keyword 'default_hdrs_check' in call to package(*,
default_deprecation = ?, distribs = ?, licenses = ?,
default_testonly = ?, default_visibility = ?, features = ?,
default_compatible_with = ?, default_restricted_to = ?).
ERROR: no such package '': Package '' contains errors. CXXFLAGS := -g -std=c++11 -Wall -O3 -march=native -Wno-sign-compare
OBJS := highway_tree_hash.o \
scalar_highway_tree_hash.o \
scalar_sip_tree_hash.o \
sip_hash.o \
sip_tree_hash.o
MAIN := sip_hash_main
all: $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) $(MAIN).cc -o $(MAIN)
clean:
rm -f $(OBJS) $(MAIN)
Then I commented out two lines in "sip_hash_main.cc": // #include "smhasher.h"
// RunAllTests(argc, argv);
Then "make" and run: nate@skylake:~/git/highwayhash$ ./sip_hash_main
ScalarSipTreeHash ... GBps=2.44 c/b=1.44
ScalarHighwayTreeHash ... GBps=1.16 c/b=3.02
SipHash ... GBps=1.54 c/b=2.27
SipTreeHash ... GBps=4.56 c/b=0.77
HighwayTreeHash ... GBps=11.49 c/b=0.30
...
The inner loop for HighwayTreeHash looks like this: 0.89 │ 60:┌─→vpor %ymm5,%ymm0,%ymm0
4.47 │ │ vpaddq (%rcx),%ymm1,%ymm1
6.04 │ │ add $0x4,%rax
0.22 │ │ add $0x20,%rcx
2.24 │ │ cmp %rax,%rdi
3.13 │ │ vpsrlq $0x20,%ymm1,%ymm2
3.36 │ │ vpmulu %ymm1,%ymm0,%ymm4
13.20 │ │ vpshuf %ymm3,%ymm4,%ymm4
11.19 │ │ vpmulu %ymm2,%ymm0,%ymm2
│ │ vpaddq %ymm1,%ymm2,%ymm1
31.32 │ │ vpaddq %ymm4,%ymm0,%ymm0
7.61 │ └──ja 60First, from any hash only a few bits are use for a hash table lookup, typically between 5-8. It depends on the size of the table. You can make your hash function long and strong, but only the last few bits count, and this does not help you at all against DDOS.
Second, against DDOS only uhash, or using no linked lists or arrays with O(n/2) lookup costs help. A random seed is good, but can be detected. E.g. a timeout as used by djb in his nameserver does help better than a stronger hash function. Or using a hash table as in glibc, gcc or the linux kernel. siphash or HighwayHash does not help at all. python and perl both fell into this trap.
But I appreciate the effort to create a fast metro like hash function, without resorting to the internal crc32 builtin. Will be included in smhasher soon.
This is not my experience. Frequently, hash tables will have a size that is a power of 2, and the address into the table will be all of the low order bits. A table with 1 million slots will use 20 bits of hash.
> Second, against DDOS only uhash, or using no linked lists or arrays with O(n/2) lookup costs help.
uhash is just one example of hash function designs based on almost-universal hashing. There are many others, including VHASH and Poly1305. Is HighwayHash almost universal?
It looked like that was what rurban was arguing? Pull out the low 5-8 bits, get a table of size 32-256?
And on top of that I guess nobody ever heard of "Cache-Conscious Collision Resolution in String Hash Tables" by Nikolas Askitis and Justin Zobel, who measured that a linear search in an array for collisions outperforms a linked lists by 2-4x, even if that can do move-to-front much easier.
People still do worry about the hash function, where they do should worry about their hash tables instead, which can easily be made 4x faster and not 2x slower.
Hash "functions" like UHASH, Poly1305, and SipHash are actually families of hash functions, parameterized by seed.
> And on top of that I guess nobody ever heard of "Cache-Conscious Collision Resolution in String Hash Tables" by Nikolas Askitis and Justin Zobel, who measured that a linear search in an array for collisions outperforms a linked lists by 2-4x, even if that can do move-to-front much easier.
If an implementation is vulnerable to hash-flooding attacks because it doesn't have a randomly-seeded almost-universal hash function, then changing the collision mechanism from linked lists to arrays isn't going to fix the problem.
Good collision resolution and good hash functions are both issues worth addressing.
and from the linked smasher page:
> You can attack every single hash function, even the best, if you detect the seed, ...
But the most efficient known way to recover the SipHash key is still bruit force.[0] Good luck making an average of 2^127 guesses.
[0] http://link.springer.com/chapter/10.1007/978-3-319-13051-4_1...
For non-cryptographic applications, CLHASH produces 64 bits of result and is 2.004/2^64 almost delta universal, at a cost of 0.16 cycles per byte on Haswell and 0.10 cycles per byte on Skylake.
For longish-strings, most of the cycles are in the preliminary rounds, so appending whatever you want onto the end should add negligible cost. This includes bitmixing (their proposed smhasher fix) or a HighwayTreeHash round.
Or better: how can I educate myself better on the proper usage of certain hashing functions?
I think BLAKE2 is probably the fastest and best cryptographic hash function you're likely to see for the foreseeable future?
I'm curious though, what are you working on that saturates ~1 GiB/s/core?