如何计算我需要多少哈希才能找到碰撞?

时间:2013-11-01 13:06:49

标签: python hash cryptography

我正在开发一个程序,该程序使用十六进制字符将图像URL散列为10个字符的字符串,例如: 64fd54ad29。

用Python编写,哈希计算如下:

def hash_short(self, url):
     return hashlib.sha1(url).hexdigest()[:10]

我担心与这么短的哈希冲突。我预计在大约一百万次哈希之后会发生碰撞,但是当我遇到蛮力时我需要一千万次哈希。

计算

十六进制数字有16个可能的值,或2 ^ 4。有十个字符,我有2 ^ 40种可能性,或40位熵。

如果概率为1,我们需要查看2 ^ 40 + 1个URL(通过鸽子原理),但我们会更快地发现碰撞。

n位散列的生日攻击(即暴力)将在2 ^(n / 2)次尝试后发现冲突。因此,我们会在大约2 ^ 20个网址后看到一次冲突,即1,048,576。

暴力强迫

我编写了一个简单的Python脚本,它迭代了很长的URL列表,并将每个哈希值与我之前看到的哈希值进行了比较。我花了10,800,000个网址来查找我的第一次碰撞:"http://c69025.r25.cf3.rackcdn.com/_image1/_Model/34897.jpg""http://media.editd.com/assets/matrix/full/72f9a997b67c65c66f4adc769ee0a127d1db25eb.jpg"都哈希到"ba2be44bd1"

import hashlib
import json

def calculate_short_hash(url):
    return hashlib.sha1(url).hexdigest()[:10]


def url_from_json(json_string):
    return json.loads(json_string)['image_url']

if __name__ == '__main__':
    short_hashes = set()

    for i, line in enumerate(open('urls.all')):
        short_hash = calculate_short_hash(url_from_json(line))

        if short_hash in short_hashes:
            print "Already seen: %s" % short_hash
            break
        else:
            short_hashes.add(short_hash)

        if i % 100000 == 0:
            print "Processed %d lines" % (i,)

摘要

要么我的数学不正确,要么我非常不走运。这是什么?我有点不走运?

1 个答案:

答案 0 :(得分:1)

我认为你的碰撞检测代码是错误的:

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

显然我的所谓网址不是,但是应该与好的哈希函数没有区别(并且SHA1有利于此目的)。如果你发现一个数据集在SHA1的前5个字节上确实具有异常低的冲突率,那么做得好!用最后5个字节再试一次: - )

你有点不走运?当你有1000万个哈希时,你的2**40空间已经满了大约100k的一部分。所以没有碰撞的概率大致是(手指在空中),(99999.0/100000) ** 10 million,即3.7e-44。因此,如果我的数学是正确的[编辑:它不是,请参阅评论]你是天文数字,被定罪 - 超出合理怀疑不幸。

作为偶然发生碰撞概率的保守上限,在已经有100万个哈希值发挥作用之后,你进行了900万次试验。没有碰撞的概率严格小于(999999.0 / 1000000) ** 9000000,仅为0.0001。你可以通过进一步分割它来产生更小的界限:你进行了100万次试验,占用了900万个哈希值。或者您可以精确计算概率(CodesInChaos所做的:1e-20

所以,贝叶斯统计数据就是这样,我认为你的代码中的错误概率高于所有这些数字,即使是非常大的保守界: - )