Welcher Hashalgorithmus eignet sich am besten für die Eindeutigkeit und Geschwindigkeit? Beispiel (gute) Verwendungen beinhalten Hash-Wörterbücher.
Ich weiß, dass es Dinge wie SHA-256 und dergleichen gibt, aber diese Algorithmen sind so konzipiert , dass sie sicher sind , was normalerweise bedeutet, dass sie langsamer sind als Algorithmen, die weniger einzigartig sind . Ich möchte, dass ein Hash-Algorithmus schnell ist und dennoch ziemlich einzigartig bleibt, um Kollisionen zu vermeiden.
algorithms
hashing
Earlz
quelle
quelle
Antworten:
Ich habe verschiedene Algorithmen getestet, die Geschwindigkeit und die Anzahl der Kollisionen messen.
Ich habe drei verschiedene Schlüsselsätze verwendet:
"1"
zu"216553"
(man denke an Postleitzahlen und wie ein schlechter Hash msn.com runtergeholt hat )Für jeden Korpus wurde die Anzahl der Kollisionen und die durchschnittliche Zeit, die für das Hashing aufgewendet wurde, aufgezeichnet.
Ich habe getestet:
xor
eher mit als+
)Ergebnisse
Jedes Ergebnis enthält die durchschnittliche Hash-Zeit und die Anzahl der Kollisionen
Anmerkungen :
Treten tatsächlich Kollisionen auf?
Ja. Ich habe angefangen, mein Testprogramm zu schreiben, um festzustellen, ob tatsächlich Hash-Kollisionen auftreten - und das ist nicht nur ein theoretisches Konstrukt. Sie passieren tatsächlich:
FNV-1-Kollisionen
creamwove
kollidiert mitquists
FNV-1a-Kollisionen
costarring
kollidiert mitliquid
declinate
kollidiert mitmacallums
altarage
kollidiert mitzinke
altarages
kollidiert mitzinkes
Murmel2-Kollisionen
cataract
kollidiert mitperiti
roquette
kollidiert mitskivie
shawl
kollidiert mitstormbound
dowlases
kollidiert mittramontane
cricketings
kollidiert mittwanger
longans
kollidiert mitwhigs
DJB2-Kollisionen
hetairas
kollidiert mitmentioner
heliotropes
kollidiert mitneurospora
depravement
kollidiert mitserafins
stylist
kollidiert mitsubgenera
joyful
kollidiert mitsynaphea
redescribed
kollidiert miturites
dram
kollidiert mitvivency
DJB2a Kollisionen
haggadot
kollidiert mitloathsomenesses
adorablenesses
kollidiert mitrentability
playwright
kollidiert mitsnush
playwrighting
kollidiert mitsnushing
treponematoses
kollidiert mitwaterbeds
CRC32-Kollisionen
codding
kollidiert mitgnu
exhibiters
kollidiert mitschlager
SuperFastHash-Kollisionen
dahabiah
kollidiert mitdrapability
encharm
kollidiert mitenclave
grahams
kollidiert mitgramary
night
kollidiert mitvigil
nights
kollidiert mitvigils
finks
kollidiert mitvinic
Randomnessification
Das andere subjektive Maß ist, wie zufällig die Hashes verteilt sind. Die Zuordnung der resultierenden HashTables zeigt, wie gleichmäßig die Daten verteilt sind. Alle Hash-Funktionen zeigen eine gute Verteilung, wenn die Tabelle linear abgebildet wird:
Oder als Hilbert Map ( XKCD ist immer relevant ):
Außer , wenn Hashing Zahlenketten (
"1"
,"2"
...,"216553"
) (zB Postleitzahlen ), wo Muster beginnen in den meisten der Hash - Algorithmen entstehen:SDBM :
DJB2a :
FNV-1 :
Alle außer FNV-1a , die für mich immer noch ziemlich zufällig aussehen:
Tatsächlich scheint Murmur2 eine noch bessere Zufälligkeit zu haben
Numbers
alsFNV-1a
:Das Extra
*
in der Tabelle gibt an, wie schlecht die Zufälligkeit ist. MitFNV-1a
der Beste zu sein, undDJB2x
ist das Schlimmste:Ich habe dieses Programm ursprünglich geschrieben, um zu entscheiden, ob ich mir überhaupt Gedanken über Kollisionen machen musste: Ich tue es.
Und dann wurde sichergestellt, dass die Hash-Funktionen ausreichend zufällig waren.
FNV-1a-Algorithmus
Der FNV1-Hash gibt es in Varianten, die 32-, 64-, 128-, 256-, 512- und 1024-Bit-Hashes zurückgeben.
Der FNV-1a-Algorithmus lautet:
Wo die Konstanten
FNV_offset_basis
undFNV_prime
von der gewünschten Rückgabe-Hash-Größe abhängen:Einzelheiten finden Sie auf der FNV-Hauptseite .
Alle meine Ergebnisse sind mit der 32-Bit-Variante.
FNV-1 besser als FNV-1a?
Nein, FNV-1a ist rundum besser. Es gab mehr Kollisionen mit FNV-1a, wenn das englische Wort Corpus verwendet wurde:
Vergleichen Sie nun Klein- und Großbuchstaben:
In diesem Fall ist FNV-1a nicht "400%" schlechter als FN-1, sondern nur 20% schlechter.
Ich denke, der wichtigste Aspekt ist, dass es zwei Klassen von Algorithmen gibt, wenn es um Kollisionen geht:
Und dann ist da noch die gleichmäßige Verteilung der Hashes:
Aktualisieren
Murmeln? Sicher warum nicht
Aktualisieren
@whatshisname fragte sich, wie sich ein CRC32 verhalten würde und fügte der Tabelle Zahlen hinzu.
CRC32 ist ziemlich gut . Nur wenige Kollisionen, aber langsamer, und der Overhead einer 1k-Nachschlagetabelle.
Schnüffeln Sie alle fehlerhaften Informationen über die CRC-Verteilung - meine schlechte
Bis heute wollte ich FNV-1a als de facto Hash-Tabellen-Hashing-Algorithmus verwenden. Aber jetzt wechsle ich zu Murmur2:
Und ich, wirklich wirklich hoffen , dass es etwas falsch mit dem
SuperFastHash
Algorithmus , den ich gefunden ; Es ist schade, so beliebt zu sein, wie es ist.Update: Von der MurmurHash3-Homepage bei Google :
Also denke ich, dass es nicht nur ich bin.
Update: Mir ist aufgefallen, warum
Murmur
es schneller ist als die anderen. MurmurHash2 verarbeitet jeweils vier Bytes. Die meisten Algorithmen sind byteweise :Dies bedeutet, dass Murmeln mit länger werdenden Tasten seine Chance hat zu leuchten.
Aktualisieren
GUIDs sind eindeutig und nicht zufällig
Ein rechtzeitiger Beitrag von Raymond Chen weist erneut darauf hin, dass "zufällige" GUIDs nicht für ihre Zufälligkeit verwendet werden sollen. Sie oder eine Teilmenge davon sind als Hash-Schlüssel ungeeignet:
Zufälligkeit ist nicht dasselbe wie Kollisionsvermeidung. Aus diesem Grund wäre es ein Fehler, einen eigenen "Hashing" -Algorithmus zu erfinden, indem Sie eine Teilmenge einer "zufälligen" Guid verwenden:
Hinweis : Auch hier setze ich "zufällige GUID" in Anführungszeichen, da es sich um die "zufällige" Variante von GUIDs handelt. Eine genauere Beschreibung wäre
Type 4 UUID
. Aber niemand weiß, was Typ 4 oder Typ 1, 3 und 5 sind. Es ist also einfacher, sie als "zufällige" GUIDs zu bezeichnen.Alle englischen Wörter spiegeln
quelle
Wenn Sie eine Hash-Map aus einem unveränderten Wörterbuch erstellen möchten, möchten Sie möglicherweise das perfekte Hashing in Betracht ziehen. Https://en.wikipedia.org/wiki/Perfect_hash_function - während der Erstellung der Hash-Funktion und der Hash-Tabelle können Sie Folgendes garantieren: Für einen bestimmten Datensatz gibt es keine Kollisionen.
quelle
Hier ist eine Liste von Hash-Funktionen, aber die Kurzversion ist:
quelle
CityHash von Google ist der Algorithmus, den Sie suchen. Es ist nicht gut für die Kryptographie, aber es ist gut für die Erzeugung von eindeutigen Hashes.
Lesen Sie den Blog für weitere Details und den Code finden Sie hier .
CityHash ist in C ++ geschrieben. Es gibt auch einen einfachen C-Port .
Informationen zur 32-Bit-Unterstützung:
quelle
plain C port
Verbindung ist unterbrochenIch habe einen kurzen Geschwindigkeitsvergleich verschiedener Hashing-Algorithmen beim Hashing von Dateien erstellt.
Die einzelnen Plots unterscheiden sich nur geringfügig in der Lesemethode und können hier ignoriert werden, da alle Dateien in einem tmpfs gespeichert wurden. Daher war der Benchmark nicht an E / A gebunden, wenn Sie sich fragen.
Algorithmen sind:
SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}
.Schlussfolgerungen:
CRC
Anweisung möglicherweise schneller ist , als meine CPU. SpookyHash war in meinem Fall immer ein bisschen vor CityHash.Die für die Grundstücke verwendete Quelle:
quelle
Die SHA - Algorithmen (einschließlich SHA-256) sind entworfen , um schnell .
In der Tat kann ihre Geschwindigkeit manchmal ein Problem sein. Insbesondere besteht eine übliche Technik zum Speichern eines von einem Passwort abgeleiteten Tokens darin, einen schnellen Standard-Hash-Algorithmus 10.000 Mal auszuführen (Speichern des Hashs des Hashs des Hashs des Hashs des ... Passworts).
Ausgabe:
quelle
bcrypt
. Verwenden Sie die richtigen Werkzeuge..rodata
und / oder Statuskosten verursachen. Wenn Sie einen Algorithmus für eine Hash-Tabelle wünschen, haben Sie normalerweise sehr kurze Schlüssel und viele davon, benötigen aber nicht die zusätzlichen Garantien einer kryptografischen Verschlüsselung. Ich benutze einen gezwickten Jenkins nach dem anderen.Die Annahme, dass kryptografische Hash-Funktionen eindeutiger sind, ist falsch, und tatsächlich kann gezeigt werden, dass sie in der Praxis häufig rückwärts sind. In Wahrheit:
Dies bedeutet, dass eine nicht kryptografische Hash-Funktion möglicherweise weniger Kollisionen aufweist als eine kryptografische für "gute" Datensätze - Datensätze, für die sie entwickelt wurde.
Wir können dies anhand der Daten in Ian Boyds Antwort und ein bisschen Mathematik demonstrieren: dem Geburtstagsproblem . Die Formel für die erwartete Anzahl von Paaren zu kollidieren , wenn Sie wählen ,
n
ganze Zahlen zufällig aus der Menge[1, d]
ist dies (aus Wikipedia):Plugging
n
= 216.553 undd
= 2 ^ 32 ergeben sich ca. 5,5 erwartete Kollisionen . Ians Tests zeigen meist Ergebnisse in der Nachbarschaft, aber mit einer dramatischen Ausnahme: Die meisten Funktionen haben bei den Tests mit fortlaufenden Zahlen keine Kollisionen . Die Wahrscheinlichkeit, zufällig 216.553 32-Bit-Zahlen auszuwählen und keine Kollisionen zu erhalten, liegt bei etwa 0,43%. Und das ist nur für eine Funktion - hier haben wir fünf verschiedene Hash-Funktionsfamilien mit null Kollisionen!Wir sehen hier also, dass die von Ian getesteten Hashes günstig mit dem Datensatz mit fortlaufenden Zahlen interagieren - dh, sie verteilen minimal unterschiedliche Eingaben weiter als eine ideale kryptografische Hash-Funktion. (Randnotiz: Dies bedeutet, dass Ians grafische Einschätzung, dass FNV-1a und MurmurHash2 für ihn im Zahlen-Datensatz "zufällig" aussehen, aus seinen eigenen Daten widerlegt werden kann. Null Kollisionen mit einem Datensatz dieser Größe für beide Hash-Funktionen, ist auffallend ungewöhnlich!)
Dies ist keine Überraschung, da dies für viele Anwendungen von Hash-Funktionen ein wünschenswertes Verhalten ist. Beispielsweise sind Hash-Tabellenschlüssel häufig sehr ähnlich. Ians Antwort erwähnt ein Problem, das MSN einmal mit Postleitzahl-Hash-Tabellen hatte . Dies ist eine Anwendung, bei der die Kollisionsvermeidung bei wahrscheinlichen Eingaben das zufällige Verhalten gewinnt.
Ein weiterer aufschlussreicher Vergleich ist der Kontrast in den Entwurfszielen zwischen CRC- und kryptografischen Hash-Funktionen:
Für CRC ist es also wieder gut , bei minimal unterschiedlichen Eingaben weniger Kollisionen als zufällig zu haben. Bei Crypto-Hashes ist dies ein Nein-Nein!
quelle
Benutze SipHash . Es hat viele wünschenswerte Eigenschaften:
Schnell. Eine optimierte Implementierung dauert ungefähr 1 Zyklus pro Byte.
Sichern. SipHash ist eine starke PRF (Pseudozufallsfunktion). Dies bedeutet, dass es nicht von einer Zufallsfunktion zu unterscheiden ist (es sei denn, Sie kennen den 128-Bit-Geheimschlüssel). Daher:
Sie müssen sich keine Sorgen machen, dass Ihre Hash-Tabellensonden aufgrund von Kollisionen zu einer linearen Zeit werden. Mit SipHash wissen Sie , dass Sie unabhängig von den Eingaben eine durchschnittliche Leistung erzielen.
Immunität gegen Hash-basierte Denial-of-Service-Angriffe.
Sie können SipHash (insbesondere die Version mit einer 128-Bit-Ausgabe) als MAC (Message Authentication Code) verwenden. Wenn Sie eine Nachricht und ein SipHash-Tag erhalten und das Tag mit dem Tag identisch ist, mit dem Sie SipHash mit Ihrem geheimen Schlüssel ausgeführt haben, wissen Sie, dass sich auch derjenige, der den Hash erstellt hat, im Besitz Ihres geheimen Schlüssels befand und weder die Nachricht noch das Hash wurden seitdem geändert.
quelle
Es hängt von den Daten ab, die Sie haschen. Einige Hashes funktionieren besser mit bestimmten Daten wie z. B. Text. Einige Hashing-Algorithmen wurden speziell für bestimmte Daten entwickelt.
Paul Hsieh hat einmal schnell gehackt . Er listet Quellcode und Erklärungen auf. Aber es wurde schon geschlagen. :)
quelle
Java verwendet diesen einfachen Multiplikations- und Additionsalgorithmus:
Es gibt wahrscheinlich viel bessere, aber das ist ziemlich weit verbreitet und scheint ein guter Kompromiss zwischen Geschwindigkeit und Einzigartigkeit zu sein.
quelle
Warum müssen Sie zuerst Ihr eigenes Hashing implementieren? Für die meisten Aufgaben sollten Sie mit Datenstrukturen aus einer Standardbibliothek gute Ergebnisse erzielen, vorausgesetzt, es ist eine Implementierung verfügbar (es sei denn, Sie tun dies nur für Ihre eigene Ausbildung).
Was die eigentlichen Hashalgorithmen angeht, ist mein persönlicher Favorit FNV. 1
Hier ist eine Beispielimplementierung der 32-Bit-Version in C:
quelle
*
und^
:h = (h * 16777619) ^ p[i]
==>h = (h ^ p[i]) * 16777619