Что такое хорошая хеш-функция?

Что такое хорошая хеш-функция? Я видел много хеш-функций и приложений на моих курсах по структурам данных в колледже, но в основном я понял, что довольно сложно создать хорошую хеш-функцию. Мой профессор, как показывает опыт, чтобы избежать столкновений, сказал:

function Hash(key)
  return key mod PrimeNumber
end

(mod - это оператор% в C и подобных языках)

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

Рассматривали ли вы использование одной или нескольких из следующих хеш-функций общего назначения: partow.net/programming/hashfunctions/index.html

Matthieu N. 24.10.2009 13:04

В fnv_func тип p [i] - char, что произойдет с h после первой итерации? Это было сделано специально?

user921223 31.08.2011 12:49

@martinatime сказал: В википедии en.wikipedia.org/wiki/Hash_function есть много информации о хэш-функциях, а в нижней части этой статьи partow.net/programming/hashfunctions/index.html содержит алгоритмы, реализованные на разных языках.

2501 28.06.2016 11:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
136
3
161 317
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Я бы сказал, что главное практическое правило - не катить самостоятельно. Попробуйте использовать что-то, что было тщательно протестировано, например, SHA-1 или что-то в этом роде.

Кажется, ему не нужно ничего криптографически безопасного, поэтому SHA-1 будет излишним.

Erik 20.08.2012 14:29

кстати, хотя никаких коллизий для SHA-1 обнаружено не было, считается, что их обнаружение займет несколько лет или месяцев. Я бы рекомендовал использовать SHA-256.

Samuel Allan 02.04.2014 17:56

Для универсальных хешей не существует такой вещи, как «хорошая хеш-функция» (ред. Да, я знаю, что есть такая вещь, как «универсальное хеширование», но я не это имел в виду). В зависимости от контекста качество хеша определяется разными критериями. Два человека уже упоминали SHA. Это криптографический хеш, и он совсем не подходит для хеш-таблиц, о которых вы, вероятно, имеете в виду.

К хеш-таблицам предъявляются самые разные требования. Но все же найти универсальную хорошую хеш-функцию сложно, потому что разные типы данных предоставляют разную информацию, которая может быть хеширована. Как правило, полезно рассматривать информацию все, которую имеет тип в равной степени. Это не всегда легко или даже возможно. По причинам статистики (и, следовательно, столкновения) также важно создать хороший разброс по проблемному пространству, то есть по всем возможным объектам. Это означает, что при хешировании чисел от 100 до 1050 не следует позволять старшей цифре играть большую роль в хеш-функции, потому что для ~ 90% объектов эта цифра будет равна 0. Гораздо важнее оставить последние три цифры. цифры определяют хеш.

Точно так же при хешировании строк важно учитывать все символы, за исключением случаев, когда заранее известно, что первые три символа всех строк будут одинаковыми; учитывая это, то это пустая трата.

На самом деле это один из случаев, когда я советую прочитать, что говорит Кнут в Искусство программирования, vol. 3. Еще одно хорошее чтение - Искусство хеширования Жюльен Уокер.

Конрад, вы, безусловно, правы с теоретической точки зрения, но пробовали ли вы когда-нибудь использовать хеш-функцию Пола Хси, о которой я упоминал в своем комментарии? Это действительно неплохо для множества различных данных!

Chris Harris 01.07.2009 12:55

Хорошая хеш-функция имеет следующие свойства:

  1. Учитывая хэш сообщения, злоумышленник с вычислительной точки зрения не может найти другое сообщение, в котором их хеши идентичны.

  2. Для данной пары сообщений m 'и m вычислительно невозможно найти два таких, что h (m) = h (m')

Два случая нет одинаковы. В первом случае существует уже существующий хэш, для которого вы пытаетесь найти коллизию. Во втором случае вы пытаетесь найти два конфликтующих сообщения любой. Вторая задача значительно проще за счет «парадокса» дня рождения.

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

Не используйте MD5 или SHA-1 в новых проектах. Большинство криптографов, включая меня, сочли бы их взломанными. Главный источник слабости обоих этих конструкций заключается в том, что второе свойство, которое я обозначил выше, не выполняется для этих конструкций. Если злоумышленник может сгенерировать два сообщения, m и m ', оба хеш-значения которых имеют одно и то же значение, они могут использовать эти сообщения против вас. SHA-1 и MD5 также страдают от атак с расширением сообщений, которые могут фатально ослабить ваше приложение, если вы не будете осторожны.

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

Надеюсь, это поможет!

Я думаю, что рекомендация криптографической хеш-функции - действительно плохой совет в этом случае.

Slava 29.12.2016 21:26

@ Слава: Почему? По каким причинам вы говорите, что «криптографическая хеш-функция - действительно плохой совет в данном случае»? Почему это плохой совет? Какие относительные недостатки делают это так?

Let Me Tink About It 02.04.2018 22:33

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

Slava 03.04.2018 05:45

Есть две основные цели хеш-функций:

  • для равномерного распределения точек данных на n бит.
  • для надежной идентификации входных данных.

Невозможно рекомендовать хеш, не зная, для чего вы его используете.

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

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

обновлена ​​ссылка на The Hash Function Lounge: larc.usp.br/~pbarreto/hflounge.html

Tim Partridge 21.11.2011 18:46

Насколько хорошо FNV выдерживает коллизию по случаю дня рождения по сравнению, скажем, с таким же количеством бит в SHA1?

