【问题标题】:Why are the results of hash() and hasher.write() not the same?为什么 hash() 和 hasher.write() 的结果不一样?
【发布时间】:2019-01-04 07:31:28
【问题描述】:

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

【问题讨论】:

    标签: hash rust


    【解决方案1】:

    正如the documentation 所说:

    RandomState 使用的默认 Hasher。内部算法未指定,因此不应依赖它及其哈希值。

    如果我们关注RandomState...

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

    Rationale:

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


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

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

    这是有道理的,因为Hash trait 旨在由用户实现,他们可以随心所欲地实现它。例如,可以将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());
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多