İyi bir Hash Fonksiyonu nedir?


130

İyi bir Hash işlevi nedir? Üniversitedeki veri yapıları derslerimde birçok karma işlevi ve uygulaması gördüm, ancak çoğunlukla iyi bir karma işlevi yapmanın oldukça zor olduğunu anladım. Genel bir kural olarak, çarpışmaları önlemek için profesörüm şunları söyledi:

function Hash(key)
  return key mod PrimeNumber
end

(mod, C ve benzeri dillerde% operatörüdür)

karma tablonun boyutu asal sayı ile. Bunun çarpışmalardan kaçınmak için biraz iyi ve hızlı bir işlev olduğunu anlıyorum, ancak daha iyisini nasıl yapabilirim? Sayısal tuşlara karşı dize anahtarları için daha iyi hash işlevleri var mı?


34
Aşağıdaki genel amaçlı hash işlevlerinden birini veya birkaçını kullanmayı düşündünüz mü: partow.net/programming/hashfunctions/index.html

Fnv_func'da, p [i] türü bir karakterdir, ilk yinelemeden sonra h ile ne olur? Bilerek mi yapıldı?

5
@martinatime şunları söyledi: wikipedia en.wikipedia.org/wiki/Hash_function içinde hash fonksiyonları hakkında bir sürü bilgi var ve bu makalenin altında partow.net/programming/hashfunctions/index.html'de çeşitli dillerde uygulanan algoritmalar var.
2501

Yanıtlar:


33

Temelde her tür veri üzerinde "normal" hash tablo aramaları yapmak için - Paul Hsieh tarafından hazırlanan bu, şimdiye kadar kullandığım en iyisi.

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

Kriptografik olarak güvenli veya daha gelişmiş herhangi bir şeyi önemsiyorsanız, YMMV. Bir hash tablosu araması için sadece bir kick ass genel amaçlı hash fonksiyonu istiyorsanız, aradığınız şey budur.


Bilgilendirici bağlantı için teşekkürler! Bob Jenkins ve diğerleri tarafından çok iyi evrensel olarak kabul edilebilir hash fonksiyonlarına işaret eden birkaç analiz biliyorum , ancak buna henüz rastlamadım.
Konrad Rudolph

Jenkins'in sitesinden
SFH'nin

2
YMMV ne anlama geliyor?
cobarzan

3
@cobarzan Kilonuz Mayıs Vary
ProgrammerDan

2
Hsieh'in hash fonksiyonu korkunç, istediğimizden çok daha fazla çarpışma var. Özellikle, yalnızca son 4 bayttan farklı olan dizeler kolayca çakışabilir. Son 4 baytta farklılık gösteren 30 karakterlik bir dizeniz varsa, 28 bayt işlendikten sonra, karmalar yalnızca son 2 baytta farklılık gösterir. Bu, kalan iki baytlık değerlerden biri için GARANTİ EDİLDİĞİNİZ anlamına gelir. (Evet, hızlı. Ne olmuş yani.)
Andrew Lazarus

51

Evrensel karmalar için "iyi karma işlevi" diye bir şey yoktur (ed. Evet, "evrensel karma" diye bir şey olduğunu biliyorum ama kastettiğim bu değil). Bağlama bağlı olarak, bir hash'in kalitesini farklı kriterler belirler. İki kişi zaten SHA'dan bahsetti. Bu bir kriptografik karmadır ve muhtemelen demek istediğiniz karma tablolar için hiç de iyi değildir.

Karma tabloların çok farklı gereksinimleri vardır. Ancak yine de, evrensel olarak iyi bir karma işlevi bulmak zordur çünkü farklı veri türleri, karma hale getirilebilecek farklı bilgileri açığa çıkarır. Genel bir kural olarak, bir türün tuttuğu tüm bilgileri eşit olarak değerlendirmek iyidir . Bu her zaman kolay ve hatta mümkün değildir. İstatistiksel nedenlerle (ve dolayısıyla çarpışmadan), sorunlu alana, yani tüm olası nesnelere iyi bir yayılma sağlamak da önemlidir. Bu, 100 ile 1050 arasındaki sayıları karma haline getirirken, en önemli basamağın karmada büyük bir rol oynamasına izin vermenin iyi olmadığı anlamına gelir çünkü nesnelerin ~% 90'ı için bu basamak 0 olacaktır. Son üçüne izin vermek çok daha önemlidir. rakamlar karmayı belirler.

