Що таке хороша хеш-функція?


130

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

function Hash(key)
  return key mod PrimeNumber
end

(mod - оператор% на C та подібних мовах)

при цьому просте число має бути розміром хеш-таблиці. Я розумію, це дещо хороша функція, щоб уникнути зіткнень та швидких, але як я можу зробити кращу? Чи є кращі хеш-функції для рядкових клавіш проти цифрових клавіш?


34
Чи розглядали ви про використання однієї або декількох із таких хеш-функцій загального призначення: partow.net/programming/hashfunctions/index.html

У fnv_func тип p [i] є char, що буде з h після першої ітерації? Це було зроблено спеціально?

5
@martinatime сказав: У wikipedia en.wikipedia.org/wiki/Hash_function є низка інформації про хеш-функції, а в нижній частині цієї статті partow.net/programming/hashfunctions/index.html алгоритми реалізовані на різних мовах.
2501,

Відповіді:


33

Здійснюючи "звичайні" пошуки хеш-таблиць на основі будь-яких даних - цей Пол Паул Хсі є найкращим, що я коли-небудь використовував.

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

Якщо ви дбаєте про криптографічно захищений або що-небудь інше більш досконале, то YMMV. Якщо ви просто хочете хеш-функцію хеш-функції загального призначення для пошуку хеш-таблиці, то це те, що ви шукаєте.


Дякуємо за інформаційне посилання! Я знаю декілька аналізів Боб Дженкінса та інших, які вказують на досить хороші загальноприйнятні хеш-функції, але я ще не стикався з цим.
Конрад Рудольф

Я читав з сайту Дженкінса, що SFH - один із найкращих тоді, але думаю, що Мурмур може зробити краще, дивіться цю чудову відповідь: programmers.stackexchange.com/questions/49550/…
nawfal

2
Що означає YMMV?
cobarzan

3
@cobarzan Your Mileage May Vary
ProgrammerDan

2
Хеш-функція Сісі жахлива, на порядок більше зіткнень, ніж ми хочемо. Зокрема, рядки, які відрізняються лише останніми 4 байтами, можуть легко стикатися. Якщо у вас є 30-символьний рядок, який відрізняється в останніх 4 байтах, після того, як 28 байтів були оброблені, хеші відрізняються лише в останніх 2 байтах. Це означає, що Ви ГАРАНТУЄМО зіткнення для одного з решти двобайтових значень. (Так, це швидко. Так що.)
Андрій Лазар

51

Не існує такого поняття, як "хороша хеш-функція" для універсальних хешей (ред. Так, я знаю, що існує таке поняття, як "універсальне хешуваннявання", але це не те, що я мав на увазі). Залежно від контексту різні критерії визначають якість хешу. Двоє людей вже згадували SHA. Це криптографічний хеш, і це зовсім не добре для хеш-таблиць, які ви, мабуть, маєте на увазі.

Таблиці хешу мають дуже різні вимоги. Але все-таки знайти хорошу хеш-функцію універсально важко, оскільки різні типи даних розкривають різну інформацію, яку можна хешировать. Як правило, добре враховувати всю інформацію, яку має тип, однаково. Це не завжди просто і навіть можливо. З міркувань статистики (а отже, і зіткнення) також важливо створити хороший розподіл по проблемному простору, тобто по всіх можливих об'єктах. Це означає, що при хешировании чисел між 100 і 1050 не годиться дозволяти найбільш значній цифрі грати велику роль у хеші, тому що для ~ 90% об'єктів ця цифра буде дорівнює 0. Набагато важливіше дозволити останнім трьом цифри визначають хеш.

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

Це насправді один із випадків, коли я раджу прочитати, що має сказати Кнут у «Мистецтві комп’ютерного програмування» , т. 3. Ще одне хороше прочитання - «Художнє хеширование» Жульєн Уокер .


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

9

Є дві основні цілі хешування функцій:

  • для рівномірного розподілу точок даних на n біт.
  • надійно ідентифікувати вхідні дані.

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

