从给定的字符串中,我使用md5生成32位唯一的哈希代码
MessageDigest.getInstance("MD5")
.digest("SOME-BIG-STRING").map("%02x".format(_)).mkString
//output: 47a8899bdd7213fb1baab6cd493474b4
有没有可能生成30位而不是32位的长度,如果这样做会有什么问题?
是否还有其他哈希算法可用于支持30个字符长和1万亿个唯一字符串的冲突概率?
安全性不重要,唯一性是必需的。
2条答案
按热度按时间crcmnpdw1#
对于从字符串生成唯一的id,哈希函数永远不是正确的答案。
您需要定义文本字符串(如“v1.0.0”)到30个字符长字符串(如“123123…”)的一对一Map。这也被称为双射,尽管在您的例子中,注入(从输入到输出的简单一对一Map,不一定是到输出)可能就足够了。正如公认的答案所指出的,散列函数不一定能确保这种Map,但也有其他的可能性,比如全周期线性同余生成器(如果它们采用一个种子,您可以将一对一Map到输入字符串值),或者其他可逆函数。
但是,如果可能的输入字符串集大于可能的输出字符串集,则由于鸽子洞原理,无法将所有输入字符串与所有输出字符串一一Map(不创建重复项)。
另请参阅这个问题:如何生成具有自定义字母表的guid,其行为类似于md5散列(在javascript中)?。
实际上,如果使用散列函数,冲突的可能性将接近于零,但永远不会完全为零(这意味着重复的风险将始终存在)。如果我们以md5为例(它产生2^128个哈希码中的任何一个),那么粗略地说,只有在生成2^64个id之后,意外冲突的可能性才变得不可忽略,这远远超过1万亿。
但是md5和其他散列函数并不是正确的方法。这将在下面讨论。
如果不能将输入字符串的格式限制为30位,不能将其压缩为30位或更少,并且不能容忍重复的风险,那么下一个最佳方法是创建一个数据库表,将输入字符串Map到随机生成的ID。
这个数据库表应该有两列:一列保存您的输入字符串(例如“
<UUID>-NAME-<UUID>
,另一列保存与这些字符串关联的随机生成的ID。由于随机数不能确保唯一性,因此每次创建新的随机id时,都需要检查该随机id是否已存在于数据库中,如果确实存在,请尝试使用新的随机id(但发现重复id的可能性会随着id大小的增加而减小)。j2qf4p5b2#
有没有可能生成30位而不是32位的长度,如果这样做会有什么问题?
对。
碰撞的概率增加了28倍。
是否还有其他哈希算法可用于支持30个字符长和1万亿个唯一字符串的冲突概率?
可能。任何加密强度哈希算法产生的哈希值的前30个十六进制数字具有大致相等的唯一性。
安全性不重要,唯一性是必需的?
在这种情况下,md5不再被认为是安全的这一事实是没有意义的(注意,md5不再被认为是安全的原因是在计算上设计一个碰撞是可行的;i、 e.为给定的md5散列查找第二个输入。)
但是,不能保证哈希的唯一性。即使使用生成n位哈希的“完美”加密强度哈希函数,任何2个任意(不同)输入的冲突概率也是2n分之一。对于足够大的n值,概率很小。但它永远不是零。