web-dev-qa-db-ja.com

ハッシュ衝突の確率を評価するにはどうすればよいですか?

検索システム用のバックエンドアプリケーションを開発しています。検索システムはファイルを一時ディレクトリにコピーし、ランダムな名前を付けます。次に、一時ファイルの名前をアプリケーションに渡します。私のアプリケーションは、限られた時間内に各ファイルを処理する必要があります。そうしないと、ファイルはシャットダウンされます。これは、ウォッチドッグのようなセキュリティ対策です。ファイルの処理には時間がかかる可能性があるため、このシナリオを処理できるアプリケーションを設計する必要があります。次回検索システムが同じファイルにインデックスを付けたいときにアプリケーションがシャットダウンした場合、別の一時的な名前が付けられる可能性があります。

明らかな解決策は、検索システムとバックエンドの間に中間層を提供することです。リクエストをバックエンドにキューイングし、結果が到着するのを待ちます。リクエストが中間レイヤーでタイムアウトした場合(問題ありません)、バックエンドは引き続き機能し、中間レイヤーのみが再起動され、後で検索システムによってリクエストが繰り返されたときにバックエンドから結果を取得できます。

問題は、ファイルを識別する方法です。彼らの名前はランダムに変わります。 MD5のようなハッシュ関数を使ってファイルの内容をハッシュするつもりです。 誕生日のパラドックス をよく知っており、リンクされた記事からの推定値を使用して確率を計算しました。 10万個以下のファイルがあると仮定すると、2つのファイルが同じMD5(128ビット)を持つ確率は約1,47x10です。-29

そのような衝突確率を気にする必要がありますか、それともハッシュ値が等しいとファイルの内容が等しいと仮定する必要がありますか?

27
sharptooth

悪意のある誰かがあなたのファイルをいじって衝突を注入していない限り、等しいハッシュは等しいファイルを意味します。 (これは、インターネットからコンテンツをダウンロードしている場合に当てはまる可能性があります)その場合は、SHA2ベースの機能を使用してください。

偶発的なMD5衝突はなく、1,47x10-29 本当に本当に本当に少ない数です。

大きなファイルの再ハッシュの問題を克服するために、私は3段階のIDスキームを使用します。

  1. ファイルサイズのみ
  2. ファイルサイズ+ファイル内のさまざまな位置にある64K * 4のハッシュ
  3. 完全なハッシュ

したがって、新しいサイズのファイルが表示された場合は、重複がないことが確実にわかります。等々。

39
Sam Saffron

確率が1/Xであるからといって、Xレコードが得られるまでそれが起こらないという意味ではありません。宝くじのようなもので、勝つ可能性は低いですが、誰かそこに意志勝ちます。

最近のコンピューターの速度と容量(セキュリティについても、信頼性についても話していません)を考えると、重要なことに対してMD5よりも大きい/優れたハッシュ関数を使用しない理由は実際にはありません。 SHA-1にステップアップすると、夜の睡眠が良くなるはずですが、特に注意したい場合は、SHA-265にアクセスして、二度と考えないでください。

パフォーマンスが本当に問題である場合は、実際にはMD5よりも高速ですが256ビット以上をサポートするBLAKE2を使用して、同じかそれ以上のパフォーマンスで衝突の可能性を低くします。ただし、BLAKE2は十分に採用されていますが、プロジェクトに新しい依存関係を追加する必要がある可能性があります。

4
ColinM

私はあなたがすべきではないと思います。

ただし、2つの等しいファイルが異なる(md5ベースではなく実際の名前)という概念がある場合は、そうする必要があります。同様に、検索システムでは、2つのドキュメントのコンテンツはまったく同じである可能性がありますが、異なる場所にあるため、区別されます。

3
alamar

衝突せずにシリアル化する必要がある分散システムにUUIDを使用しながら、安全にスリープできるようにするためのモンテカルロアプローチを思いつきました。

from random import randint
from math import log
from collections import Counter

def colltest(exp):
    uniques = []
    while True:
        r = randint(0,2**exp)
        if r in uniques:
            return log(len(uniques) + 1, 2)
        uniques.append(r)

for k,v in Counter([colltest(20) for i in xrange(1000)]):
    print k, "hash orders of magnitude events before collission:",v

次のようなものを印刷します:

5 hash orders of magnitude events before collission: 1
6 hash orders of magnitude events before collission: 5
7 hash orders of magnitude events before collission: 21
8 hash orders of magnitude events before collission: 91
9 hash orders of magnitude events before collission: 274
10 hash orders of magnitude events before collission: 469
11 hash orders of magnitude events before collission: 138
12 hash orders of magnitude events before collission: 1

以前に式を聞いたことがあります。log(x/2)キーを格納する必要がある場合は、少なくともキースペースe **(x)を持つハッシュ関数を使用してください。

繰り返された実験は、1000 log-20スペースの母集団の場合、log(x/4)という早い段階で衝突が発生することがあることを示しています。

122ビットのuuid4の場合、約2 ** 31個のアイテムができるまで、いくつかのコンピューターがランダムなuuidを選択している間、安全にスリープすることを意味します。私が考えているシステムのピークトランザクションは、1秒あたり約10〜20イベントであり、平均7と想定しています。極端なパラノイアを考えると、約10年の運用ウィンドウが得られます。

これは、任意のハッシュサイズとオブジェクト数の衝突の確率を推定できるインタラクティブな計算機です http://everydayinternetstuff.com/2015/04/hash-collision-probability-calculator/

0
Ghostrider