Hvilken hashingalgoritme er bedst for unikhed og hastighed? Eksempel (gode) anvendelser inkluderer hash-ordbøger.
Jeg ved, at der er ting som SHA-256 og lignende, men disse algoritmer er designet til at være sikker , hvilket normalt betyder, at de er langsommere end algoritmer der er mindre unikke . Jeg vil have en hash-algoritme designet til at være hurtig, men alligevel forblive temmelig unik for at undgå kollisioner.
Kommentarer
- Til hvilket formål, sikkerhed eller andet?
- @Orbling, til implementering af en hashordbog. Så kollisioner skal holdes på et minimum, men det har slet ingen sikkerhedsformål.
- Bemærk, at du bliver nødt til at forvente mindst nogle kollisioner i din hash-tabel, ellers bordet skal være enormt for at kunne håndtere selv et relativt lille antal nøgler …
- Fantastisk indlæg! Kunne du også kontrollere ‘ s Yann Collet ‘ s xxHash (skaberen eller LZ4), hvilket er dobbelt så hurtigt som Murmur? Hjemmeside: code.google.com/p/xxhash Mere info: fastcompression.blogspot.fr/2012/ 04 / …
- @zvrba Afhænger af algoritmen. bcrypt er designet til at være langsom.
Svar
Jeg testede nogle forskellige algoritmer med måling af hastighed og antal kollisioner .
Jeg brugte tre forskellige nøglesæt:
- En liste med 216.553 engelske ord 🕗 arkiv (med små bogstaver)
- Tallene
"1"
til"216553"
(tænk postnummer og hvordan en dårlig hash fjernede msn.com 🕗 arkiv ) - 216.553 ” tilfældig “(dvs. type 4 uuid ) GUIDer
For hvert corpus er antallet af kollisioner og den gennemsnitlige tid brugt hashing blev optaget.
Jeg testede:
- DJB2
- DJB2a (variant ved hjælp af
xor
i stedet for+
) - FNV-1 (32-bit)
- FNV-1a (32-bit)
- SDBM
- CRC32
- Murmur2 (32-bit)
- SuperFastHash
Resultater
Hvert resultat indeholder den gennemsnitlige hashtid og antallet af kollisioner
Hash Lowercase Random UUID Numbers ============= ============= =========== ============== Murmur 145 ns 259 ns 92 ns 6 collis 5 collis 0 collis FNV-1a 152 ns 504 ns 86 ns 4 collis 4 collis 0 collis FNV-1 184 ns 730 ns 92 ns 1 collis 5 collis 0 collis▪ DBJ2a 158 ns 443 ns 91 ns 5 collis 6 collis 0 collis▪▪▪ DJB2 156 ns 437 ns 93 ns 7 collis 6 collis 0 collis▪▪▪ SDBM 148 ns 484 ns 90 ns 4 collis 6 collis 0 collis** SuperFastHash 164 ns 344 ns 118 ns 85 collis 4 collis 18742 collis CRC32 250 ns 946 ns 130 ns 2 collis 0 collis 0 collis LoseLose 338 ns - - 215178 collis
Noter :
- LoseLose-algoritme (hvor hash = hash + tegn) er virkelig forfærdelig . Alt kolliderer i de samme 1.375 spande
- SuperFastHash er hurtig, med tingene ser ret spredte ud; af min godhed antallet kollisionerne. Jeg håber den fyr, der portede det, fik noget galt; det er ret dårligt
- CRC32 er ret godt . Langsommere og en opslagstabel på 1k
Er der faktisk kollisioner?
Ja. Jeg begyndte at skrive mit testprogram for at se, om hashkollisioner faktisk sker – og ikke kun er en teoretisk konstruktion.De sker faktisk:
FNV-1 kollisioner
-
creamwove
kolliderer medquists
FNV -1a kollisioner
-
costarring
kolliderer medliquid
-
declinate
kolliderer medmacallums
-
altarage
kolliderer medzinke
-
altarages
kolliderer medzinkes
Murmur2 kollisioner
-
cataract
kolliderer medperiti
-
roquette
kolliderer medskivie
-
shawl
kolliderer medstormbound
-
dowlases
kolliderer medtramontane
-
cricketings
kolliderer medtwanger
-
longans
kolliderer medwhigs
DJB2-kollisioner
-
hetairas
kolliderer medmentioner
-
heliotropes
kolliderer medneurospora
-
depravement
kolliderer medserafins
-
stylist
kolliderer medsubgenera
-
joyful
kolliderer medsynaphea
-
redescribed
kolliderer medurites
-
dram
kolliderer medvivency
DJB2a kollisioner
-
haggadot
kolliderer medloathsomenesses
-
adorablenesses
kolliderer medrentability
-
playwright
kolliderer medsnush
-
playwrighting
kolliderer medsnushing
-
treponematoses
kolliderer medwaterbeds
CRC32-kollisioner
-
codding
kolliderer medgnu
-
exhibiters
kolliderer medschlager
SuperFastHash kollisioner
-
dahabiah
kolliderer meddrapability
-
encharm
kolliderer medenclave
-
grahams
kolliderer medgramary
- … klip 79 kollisioner …
-
night
kolliderer medvigil
- kolliderer med
vigils
-
finks
kolliderer medvinic
Randomnessification
Det andet subjektive mål er, hvor tilfældigt fordelte hasherne er. Kortlægning af de resulterende HashTables viser, hvor jævnt dataene fordeles. Alle hash-funktionerne viser god fordeling, når de kortlægger tabellen lineært:
Eller som en Hilbert Map ( XKCD er altid relevant ):
Undtagen når hashing nummerstrenge ("1"
, "2"
, …, "216553"
) (f.eks. postnumre ), hvor mønstre begynder at dukke op i de fleste hashingalgoritmer:
SDBM :
DJB2a :
FNV-1 :
Alle undtagen
FNV-1a , som stadig ser ret tilfældigt ud for mig:
Faktisk synes Murmur2 at have endnu bedre tilfældighed med Numbers
end FNV-1a
:
Når jeg ser på
FNV-1a
“nummer” -kortet, så tænk Jeg ser subtile lodrette mønstre. Med Murmur ser jeg slet ingen mønstre. Hvad synes du?
Det ekstra *
i tabellen angiver, hvor dårlig tilfældigheden er. Med FNV-1a
som det bedste og DJB2x
som værst:
Murmur2: . FNV-1a: . FNV-1: ▪ DJB2: ▪▪ DJB2a: ▪▪ SDBM: ▪▪▪ SuperFastHash: . CRC: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ Loselose: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
Jeg skrev oprindeligt dette program for at beslutte, om jeg endda skulle bekymre mig om kollisioner: Det gør jeg.
Og så blev det til at sikre, at hash-funktionerne var tilstrækkeligt tilfældige.
FNV-1a-algoritme
FNV1-hashen kommer i varianter, som returnere 32, 64, 128, 256, 512 og 1024 bit hashes.
FNV-1a algoritme er:
hash = FNV_offset_basis for each octetOfData to be hashed hash = hash xor octetOfData hash = hash * FNV_prime return hash
Hvor konstanterne FNV_offset_basis
og FNV_prime
afhænger af den ønskede hash-størrelse :
Hash Size =========== 32-bit prime: 2^24 + 2^8 + 0x93 = 16777619 offset: 2166136261 64-bit prime: 2^40 + 2^8 + 0xb3 = 1099511628211 offset: 14695981039346656037 128-bit prime: 2^88 + 2^8 + 0x3b = 309485009821345068724781371 offset: 144066263297769815596495629667062367629 256-bit prime: 2^168 + 2^8 + 0x63 = 374144419156711147060143317175368453031918731002211 offset: 100029257958052580907070968620625704837092796014241193945225284501741471925557 512-bit prime: 2^344 + 2^8 + 0x57 = 35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759 offset: 9659303129496669498009435400716310466090418745672637896108374329434462657994582932197716438449813051892206539805784495328239340083876191928701583869517785 1024-bit prime: 2^680 + 2^8 + 0x8d = 5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573 offset: 1419779506494762106872207064140321832088062279544193396087847491461758272325229673230371772250864096521202355549365628174669108571814760471015076148029755969804077320157692458563003215304957150157403644460363550505412711285966361610267868082893823963790439336411086884584107735010676915
Se FNV-hovedsiden for detaljer.
Alle mine resultater er med 32-bit-varianten.
FNV-1 bedre end FNV-1a?
Nej. FNV-1a er rundt omkring bedre. Der var flere kollisioner med FNV-1a, når du bruger det engelske ord corpus:
Hash Word Collisions ====== =============== FNV-1 1 FNV-1a 4
Sammenlign nu små og store bogstaver:
Hash lowercase word Collisions UPPERCASE word collisions ====== ========================= ========================= FNV-1 1 9 FNV-1a 4 11
I dette tilfælde er FNV-1a ikke” t “400%” dårligere end FN-1, kun 20% dårligere.
Jeg tror, at vigtigere takeaway er, at der er to klasser af algoritmer, når det kommer til kollisioner:
- kollisioner sjældne : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
- kollisioner fælles : SuperFastHash, Loselose
Og så er der hvor jævnt fordelt hash er:
- fremragende fordeling: Murmur2, FNV-1a, SuperFastHas
- fremragende fordeling: FNV-1
- god fordeling: SDBM, DJB2, DJB2a
-
frygtelig fordeling: Loselose
Opdater
Murmur? Sikker på, hvorfor ikke
Opdater
@whatshisname undrede sig over, hvordan en CRC32 ville udføre, tilføjede tal til tabellen.
CRC32 er ret godt . Få kollisioner, men langsommere, og omkostningerne ved en 1k-opslagstabel.
Klip alle fejlagtige ting om CRC-distribution – min dårlige
Op indtil i dag skulle jeg bruge FNV-1a som min de facto hash-tabel hashing algoritme. Men nu skifter jeg til Murmur2:
- Hurtigere
- Bedre tilfældighed af alle klasser af input
Og jeg håber virkelig virkelig der er noget galt med SuperFastHash
algoritmen, jeg fandt ; det er for dårligt at være så populært som det er.
Opdatering: Fra MurmurHash3-hjemmesiden på Google :
(1) – SuperFastHash har meget dårlige kollisionsegenskaber, som er blevet dokumenteret andetsteds.
Så jeg antager, at det ikke bare er mig.
Opdatering: Jeg indså, hvorfor Murmur
er hurtigere end de andre. MurmurHash2 fungerer på fire byte ad gangen. De fleste algoritmer er byte for byte :
for each octet in Key AddTheOctetToTheHash
Dette betyder, at når nøglerne bliver længere, får Murmur sin chance for at skinne.
Opdater
GUIDer er designet til at være unikke, ikke tilfældige
Et rettidig indlæg af Raymond Chen gentager det faktum, at “tilfældige” GUIDer ikke er beregnet til at blive brugt til deres tilfældighed. De eller en delmængde af dem er uegnede som en hash-nøgle:
Selv version 4 GUID-algoritmen er ikke garanteret at være uforudsigelig, fordi algoritmen specificerer ikke kvaliteten af tilfældig talgenerator. Wikipedia-artiklen til GUID indeholder primær forskning, der antyder , at fremtidige og tidligere GUIDer kan forudsiges på baggrund af kendskab til tilfældig talgeneratortilstand, da generatoren ikke er kryptografisk stærk.
Tilfældighed er ikke det samme som kollisionsundgåelse; det er derfor, det ville være en fejl at forsøge at opfinde din egen “hashing” -algoritme ved at tage en delmængde af en “tilfældig” vejledning:
int HashKeyFromGuid(Guid type4uuid) { //A "4" is put somewhere in the GUID. //I can"t remember exactly where, but it doesn"t matter for //the illustrative purposes of this pseudocode int guidVersion = ((type4uuid.D3 & 0x0f00) >> 8); Assert(guidVersion == 4); return (int)GetFirstFourBytesOfGuid(type4uuid); }
Bemærk : Igen sætter jeg “tilfældig GUID” i anførselstegn, fordi det er “tilfældigt” variant af GUIDer. En mere nøjagtig beskrivelse ville være Type 4 UUID
. Men ingen ved, hvad type 4 eller type 1, 3 og 5 er. Så det er bare nemmere at kalde dem “tilfældige “GUIDer.
Alle engelske ord spejler
- https://web.archive.org/web/20070221060514/http://www.sitopreferito.it/html/all_english_words.html
- https://drive.google.com/file/d/0B3BLwu7Vb2U-dEw1VkUxc3U4SG8/view?usp=sharing
Kommentarer
- Det ville være rigtig interessant at se, hvordan SHA sammenligner, ikke fordi det ‘ er en god kandidat til en hashingalgoritme her, men det ville være rigtig interessant at se, hvordan kryptografisk hash sammenlignes med disse lavet til hastighedsalgoritmer.
- En ny hash ved navn e af ‘ xxHash ‘, af Yann Collet, gjorde for nylig runderne. Jeg ‘ er altid mistænksom over for en ny hash. Det ville være interessant at se det i din sammenligning (hvis du ikke er ‘ t træt af folk, der foreslår tilfældige hash, har de ‘ hørt om skal tilføjes …)
- Faktisk. De præstationsnumre, der er annonceret af xxHash-projektsiden, ser imponerende ud, måske for meget til at være sandt. I det mindste er det ‘ et open source-projekt: code.google.com/p/xxhash
- Hej Ian, min Delphi-implementering af SuperFastHash er korrekt. Under implementeringen oprettede jeg et testsæt i C og Delphi for at sammenligne resultaterne af min implementering og referenceimplementeringen. Der er ingen forskelle. Så hvad du ser er hashens faktiske dårlighed … (Derfor offentliggjorde jeg også en MurmurHash-implementering: landman-code.blogspot.nl/2009/02/ … )
- Er plakaten opmærksom på, at dette ikke bare er et fantastisk svar – dette er verden ‘ s de facto reference ressource om emnet? Når som helst jeg har brug for hashes, løser mit problem så hurtigt og autoritativt, at jeg ikke ‘ behøver noget andet.
Svar
Hvis du ønsker at oprette et hash-kort fra en uændret ordbog, kan du overveje at foretage perfekt hashing https://en.wikipedia.org/wiki/Perfect_hash_function – under konstruktionen af hash-funktionen og hash-tabellen kan du garantere for et givet datasæt, at der ikke er nogen kollisioner.
Kommentarer
- Her ‘ er mere om (minimal) Perfect Hashing burtleburtle.net/bob/hash/perfect.html inklusive ydeevnedata, skønt den ikke ‘ ikke bruger den nyeste processor osv.
- Det ‘ er ret indlysende, men det er værd at påpege, at nøglerne for at garantere ingen kollisioner skal have samme størrelse som værdierne, medmindre der er begrænsninger for de værdier, som algoritmen kan udnytte.
- @ devios1 Din erklæring er meningsløs. For det første er værdierne i en hash-tabel, perfekte eller ej, uafhængige af nøglerne. For det andet er en perfekt hash-tabel bare en lineær række af værdier, indekseret af resultatet af en funktion, der er udformet, så alle indekserne er unikke.
- @MarcusJ Perfect hashing bruges normalt med mindre end 100 nøgler, men kig på cmph.sourceforge.net … stadig langt fra dit interval.
- @DavidCary Intet til din link understøtter dit krav. Muligvis har du forvekslet O (1) med ” ingen kollisioner “, men de er ikke ‘ t overhovedet den samme ting. Selvfølgelig garanterer perfekt hashing ingen kollisioner, men det kræver, at alle nøgler er kendt på forhånd, og at der er relativt få af dem. (Men se linket til cmph ovenfor.)
Svar
Her er en liste over hash-funktioner, men den korte version er:
Hvis du bare vil have en god hash-funktion , og kan ikke vente,
djb2
er en af de bedste streng-hash-funktioner, jeg kender. Det har fremragende fordeling og hastighed på mange forskellige sæt nøgler og tabelstørrelser
unsigned long hash(unsigned char *str) { unsigned long hash = 5381; int c; while (c = *str++) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ return hash; }
Kommentarer
- Djb2 er faktisk nulfølsom, da de fleste sådanne enkle hashfunktioner, så du nemt kan bryde sådanne hashes.Det har en dårlig bias for mange kollisioner og en dårlig fordeling, det bryder på de fleste smhasher kvalitetstest: Se github.com/rurban/smhasher/blob/master/doc/bernstein Hans cdb-database bruger den, men jeg ville ikke ‘ ikke bruge den med offentlig adgang.
- DJB er ret dårlig set fra et præstations- og distributionssynspunkt. Jeg ville ikke ‘ ikke bruge det i dag.
- @ConradMeyer Jeg ‘ satsede, DJB kan øges med en faktor på tre ligesom i dette spørgsmål af mig , og så slog det ‘ sandsynligvis de mest anvendelige algoritmer. Med hensyn til distributionen er jeg enig. En hash, der producerer kollisioner, selv for to bogstavstrenge, kan ‘ ikke være rigtig god.
- Gutter, jeg er i tvivl. Du siger, at
djb2
er dårligt, men testresultaterne af det accepterede svar viser, at det er godt. - Du kan i det mindste bruge en fornuftig prime, der giver mindre kollisioner i stedet for 33. stackoverflow.com/a/2816747/21499
Svar
CityHash fra Google er den algoritme, du leder efter. Det er ikke godt for kryptografi, men det er godt til at generere unikke hashes.
Læs blog for at få flere oplysninger og -koden er tilgængelig her .
CityHash er skrevet i C ++. Der er også en almindelig C-port .
Alle CityHash-funktioner er indstillet til 64-bit processorer. Når det er sagt, vil de køre (bortset fra de nye, der bruger SSE4.2) i 32-bit kode. De vil dog ikke være meget hurtige. Det kan være en god idé at bruge Murmur eller noget andet i 32-bit kode.
Kommentarer
- Er CityHash udtalt svarende til ” City Sushi? ”
- Har en se også på SipHash, det er meningen at erstatte MurmurHash / CityHash / osv.: 131002.net/siphash
- Se også FarmHash, en efterfølger til CitHash. code.google.com/p/farmhash
- xxHash hævder at være 5 gange hurtigere end CityHash.
-
plain C port
link er brudt
Svar
Jeg har tegnet en kort hastighedssammenligning af forskellige hashingalgoritmer, når hashing filer.
De enkelte plotter adskiller sig kun lidt i læsemetoden og kan ignoreres her, da alle filer blev gemt i en tmpfs. Derfor var benchmarket ikke IO-bundet, hvis du undrer dig.
Algoritmer inkluderer: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}
.
Konklusioner:
- Ikke-kryptografiske hashfunktioner som Murmur3, Cityhash og Spooky er ret tæt på hinanden. Man skal bemærke, at Cityhash kan være hurtigere på CPUer med SSE 4.2s
CRC
instruktion, som min CPU ikke har. SpookyHash var i mit tilfælde altid en lille smule før CityHash. - MD5 ser ud til at være en god kompromis, når man bruger kryptografiske hashfunktioner, selvom SHA256 kan være mere sikker på kollisionssårbarheder af MD5 og SHA1.
- Kompleksiteten af alle algoritmer er lineær – hvilket virkelig ikke er overraskende, da de fungerer blokvis. (Jeg ville se, om læsemetoden gør en forskel, så du bare kan sammenligne de længste værdier).
- SHA256 var langsommere end SHA512.
- Jeg undersøgte ikke tilfældigheden af hash-funktionerne. Men her er en god sammenligning af de hash-funktioner, der mangler i Ian Boyds svar . Dette påpeger, at CityHash har nogle problemer i hjørnesager.
Kilden, der er brugt til plottene:
- https://github.com/sahib/rmlint/tree/gh-pages/plots (undskyld den grimme kode)
Kommentarer
- Grafen for lineær skala afskærer y-aksens etiket, der siger, hvilken mængde den planlægger. Jeg antager, at det sandsynligvis ville være ” tid i sekunder “, samme som den logaritmiske skala. Det er ‘ værd at rette.
Svar
Jeg ved, at der er ting som SHA-256 og sådan, men disse algoritmer er designet at være sikker , hvilket normalt betyder, at de er langsommere end algoritmer, der er mindre unikke .
Antagelsen om, at kryptografiske hashfunktioner er mere unikke, er forkert, og faktisk kan det vises, at den ofte er bagud i praksis. I sandhed:
- Kryptografiske hashfunktioner skal ideelt set være der ikke kan skelnes fra tilfældig ;
- Men med ikke-kryptografiske hashfunktioner er det ønskeligt, at de interagerer gunstigt med sandsynlige input .
Hvilket betyder, at en ikke-kryptografisk hash-funktion godt kan have færre kollisioner end en kryptografisk for “godt” datasæt – datasæt, som det var designet til.
Vi kan faktisk demonstrere dette med dataene i Ian Boyds svar og lidt matematik: Fødselsdagsproblem . Formlen for det forventede antal kolliderende par, hvis du vælger n
tilfældige tal helt fra sættet [1, d]
er dette (taget fra Wikipedia):
n - d + d * ((d - 1) / d)^n
Tilslutning n
= 216.553 og d
= 2 ^ 32 får vi ca. 5.5 forventede kollisioner . Ians tests viser for det meste resultater omkring dette kvarter, men med en dramatisk undtagelse: de fleste af funktionerne fik nul kollisioner i fortløbende nummertest. Sandsynligheden for at vælge 216.553 32-bit numre tilfældigt og få nul kollisioner er omkring 0,43%. Og det er bare for en funktion – her har vi fem forskellige hashfunktionsfamilier med nul kollisioner!
Så hvad vi ser her er, at de hashes, som Ian testede, interagerer fordelagtigt med datasættet på hinanden følgende numre – dvs. de spredes minimalt forskellige input mere bredt end en ideel kryptografisk hash-funktion ville. (Sidebemærkning: dette betyder, at Ians grafiske vurdering af, at FNV-1a og MurmurHash2 “ser tilfældigt ud” for ham i tallene datasættet kan tilbagevises fra hans egne data. Nul kollisioner på et datasæt af den størrelse, for begge hash-funktioner, er slående ikke tilfældigt!)
Dette er ikke en overraskelse, fordi dette er en ønskelig opførsel for mange anvendelser af hash-funktioner. F.eks. er hash-tabel nøgler ofte meget ens; Ians svar nævner et problem, MSN engang havde med postnummer hash-tabeller . Dette er en anvendelse, hvor kollisionsundgåelse på sandsynlige input vinder tilfældig-lignende opførsel.
En anden instruktiv sammenligning her er kontrasten i designmålene mellem CRC og kryptografiske hashfunktioner:
- CRC er designet til at fange fejl som følge af støjende kommunikationskanaler , som sandsynligvis vil være et lille antal bitflip;
- Crypto-hashes er designet til at fange ændringer foretaget af ondsindede angribere , der er tildelt begrænsede beregningsressourcer, men vilkårligt meget kloge.
Så for CRC er det igen godt at have færre kollisioner end tilfældigt i minimalt forskellige input. Med krypto-hashes er dette et nej-nej!
Svar
SHA-algoritmerne (inklusive SHA-256) er designet til at være hurtig .
Faktisk kan deres hastighed nogle gange være et problem. Især er en almindelig teknik til lagring af et adgangskodeafledt token at køre en standard hurtig hash-algoritme 10.000 gange (lagring af hash af hash af hash af hash af … adgangskode).
#!/usr/bin/env ruby require "securerandom" require "digest" require "benchmark" def run_random_digest(digest, count) v = SecureRandom.random_bytes(digest.block_length) count.times { v = digest.digest(v) } v end Benchmark.bmbm do |x| x.report { run_random_digest(Digest::SHA256.new, 1_000_000) } end
Output:
Rehearsal ------------------------------------ 1.480000 0.000000 1.480000 ( 1.391229) --------------------------- total: 1.480000sec user system total real 1.400000 0.000000 1.400000 ( 1.382016)
Kommentarer
- Det ‘ er relativt hurtigt, sikkert, for en kryptografisk hashingalgoritme . Men OP vil bare gemme værdier i en hashtable, og jeg tror ikke ‘ at en kryptografisk hash-funktion virkelig er passende til det.
- Spørgsmålet rejst (tangentielt ser det nu ud) emnet for de kryptografiske hash-funktioner. At ‘ er den bit, jeg reagerer på.
- Bare for at afskrække folk fra ideen om ” Især , en almindelig teknik til lagring af et adgangskodeafledt token er at køre en standard hurtig hash-algoritme 10.000 gange ” – mens det er almindeligt, at ‘ er bare dumt. Der er algoritmer designet til disse scenarier, f.eks.
bcrypt
. Brug de rigtige værktøjer. - Kryptografiske hashes er designet til at have en høj kapacitet, men det betyder ofte, at de har høje opsætnings-, nedbrydnings-,
.rodata
og / eller statslige omkostninger .Når du vil have en algoritme til en hashtable, har du normalt meget korte nøgler og mange af dem, men har ikke brug for de ekstra garantier, som en kryptografisk har. Jeg bruger en tweaked Jenkins en ad gangen selv. - @ChrisMorgan: I stedet for at bruge en kryptografisk sikker hash kan HashTable DoS løses meget mere effektivt ved hjælp af hash-randomisering, så hver kørsel af programmerne eller endda på hver hashtable, så dataene ‘ grupperes ikke i den samme spand hver gang.
Svar
Brug SipHash . Det har mange ønskelige egenskaber:
-
Hurtigt. En optimeret implementering tager cirka 1 cyklus pr. byte.
-
Sikker. SipHash er en stærk PRF (pseudorandom-funktion). Dette betyder, at den ikke kan skelnes fra en tilfældig funktion (medmindre du kender den 128-bit hemmelige nøgle). Derfor:
-
Ingen grund til at bekymre sig om, at dine hash-tabel-sonder bliver lineære på grund af kollisioner. Med SipHash ved du at du i gennemsnit får gennemsnitlig sagsydelse uanset input.
-
Immunitet mod hash-baseret denial of service-angreb.
-
Du kan bruge SipHash (især versionen med en 128-bit output) som en MAC (Beskedgodkendelseskode). Hvis du modtager en besked og et SipHash-tag, og tagget er det samme som at køre SipHash med din hemmelige nøgle, så ved du, at den, der oprettede hash, også var i besiddelse af din hemmelige nøgle, og at hverken meddelelsen eller hash er blevet ændret siden.
-
Kommentarer
- Isn ‘ t SipHash overkill, medmindre du har brug for sikkerhed? Kræver en 128-bit nøgle, som bare er et glorificeret hashfrø. For ikke at nævne MurmurHash3 har 128-bit output og SipHash har kun en 64-bit output. Det er klart, at den større fordøjelse har en mindre kollisionschance.
- @bryc Forskellen er, at SipHash fortsat vil være velopdragen, selv ved ondsindet input. En hash-tabel baseret på SipHash kan bruges til data fra potentielt fjendtlige kilder og kan bruge en algoritme såsom lineær sondering, der er meget følsom over for detaljerne i hash-funktionen.
- Siphash (og relateret nyere prng stilfunktioner) er mit standardvalg for sikkerhed. For ydeevne er xxhash svært at slå. Der er masser af dårlige hashing-råd på internettet, selv i diskussionerne her. God ydelse på tilfældige eller semi-tilfældige input er meningsløs. Hvad er den værst tænkelige ydeevne med input fra den virkelige verden? Hvad er resultatet med ondsindede input? Din hash-tabel bliver i sidste ende en angrepsvektor.
Svar
Det afhænger af de data, du hashing. Nogle hashing fungerer bedre med specifikke data som tekst. Nogle hashingalgoritmer var specifikt designet til at være gode til specifikke data.
Paul Hsieh lavede engang hurtig hash . Han lister kildekode og forklaringer. Men det var allerede slået. 🙂
Svar
Java bruger denne enkle gang -og-tilføj algoritme:
Hashkoden for et strengobjekt beregnes som
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
ved hjælp af int-aritmetik, hvor
s[i]
er i -strengen,n
er længden af strengen, og^
angiver eksponentiering. (Hash-værdien for den tomme streng er nul.)
Der er sandsynligvis meget bedre derude, men dette er ret udbredt og synes at være en god kompromis mellem hastighed og unikhed.
Kommentarer
- Jeg ville ‘ ikke bruge nøjagtigt det samme en bruges her, da det ‘ stadig er relativt let at producere kollisioner med dette. Det ‘ er bestemt ikke forfærdeligt, men der er meget bedre derude. Og hvis der ‘ ikke er nogen væsentlig grund til at være kompatibel med Java, skal det ikke vælges.
- Hvis du stadig vælger dette af hash af en eller anden grund, kan du i det mindste bruge en bedre prime som 92821 som en multiplikator. Det reducerer kollisioner meget. stackoverflow.com/a/2816747/21499
- Du kan lige så godt bruge FNV1a i stedet. Det ‘ er også en simpel multiplikationsbaseret hash, men bruger en større multiplikator, som spreder hashen bedre.
- Du don ‘ vil ikke gøre
s[0]*31^3 + s[1]*31^2 + s[2]*31 + s[3]
. Undgå el-operatøren (^) og gør det på denne måde:((s[0]*31 + s[1])*31 + s[2])*31 + s[3]
. - @LeopoldoSanczyk Ja, i koden er det (og skal gøres) iterativt, det var bare lettere at forstå i en lukket formel.
Svar
Først og fremmest, hvorfor har du brug for at implementere din egen hashing? For de fleste opgaver skal du få gode resultater med datastrukturer fra et standardbibliotek, forudsat at der er en implementering tilgængelig (medmindre du bare gør dette for din egen uddannelse).
Hvad angår faktiske hashingalgoritmer, er min personlige favorit FNV. 1
Her er et eksempel på implementering af 32-bit versionen i C:
unsigned long int FNV_hash(void* dataToHash, unsigned long int length) { unsigned char* p = (unsigned char *) dataToHash; unsigned long int h = 2166136261UL; unsigned long int i; for(i = 0; i < length; i++) h = (h * 16777619) ^ p[i] ; return h; }
Kommentarer
- FNV-1a-varianten er lidt bedre med tilfældighed. Skift rækkefølgen af
*
og^
:h = (h * 16777619) ^ p[i]
== >h = (h ^ p[i]) * 16777619