我的目标是为一个字符串生成一个包含6个字符的短Hash字符串(可能包含字符[A-Z] [a-z] [0-9]),该字符串长度为42个不区分大小写的字母数字字符。唯一性是关键要求。安全性或性能不是那么重要。
是否有特定算法可以提供此结果,还是应该坚持截断MD5哈希或SHA-1哈希(Like in this question)?如果是这样,碰撞的概率是多少?
答案 0 :(得分:14)
你最好的选择是截断众所周知的哈希函数(MD5或SHA-family),因为这些算法在哈希值上具有统计上良好的均匀分布(并且还使用完整哈希而不仅仅是6个字符)。
现在对碰撞概率进行一些计算
- Number of letters in English alphabet: 26 - Add capitals: 26 - Add numerics: 10 -------------- In total you get 26 + 26 + 10 = 62 characters. Now you have 6 places, which gives you 62^6 possible combinations. That is 56.800.235.584 ~ 57 billion combinations. This is a space of possible hash values - N. -------------- To compute collisions let's use the formula Pcollision = K^2 / 2N Which is a very rough approximation of collision probability
现在让我们看一下表格中许多项目的结果表 - K
# items | Probability of collision --------------------------------------- 10 | 1.7 * 10^-9 100 | 1.7 * 10^-7 1K | 1.7 * 10^-5 10K | 1.7 * 10^-3 100K | 0.17
此公式只能用于小K,但它表明在散列表中给定100K条目时,大概有17%的碰撞几率。
答案 1 :(得分:7)
简易哈希:)
private string Hash(string str)
{
var allowedSymbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
var hash = new char[6];
for (int i = 0; i < str.Length; i++)
{
hash[i % 6] = (char)(hash[i % 6] ^ str[i]);
}
for (int i = 0; i < 6; i++)
{
hash[i] = allowedSymbols[hash[i] % allowedSymbols.Length];
}
return new string(hash);
}
答案 2 :(得分:1)
最好的解决方案几乎可以肯定是使用SHA1,转换为Base62(尽管Base64会更容易,因为它内置于框架Convert.ToBase64String。你需要做一些寻找合适的Base62库) ,然后将输出截断为6个字节。
我不会使用GetHashCode()
,因为它有history of collision problems。 (我不是要声称这个特定的错误适用于你,只是提到这是GetHashCode
过去没有得到很好实施的证据。)
我也不会实现自定义散列算法,因此很容易意外地编写具有高冲突率的算法。对SHA1和其他主要的哈希算法进行了大量的研究和审查,你很难想出更好的东西。