Benzer şekilde, dizelere hashing uygularken tüm karakterleri dikkate almak önemlidir - tüm dizelerin ilk üç karakterinin aynı olacağı önceden bilinmesi dışında; bunları düşünmek israftır.

Aslında bu, Knuth'un The Art of Computer Programming , cilt 2'de söyleyeceklerini okumanızı tavsiye ettiğim durumlardan biridir . 3. Bir başka iyi okuma Julienne Walker'ın The Art of Hashing adlı eseridir .


1
Konrad, teorik açıdan kesinlikle haklısınız, ancak yorumumda bahsettiğim Paul Hsieh hash işlevini kullanmayı hiç denediniz mi? Pek çok farklı türde veriye karşı gerçekten oldukça iyi!
Chris Harris

9

Hashing işlevlerinin iki ana amacı vardır:

  • veri noktalarını eşit şekilde n bit halinde dağıtmak için.
  • giriş verilerini güvenli bir şekilde tanımlamak için.

Ne için kullandığınızı bilmeden bir karma tavsiye etmek imkansızdır.

Bir programda sadece bir hash tablosu yapıyorsanız, algoritmanın ne kadar tersine çevrilebilir veya hacklenebilir olduğu konusunda endişelenmenize gerek yoktur ... SHA-1 veya AES bunun için tamamen gereksizdir, kullanmanız daha iyi olur FNV'nin bir varyasyonu . FNV, bahsettiğiniz gibi basit bir ana moddan daha iyi dağılım (ve dolayısıyla daha az çarpışma) sağlar ve çeşitli giriş boyutlarına daha uyarlanabilir.

Genel bilgileri gizlemek ve doğrulamak için karmaları kullanıyorsanız (bir parola veya belgeye hashing uygulamak gibi), o zaman genel incelemeyle incelenen ana karma algoritmalardan birini kullanmalısınız. Hash Function Lounge , başlamak için iyi bir yerdir.


Hash Function Lounge'a bağlantı güncellendi: larc.usp.br/~pbarreto/hflounge.html
Tim Partridge

FNV, bir SHA1'deki aynı sayıda bit ile karşılaştırıldığında doğum günü çarpışmasına ne kadar dayanır?
Kevin Hsu

@Kevin Bir hash'in çığ özellikleri iyi olduğu sürece (girdideki küçük değişiklikler = çıktıdaki büyük değişiklikler), doğum günü çarpışmaları karma içindeki bitlerin bir fonksiyonudur. FNV-1a bu bakımdan mükemmeldir ve hash'de istediğiniz kadar çok veya az bite sahip olabilirsiniz (2'nin gücü olmayan biraz saymak biraz daha fazla çaba gerektirse de).
Myrddin Emrys

5

Bu iyi bir örnek ve aynı zamanda neden asla yazmak istemeyeceğinize dair bir örnek. Bu bir Fowler / Noll / Vo (FNV) Hash, eşit derecede bilgisayar bilimi dehası ve saf vudu:

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

Düzenle:

  • Landon Curt Noll , sitesinde orijinal FVN-1 algoritması yerine FVN-1A algoritmasını önermektedir : Geliştirilmiş algoritma, karmadaki son baytı daha iyi dağıtır. Algoritmayı buna göre ayarladım.

3
Bu değerlerin neden seçildiğine dair bazı bilgiler için bu siteye bakmak isteyebilirsiniz: isthe.com/chongo/tech/comp/fnv/#fnv-prime
Cthutu

Seni korusun. Bu kısa, basit, verimli, genel ve etkili 64-bit hash fonksiyonu tam da ihtiyacım olan şeydi.
mattarod

3

Temel kuralın kendi başınıza yuvarlanmak olmadığını söyleyebilirim. İyice test edilmiş bir şeyi, örneğin SHA-1 veya bu doğrultuda bir şey kullanmaya çalışın.


Kriptografik olarak güvenli bir şeye ihtiyacı yok gibi görünüyor, bu yüzden SHA-1 çok fazla olur.
Erik

bu arada, SHA-1 için herhangi bir çarpışma bulunmamasına rağmen, bir tane bulunmasının yıllar veya aylar meselesi olduğuna inanılıyor. SHA-256 kullanmanızı tavsiye ederim.
Samuel Allan

1

İyi bir hash işlevi aşağıdaki özelliklere sahiptir:

  1. Bir mesajın karması verildiğinde, bir saldırganın hash'lerinin aynı olacak şekilde başka bir mesaj bulması sayısal olarak mümkün değildir.

  2. Bir çift mesaj verildiğinde, m 've m, h (m) = h (m') olacak şekilde iki tane bulmak sayısal olarak olanaksızdır.

