为什么hash()和hasher.write()的结果不同?

时间:2019-01-04 07:31:28

标签: hash rust

如果我使用1234hash()函数,则像hasher.write()这样的数字具有相同的结果,但是像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

1 个答案:

答案 0 :(得分:3)

the documentation说:

  

Hasher使用的默认RandomState。内部算法未指定,因此它及其散列不应该依赖过度发布。

如果我们遵循RandomState ...

  

特定的实例RandomState将创建Hasher的相同实例,但是由两个不同的RandomState实例创建的散列对于相同的值不太可能产生相同的结果。

Rationale

  

默认情况下,HashMap使用选定的哈希算法来抵抗HashDoS攻击。该算法是随机种子的,并且做出了合理的努力,以从主机提供的高质量,安全的随机性源生成该种子,而不会阻塞程序。因此,种子的随机性取决于创建种子时系统的随机数生成器的输出质量。特别是,当系统的熵池异常低(例如在系统启动期间)时生成的种子可能质量较低。


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

唯一的要求是Hash特性必须使用k1 == k2 -> hash(k1) == hash(k2)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()拥有您想要的行为,但并没有说总是这样(但是我认为这是预期的行为,并且不会改变,我问{{3 }}。

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());
}