64fd54ad29 などの 16 進数文字を使用して、画像 URL を 10 文字の文字列にハッシュするプログラムに取り組んでいます。
これは Python で書かれており、ハッシュは次のように計算されます。
def hash_short(self, url):
return hashlib.sha1(url).hexdigest()[:10]
このような短いハッシュとの衝突が心配です。約 100 万回のハッシュ後に衝突を予想していましたが、ブルート フォースを実行すると 1,000 万回のハッシュが必要になりました。
計算
16 進数には 16 の可能な値、つまり 2^4 があります。10 文字の場合、2^40 の可能性、つまり 40 ビットのエントロピーがあります。
確率を 1 にするには、2^40 + 1 個の URL を確認する必要がありますが (ピジョンホールの原理により)、衝突はもっと早く発生すると予想されます。
n ビット ハッシュの誕生日攻撃 (つまりブルート フォース) は、2^(n/2) 回の試行後に衝突を検出します。したがって、約 2^20 の URL、つまり 1,048,576 の後に衝突が見られます。
ブルートフォース
URL の長いリストを反復処理し、各ハッシュを以前に見たものと比較する単純な Python スクリプトを作成しました。"http://c69025.r25.cf3.rackcdn.com/_image1/_Model/34897.jpg"
最初の衝突を見つけるのに 10,800,000 個の URL が必要でした。"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,)
概要
私の計算が間違っているか、運が悪かったかのどちらかです。それはどれですか?私はどれほど不運でしたか?