İki durum aynı değil . İlk durumda, bir çakışma bulmaya çalıştığınız önceden var olan bir hash vardır. İkinci durumda, çakışan herhangi iki mesajı bulmaya çalışıyorsunuz . İkinci görev, doğum günü "paradoksu" nedeniyle önemli ölçüde daha kolaydır.

Performansın o kadar büyük bir sorun olmadığı durumlarda, her zaman güvenli bir hash işlevi kullanmalısınız. Bir hash'de çarpışmaları zorlayarak gerçekleştirilebilecek çok akıllı saldırılar vardır. Başlangıçtan itibaren güçlü bir şey kullanırsanız, kendinizi bunlara karşı koruyacaksınız.

Yeni tasarımlarda MD5 veya SHA-1 kullanmayın. Benim de dahil olmak üzere çoğu kriptograf onların bozuk olduğunu düşünür. Bu tasarımların her ikisinde de temel zayıflık kaynağı, yukarıda özetlediğim ikinci özelliğin bu yapılar için geçerli olmamasıdır. Bir saldırgan, m ve m 'olmak üzere iki mesaj oluşturabilirse, her ikisi de aynı değere karma bu mesajları size karşı kullanabilir. SHA-1 ve MD5 ayrıca, dikkatli olmazsanız uygulamanızı ölümcül şekilde zayıflatabilecek mesaj uzatma saldırılarından da muzdariptir.

Whirpool gibi daha modern bir hash daha iyi bir seçimdir. Bu mesaj uzantısı saldırılarından etkilenmez ve AES'in çeşitli saldırılara karşı güvenliği kanıtlamak için kullandığı matematiği kullanır.

Umarım yardımcı olur!


1
Bu durumda kriptografik hash fonksiyonunun önerilmesinin gerçekten kötü bir tavsiye olduğunu düşünüyorum.
Slava

@Slava: Neden? "Kriptografik bir hash işlevi bu durumda gerçekten kötü bir tavsiye" demenizin nedenleri nelerdir? Neden kötü bir tavsiye? Bunu yapan göreceli dezavantajlar nelerdir?
Let Me Tink About It

2
@Mowzer, karma haritada kullanılan bir karma işlevinin hızlı ve hafif olması gerektiğinden (hala iyi bir karma sağladığını varsayarsak), kripto karmalarının kaba kuvvet saldırısını önlemek için hesaplama açısından pahalı olduğu açıkça görülüyordu.
Slava

1

Burada söylediğiniz, çarpışma direncine sahip kullanan birine sahip olmak istiyorsunuz. SHA-2 kullanmayı deneyin. Ya da Miyaguchi-Preenel modunda AES gibi tek yönlü bir sıkıştırma işlevinde (daha önce hiç denemedim) bir (iyi) blok şifresi kullanmayı deneyin. Bununla ilgili sorun şudur:

1) IV sahibi olmanız gerekir . Khinchin sabitinin kesirli kısımlarının ilk 256 bitini veya bunun gibi bir şeyi kullanmayı deneyin. 2) bir dolgu şemasına sahip. Kolay. MD5 veya SHA-3 gibi bir hash'den (Keccak ['ket-chak' olarak telaffuz edilir]) alın. Güvenlik umurunuzda değilse (birkaç kişi bunu söyledi), FNV'ye bakın veya Bob Jenkins'in arama2'sine bakın (aslında aramayı öneren ilk kişi benim) Ayrıca MurmurHash'ı deneyin, hızlıdır (şunu kontrol edin: .16 cpb ).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.