Как оценить вероятность столкновения хэшей?

Я разрабатываю back-end приложение для поисковой системы. Система поиска копирует файлы во временный каталог и дает им случайные имена. Затем он передает имена временных файлов в мое приложение. Мое приложение должно обрабатывать каждый файл в течение ограниченного периода времени, в противном случае он отключается - это мера безопасности, подобная сторожевому таймеру. Обработка файлов, вероятно, займет много времени, поэтому мне нужно разработать приложение, способное обрабатывать этот сценарий. Если мое приложение будет отключено в следующий раз, когда поисковая система хочет индексировать один и тот же файл, он, скорее всего, даст ему другое временное имя.

Очевидным решением является предоставление промежуточного слоя между поисковой системой и бэкэнд. Он поставит очередь на запрос на бэкэнд и дождитесь, пока результат не появится. Если запрос истекает на промежуточном уровне - без проблем, бэкэнд продолжит работу, перезапускается только промежуточный уровень, и он может извлечь результат из бэкэнд, когда запрос будет повторно повторен поисковой системой.

Проблема заключается в том, как идентифицировать файлы. Их имена изменяются случайным образом. Я намерен использовать хеш-функцию, такую ​​как MD5, для хеширования содержимого файла. Я хорошо знаю парадокс дня рождения и использовал оценку из связанной статьи для вычисления вероятности. Если я предполагаю, что у меня есть не более 100 файлов, вероятность того, что два файла имеют тот же MD5 (128 бит), составляет около 1,47x10 -29.

Должен ли я заботиться о такой вероятности столкновения или просто предположить, что равные хеш-значения означают равное содержимое файла?

Ответ 1

Равный хеш означает равный файл, если только кто-то вредоносный не вмешивается в ваши файлы и не вводит коллизии. (это может быть так, если они загружают материал из Интернета). Если это так, перейдите на функцию на основе SHA2.

Нет случайных столкновений MD5, 1,47x10 -29 - действительно действительно очень небольшое число.

Чтобы преодолеть проблему переименования больших файлов, у меня была бы схема с тремя фазами.

  • Только размер файла
  • Размер файла + хэш 64K * 4 в разных позициях в файле
  • Полный хэш

Итак, если вы видите файл с новым размером, вы наверняка знаете, что у вас нет дубликата. И так далее.

Ответ 2

Думаю, что не стоит.

Однако, если у вас есть понятие двух равных файлов, имеющих разные (настоящие имена, а не md5-based). Например, в поисковой системе два документа могут иметь точно такое же содержимое, но быть разными, потому что они расположены в разных местах.

Ответ 3

Просто потому, что вероятность равна 1/X, это не значит, что это не произойдет с вами, пока у вас не будет записей X. Это похоже на лотерею, вы вряд ли выиграете, но кто-то там победит.

Благодаря скорости и емкости компьютеров в эти дни (даже не говоря о безопасности, просто надежности) нет причин не просто использовать более крупную/улучшенную хеш-функцию, чем MD5 для чего-либо критического. Переход на SHA-1 должен помочь вам лучше спать по ночам, но если вы хотите быть осторожным, то отправляйтесь на SHA-265 и никогда больше не задумывайтесь об этом.

Если производительность действительно является проблемой, используйте BLAKE2, который на самом деле быстрее MD5, но поддерживает 256 бит, чтобы сделать конфликты менее вероятными при одинаковой или лучшей производительности. Однако, хотя BLAKE2 был хорошо принят, вероятно, потребуется добавить новую зависимость к вашему проекту.

Ответ 4

Я придумал подход Монте-Карло, чтобы иметь возможность спокойно спать, используя 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

Я слышал формулу раньше: если вам нужно хранить ключи журнала (x/2), используйте функцию хэширования, которая имеет по крайней мере пространство ключей e ** (x).

Повторные эксперименты показывают, что для популяции 1000 лог-20 пробелов вы иногда получаете столкновение уже в журнале (x/4).

Для uuid4, который составляет 122 бита, это означает, что я безопасно спал, в то время как несколько компьютеров выбирают случайный uuid, пока у меня не будет около 2 ** 31 предметов. Пиковые транзакции в системе, о которой я думаю, составляют примерно 10-20 событий в секунду, я принимаю в среднем 7 баллов. Это дает мне окно работы примерно 10 лет с учетом крайней паранойи.