Можно ли использовать CRC32 в качестве хеш-функции?

Можно ли использовать CRC32 в качестве хеш-функции? Есть ли у этого подхода недостатки? Любые компромиссы?


person Pradyot    schedule 08.06.2012    source источник
comment
Уже вроде бы спрашивают. stackoverflow.com/questions/2694740/   -  person Pradyot    schedule 08.06.2012
comment
Это зависит от того, для чего вы хотите использовать хеш.   -  person Gumbo    schedule 08.06.2012
comment
Для некоторого подмножества установленного хэша - да. Однако это не блочный код, это потоковый код. Для очень маленьких блоков быстрее использовать стол.   -  person starbolin    schedule 08.06.2012


Ответы (3)


CRC32 очень хорошо работает как алгоритм хеширования. Весь смысл CRC состоит в том, чтобы хэшировать поток байтов с минимальным количеством конфликтов, насколько это возможно. Тем не менее, есть несколько моментов, которые следует учитывать:

  • CRC небезопасны. Для безопасного хеширования вам понадобится гораздо более затратный в вычислительном отношении алгоритм. Для простого хэшера ведра безопасность обычно не является проблемой.

  • Существуют разные ароматы CRC с разными свойствами. Убедитесь, что вы используете правильный алгоритм, например с хеш-полиномом 0x11EDC6F41 (CRC32C), который является оптимальным выбором общего назначения.

  • Как компромисс между скоростью хеширования и качеством, инструкцию x86 CRC32 сложно превзойти. Однако этой инструкции нет в старых процессорах, поэтому остерегайтесь проблем с переносимостью.

---- РЕДАКТИРОВАТЬ ----

Марк Адлер предоставил ссылку на полезную статью Брета Малви по оценке хэша. Используя исходный код, представленный в статье, я провел «тест корзины» как для CRC32C, так и для Jenkins96. Эти таблицы показывают вероятность того, что действительно равномерное распределение будет хуже, чем результат измерения случайно. Итак, большее число лучше. Автор считал 0,05 или меньше слабым, а 0,01 или меньше очень слабым. Во всем этом я полностью доверяю автору и просто сообщаю результаты.

Я поставил * все экземпляры, в которых CRC32C работает лучше, чем Jenkins96. Судя по этому простому подсчету, CRC32C был более однородным хешем, чем Jenkins96 54 из 96 раз. Особенно, если вы можете использовать инструкцию x86 CRC32, соотношение скорости и производительности будет отличным.

CRC32C (0x1EDC6F41)

       Uniform keys        Text keys         Sparse keys

Bits  Lower    Upper     Lower    Upper     Lower    Upper
 1    0.671   *0.671    *1.000    0.120    *0.572   *0.572
 2   *0.706   *0.165    *0.729   *0.919     0.277    0.440
 3   *0.878   *0.879    *0.556    0.362    *0.535   *0.542
 4    0.573    0.332     0.433    0.462    *0.855    0.393
 5    0.023   *0.681     0.470    0.907     0.266    0.059
 6   *0.145   *0.523     0.354   *0.172    *0.336    0.588
 7    0.424    0.722     0.172   *0.736     0.184   *0.842
 8   *0.767    0.507    *0.533    0.437     0.337    0.321
 9    0.480    0.725    *0.753   *0.807    *0.618    0.025
10   *0.719    0.161    *0.970   *0.740    *0.789    0.344
11   *0.610    0.225    *0.849   *0.814    *0.854   *0.003
12   *0.979   *0.239    *0.709    0.786     0.171   *0.865
13   *0.515    0.395     0.192    0.600     0.869   *0.238
14    0.089   *0.609     0.055   *0.414    *0.286   *0.398
15   *0.372   *0.719    *0.944    0.100    *0.852   *0.300
16    0.015   *0.946    *0.467    0.459     0.372   *0.793

А для Jenkins96, который автор статьи посчитал отличным хешем:

Jenkins96

      Uniform keys         Text keys         Sparse keys

Bits  Lower    Upper     Lower    Upper     Lower    Upper
 1    0.888    0.572     0.090    0.322     0.090    0.203
 2    0.198    0.027     0.505    0.447     0.729    0.825
 3    0.444    0.510     0.360    0.444     0.467    0.540
 4    0.974    0.783     0.724    0.971     0.439    0.902
 5    0.308    0.383     0.686    0.940     0.424    0.119
 6    0.138    0.505     0.907    0.103     0.300    0.891
 7    0.710    0.956     0.202    0.407     0.792    0.506
 8    0.031    0.552     0.229    0.573     0.407    0.688
 9    0.682    0.990     0.276    0.075     0.269    0.543
