I'm looking for a very fast function $f(m, k) $ that takes a 64-bit integer $m$ and a fixed secret key $k$ of virtually any size (generated by a CSPRNG) and turns them into a 64- or 32-bit integer $ r $, with a few additional requirements:
- $ r $ must depend on both $m$ and $ k $ and be reasonably well-distributed
- if a pair of $ m $ and $ r $ is known, it should not be possible to efficiently calculate $ k $ or produce $ f(m_1, k) = r_1 $
- $ r $ will be used as a kind of a key or tag associated with $ m $, but it doesn't have to uniquely identify $ m $ (i.e. the existence of $ m_1 $, $ m_2 $ such that $f(m_1, k) = f(m_2, k) = r $ is completely normal), so I'm not too concerned about collisions
IOW, I need a way to quickly and irreversibly transform/compress/scramble a fixed-size integer (possibly shortening it) using a secret.
I think ideally this would be solved by a keyed cryptographic hash function like Blake* or Siphash. For example, Siphash was specifically designed to work well on small inputs and maintain key secrecy, and it's currently used in CPython for hash table lookups. Performance-wise Siphash-2-4 is maybe tolerable for my use case and seems to check all the boxes, but since I only need to process a 64-bit integer, it feels like an overkill and I'm still interested in anything more lightweight.
I've also looked at several non-cryptographic hash functions and their performance is very appealing, but I'm afraid many of them will fail the second requirement I listed (especially if I feed them $ k || m $, which simplifies brute-force attack in case of FNV-1A and Murmurhash3). XXH3 explicitly lets me provide a
secret to customize hash values, and it seems to outperform any other decent hash function in existence, but it's also explicitly non-cryptographic, so unfortunately I'm not sure if it can provide the same level of security as Siphash, even for a use case as simple as mine.
I've also tried creating my own mixing/compression function (which most likely is not secure) and considered using a mixing/compression function from an existing algorithm (most likely not designed to be used separately from the original algorithm).
Am I missing a simpler way to do this?