Apa itu Fungsi Hash yang baik?


130

Apa fungsi Hash yang baik? Saya melihat banyak fungsi hash dan aplikasi dalam mata kuliah struktur data saya di perguruan tinggi, tetapi kebanyakan saya cukup sulit membuat fungsi hash yang baik. Sebagai aturan praktis untuk menghindari tabrakan, profesor saya mengatakan bahwa:

function Hash(key)
  return key mod PrimeNumber
end

(mod adalah% operator dalam bahasa C dan sejenisnya)

dengan bilangan prima menjadi ukuran tabel hash. Saya mendapatkan bahwa itu adalah fungsi yang agak baik untuk menghindari tabrakan dan yang cepat, tetapi bagaimana saya bisa membuat yang lebih baik? Apakah ada fungsi hash yang lebih baik untuk kunci string terhadap kunci numerik?


34
Pernahkah Anda mempertimbangkan untuk menggunakan satu atau lebih fungsi hash tujuan umum berikut: partow.net/programming/hashfunctions/index.html

Dalam fnv_func, tipe p [i] adalah char, apa yang akan terjadi dengan h setelah iterasi pertama? Apakah itu dilakukan dengan sengaja?

5
@martinatime berkata: Ada banyak informasi seputar fungsi hash di wikipedia en.wikipedia.org/wiki/Hash_function dan bagian bawah artikel ini partow.net/programming/hashfunctions/index.html memiliki algoritma yang diimplementasikan dalam berbagai bahasa.
2501

Jawaban:


33

Untuk melakukan pencarian tabel hash "normal" pada dasarnya semua jenis data - yang ini oleh Paul Hsieh adalah yang terbaik yang pernah saya gunakan.

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

Jika Anda peduli tentang keamanan kriptografis atau hal lain yang lebih canggih, maka YMMV. Jika Anda hanya ingin fungsi hash tujuan umum pantat pantat untuk pencarian tabel hash, maka ini adalah apa yang Anda cari.


Terima kasih atas tautan informatif! Saya tahu beberapa analisis oleh Bob Jenkins dan lainnya yang menunjukkan fungsi hash yang cukup baik secara universal, tetapi saya belum menemukan yang satu ini.
Konrad Rudolph

Saya telah membaca dari situs Jenkins bahwa SFH adalah salah satu yang terbaik saat itu, tetapi saya pikir Murmur mungkin melakukan yang lebih baik, lihat jawaban yang sangat bagus ini: programmers.stackexchange.com/questions/49550/…
nawfal

2
Untuk apa YMMV berdiri?
cobarzan

3
@cobarzan Mileage Anda May Vary
ProgrammerDan

2
Fungsi hash Hsieh mengerikan, dengan urutan besarnya lebih banyak tabrakan dari yang kita inginkan. Secara khusus, string yang berbeda hanya dalam 4 byte terakhir dapat bertabrakan dengan mudah. Jika Anda memiliki string 30 karakter, yang berbeda dalam 4 byte terakhir, setelah 28 byte diproses, hash hanya berbeda dalam 2 byte terakhir. Itu berarti Anda DIJAMIN tabrakan untuk salah satu dari nilai dua byte yang tersisa. (Ya, cepat. Jadi bagaimana.)
Andrew Lazarus

51

Tidak ada yang namanya "fungsi hash baik" untuk hash universal (ed. Ya, saya tahu ada yang namanya "universal hashing" tapi bukan itu yang saya maksudkan). Tergantung pada konteksnya kriteria yang berbeda menentukan kualitas hash. Dua orang sudah menyebutkan SHA. Ini adalah hash kriptografi dan sama sekali tidak baik untuk tabel hash yang mungkin Anda maksud.

Tabel hash memiliki persyaratan yang sangat berbeda. Tetapi tetap saja, menemukan fungsi hash yang baik secara universal sulit karena tipe data yang berbeda mengekspos informasi yang berbeda yang dapat di hash. Sebagai patokan, baik untuk mempertimbangkan semua informasi yang dimiliki oleh suatu jenis. Ini tidak selalu mudah atau bahkan mungkin. Untuk alasan statistik (dan karenanya tabrakan), juga penting untuk menghasilkan penyebaran yang baik ke ruang masalah, yaitu semua objek yang mungkin. Ini berarti bahwa ketika hashing angka antara 100 dan 1050 itu tidak baik untuk membiarkan digit paling signifikan memainkan peran besar dalam hash karena untuk ~ 90% dari objek, digit ini akan menjadi 0. Jauh lebih penting untuk membiarkan tiga terakhir digit menentukan hash.

