MurmurHash3 是否可以生成高 32 位全为 0 的 64 位哈希?
is it possible for MurmurHash3 to produce a 64 bit hash where the upper 32 bits are all 0?
看着 https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp 我不这么认为,但我想检查一下。
情况是这样的,如果我有一个 1、2、3 或 4 个字节的密钥,简单地取这些字节的数值而不是散列到 8 个字节是否可靠,或者那些会导致冲突对于使用 murmur3 散列的大于 4 个字节的密钥?
这样的 属性 是一个 不好的 属性 哈希函数。它有效地缩小了函数共域,增加了碰撞机会,所以这似乎不太可能。
此外,this blog post为MurmurHash提供了一个反转函数:
uint64 murmur_hash_64(const void * key, int len, uint64 seed)
{
const uint64 m = 0xc6a4a7935bd1e995ULL;
const int r = 47;
uint64 h = seed ^ (len * m);
const uint64 * data = (const uint64 *)key;
const uint64 * end = data + (len / 8);
while (data != end)
{
#ifdef PLATFORM_BIG_ENDIAN
uint64 k = *data++;
char *p = (char *)&k;
char c;
c = p[0]; p[0] = p[7]; p[7] = c;
c = p[1]; p[1] = p[6]; p[6] = c;
c = p[2]; p[2] = p[5]; p[5] = c;
c = p[3]; p[3] = p[4]; p[4] = c;
#else
uint64 k = *data++;
#endif
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
const unsigned char * data2 = (const unsigned char*)data;
switch (len & 7)
{
case 7: h ^= uint64(data2[6]) << 48;
case 6: h ^= uint64(data2[5]) << 40;
case 5: h ^= uint64(data2[4]) << 32;
case 4: h ^= uint64(data2[3]) << 24;
case 3: h ^= uint64(data2[2]) << 16;
case 2: h ^= uint64(data2[1]) << 8;
case 1: h ^= uint64(data2[0]);
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
uint64 murmur_hash_64_inverse(uint64 h, uint64 seed)
{
const uint64 m = 0xc6a4a7935bd1e995ULL;
const uint64 minv = 0x5f7a0ea7e59b19bdULL; // Multiplicative inverse of m under % 2^64
const int r = 47;
h ^= h >> r;
h *= minv;
h ^= h >> r;
h *= minv;
uint64 hforward = seed ^ (((uint64)8) * m);
uint64 k = h ^ hforward;
k *= minv;
k ^= k >> r;
k *= minv;
#ifdef PLATFORM_BIG_ENDIAN
char *p = (char *)&k;
char c;
c = p[0]; p[0] = p[7]; p[7] = c;
c = p[1]; p[1] = p[6]; p[6] = c;
c = p[2]; p[2] = p[5]; p[5] = c;
c = p[3]; p[3] = p[4]; p[4] = c;
#endif
return k;
}
您可以找到任意数量的具有哈希值 <2^32
的输入。
您关于可靠性的问题没有多大意义:您必须始终准备好正确处理碰撞。根据我的实践,我不建议使用普通整数或指针值作为散列,因为它们会产生不需要的模式。
看着 https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp 我不这么认为,但我想检查一下。
情况是这样的,如果我有一个 1、2、3 或 4 个字节的密钥,简单地取这些字节的数值而不是散列到 8 个字节是否可靠,或者那些会导致冲突对于使用 murmur3 散列的大于 4 个字节的密钥?
这样的 属性 是一个 不好的 属性 哈希函数。它有效地缩小了函数共域,增加了碰撞机会,所以这似乎不太可能。
此外,this blog post为MurmurHash提供了一个反转函数:
uint64 murmur_hash_64(const void * key, int len, uint64 seed)
{
const uint64 m = 0xc6a4a7935bd1e995ULL;
const int r = 47;
uint64 h = seed ^ (len * m);
const uint64 * data = (const uint64 *)key;
const uint64 * end = data + (len / 8);
while (data != end)
{
#ifdef PLATFORM_BIG_ENDIAN
uint64 k = *data++;
char *p = (char *)&k;
char c;
c = p[0]; p[0] = p[7]; p[7] = c;
c = p[1]; p[1] = p[6]; p[6] = c;
c = p[2]; p[2] = p[5]; p[5] = c;
c = p[3]; p[3] = p[4]; p[4] = c;
#else
uint64 k = *data++;
#endif
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
const unsigned char * data2 = (const unsigned char*)data;
switch (len & 7)
{
case 7: h ^= uint64(data2[6]) << 48;
case 6: h ^= uint64(data2[5]) << 40;
case 5: h ^= uint64(data2[4]) << 32;
case 4: h ^= uint64(data2[3]) << 24;
case 3: h ^= uint64(data2[2]) << 16;
case 2: h ^= uint64(data2[1]) << 8;
case 1: h ^= uint64(data2[0]);
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
uint64 murmur_hash_64_inverse(uint64 h, uint64 seed)
{
const uint64 m = 0xc6a4a7935bd1e995ULL;
const uint64 minv = 0x5f7a0ea7e59b19bdULL; // Multiplicative inverse of m under % 2^64
const int r = 47;
h ^= h >> r;
h *= minv;
h ^= h >> r;
h *= minv;
uint64 hforward = seed ^ (((uint64)8) * m);
uint64 k = h ^ hforward;
k *= minv;
k ^= k >> r;
k *= minv;
#ifdef PLATFORM_BIG_ENDIAN
char *p = (char *)&k;
char c;
c = p[0]; p[0] = p[7]; p[7] = c;
c = p[1]; p[1] = p[6]; p[6] = c;
c = p[2]; p[2] = p[5]; p[5] = c;
c = p[3]; p[3] = p[4]; p[4] = c;
#endif
return k;
}
您可以找到任意数量的具有哈希值 <2^32
的输入。
您关于可靠性的问题没有多大意义:您必须始终准备好正确处理碰撞。根据我的实践,我不建议使用普通整数或指针值作为散列,因为它们会产生不需要的模式。