Якщо ви просто створюєте хеш-таблицю в програмі, то вам не потрібно турбуватися про те, наскільки зворотний або руйнується алгоритм ... SHA-1 або AES абсолютно непотрібні для цього, вам краще використовувати зміна FNV . FNV досягає кращої дисперсії (а отже, меншої кількості зіткнень), ніж простий основний мод, як ви згадали, і він більш пристосований до різних розмірів вводу.

Якщо ви використовуєте хеші для приховування та автентифікації публічної інформації (наприклад, хешування пароля чи документа), вам слід скористатися одним із основних алгоритмів хешування, перевірених публічним контролем. Функціональний зал Hash - хороше місце для початку.


оновлене посилання на The Hash Function Lounge: larc.usp.br/~pbarreto/hflounge.html
Тім Партрідж

Наскільки добре FNV витримує зіткнення з днем ​​народження порівняно з, скажімо, однаковою кількістю бітів від SHA1?
Кевін Хсу

@Kevin Поки лавінні характеристики хеша є хорошими (крихітні зміни вхідних даних = великі зміни у виході), то зіткнення з днем ​​народження - це просто функція бітів у хеші. FNV-1a є прекрасним у цьому плані, і ви можете мати стільки або стільки бітів у хеші, скільки вам захочеться (хоча потрібно трохи додаткових зусиль, щоб трохи порахувати, що це не сила 2).
Мирддін Емріс

5

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

3
Ви можете ознайомитися з цим сайтом, щоб дізнатись, чому саме ці значення обрані: isthe.com/chongo/tech/comp/fnv/#fnv-prime
Cthutu

Будь здоровий. Ця коротка, проста, ефективна, загальна та ефективна 64-бітна хеш-функція була саме тим, що мені було потрібно.
mattarod

3

Я б сказав, що головне правило - не котити своє. Спробуйте використовувати те, що було ретельно випробувано, наприклад, SHA-1 або щось подібне.


Він, здається, не потребує нічого криптографічно захищеного, тому SHA-1 був би надмірним.
Ерік

до речі, незважаючи на те, що жодних зіткнень для SHA-1 не знайдено, вважається, це буде роком років чи місяців, перш ніж його знайдуть. Я рекомендую використовувати SHA-256.
Семюель Аллан

1

Хороша хеш-функція має такі властивості:

  1. З огляду на хеш повідомлення, зловмисник обчислювально не може знайти інше повідомлення таким чином, щоб їх хеши були ідентичними.

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

Ці два випадки НЕ те ж саме. У першому випадку є попередньо створений хеш, для якого ви намагаєтеся зіткнутись. У другому випадку ви намагаєтесь знайти будь-які два повідомлення, які стикаються. Друге завдання значно простіше через день народження "парадокс".

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

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

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

Сподіваюся, що це допомагає!


1
Я думаю, що рекомендація щодо криптографічного хеш-функції в цьому випадку є дуже поганою порадою.
Слава

@Slava: Чому? Які ваші причини сказати, що "криптографічна хеш-функція - це справді погана порада в цьому випадку?" Чому це погана порада? Які відносні недоліки роблять це так?
Дозвольте мені подумати про це

2
@Mowzer, оскільки хеш-функція, яка використовується в хеш-карті, повинна бути швидкою і легкою (якщо припустити, що вона все ще забезпечує хороший хеш), крипто хеші явно були покоївками, щоб бути обчислювально дорогими, щоб запобігти грубій атаці.
Слава

1

Що ви тут говорите, ви хочете, щоб той, який використовує, має стійкість до зіткнення. Спробуйте використовувати SHA-2. Або спробуйте використовувати (хороший) блок-шифр у функції одностороннього стиснення (ніколи раніше не пробував цього), як AES в режимі Міягучі-Прінел. Проблема в тому, що вам потрібно:

1) мати IV. Спробуйте використовувати перші 256 біт дробових частин константи Хінчіна чи щось подібне. 2) мати схему оббивки. Легко. Заграйте його з хешу, як MD5 або SHA-3 (Keccak [вимовляється "кет-чак"). Якщо ви не піклуєтесь про безпеку (кілька інших сказали це), подивіться на FNV або lookup2 від Bob Jenkins (насправді я перший, хто рекомендує lookup2) Також спробуйте MurmurHash, це швидко (перевірте це: .16 cpb ).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.