Który algorytm mieszania jest najlepszy dla wyjątkowości i szybkości? Przykłady (dobrych) zastosowań obejmują słowniki skrótów.
Wiem, że istnieją rzeczy takie jak SHA-256 i tym podobne, ale te algorytmy są zaprojektowane tak, aby były bezpieczne , co zwykle oznacza, że są wolniejsze niż algorytmy mniej unikalne . Chcę algorytmu skrótu zaprojektowanego tak, aby był szybki, ale pozostać dość unikalny, aby uniknąć kolizji.
algorithms
hashing
Earlz
źródło
źródło
Odpowiedzi:
Testowałem różne algorytmy, mierząc prędkość i liczbę kolizji.
Użyłem trzech różnych zestawów kluczy:
"1"
do"216553"
(pomyśl o kodach pocztowych i o tym , jak słaby hash usunął msn.com )Dla każdego korpusu rejestrowano liczbę kolizji i średni czas haszowania.
Testowałem:
xor
zamiast+
)Wyniki
Każdy wynik zawiera średni czas mieszania i liczbę kolizji
Uwagi :
Czy faktycznie dochodzi do kolizji?
Tak. Zacząłem pisać mój program testowy, aby sprawdzić, czy rzeczywiście występują kolizje skrótów - i nie są to tylko teoretyczne konstrukcje. Rzeczywiście się zdarzają:
Zderzenia FNV-1
creamwove
koliduje zquists
Zderzenia FNV-1a
costarring
koliduje zliquid
declinate
koliduje zmacallums
altarage
koliduje zzinke
altarages
koliduje zzinkes
Kolizje Murmur2
cataract
koliduje zperiti
roquette
koliduje zskivie
shawl
koliduje zstormbound
dowlases
koliduje ztramontane
cricketings
koliduje ztwanger
longans
koliduje zwhigs
Zderzenia DJB2
hetairas
koliduje zmentioner
heliotropes
koliduje zneurospora
depravement
koliduje zserafins
stylist
koliduje zsubgenera
joyful
koliduje zsynaphea
redescribed
koliduje zurites
dram
koliduje zvivency
Zderzenia DJB2a
haggadot
koliduje zloathsomenesses
adorablenesses
koliduje zrentability
playwright
koliduje zsnush
playwrighting
koliduje zsnushing
treponematoses
koliduje zwaterbeds
Zderzenia CRC32
codding
koliduje zgnu
exhibiters
koliduje zschlager
Kolizje SuperFastHash
dahabiah
koliduje zdrapability
encharm
koliduje zenclave
grahams
koliduje zgramary
night
koliduje zvigil
nights
koliduje zvigils
finks
koliduje zvinic
Randomnessification
Inną subiektywną miarą jest losowe rozmieszczenie skrótów. Odwzorowanie powstałych tabel skrótów pokazuje, jak równomiernie dane są rozmieszczone. Wszystkie funkcje skrótu wykazują dobry rozkład podczas liniowego mapowania tabeli:
Lub jako mapa Hilberta ( XKCD jest zawsze odpowiedni ):
Z wyjątkiem gdy mieszania ciągów numer (
"1"
,"2"
, ...,"216553"
) (na przykład kody pocztowe ), gdzie wzorce zaczynają się pojawiać w większości algorytmów mieszaja:SDBM :
DJB2a :
FNV-1 :
Wszystkie oprócz FNV-1a , które nadal wyglądają dla mnie dość losowo:
W rzeczywistości Murmur2 wydaje się mieć jeszcze lepszą losowość
Numbers
niżFNV-1a
:Dodatek
*
w tabeli wskazuje, jak zła jest losowość. ZFNV-1a
bycia najlepszym, aDJB2x
będąc najgorsze:Pierwotnie napisałem ten program, aby zdecydować, czy w ogóle muszę się martwić o kolizje: tak.
A potem okazało się, że funkcje haszujące były wystarczająco losowe.
Algorytm FNV-1a
Skrót FNV1 występuje w wariantach, które zwracają skróty 32, 64, 128, 256, 512 i 1024 bitów.
Algorytm FNV-1a jest:
Gdzie stałe
FNV_offset_basis
iFNV_prime
zależą od żądanego rozmiaru zwracanej wartości skrótu:Szczegółowe informacje można znaleźć na głównej stronie FNV .
Wszystkie moje wyniki dotyczą wariantu 32-bitowego.
FNV-1 lepszy niż FNV-1a?
Nie. FNV-1a jest lepszy. Podczas używania angielskiego słowa corpus doszło do większej liczby kolizji z FNV-1a:
Teraz porównaj małe i wielkie litery:
W tym przypadku FNV-1a nie jest „400%” gorszy niż FN-1, tylko 20% gorzej.
Myślę, że ważniejsze jest to, że istnieją dwie klasy algorytmów, jeśli chodzi o kolizje:
A potem jest to, jak równomiernie rozłożone są skróty:
Aktualizacja
Szmer? Jasne, czemu nie
Aktualizacja
@ whatshisname zastanawiał się, jak będzie działać CRC32 , dodał liczby do tabeli.
CRC32 jest całkiem niezły . Mało kolizji, ale wolniej, i narzut 1-krotnej tabeli odnośników.
Zniszcz wszystkie błędne informacje o dystrybucji CRC - moje złe
Do dzisiaj miałem używać FNV-1a jako mojego de facto algorytmu haszującego tablicę skrótów. Ale teraz przełączam się na Murmur2:
I naprawdę, naprawdę mam nadzieję, że coś jest nie tak z
SuperFastHash
algorytmem, który znalazłem ; szkoda być popularnym.Aktualizacja: Od głównej MurmurHash3 w Google :
Myślę, że to nie tylko ja.
Aktualizacja: Zrozumiałem, dlaczego
Murmur
jest szybszy od innych. MurmurHash2 działa na czterech bajtach jednocześnie. Większość algorytmów jest bajt po bajcie :Oznacza to, że gdy klucze stają się dłuższe, Murmur ma szansę zabłysnąć.
Aktualizacja
Identyfikatory GUID są zaprojektowane tak, aby były unikalne, a nie losowe
Terminowy post Raymonda Chena potwierdza fakt, że „losowe” identyfikatory GUID nie są przeznaczone do ich losowości. One lub ich część nie są odpowiednie jako klucz skrótu:
Losowość to nie to samo, co unikanie kolizji; dlatego błędem byłoby wymyślić własny algorytm „mieszający”, przyjmując pewien podzbiór „losowego” przewodnika:
Uwaga : Znów wstawiłem „przypadkowy GUID” w cudzysłowie, ponieważ jest to „losowy” wariant GUID. Bardziej dokładny opis byłby
Type 4 UUID
. Ale nikt nie wie, jaki jest typ 4 lub typy 1, 3 i 5. Łatwiej więc nazwać je „losowymi” identyfikatorami GUID.Lustra wszystkich angielskich słów
źródło
Jeśli chcesz utworzyć mapę skrótów z niezmiennego słownika, możesz rozważyć idealne haszowanie https://en.wikipedia.org/wiki/Perfect_hash_function - podczas budowy funkcji skrótu i tabeli skrótów możesz zagwarantować, dla danego zestawu danych, że nie będzie kolizji.
źródło
Oto lista funkcji skrótu, ale krótka wersja to:
źródło
CityHash firmy Google to algorytm, którego szukasz. Nie nadaje się do kryptografii, ale jest dobry do generowania unikatowych skrótów.
Przeczytaj blog, aby uzyskać więcej informacji, a kod jest dostępny tutaj .
CityHash jest napisany w C ++. Jest też zwykły port C .
O obsłudze 32-bitowej:
źródło
plain C port
link jest zepsutySporządziłem krótkie porównanie różnych algorytmów haszujących podczas haszowania plików.
Poszczególne wykresy różnią się tylko nieznacznie metodą odczytu i można je tutaj zignorować, ponieważ wszystkie pliki zostały zapisane w pliku tmpfs. Dlatego, jeśli zastanawiasz się, test nie był związany z IO.
Algorytmy obejmują:
SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}
.Wnioski:
CRC
instrukcją SSE 4.2s , których mój procesor nie ma. SpookyHash był w moim przypadku zawsze trochę przed CityHash.Źródło użyte do wykresów:
źródło
Algorytmy SHA (w tym SHA-256) są zaprojektowane tak, aby były szybkie .
W rzeczywistości ich prędkość może czasem stanowić problem. W szczególności powszechną techniką przechowywania tokenu pochodnego hasła jest uruchomienie standardowego algorytmu szybkiego hashowania 10 000 razy (przechowywanie skrótu skrótu skrótu skrótu ... hasła).
Wynik:
źródło
bcrypt
. Użyj odpowiednich narzędzi..rodata
koszty konfiguracji, porzucenia i / lub stanu. Kiedy potrzebujesz algorytmu dla tablicy mieszającej, zwykle masz bardzo krótkie klucze i wiele z nich, ale nie potrzebujesz dodatkowych gwarancji kryptograficznych. Sam korzystam z ulepszonej wersji Jenkinsa.Założenie, że kryptograficzne funkcje skrótu są bardziej unikalne, jest błędne i w rzeczywistości można wykazać, że w praktyce często jest ono cofane. Wprawdzie:
Co oznacza, że nieszyfrowa funkcja skrótu może mieć mniej kolizji niż kryptograficzna dla „dobrego” zestawu danych - zestawów danych, dla których została zaprojektowana.
Możemy to właściwie wykazać za pomocą danych zawartych w odpowiedzi Iana Boyda i odrobiny matematyki: problem urodzinowy . Wzór na oczekiwaną liczbę kolidujących par, jeśli wybierzesz
n
losowo liczby całkowite ze zbioru,[1, d]
jest następujący (wzięty z Wikipedii):Podłączając
n
= 216 553 id
= 2 ^ 32 otrzymujemy około 5,5 oczekiwanych kolizji . Testy Iana przeważnie pokazują wyniki w tej okolicy, ale z jednym dramatycznym wyjątkiem: większość funkcji uzyskała zerową kolizję w kolejnych testach liczbowych. Prawdopodobieństwo losowego wyboru 216 553 liczb 32-bitowych i uzyskania zerowych kolizji wynosi około 0,43%. I to tylko dla jednej funkcji - tutaj mamy pięć różnych rodzin funkcji skrótu z zerowymi kolizjami!Widzimy więc, że skróty, które testował Ian, działają korzystnie z zestawem danych z kolejnymi liczbami - tzn. Rozpraszają minimalnie różne dane wejściowe szerzej niż idealna funkcja skrótu kryptograficznego. (Uwaga dodatkowa: oznacza to, że graficzną ocenę Iana, że FNV-1a i MurmurHash2 „wyglądają mu losowo” w zestawie danych liczbowych, można odrzucić na podstawie jego własnych danych. Zero zderzeń na zestawie danych tego rozmiaru dla obu funkcji skrótu, jest uderzająco nielosowy!)
Nie jest to niespodzianką, ponieważ jest to pożądane zachowanie dla wielu zastosowań funkcji skrótu. Na przykład klucze tabeli skrótów są często bardzo podobne; Odpowiedź Iana wspomina o problemie, jaki MSN miał kiedyś z tablicami skrótu kodów pocztowych . Jest to zastosowanie, w którym unikanie kolizji na prawdopodobnych danych wejściowych wygrywa z zachowaniem losowym.
Innym pouczającym porównaniem tutaj jest kontrast w celach projektowych między CRC a kryptograficznymi funkcjami skrótu:
Więc dla CRC to kolejny dobry mieć mniej kolizji niż losowo minimalnie różnych wejść. W przypadku skrótów kryptograficznych jest to nie-nie!
źródło
Użyj SipHash . Ma wiele pożądanych właściwości:
Szybki. Zoptymalizowana implementacja zajmuje około 1 cyklu na bajt.
Bezpieczne. SipHash jest silnym PRF (funkcja pseudolosowa). Oznacza to, że nie można go odróżnić od funkcji losowej (chyba że znasz 128-bitowy tajny klucz). W związku z tym:
Nie musisz się martwić, że sondy tabeli skrótów staną się liniowe z powodu kolizji. Dzięki SipHash wiesz , że średnio uzyskasz średnią wydajność, niezależnie od danych wejściowych.
Odporność na ataki typu odmowa usługi oparte na haszowaniu.
Możesz użyć SipHash (szczególnie wersja ze 128-bitowym wyjściem) jako MAC (Message Authentication Code). Jeśli otrzymasz wiadomość i znacznik SipHash, a znacznik jest taki sam, jak po uruchomieniu SipHash z tajnym kluczem, to wiesz, że ktokolwiek stworzył skrót, był również w posiadaniu twojego tajnego klucza i że ani wiadomość, ani hash został zmieniony od tego czasu.
źródło
To zależy od haszowanych danych. Niektóre skróty działają lepiej z określonymi danymi, takimi jak tekst. Niektóre algorytmy mieszające zostały specjalnie zaprojektowane tak, aby były odpowiednie dla określonych danych.
Paul Hsieh kiedyś zrobił szybki skrót . Wymienia kod źródłowy i objaśnienia. Ale już zostało pobite. :)
źródło
Java używa tego prostego algorytmu wielokrotnego dodawania i dodawania:
Prawdopodobnie są o wiele lepsze, ale jest to dość powszechne i wydaje się być dobrym kompromisem między szybkością a wyjątkowością.
źródło
Po pierwsze, dlaczego musisz wdrożyć swój własny skrót? W przypadku większości zadań powinieneś uzyskać dobre wyniki ze strukturami danych ze standardowej biblioteki, zakładając, że dostępna jest implementacja (chyba że robisz to tylko dla własnej edukacji).
Jeśli chodzi o rzeczywiste algorytmy mieszające, moim ulubionym jest FNV. 1
Oto przykładowa implementacja 32-bitowej wersji w C:
źródło
*
i^
:h = (h * 16777619) ^ p[i]
==>h = (h ^ p[i]) * 16777619