“数字食谱”一书提供了一种计算64位哈希码的方法,以减少碰撞次数。
该算法显示在http://www.javamex.com/tutorials/collections/strong_hash_code_implementation_2.shtml,并在此处复制以供参考:
private static final createLookupTable() {
byteTable = new long[256];
long h = 0x544B2FBACAAF1684L;
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 31; j++) {
h = (h >>> 7) ^ h;
h = (h << 11) ^ h;
h = (h >>> 10) ^ h;
}
byteTable[i] = h;
}
return byteTable;
}
public static long hash(CharSequence cs) {
long h = HSTART;
final long hmult = HMULT;
final long[] ht = byteTable;
final int len = cs.length();
for (int i = 0; i < len; i++) {
char ch = cs.charAt(i);
h = (h * hmult) ^ ht[ch & 0xff];
h = (h * hmult) ^ ht[(ch >>> 8) & 0xff];
}
return h;
}
我的问题:
1)考虑到所谓的生日悖论,是否存在估计碰撞概率的公式?
2)你能估算出碰撞的概率(即两个散列到相同值的键)吗?让我们说1000键和10,000键?
编辑:重新说明/更正问题3
3)假设合理数量的密钥(例如,少于10,000个密钥)的碰撞是如此不可能是安全的,这样如果2个哈希码相同,我们可以说密钥是相同的,没有任何密钥进一步检查? e.g。
static boolean equals(key1, key2) {
if (key1.hash64() == key2.hash64())
return true; // probability of collision so low we don't need further check
return false;
}
这不是为了安全,但执行速度是必要的,因此避免进一步检查密钥将节省时间。如果概率很低,比如说小于(100,000个键中的十分之一十亿)那么它可能是可以接受的。
TIA!
答案 0 :(得分:31)
考虑到所谓的生日悖论,是否存在估算碰撞概率的公式?
使用生日悖论公式只会告诉您需要在什么时候开始担心发生碰撞。这大约是Sqrt[n]
,其中n
是可能的哈希值的总数。在这种情况下n = 2^64
所以生日悖论公式告诉您,只要密钥数明显少于Sqrt[n] = Sqrt[2^64] = 2^32
或大约40亿,您就不必担心冲突。 n
越高,估计越准确。事实上,p(k)
键发生碰撞的概率k
接近阶梯函数,n
变大,步骤发生在k=Sqrt[n]
。
你能估算出碰撞的概率(即两个散列到相同值的键)吗?让我们说1000键和10,000键?
假设散列函数是均匀分布的,那么直接推导出公式。
p(no collision for k keys) = 1 * (n-1)/n * (n-2)/n * (n-3)/n * ... * (n-(k-1))/n
该公式直接从1键开始:与1键无冲突的概率当然是1.与2键无冲突的概率为1 * (n-1)/n
。等等所有k
键。为方便起见,Mathematica有一个Pochhammer[]函数来简洁地表达这个:
p(no collision for k keys) = Pochhammer[n-(k-1),k]/n^k
然后,要计算k
个密钥至少发生1次冲突的概率,请从1减去它:
p(k) = 1 - p(no collision for k keys) = 1 - Pochhammer[n-(k-1),k]/n^k
使用Mathematica,可以计算n=2^64
:
假设合理数量的密钥(例如,少于10,000个密钥)的碰撞是如此不可能是安全的,因此如果2个哈希码相同,我们可以说密钥是相同的而无需进一步检查?
准确地回答这个问题取决于10,000个密钥中的2个是相同的概率。我们要找的是:
p(a=b|h(a)=h(b)) = The probability that a=b given h(a)=h(b)
其中a
和b
是键(可能相同),h()
是散列函数。我们可以直接申请Bayes' Theorem:
p(a=b|h(a)=h(b)) = p(h(a)=h(b)|a=b) * p(a=b) / p(h(a)=h(b))
我们立即看到p(h(a)=h(b)|a=b) = 1
(如果a=b
当然是h(a)=h(b)
),那么我们就得到了
p(a=b|h(a)=h(b)) = p(a=b) / p(h(a)=h(b))
正如您所看到的,这取决于p(a=b)
a
和b
实际上是同一个键的概率。这取决于首先如何选择10,000组密钥。前两个问题的计算假设所有键都是不同的,因此需要有关此方案的更多信息才能完全回答它。
答案 1 :(得分:1)
考虑到所谓的生日悖论,是否存在估算碰撞概率的公式?
请参阅:Birthday attack。
假设散列的分布是均匀的,n
键的碰撞概率大约为n 2 / 2 65 。
假设合理数量的密钥(例如,少于10,000个密钥)的冲突是如此不可能是否安全,以便如果2个哈希码不同,我们可以说密钥是不同的而无需进一步检查?< / p>
使用加密哈希函数时,这是唯一安全的。即使你可以容忍每3 * 10 11 次的错误,你可能不得不考虑输入是专门构建来创建哈希冲突的可能性,作为对程序的攻击。</ p >
答案 2 :(得分:1)
我将提供其他答案中提供的确切公式的粗略近似值;近似值可以帮助您回答#3。粗略近似是对于k <&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; ñ。对于具有64位散列的100,000个密钥,这是10 ^ 10 / 32x10 ^ 18或大约1/30亿。
但是,我怀疑如果你没有检查碰撞时的实际键值,那么你很可能会发现哈希算法毕竟不够“好”。
答案 3 :(得分:1)
1)是否有一个公式来估计碰撞的可能性 考虑到所谓的生日悖论?
发生单次碰撞的概率取决于生成的密钥集,因为哈希函数是统一的,我们可以按照以下方式计算碰撞在生成k密钥时不发生的概率: -
x = hash size
p(k=2) = (x-1)/x
p(k=3) = p(k=2)*(x-2)/x
..
p(k=n) = (x-1)*(x-2)..(x-n+1)/x^n
p(k=n) ~ e^-(n*n)/2x
p(collision|k=n) = 1-p(k=n) = 1 - e^(-n^2)/2x
p(collision) > 0.5 if n ~ sqrt(x)
因此,如果生成sqrt(2^64)
密钥2^32
密钥,则发生单次冲突的可能性更高。
2)你能估计碰撞的概率(即两个关键点 哈希到相同的值)?让我们说1000键和10,000 键?
x = 2^64
Use the formula pc(k=n) = 1 - e^-(n^2)/2x
3)假设合理数量的碰撞是否安全 密钥(比如,少于10,000个密钥)是如此不可能,所以如果2哈希 我们可以说代码是相同的,没有任何代码 进一步检查?
这是一个非常有趣的问题,因为它取决于密钥空间的大小。假设您的密钥是从size = s
的空格中随机生成的,并且正如您所提到的那样,哈希空间为x=2^64
。碰撞概率为Pc(k=n|x) = 1-e^(-n^2)/2x
。如果在密钥空间中选择相同密钥的概率为P(k=n|s) = 1-e^(-n^2)/2s
。为了确保如果哈希是相同的,那么键是相同的: -
P(k=n|s) > Pc(k=n|x)
1-e^-(n^2/2s) > 1-e^-(n^2/2x)
n^2/2s > n^2/2x
s < x
s < 2^64
因此,它表明,如果散列相同,则密钥相同,密钥集大小必须小于2^64
,否则哈希中的冲突可能比密钥集更多。结果与生成的密钥数无关。