Okay. I think I see the problem you are trying to describe:
Suppose that an attacker has somehow prepared a large repository of [u8]
s that all produce the same hash value when fed to DefaultHasher::new()
. I.e.
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn unsalted_hash<T: Hash>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
// Let's just assume that this is true:
assert_eq!(
unsalted_hash(b"Hello world!"),
unsalted_hash(b"pwned"),
);
Theoretically, if it existed, such a repository could be used to perform a DOS attack by filling a hash map with collisions. However, the repository would take a very long time to build, and would thus have to be prepared ahead of time.
Rust's random initialization prevents this attack, by making the initial state of the hasher unpredictable. With the hasher in a different state, the keys already prepared by the attacker will most likely no longer produce collisions for any arbitrary HashMap. That is to say:
let init = RandomState::new();
let salted_hash = |s: &[u8]| {
let mut hasher = init.build_hasher();
hasher.write(s);
hasher.finish()
};
assert_ne!(
salted_hash(b"Hello world!"),
salted_hash(b"pwned"),
);
Now... suppose we had a type like this:
struct Unsalted<T>(T);
impl<T: Hash> Hash for Unsalted<T> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
hasher.write_u64(unsalted_hash(self));
}
}
One can see that, regardless of the salt, collisions in unsalted_hash
produce collisions in the outer hasher:
assert_eq!(
salted_hash(Unsalted(b"Hello world!")),
salted_hash(Unsalted(b"pwned")),
);
meaning the precomputed table of collisions is once again viable. To turn this example into the author's problem, imagine that Unsalted
holds an Erlang term, and unsalted hash()
simply calls enif_hash
with a salt of 0.
Of course, this all hinges on the existence of such a table. I am not an expert in crypto, and I have no idea what kind of resources would be necessary to produce an n
-way collision for a cryptographically-secure 64-bit hash function. But if enif_hash
has any cryptographic weaknesses, the aforementioned table could be easier to construct, and might even already exist.
Is that right?
I don't really feel qualified to comment on your solution using finish
.