C++ 仅在boost::hash_combine中运行一个程序时保证确定性
在寻找整数的一些确定性(多次运行、多台机器)哈希程序时,我偶然发现了C++ 仅在boost::hash_combine中运行一个程序时保证确定性,c++,boost,hash,deterministic,C++,Boost,Hash,Deterministic,在寻找整数的一些确定性(多次运行、多台机器)哈希程序时,我偶然发现了boost::hash\u combine(size\u t&seed、t const&v)。不幸的是,报告中指出 此哈希函数不适用于一般用途,也不能保证在程序的单独运行期间相等-因此请不要将其用于任何持久存储或通信 但是,在查看实现时,我没有看到任何可疑代码,这些代码可能会在单独的运行中导致不同的行为-只是一些乘法和加法(可能会溢出)、位移位和异或操作,所有操作都使用常量。更重要的是,hasher在多次执行时表现一致 那么,禁
boost::hash\u combine(size\u t&seed、t const&v)
。不幸的是,报告中指出
此哈希函数不适用于一般用途,也不能保证在程序的单独运行期间相等-因此请不要将其用于任何持久存储或通信
但是,在查看实现时,我没有看到任何可疑代码,这些代码可能会在单独的运行中导致不同的行为-只是一些乘法和加法(可能会溢出)、位移位和异或操作,所有操作都使用常量。更重要的是,hasher在多次执行时表现一致
那么,禁止在整个过程中保证决定论的实际问题在哪里呢
粘贴以下最有趣的作品:
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
boost::hash<T> hasher;
return boost::hash_detail::hash_combine_impl(seed, hasher(v));
}
template <typename T>
typename boost::hash_detail::basic_numbers<T>::type hash_value(T v)
{
return static_cast<std::size_t>(v);
}
inline void hash_combine_impl(boost::uint64_t& h,
boost::uint64_t k)
{
const boost::uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
const int r = 47;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
// Completely arbitrary number, to prevent 0's
// from hashing to 0.
h += 0xe6546b64;
}
模板
内联无效哈希组合(标准::大小\u t和种子,t常量和v)
{
boost::散列哈希器;
返回boost::hash_detail::hash_combine_impl(seed,hasher(v));
}
样板
typename boost::hash_detail::basic_number::type hash_value(tv)
{
返回静态_-cast(v);
}
内联无效哈希合并impl(boost::uint64\u t&h,
boost::uint64_t k)
{
常数boost::uint64_t m=uint64_C(0xc6a4a7935bd1e995);
常数int r=47;
k*=m;
k^=k>>r;
k*=m;
h^=k;
h*=m;
//完全任意数,以防止0
//从散列到0。
h+=0xe6546b64;
}
原因是哈希表中经常使用哈希。试图攻击服务的恶意用户(使用包含哈希表的C++代码)可能会通过对插入到哈希表中的项目强制散列冲突而大幅降低其性能(对于从O(1)到O(n))的共同操作的性能。通过让每次运行都使用不同的哈希函数,这将变得更加困难
std::hash
也是这样标准化的。引用:
散列函数只需要在程序的一次执行中为相同的输入生成相同的结果;这允许使用盐哈希来防止碰撞DoS攻击。(C++ 14)
也许没问题。仅仅因为它不打算这样使用,它并不一定意味着你不能这样使用它,但它确实意味着,如果你依赖于某些无法保证的行为,那么当你进入下一个版本的库时,你可能会运气不佳,只是说……这绝对有意义,但在这个具体案例中,我看不到任何机制会改变几次运行之间的行为。我是否应该将此“免责声明”解释为未来的安全措施,何时实施此类机制?