我想存储大约20亿个字符串的哈希值。为此,我希望尽可能少地使用存储空间。
考虑一种理想的散列算法,它将散列作为一系列十六进制数字(如md5散列)返回。 据我了解这个想法,这意味着我需要散列不少于8个符号并且长度不超过8个符号。因为这样的散列能够散列4亿个(16 * 16 * 16 * 16 * 16 * 16 * 16 * 16)个不同的字符串。
所以我想知道将散列切割到一定长度以节省空间是否安全? (哈希当然不应该碰撞)
是/否/可能 - 我希望得到解释或相关研究链接的答案。
P.S。 - 我知道我可以测试8个字符的哈希是否可以存储20亿个字符串。但我需要将20亿个哈希值与其20亿个切割版本进行比较。这对我来说似乎并不重要,所以在我这样做之前我最好先问一下。
答案 0 :(得分:0)
哈希是一个数字,而不是十六进制数字(字符)的字符串。在MD5的情况下,以有效的形式保存128位或16字节。如果你的问题仍然适用,你肯定可以考虑截断数字(通过转换成一个单词或先进行位移)。好的哈希算法均匀地分配给所有比特。
附录:
通常,只要处理哈希值,就要检查字符串是否真的匹配。这照顾了碰撞哈希的可能性。切割哈希的次数越多,您获得的冲突就越多。但是计划在这个阶段发生的事情是很好的。
答案 1 :(得分:0)
是否可以安全地将 x 值存储在只能表示 2x 不同哈希值的哈希域中,完全取决于您是否可以容忍冲突。
哈希函数实际上是随机数生成器,因此您的20亿个计算哈希值将均匀分布在40亿个可能的结果中。这意味着您必须遵守Birthday Problem。
在你的情况下,如果你计算2 ^ 31(20亿)哈希值只有2 ^ 32(40亿)个可能的哈希值,那么至少有两个具有相同哈希值(碰撞)的几率非常非常接近100%。 (并且三个相同的几率也非常非常接近100%。依此类推。)我无法根据这些数字找到计算碰撞可能数量的公式,但我怀疑它是一个数量巨大。
如果在您的情况下,哈希冲突不是灾难(例如在Java的HashMap实现中,它通过将哈希目标转换为共享相同哈希键的对象列表来处理冲突,尽管代价是性能降低)那么也许你可以忍受大量碰撞的确定性。但是,如果您需要唯一性,那么您需要一个更大,更大的哈希域,或者您需要为每个记录分配一个保证唯一的序列ID号,具体取决于您的目的。
最后,请注意Keccak能够生成任何所需的输出长度,因此花费CPU资源生成长哈希输出只是为了在之后修剪它是没有意义的。您应该能够告诉您的Keccak功能只提供您需要的位数。 (另请注意,Keccak输出长度的变化不会影响初始输出位,因此结果与之后进行手动按位调整的结果完全相同。)