# About the low quality of Base.hash()

**URL:** <https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707>\
**Category:** General Usage\
**Tags:** question, hash\
**Created:** [April 4, 2025, 1:55pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707 "2025-04-04T13:55:57Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![noteas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/noteas/32/216139_2.png) [@noteas](https://discourse.julialang.org/u/noteas)\
**Post date:** [April 4, 2025, 1:55pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/1 "2025-04-04T13:55:57Z")

</div>

I was implementing a 1d noise function where hashes of `Int`s were needed, when I found Base.hash() is of surprisingly low quality. I wonder whether this should be an issue or not.

Consider the following example:

```julia
using Plots
x = -100:100
plot(x, hash.(x), label="hash(x)")

```

yields

 ![hash](https://global.discourse-cdn.com/julialang/original/3X/0/c/0c16247fff2e3646d66375e98d75c0ab2a24768a.png)  
Notice that it exhibits regular patterns for positive x, and the patterns are substantially inconsistent with negative x, which indicates bad hash quality.  
Glancing at the implementation at [base/hashing.jl](https://github.com/JuliaLang/julia/blob/master/base/hashing.jl), the hash\_64\_64() function only utilizes additions, shifts and exclusive-ors, so no wonder it has such bad quality.  
Empirically, we should introduce multiplications. Replacing it with a hash derived from [O’Neill, M. E. 2014. PCG: A Family of Simple Fast Space-Efficient Statistically Good Algorithms for Random Number Generation.](https://www.cs.hmc.edu/tr/hmc-cs-2014-0905.pdf) gives a better result:

```julia
using Plots
function myhash(x::UInt64)
       x = 0xd55e8028f0ba2e7d * (x + UInt64(1))
       x ⊻= x >>> ((x >>> 59) % UInt8 + UInt8(6))
       x = 0xd55e8028f0ba2e7d * (x + UInt64(1))
       x ⊻ (x >>> ((x >>> 59) % UInt8 + UInt8(6)))
end
myhash(x::Int64) = myhash(reinterpret(UInt64, x))
x = -100:100
plot(x, myhash.(x), label="myhash(x)")

```

 ![myhash](https://global.discourse-cdn.com/julialang/original/3X/1/8/18f8cc34558cc094da67ce0235a2ebb14f13a6fb.png)

```julia

```

---

<div class="post-metadata">

**Author:** ![noteas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/noteas/32/216139_2.png) [@noteas](https://discourse.julialang.org/u/noteas)\
**Post date:** [April 4, 2025, 1:56pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/2 "2025-04-04T13:56:54Z")

</div>

Sorry my last thread was carelessly deleted by myself.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [April 4, 2025, 1:59pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/3 "2025-04-04T13:59:17Z")

</div>

`hash` is not a cryptographic hashing function, it’s mostly used as a default fallback for `Dict` and `Set` and the like. For this purpose, more randomness can be a negative thing. Hence, the quality you observe may not necessarily be the most important factor for its implementation.

---

<div class="post-metadata">

**Author:** ![noteas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/noteas/32/216139_2.png) [@noteas](https://discourse.julialang.org/u/noteas)\
**Post date:** [April 4, 2025, 2:02pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/4 "2025-04-04T14:02:18Z")

</div>

I see. But does Julia provide fast random integer hashing? SHA and CRC32 are too slow for my purpose.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [April 4, 2025, 2:04pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/5 "2025-04-04T14:04:18Z")

</div>

I’m not sure that you’ll find exactly what you’re looking for in the stdlib. There is fast random number generation in the Random stdlib (using Xoshiro), but probably nothing purpose made as a 1D noise function.

Depending in your domain, there may be a package that does this?

---

<div class="post-metadata">

**Author:** ![noteas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/noteas/32/216139_2.png) [@noteas](https://discourse.julialang.org/u/noteas)\
**Post date:** [April 4, 2025, 2:15pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/6 "2025-04-04T14:15:03Z")

</div>

Thanks. I’ll implement it myself.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [April 4, 2025, 2:26pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/7 "2025-04-04T14:26:51Z")

</div>

see also [use rapidhash by adienes · Pull Request #57509 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/57509)

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [April 4, 2025, 4:47pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/8 "2025-04-04T16:47:14Z")

</div>

> [@noteas](#):
>
> hash\_64\_64() function only utilizes additions, shifts and exclusive-ors, so no wonder it has such bad quality.

This is utter nonsense. For example, [chacha20](https://en.wikipedia.org/wiki/Salsa20) is a perfectly fine block cypher using only additions, shifts and xors.

There is no inherent quality, security, or performance issue with restricting to these operations. It might be a questionable choice for julia specifically – julia is typically run on CPUs that have good multiplication circuitry anyways; might as well use the cheap multiply if you don’t need to run on micro-controllers / ASIC.

Whether it is a good idea to use the existing fast multiply circuitry is something up to debate, in hashing, cryptography, random number generation. It certainly looses flexibility when porting to microcontrollers / fpgas / asics, and its not entirely clear whether the multiply buys you anything compared to a well-designed addition/shift/xor algorithm. But it is certainly much easier for non-experts to produce something non-terrible when you allow them multiply! (I am not an expert on that level. Don’t ask me to design crypto primitives.)

I also question the validity of your plot. Your plot simply looks at the most significant digits, but julia hash’s design goals are concentrated on giving best quality on the least significant digits! (for use in Dict / Set)

Further, if you want to look at the literature, julia’s hash is afaiu based on some murmur version.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 4, 2025, 10:04pm UTC](https://discourse.julialang.org/t/about-the-low-quality-of-base-hash/127707/9 "2025-04-04T22:04:49Z")

</div>

This is stated a bit harshly but the basic point is correct: you can’t judge the quality of a hash function by the simplicity of the primitives it uses—even the most secure hashes are built from simple basic operations.

If anything, our hash should probably be worse. It likely does more work than is necessary for its purpose which is to be just good enough to minimize hash collisions. Python somewhat famously uses the identity function for hashing small positive integers. I’m not saying we should do that, but it’s just a case where a “bad” hash function can make sense for a variety of reasons.
