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

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

function Hash(key)
  return key mod PrimeNumber
end

(mod - оператор% в C и аналогичные языки)

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

Ответ 1

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

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

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

Ответ 2

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

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

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

Это на самом деле один из тех случаев, когда я советую прочитать, что должен сказать Кнут в "Art of Computer Programming", том. 3. Еще одно хорошее чтение - Жюльен Уокер Искусство Хэшинга.

Ответ 3

Существуют две основные цели хэширования:

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

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

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

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

Ответ 4

Это пример хорошего, а также пример того, почему вы никогда не захотите его написать. Это Hash 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: улучшенный алгоритм лучше рассеивает последний байт в хеше. Я соответствующим образом скорректировал алгоритм.

Ответ 5

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

Ответ 6

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

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

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

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

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

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

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

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

Ответ 7

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

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