Demikian pula, ketika hashing string, penting untuk mempertimbangkan semua karakter - kecuali ketika diketahui sebelumnya bahwa tiga karakter pertama dari semua string akan sama; mengingat ini adalah pemborosan.

Ini sebenarnya adalah salah satu kasus di mana saya menyarankan untuk membaca apa yang dikatakan Knuth dalam The Art of Computer Programming , vol. 3. Bacaan lain yang bagus adalah The Art of Hashing karya Julienne Walker .


1
Konrad, Anda tentu benar dari sudut pandang teoretis, tetapi apakah Anda pernah mencoba menggunakan fungsi hash Paul Hsieh yang saya sebutkan dalam komentar saya? Ini sangat bagus terhadap banyak jenis data yang berbeda!
Chris Harris

9

Ada dua tujuan utama fungsi hashing:

  • untuk membubarkan titik data secara seragam menjadi n bit.
  • untuk mengidentifikasi data input dengan aman.

Tidak mungkin untuk merekomendasikan hash tanpa mengetahui untuk apa Anda menggunakannya.

Jika Anda hanya membuat tabel hash dalam sebuah program, maka Anda tidak perlu khawatir tentang bagaimana algoritme yang dapat dibalik atau diretas ... SHA-1 atau AES sama sekali tidak diperlukan untuk ini, Anda akan lebih baik menggunakan sebuah variasi FNV . FNV mencapai dispersi yang lebih baik (dan dengan demikian lebih sedikit tabrakan) daripada mod prime sederhana seperti yang Anda sebutkan, dan itu lebih mudah beradaptasi dengan berbagai ukuran input.

Jika Anda menggunakan hash untuk menyembunyikan dan mengotentikasi informasi publik (seperti hashing password, atau dokumen), maka Anda harus menggunakan salah satu algoritma hashing utama yang diperiksa oleh pengawasan publik. Hash Function Lounge adalah tempat yang baik untuk memulai.


tautan yang diperbarui ke The Hash Function Lounge: larc.usp.br/~pbarreto/hflounge.html
Tim Partridge

Seberapa baik FNV menahan tabrakan ulang tahun dibandingkan dengan, katakanlah, jumlah bit yang sama dari SHA1?
Kevin Hsu

@Kevin Selama karakteristik longsoran hash baik (perubahan kecil dalam input = perubahan besar dalam output) maka tabrakan ulang tahun hanyalah fungsi dari bit dalam hash. FNV-1a sangat baik dalam hal ini, dan Anda dapat memiliki sebanyak atau beberapa bit dalam hash yang Anda inginkan (meskipun dibutuhkan sedikit usaha ekstra untuk mendapatkan jumlah sedikit yang bukan kekuatan 2).
Myrddin Emrys

5

Ini adalah contoh yang bagus dan juga contoh mengapa Anda tidak ingin menulisnya. Ini adalah Fowler / Noll / Vo (FNV) Hash yang merupakan bagian jenius ilmu komputer yang sama dan voodoo murni:

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;
}

Edit:

  • Landon Curt Noll merekomendasikan di situsnya algoritma FVN-1A di atas algoritma FVN-1 yang asli: Algoritma yang ditingkatkan lebih baik menyebarkan byte terakhir dalam hash. Saya menyesuaikan algoritme sesuai.

3
Anda mungkin ingin melihat situs ini untuk mendapatkan beberapa informasi mengapa nilai-nilai ini dipilih: isthe.com/chongo/tech/comp/fnv/#fnv-prime
Cthutu

Diberkatilah Anda. Fungsi hash singkat, sederhana, efisien, generik, dan efektif 64-bit ini persis seperti yang saya butuhkan.
mattarod

3

Saya akan mengatakan bahwa aturan utama adalah tidak menggulung Anda sendiri. Cobalah untuk menggunakan sesuatu yang telah diuji secara menyeluruh, misalnya, SHA-1 atau sesuatu di sepanjang garis itu.


