【问题标题】:How to generate unique but consistent N-bit hash (less than 64 bit) for strings?如何为字符串生成唯一但一致的 N 位哈希(小于 64 位)?
【发布时间】:2018-10-17 03:47:49
【问题描述】:

我想要以下机制:

int64_t MyHash (const std::string& value);
  • 输入任何std::string(通常为 100 字节)
  • 函数输出一个 64 位整数值
  • 但是,该整数表示的最大值应在-2<sup>53</sup> to 2<sup>53</sup>-1 的范围内

我尝试使用std::hash();问题在于:每个平台都不同。不仅如此,每次运行都会有所不同。

目前,使用QtQCryptographicHash 我得到一个SHA256 校验和,并且我正在截断为64 位。即使在这种截断中,碰撞的可能性也会增加。
无论如何,我的目标是在 54 位内获得该值。一个明显的解决方案是将这个数字除以 2048。

问题:有没有更好的解决方案来获得 54 位的哈希?
Javascript解决方案也很好。

目的:这个值被传递给 Javascript。现在它的数据类型 number 可以容纳一个 64 位双精度数,即 54 位。

【问题讨论】:

  • 鸽巢原理说,你根本不可能有 256^100 个不同的字符串到 2^54 个唯一的哈希值。事实上,你甚至不能将 256^7 个不同的字符串散列为 2^54 个唯一的散列。您可以期望的最好结果是均匀分布的,即每个哈希有 2^746 次冲突。

标签: javascript c++ qt hash checksum


【解决方案1】:

获得 54 位哈希,您可能会以质量换取速度。在 SHA256 中,最低 54 位将提供尽可能可靠的哈希值,但代价不是最佳性能。

其他可能性是 64 位 CRC,可以通过快速的谷歌搜索很容易找到。这可能会更快,并且对于任何合理的用例来说仍然可能没问题。

至于 [-253 .. 253 - 1] 范围的截断,我只需使用带有合适位掩码的&,然后减去 253.

253 是 0x20000000000000,所以它只是:

crc = crc - 0x20000000000000LL;

至于 64 位 CRC 本身,以下代码直接取自 http://andrewl.dreamhosters.com/filedump/crc64.cpp,这是一个可下载的 .cpp 文件。原文是用Windows数据类型写的,我这里转换成普通的stdint.h类型。

unit64_t const poly = 0xC96C5795D7870F42ULL;
uint64_t table[256];

void generate_table()
{
    for(int i = 0; i < 256; ++i)
    {
        uint64_t crc = i;

        for(int j = 0; j < 8; ++j)
        {
            if(crc & 1)
            {
                crc >>= 1;
                crc ^= poly;
            }
            else
            {
                crc >>= 1;
            }
        }
        table[i] = crc;
    }
}

您需要在程序启动时只调用一次generate_table()。要么这样,要么在一个只打印出结果的小工具中运行它,然后使用这些值直接初始化表。

要实际评估 crc,请将字节序列和长度传递给它:

uint64_t calculate_crc(uint8_t *stream, size_t n)
{
    uint64_t crc = 0;

    for(size_t i = 0; i < n; ++i)
    {
        uint8_t index = stream[i] ^ crc;
        uint64_t lookup = table[index];

        crc >>= 8;
        crc ^= lookup;
    }
    return crc;
}

根据您的好奇程度,可能值得查看链接源,它有大量的 cmets 可以解释发生了什么。

【讨论】:

  • 谢谢。你能放任何已知的CRC算法吗?另外,减去 2^53 是什么意思?一个等式会很有帮助。
  • @iammilind:你首先产生一个范围为 [0...2^52^-1] 的值,然后减去 2^53 得到一个可能的范围 [-2^53, 2 ^53-1]
猜你喜欢
  • 2015-05-22
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-06
  • 1970-01-01
相关资源
最近更新 更多