64位哈希码冲突的概率

时间:2014-02-26 00:09:40

标签: algorithm math hash statistics probability

“数字食谱”一书提供了一种计算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!

4 个答案:

答案 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)

其中ab是键(可能相同),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) ab实际上是同一个键的概率。这取决于首先如何选择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,否则哈希中的冲突可能比密钥集更多。结果与生成的密钥数无关。