Dia tampaknya tidak membutuhkan sesuatu yang aman secara kriptografis sehingga SHA-1 akan menjadi cara yang berlebihan.
Erik

omong-omong meskipun tidak ada tabrakan untuk SHA-1 telah ditemukan itu diyakini masalah hitungan tahun atau bulan sebelum satu ditemukan. Saya akan merekomendasikan menggunakan SHA-256.
Samuel Allan

1

Fungsi hash yang baik memiliki properti berikut:

  1. Mengingat hash pesan, secara komputasi tidak mungkin bagi penyerang untuk menemukan pesan lain sehingga hash mereka identik.

  2. Diberikan sepasang pesan, m 'dan m, secara komputasi tidak layak untuk menemukan dua sehingga h (m) = h (m')

Kedua kasus itu tidak sama. Dalam kasus pertama, ada hash yang sudah ada yang Anda coba cari tabrakan. Dalam kasus kedua, Anda mencoba untuk menemukan setiap dua pesan yang bertabrakan. Tugas kedua secara signifikan lebih mudah karena ulang tahun "paradoks."

Di mana kinerja bukanlah masalah besar, Anda harus selalu menggunakan fungsi hash yang aman. Ada serangan yang sangat cerdas yang dapat dilakukan dengan memaksa tabrakan dalam hash. Jika Anda menggunakan sesuatu yang kuat sejak awal, Anda akan mengamankan diri Anda dari ini.

Jangan gunakan MD5 atau SHA-1 dalam desain baru. Kebanyakan cryptographers, termasuk saya, akan menganggapnya rusak. Sumber utama kelemahan dalam kedua desain ini adalah bahwa properti kedua, yang saya uraikan di atas, tidak berlaku untuk konstruksi ini. Jika seorang penyerang dapat menghasilkan dua pesan, m dan m ', yang keduanya hash dengan nilai yang sama mereka dapat menggunakan pesan-pesan ini terhadap Anda. SHA-1 dan MD5 juga menderita serangan ekstensi pesan, yang dapat melemahkan aplikasi Anda secara fatal jika Anda tidak berhati-hati.

Hash yang lebih modern seperti Whirpool adalah pilihan yang lebih baik. Itu tidak menderita dari serangan ekstensi pesan ini dan menggunakan matematika yang sama seperti AES digunakan untuk membuktikan keamanan terhadap berbagai serangan.

Semoga itu bisa membantu!


1
Saya pikir rekomendasi fungsi hash kriptografi adalah saran yang sangat buruk dalam kasus ini.
Slava

@Slava: Kenapa? Apa alasan Anda untuk mengatakan "fungsi hash kriptografis adalah saran yang sangat buruk dalam kasus ini?" Mengapa itu saran yang buruk? Apa kerugian relatif yang membuatnya demikian?
Let Me Tink About It

2
@Mowzer karena fungsi hash yang digunakan dalam peta hash harus cepat dan ringan (dengan asumsi masih memberikan hash yang baik), hasp crypto secara eksplisit adalah pembantu yang secara komputasi mahal untuk mencegah serangan brute force.
Slava

1

Apa yang Anda katakan di sini adalah Anda ingin memiliki yang menggunakan memiliki resistensi tabrakan. Coba gunakan SHA-2. Atau coba gunakan cipher blok (baik) dalam fungsi kompresi satu arah (tidak pernah mencobanya sebelumnya), seperti AES dalam mode Miyaguchi-Preenel. Masalahnya adalah Anda perlu:

1) memiliki infus. Coba gunakan 256 bit pertama dari bagian pecahan konstanta Khinchin atau sesuatu seperti itu. 2) memiliki skema bantalan. Mudah. Barrow dari hash seperti MD5 atau SHA-3 (Keccak [diucapkan 'ket-chak']). Jika Anda tidak peduli dengan keamanan (beberapa orang lain mengatakan ini), lihat FNV atau lookup2 oleh Bob Jenkins (sebenarnya saya orang pertama yang merekomendasikan lookup2). Juga coba MurmurHash, cepat (periksa ini: .16 cpb ).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.