Python 如何计算查找冲突所需的哈希数?
我正在开发一个程序,该程序使用十六进制字符将图像URL散列为10个字符的字符串,例如64fd54ad29 它是用Python编写的,散列计算如下:Python 如何计算查找冲突所需的哈希数?,python,hash,cryptography,Python,Hash,Cryptography,我正在开发一个程序,该程序使用十六进制字符将图像URL散列为10个字符的字符串,例如64fd54ad29 它是用Python编写的,散列计算如下: def hash_short(self, url): return hashlib.sha1(url).hexdigest()[:10] 我担心与如此短的哈希冲突。我预计大约100万次哈希之后会发生冲突,但当我运行蛮力时,我需要1000万次哈希 计算 十六进制数字有16个可能的值,或2^4。对于10个字符,我有2^40个可能性,或40位熵
def hash_short(self, url):
return hashlib.sha1(url).hexdigest()[:10]
我担心与如此短的哈希冲突。我预计大约100万次哈希之后会发生冲突,但当我运行蛮力时,我需要1000万次哈希
计算
十六进制数字有16个可能的值,或2^4。对于10个字符,我有2^40个可能性,或40位熵
为了获得1的概率,我们需要查看2^40+1 URL(根据鸽子洞原理),但我们预计冲突会更快
n位哈希的生日攻击(即暴力攻击)将在2^(n/2)次尝试后发现冲突。因此,我们将在大约2^20个URL后看到冲突,即1048576
暴力强迫
我编写了一个简单的Python脚本,它迭代了一长串URL,并将每个哈希值与我以前看到的进行了比较。我花了10800000个URL找到我的第一个冲突:“http://c69025.r25.cf3.rackcdn.com/_image1/_Model/34897.jpg“
和”http://media.editd.com/assets/matrix/full/72f9a997b67c65c66f4adc769ee0a127d1db25eb.jpg“
将两个哈希都添加到“ba2be44bd1”
总结
不是我的数学不正确就是我很不走运。是哪一个?我有多倒霉?我想你的碰撞检测代码错了:
import hashlib
import random
import string
def hash_short(url):
return hashlib.sha1(url).hexdigest()[:10]
hashes = dict()
while True:
if len(hashes) % 10000 == 0:
print len(hashes)
newurl = ''.join(random.choice(string.lowercase) for _ in xrange(30))
newhash = hash_short(newurl)
if newhash in hashes and newurl != hashes[newhash]:
print 'found a collision!'
print newhash
print newurl
print hashes[newhash]
print len(hashes)
break
hashes[newhash] = newurl
输出(运行一次):
很明显,我所谓的URL不是,但这应该与一个好的散列函数没有区别(SHA1适合于此)。如果您发现一个数据集在SHA1的前5个字节上的冲突率非常低,那么做得很好!请使用最后5个字节重试:-) 你有多倒霉?当你有1000万个散列时,你的
2**40
空间已经占满了大约100k的一部分。因此,没有碰撞的概率大致为(手指悬空),(99999.0/100000)**1000万,即3.7e-44
。所以,如果我的数学是正确的[编辑:事实并非如此,请参阅评论]你在天文学上被判有罪,毫无疑问是不幸的
作为一个保守的概率上限,在已经有100万个哈希之后,你进行了900万次试验。无碰撞的概率严格小于(999999.0/1000000)**9000000
,仅为0.0001。您可以通过进一步拆分来生成更小的边界:您进行了100万次试验,占用了900万个哈希。或者你可以精确地计算概率(CodesInChaos做到了:1e-20
)
因此,贝叶斯统计就是这样,我估计代码中出现错误的概率比所有这些数字都高,即使是非常大的保守界:-)您尝试过多少次?您的代码不正确。它应该只需要那么长的时间,概率为10^-20@alKid我只搜索了一次冲突,但我使用的是程序中的实际URL。@code我已经添加了代码。这是非常简单的东西,我没有看到任何明显的错误。@CodesInChaos:你使用了和我一样的估算技术(即你在抱怨我的计算器)还是更好的估算技术(即你在抱怨我的手指在空中)?我使用了两种技术。根据经验:exp(-0.5*10^2)
作为一种正确的技术n=2**40;p=1;对于(inti=0;;i++){p*=(n-i)/n;}
@CodesInChaos:那就足够了。不过,正如你所说,我的估计“只”差10^-20;-)“用最后5个字节再试一次”啊哈!我尝试了不同的5字节片段,发现140万和190万个URL之间的冲突取决于片段。我不得不得出结论,给我的数据集一直在丢弃具有相同散列的URL。@Wilfredhaughes:啊,是的,我没有想到创建你的数据集的人可能知道你在计划什么,并采取行动破坏你的一天;-)
import hashlib
import random
import string
def hash_short(url):
return hashlib.sha1(url).hexdigest()[:10]
hashes = dict()
while True:
if len(hashes) % 10000 == 0:
print len(hashes)
newurl = ''.join(random.choice(string.lowercase) for _ in xrange(30))
newhash = hash_short(newurl)
if newhash in hashes and newurl != hashes[newhash]:
print 'found a collision!'
print newhash
print newurl
print hashes[newhash]
print len(hashes)
break
hashes[newhash] = newurl
...
770000
780000
found a collision!
216be03ec7
txnbkwrfkpkmiexloxrifdsnjumkex
xlnmlhobtsswjvmqnjupaybkspptpo
780758