10    0.382    0.933     0.038    0.559     0.746    0.511
11    0.043    0.918     0.101    0.290     0.584    0.822
12    0.895    0.036     0.207    0.966     0.486    0.533
13    0.290    0.872     0.902    0.934     0.877    0.155
14    0.859    0.568     0.428    0.027     0.136    0.265
15    0.290    0.420     0.915    0.465     0.532    0.059
16    0.155    0.922     0.036    0.577     0.545    0.336
person srking    schedule 09.06.2012
comment
Нет, CRC не избегает коллизий, как и другие алгоритмы. См. home.comcast.net/~bretm/hash. - person Mark Adler; 10.06.2012
comment
@Mark, автор не использовал полином CRC32C. CRC32C прекрасно работает как хеш для разбивки строк байтов в его тестовую программу. - person srking; 11.06.2012
comment
Хорошее исследование! +1. Однако я все еще не думаю, что даже с инструкцией crc32 она превзойдет алгоритмы хеширования, предназначенные для (не криптографического) хеширования. Вы можете найти более сложные разработки и тестирование алгоритмов хеширования здесь: code.google.com/p/smhasher < / а>. - person Mark Adler; 11.06.2012
comment
@Mark, спасибо за еще одну хорошую ссылку. Я не знаю о качестве хеширования, но автор указывает ~ 29 тактов на 16 байт для murmerhash3, по сравнению с инструкцией CRC32C, которая составляет ~ 6 тактов на 16 байт. Я придерживаюсь своей истории, что инструкция CRC32C - это золотая середина. - person srking; 11.06.2012
comment
Кстати, Брет Малви переместил этот сайт несколько месяцев назад по адресу: bretmulvey.com/hash - person Nico Erfurth; 27.08.2014
comment
инструкция Intel CRC32 имеет задержку 3 и пропускную способность 1 и может занимать 8 байт за раз (если я правильно понял документацию). Это означает, что вы можете получить 8 байтов за цикл (если у вас достаточно длинный ввод). Для меньших выходов 8 байтов = 4 цикла (3 + 1), 16 байтов = 5 циклов (3 +1), 24 байта = 6 (3 + 3) и т. Д. - person RubenLaguna; 02.07.2015
comment
после небольшого исследования, задержка в 3 цикла означает, что если следующая инструкция CRC32 зависит от вывода первой, то она должна подождать. Вот почему вы часто видите, что входные данные делятся на 3 части, и все фрагменты обрабатываются параллельно, так что эти 3 инструкции не зависят друг от друга и, следовательно, конвейер может оставаться заполненным. - person RubenLaguna; 03.07.2015
comment
У SMHasher теперь есть форк на Github: github.com/rurban/smhasher Интересно, что CRC упоминается в раздел с проблемными хеш-функциями с примечанием: небезопасный, 100% предвзятость, коллизии, distrib. Я не совсем понимаю, что это значит :) - person Max Galkin; 16.05.2016
comment
@NicoErfurth: Спасибо за будущее, веб-архив не зацепил страницу до того, как она исчезла. - person i336_; 04.05.2017
comment
Все еще нет. И CRC-32, и CRC-32C резко не прошли лавинный тест. - person Mark Adler; 18.11.2018
comment
Страница снова переместилась, и низкие жизни живут по адресу papa.bretmulvey.com/post/124027987928/hash -функции - person Lorenz; 30.09.2020
comment
Я могу подтвердить, что crc32 (включая c) довольно плох с точки зрения коллизий: я только что провел несколько тестов своей хеш-таблицы в английском словаре на 150 тыс. Слов и емкости 300 тыс., И crc32 давал в среднем 1140 коллизий на хэш, тогда как fnv-1a только дал 1.5 - person abel1502; 10.04.2021

Я не знаю, почему Марк Адлер сказал, что «crc32 плохо распределяет входные биты по хешу». В хэше crc32 нет ни одного бита, который в точности равнялся бы входным битам. Любой бит хеша представляет собой линейную комбинацию входных битов. Во-вторых, crc всегда равномерно отображает одно и то же количество различных входных последовательностей на заданное значение хеш-функции. Например, если у вас есть сообщение длиной 1000 бит, после crc32 вы всегда можете найти 2 ^ (1000-32) последовательности, которые производят заданное хеш-значение, не больше и не меньше.

Если вам не нужна функция безопасности, crc может отлично служить хешем.

На самом деле, я думаю, что другие незащищенные хэш-функции могут быть проще, чем crc, если вам нужно иметь более длинный crc, например crc-256.

person Heng Tang    schedule 27.02.2015
comment
Я полагаю, он сказал, что, поскольку CRC не проходит тесты статистической случайности - равномерно распределен по диапазону кода, нет смещения в сторону определенных битов. - person bryc; 05.12.2017

CRC32 преобразует байты в 32-битные целые числа перед их накоплением с помощью xor. Это означает, что каждый байт влияет только на 8 из 32 бит вашего хеша. Конечно, CRC32 тоже переключается, но это только скрывает проблему под ковриком. Т.е. он будет распределять ключи неравномерно, в каком-то регионе будет сильная кластеризация. Может показаться, что такой хеш работает нормально, пока вы не попадете в этот регион, и вдруг ваша хеш-таблица O (1) превратится в таблицу O (n).

CRC32 был разработан для обнаружения поврежденных файлов, а не для хеширования. И, как упомянул Марк, это не защитит ваши файлы от изменений, поскольку хакеры могут изменять их по своему желанию, просто вставив правильно созданное 32-битное значение после изменения.

person Nash Gold    schedule 05.10.2020