hash - 为什么 hash() 和 hasher.write() 的结果不一样?

标签 hash rust

如果我使用 hash()hasher.write() 函数,像 1234 这样的数字会得到相同的结果,但是一个字节slice like b"Cool" 不会。我认为应该是一样的;为什么不是呢?

use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::mem;

fn main() {
    let mut hasher = DefaultHasher::new();
    1234.hash(&mut hasher);
    println!("Hash is {:x}", hasher.finish());

    let mut hasher = DefaultHasher::new();
    hasher.write(unsafe { &mem::transmute::<i32, [u8; 4]>(1234) });
    println!("Hash is {:x}", hasher.finish());

    let mut hasher = DefaultHasher::new();
    b"Cool".hash(&mut hasher);
    println!("Hash is {:x}", hasher.finish());

    let mut hasher = DefaultHasher::new();
    hasher.write(b"Cool");
    println!("Hash is {:x}", hasher.finish());
}
Hash is 702c1e2053bd76
Hash is 702c1e2053bd76
Hash is 9bf15988582e5a3f
Hash is 7fe67a564a06876a

最佳答案

作为the documentation说:

The default Hasher used by RandomState. The internal algorithm is not specified, and so it and its hashes should not be relied upon over releases.

如果我们遵循RandomState ...

A particular instance RandomState will create the same instances of Hasher, but the hashers created by two different RandomState instances are unlikely to produce the same result for the same values.

Rationale :

By default, HashMap uses a hashing algorithm selected to provide resistance against HashDoS attacks. The algorithm is randomly seeded, and a reasonable best-effort is made to generate this seed from a high quality, secure source of randomness provided by the host without blocking the program. Because of this, the randomness of the seed depends on the output quality of the system's random number generator when the seed is created. In particular, seeds generated when the system's entropy pool is abnormally low such as during system boot may be of a lower quality.


我稍微研究了一下,没有要求 hash()write()共享相同的行为。

唯一的要求是k1 == k2 -> hash(k1) == hash(k2)对于 Hash 特征。 Hasher 特性具有相同的属性,但不要求 k1 -> hash(k1) == hasher(k1)

这是有道理的,因为 Hash 特性旨在由用户实现,并且他们可以按照自己的喜好实现它。例如,可以添加 salt进入哈希。

这是一个最小的完整且不可验证的示例,它可能会产生相同的输出或不同的输出,具体取决于实现:

use std::collections::hash_map::{DefaultHasher, RandomState};
use std::hash::{BuildHasher, Hasher, Hash};

fn main() {
    let s = RandomState::new();

    let mut hasher = s.build_hasher();
    b"Cool".hash(&mut hasher);
    println!("Hash is {:x}", hasher.finish());

    let mut hasher = s.build_hasher();
    hasher.write(b"Cool");
    println!("Hash is {:x}", hasher.finish());

    let s = DefaultHasher::new();

    let mut hasher = s.clone();
    b"Cool".hash(&mut hasher);
    println!("Hash is {:x}", hasher.finish());

    let mut hasher = s.clone();
    hasher.write(b"Cool");
    println!("Hash is {:x}", hasher.finish());
}

您可以 see切片的 Hash 的实现也写入了切片的长度:

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for [T] {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(self, state)
    }
}

此外,它看起来像 hash_slice()具有您想要的行为,但并未说明情况总是如此(但我认为这是预期的行为并且不会改变,我问过 here )。

use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;

fn main() {
    let s = DefaultHasher::new();

    let mut hasher = s.clone();
    std::hash::Hash::hash_slice(b"Cool", &mut hasher);
    println!("Hash is {:x}", hasher.finish());

    let mut hasher = s.clone();
    hasher.write(b"Cool");
    println!("Hash is {:x}", hasher.finish());
}

关于hash - 为什么 hash() 和 hasher.write() 的结果不一样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54034727/

相关文章:

java - 什么是java中的哈希函数?

math - SHA(-1-2-3) 是一对一的函数,输入的长度与输出的长度相同吗?

javascript - 在具有良好分布的两个整数之间散列字符串(均匀散列)

arrays - 如果具有该值的散列不存在,则在数组中添加散列,否则扩展现有散列

sqlite - 如何存储 SQLite 准备好的语句供以后使用?

rust - 是否可以在 Rust 的函数中定义可选参数?

Rust if let Optionals 和比较条件

macos - 编写 .cargo/config.toml 以允许 rust 代码被 python 导入

php - password_hash 每次返回不同的值

arrays - 如何编写内部数组长度不同的嵌套数组?