Kevin Hsu 10.12.2011 01:26

@Kevin Пока лавинообразные характеристики хэша хороши (крошечные изменения на входе = большие изменения на выходе), коллизии по случаю дня рождения являются просто функцией битов в хэше. FNV-1a превосходен в этом отношении, и вы можете иметь столько битов в хэше, сколько захотите (хотя требуется немного дополнительных усилий, чтобы получить количество битов, которое не является степенью двойки).

Myrddin Emrys 10.12.2011 20:19

Это пример хорошего, а также пример того, почему вы никогда не захотите его писать. Это хэш Fowler / Noll / Vo (FNV), который в равной степени является гением информатики и чистым вуду:

unsigned fnv_hash_1a_32 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned h = 0x811c9dc5;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x01000193;

   return h;
}

unsigned long long fnv_hash_1a_64 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned long long h = 0xcbf29ce484222325ULL;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x100000001b3ULL;

   return h;
}

Редактировать:

  • Лэндон Курт Нолл рекомендует для его сайт алгоритм FVN-1A по сравнению с исходным алгоритмом FVN-1: улучшенный алгоритм лучше распределяет последний байт в хэше. Соответственно скорректировал алгоритм.

Вы можете посмотреть на этом сайте некоторую информацию о том, почему выбраны эти значения: isthe.com/chongo/tech/comp/fnv/#fnv-prime

Cthutu 10.09.2010 18:23

Будьте здоровы. Эта короткая, простая, эффективная, универсальная и эффективная 64-битная хеш-функция была именно тем, что мне было нужно.

mattarod 14.11.2018 01:21
Ответ принят как подходящий

Для выполнения «нормального» поиска по хэш-таблице практически по любым данным - эта, написанная Полом Хси, - лучшее, что я когда-либо использовал.

http://www.azillionmonkeys.com/qed/hash.html

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

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

Konrad Rudolph 02.07.2009 10:36

Я читал с сайта Дженкинса, что SFH тогда был одним из лучших, но я думаю, что Murmur мог бы справиться лучше, см. Этот отличный ответ: programmers.stackexchange.com/questions/49550/…

nawfal 15.04.2013 01:39

Что означает YMMV?

cobarzan 24.08.2015 03:41

@cobarzan Ваш пробег может отличаться

ProgrammerDan 08.10.2015 19:16

Хеш-функция Се ужасна, с на порядок больше коллизий, чем мы хотим. В частности, строки, которые отличаются только последними 4 байтами, могут легко конфликтовать. Если у вас есть 30-символьная строка, которые отличаются последними 4 байтами, после обработки 28 байтов хэши различаются только в последних 2 байтах. Это означает, что вам ГАРАНТИРУЕТСЯ коллизия для одного из оставшихся двухбайтовых значений. (Да, это быстро. Ну и что.)

Andrew Lazarus 12.03.2016 03:27

То, что вы здесь говорите, это то, что вы хотите иметь тот, который использует сопротивление столкновению. Попробуйте использовать SHA-2. Или попробуйте использовать (хороший) блочный шифр с функцией одностороннего сжатия (никогда не пробовал раньше), например AES в режиме Миягути-Принил. Проблема в том, что вам необходимо:

1) иметь IV. Попробуйте использовать первые 256 бит дробных частей константы Хинчина или что-то в этом роде. 2) иметь схему заполнения. Легко. Выбросьте его из хэша, такого как MD5 или SHA-3 (Keccak [произносится как "кет-чак"]). Если вас не волнует безопасность (некоторые другие сказали это), посмотрите FNV или lookup2 Боба Дженкинса (на самом деле я первый, кто рекомендует lookup2) Также попробуйте MurmurHash, это быстро (проверьте это: 0,16 cpb ).

Хорошая хеш-функция должна

  1. быть биективным, чтобы не терять информацию, где это возможно, и иметь наименьшее количество конфликтов
  2. каскадировать как можно больше и равномернее, т.е. каждый входной бит должен переворачивать каждый выходной бит с вероятностью 0,5 и без очевидных шаблонов.
  3. если он используется в криптографическом контексте, не должно существовать эффективного способа его инвертирования.

Модуль простого числа не удовлетворяет ни одной из этих точек. Этого просто недостаточно. Часто это лучше, чем ничего, но даже не быстро. Умножение на беззнаковое целое число и взятие модуля степени двойки так же хорошо распределяет значения, что совсем нехорошо, но всего с 2 циклами ЦП это намного быстрее, чем от 15 до 40, которое займет простой модуль ( да, целочисленное деление действительно такое медленное).

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

Среди прочих полезных перестановок:

  • умножение на нечетное целое число
  • бинарные вращения
  • xorshift

Следуя этому рецепту, мы можем создать свой собственный хеш-функция или взять сплитмикс, который протестирован и хорошо принят.

Если требуются криптографические качества, я настоятельно рекомендую использовать функцию семейства sha, которая хорошо протестирована и стандартизирована, но в образовательных целях вы бы сделали ее следующим образом:

Сначала вы берете хорошую некриптографическую хеш-функцию, затем применяете одностороннюю функцию, такую ​​как возведение в степень для простого поля или k, многие приложения (n*(n+1)/2) mod 2^k, перемежающиеся с xorshift, когда k - это количество бит в результирующем хеш-коде.

Другие вопросы по теме