Disochash is a simple prime-multiplication ARX (addition rotation XOR) hash that's high-quality and fast. It's only 120 lines of code.

There's lots of great hash functions out there: some are super fast, like xxhash and highly optimized, others are also super fast like umash and based on interesting math ideas from finite fields^1, while maintaining high quality (according to SMHasher). Others are also fast and interesting (tabulation hash, that may sometimes be seemingly universal): one of the main originators of tabulation hash ideas is Mikkel Thorup^2.

Anyway, a couple of years ago I also tried my hand at building hashes and created a few that passed SMHasher (tifuhash ~ a floating point hash, beamsplitter - a seemingly-universal tabulation style hash, and this one discohash - a "more traditional" ARX-based design (addition rotation xor)^3 ).

0: https://github.com/rurban/smhasher/blob/master/xxh3.h

1: https://pvk.ca/Blog/2022/12/29/fixing-hashing-modulo-alpha-e...

2: https://arxiv.org/abs/1505.01523

3: https://eprint.iacr.org/2018/898.pdf https://crypto.polito.it/content/download/480/2850/file/docu...

4: https://en.wikipedia.org/wiki/BLAKE_(hash_function)

Discohash (posted here) is the fastest one I made, it's simple and doesn't rely on any arch-specific optimizations or vector instructions (AVX etc ~ tho I suppose...they could be added? I'm definitely no expert in them, I barely get away with doing the C/C++ implementations!)

The main mixing round function is:

mix(const int A) {
const int B = A + 1;

ds[A] *= P;
ds[A] = rot(ds[A], 23);
ds[A] *= Q;

ds[B] ^= ds[A];

ds[B] *= P;
ds[B] = rot(ds[B], 23);
ds[B] *= Q;
}

where P and Q are two randomly chosen 64-bit primes (P is actually the largest unsigned 64-bit prime!), and A is an index into the 256-bit internal state.

I love it because of its simplicity (and because I Created it :) ha), but I think it has some room to grow. An interesting design feature is the internal state is actually variable, it can be larger than 32-bytes.

Some future directions (for anyone who is interested and wants to extend it):

- add a sponge construction to create an infinite output stream / keystream generator

- add AVX instructions (or other optimizations to squeeze more out of a serial implementation)

- figure out how to use a Merkle construction on discohash (like the Blake hashes^4 use to improve their not-that-impressive serial speed using parallelization), hard for discohash I think because state operations are essentially "chained together"

- see if it can be parameterized with other pairs of primes (perhaps into a "universal" family of functions). P & Q in discohash have the interesting and quite rare property that P - Q = P ^ Q (their difference equals their XOR), I surmise that may required for other P and Q to work in discohash.

I just added a PR to Smhasher^5 to update the hash to a faster version and fix some implementation issues related to memory alignment that after much fuffing about with ChatGPT I was thankfully able to resolve! Relief!

I'm no math expert, nor an expert in optimization, nor cryptanalysis, I basically just developed these hashes intuitively, flying by the seat of my pants! But they worked, hoo rah! :)

5: https://github.com/rurban/smhasher/pull/268