Hvilken hashingalgoritme er best for unikhet og hastighet? Eksempel (gode) bruksområder inkluderer hash-ordbøker.
Jeg vet at det er ting som SHA-256 og slikt, men disse algoritmene er designet for å være sikker , noe som vanligvis betyr at de er langsommere enn algoritmer som er mindre unike . Jeg vil ha en hash-algoritme designet for å være rask, men likevel være ganske unik for å unngå kollisjoner.
Kommentarer
- For hvilket formål, sikkerhet eller annet?
- @Orbling, for implementering av en hashordbok. Så kollisjoner bør holdes på et minimum, men det har ingen sikkerhetsformål i det hele tatt.
- Merk at du må forvente minst noen kollisjoner i hasjbordet ditt, ellers bordet må være enormt for å kunne håndtere selv et relativt lite antall nøkler …
- Flott innlegg! Kan du også sjekke ‘ s Yann Collet ‘ s xxHash (skaper eller LZ4), som er dobbelt så raskt som Murmur? Hjemmeside: code.google.com/p/xxhash Mer info: fastcompression.blogspot.fr/2012/ 04 / …
- @zvrba Avhenger av algoritmen. bcrypt er designet for å være tregt.
Svar
Jeg testet noen forskjellige algoritmer, og målte hastighet og antall kollisjoner .
Jeg brukte tre forskjellige nøkkelsett:
- En liste med 216 553 engelske ord 🕗 arkiv (med små bokstaver)
- Tallene
"1"
til"216553"
(tenk postnummer, og hvordan en dårlig hash tok ned msn.com 🕗 arkiv ) - 216,553 » tilfeldig «(dvs. type 4 uuid ) GUIDer
For hvert korpus, antall kollisjoner og gjennomsnittlig tid brukt hashing ble spilt inn.
Jeg testet:
- DJB2
- DJB2a (variant som bruker
xor
i stedet for+
) - FNV-1 (32-bit)
- FNV-1a (32-bit)
- SDBM
- CRC32
- Murmur2 (32-bit)
- SuperFastHash
Resultater
Hvert resultat inneholder gjennomsnittlig hashtid og antall kollisjoner
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
Merknader :
- LoseLose-algoritmen (der hash = hash + tegn) er virkelig forferdelig . Alt kolliderer i de samme 1 375 bøttene
- SuperFastHash er rask, med ting som ser ganske spredt ut; av min godhet antall kollisjonene. Jeg håper fyren som porterte det, fikk noe galt. Det er ganske ille
- CRC32 er ganske bra . Tregere og en oppslagstabell på 1k
Skjer kollisjoner egentlig?
Ja. Jeg begynte å skrive testprogrammet mitt for å se om hasjkollisjoner faktisk skjer – og ikke bare er en teoretisk konstruksjon.De skjer faktisk:
FNV-1 kollisjoner
-
creamwove
kolliderer medquists
FNV -1a kollisjoner
-
costarring
kolliderer medliquid
-
declinate
kolliderer medmacallums
-
altarage
kolliderer medzinke
-
altarages
kolliderer medzinkes
Murmur2-kollisjoner
-
cataract
kolliderer medperiti
-
roquette
kolliderer medskivie
-
shawl
kolliderer medstormbound
-
dowlases
kolliderer medtramontane
-
cricketings
kolliderer medtwanger
-
longans
kolliderer medwhigs
DJB2-kollisjoner
-
hetairas
kolliderer medmentioner
-
heliotropes
kolliderer medneurospora
-
depravement
kolliderer medserafins
-
stylist
kolliderer medsubgenera
-
joyful
kolliderer medsynaphea
-
redescribed
kolliderer medurites
-
dram
kolliderer medvivency
DJB2a kollisjoner
-
haggadot
kolliderer medloathsomenesses
-
adorablenesses
kolliderer medrentability
-
playwright
kolliderer medsnush
-
playwrighting
kolliderer medsnushing
-
treponematoses
kolliderer medwaterbeds
CRC32-kollisjoner
-
codding
kolliderer medgnu
-
exhibiters
kolliderer medschlager
SuperFastHash-kollisjoner
-
dahabiah
kolliderer meddrapability
-
encharm
kolliderer medenclave
-
grahams
kolliderer medgramary
- … klipp 79 kollisjoner …
-
night
kolliderer medvigil
- kolliderer med
vigils
-
finks
kolliderer medvinic
Randomnessification
Det andre subjektive målet er hvor tilfeldig fordelt hasjene er. Kartlegging av de resulterende HashTables viser hvor jevnt dataene distribueres. Alle hashfunksjonene viser god fordeling når du kartlegger tabellen lineært:
Eller som en Hilbert Map ( XKCD er alltid relevant ):
Bortsett fra når hashing nummerstrenger ("1"
, "2"
, …, "216553"
) (for eksempel postnummer ), der mønstre begynner å dukke opp i de fleste hashingalgoritmene:
SDBM :
DJB2a :
FNV-1 :
Alle unntatt
FNV-1a , som fremdeles ser ganske tilfeldig ut for meg:
Faktisk, Murmur2 ser ut til å ha enda bedre tilfeldighet med Numbers
enn FNV-1a
:
Når jeg ser på
FNV-1a
«nummer» -kartet, tenk Jeg ser subtile vertikale mønstre. Med Murmur ser jeg ingen mønstre i det hele tatt. Hva tror du?
Det ekstra *
i tabellen angir hvor dårlig tilfeldigheten er. Med FNV-1a
som best, og DJB2x
er det verste:
Murmur2: . FNV-1a: . FNV-1: ▪ DJB2: ▪▪ DJB2a: ▪▪ SDBM: ▪▪▪ SuperFastHash: . CRC: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ Loselose: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
Jeg skrev opprinnelig dette programmet for å avgjøre om jeg til og med måtte bekymre meg for kollisjoner: Jeg gjør det.
Og så ble det til å sørge for at hashfunksjonene var tilstrekkelig tilfeldige.
FNV-1a algoritme
FNV1 hash kommer i varianter som returner 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 konstantene FNV_offset_basis
og FNV_prime
avhenger av returhashstørrelsen du vil ha :
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 resultatene mine er med 32-bits varianten.
FNV-1 bedre enn FNV-1a?
Nei. FNV-1a er bedre. Det var flere kollisjoner med FNV-1a når det engelske ordet corpus ble brukt:
Hash Word Collisions ====== =============== FNV-1 1 FNV-1a 4
Sammenlign nå små og store bokstaver:
Hash lowercase word Collisions UPPERCASE word collisions ====== ========================= ========================= FNV-1 1 9 FNV-1a 4 11
I dette tilfellet er FNV-1a ikke» t «400%» dårligere enn FN-1, bare 20% dårligere.
Jeg tror viktigere takeaway er at det er to klasser av algoritmer når det gjelder kollisjoner:
- kollisjoner sjeldne : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
- kollisjoner vanlig : SuperFastHash, Loselose
Og så er det hvor jevnt fordelt hasjene er:
- fremragende fordeling: Murmur2, FNV-1a, SuperFastHas
- utmerket distribusjon: FNV-1
- god distribusjon: SDBM, DJB2, DJB2a
-
fryktelig fordeling: Loselose
Oppdater
Murmur? Jada, hvorfor ikke
Oppdater
@whatshisname lurte på hvordan en CRC32 ville utføre, la til tall i tabellen.
CRC32 er ganske bra . Få kollisjoner, men langsommere, og overhead på en 1k oppslagstabell.
Klipp ut alle feilaktige ting om CRC-distribusjon – min dårlige
Opp til i dag skulle jeg bruke FNV-1a som min de facto hash-tabell hashing-algoritme. Men nå bytter jeg til Murmur2:
- Raskere
- Bedre randomisering for alle klasser av input
Og jeg håper virkelig virkelig det er noe galt med SuperFastHash
algoritmen jeg fant ; det er så ille å være så populært som det er.
Oppdatering: Fra MurmurHash3-hjemmesiden på Google :
(1) – SuperFastHash har svært dårlige kollisjonsegenskaper, som har blitt dokumentert andre steder.
Så jeg antar at det ikke bare er meg.
Oppdatering: Jeg skjønte hvorfor Murmur
er raskere enn de andre. MurmurHash2 fungerer på fire byte om gangen. De fleste algoritmer er byte for byte :
for each octet in Key AddTheOctetToTheHash
Dette betyr at når nøklene blir lengre, får Murmur sjansen til å skinne.
Oppdater
GUID-er er designet for å være unike, ikke tilfeldige
Et betimelig innlegg av Raymond Chen gjentar det faktum at «tilfeldige» GUID-er ikke er ment å brukes til deres tilfeldighet. De, eller en delmengde av dem, er uegnet som hash-nøkkel:
Selv versjon 4 GUID-algoritmen er garantert ikke uforutsigbar, fordi algoritmen spesifiserer ikke kvaliteten på tilfeldig tallgenerator. Wikipedia-artikkelen for GUID inneholder primærforskning som antyder at fremtidige og tidligere GUIDer kan forutsies basert på kunnskap om tilfeldig tallgeneratortilstand, siden generatoren ikke er kryptografisk sterk.
Tilfeldighet er ikke det samme som å unngå kollisjon; det er derfor det ville være en feil å prøve å finne på din egen «hashing» -algoritme ved å ta noen delmengder av en «tilfeldig» guide:
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); }
Merk : Igjen setter jeg «tilfeldig GUID» i anførselstegn, fordi det er «tilfeldig» variant av GUID-er. En mer nøyaktig beskrivelse vil være Type 4 UUID
. Men ingen vet hva type 4, eller type 1, 3 og 5 er. Så det er bare lettere å kalle dem «tilfeldige «GUIDs.
Alle engelske ord speiler
- 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ært veldig interessant å se hvordan SHA sammenligner seg, ikke fordi det ‘ er en god kandidat for en hashingalgoritme her, men det ville være veldig interessant å se hvordan kryptografisk hash sammenlignes med disse laget for hastighetsalgoritmer.
- En ny hash ved navn e av ‘ xxHash ‘, av Yann Collet, gjorde rundene nylig. Jeg ‘ er alltid mistenksom mot en ny hash. Det ville være interessant å se det i sammenligningen din (hvis du ikke er ‘ t lei av folk som foreslår tilfeldige hash, har de ‘ hørt om skal legges til …)
- Faktisk. Ytelsestallene kunngjort av xxHash-prosjektsiden ser imponerende ut, kanskje for mye til å være sant. I det minste er det ‘ et open source-prosjekt: code.google.com/p/xxhash
- Hei Ian, min Delphi-implementering av SuperFastHash er riktig. Ved implementering opprettet jeg et testsett i C og Delphi for å sammenligne resultatene av implementeringen min og referanseimplementeringen. Det er ingen forskjeller. Så det du ser er hashens faktiske ondskap … (Derfor ga jeg også ut en MurmurHash-implementering: landman-code.blogspot.nl/2009/02/ … )
- Er plakaten klar over at dette ikke bare er et fantastisk svar – dette er verden ‘ s de facto referanse ressurs om emnet? Når som helst jeg trenger å håndtere hashes, løser problemet mitt så raskt og autoritativt at jeg ikke trenger ‘ jeg trenger aldri noe annet.
Svar
Hvis du ønsker å lage et hash-kart fra en uforanderlig ordbok, vil du kanskje vurdere perfekt hashing https://en.wikipedia.org/wiki/Perfect_hash_function – under konstruksjonen av hash-funksjonen og hash-tabellen kan du garantere, for et gitt datasett, at det ikke blir noen kollisjoner.
Kommentarer
- Her ‘ er mer om (minimal) Perfect Hashing burtleburtle.net/bob/hash/perfect.html inkludert ytelsesdata, selv om det ikke ‘ ikke bruker den nyeste prosessoren osv.
- Det ‘ er ganske åpenbart, men det er verdt å påpeke at for å garantere ingen kollisjoner, må tastene ha samme størrelse som verdiene, med mindre ere er begrensninger for verdiene algoritmen kan kapitalisere på.
- @ devios1 Ditt utsagn er meningsløst. For det første er verdiene i en hash-tabell, perfekte eller ikke, uavhengige av tastene. For det andre er en perfekt hash-tabell bare et lineært verdigrunnlag, indeksert av resultatet av funksjonen som er laget slik at alle indeksene er unike.
- @MarcusJ Perfect hashing brukes vanligvis med mindre enn 100 nøkler, men ta en titt på cmph.sourceforge.net … fremdeles langt utenfor rekkevidden.
- @DavidCary Ingenting på din side link støtter kravet ditt. Muligens har du forvekslet O (1) med » ingen kollisjoner «, men de er ikke ‘ div i det hele tatt det samme. Selvfølgelig garanterer perfekt hashing ingen kollisjoner, men det krever at alle nøklene er kjent på forhånd, og at det er relativt få av dem. (Men se lenken til cmph ovenfor.)
Svar
Her er en liste over hashfunksjoner, men kortversjonen er:
Hvis du bare vil ha en god hash-funksjon , og kan ikke vente,
djb2
er en av de beste streng-hash-funksjonene jeg vet. Den har utmerket fordeling og hastighet på mange forskjellige sett med nøkler og tabellstø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 nullfølsom, da de fleste slike enkle hashfunksjoner, slik at du enkelt kan bryte slike hashes.Den har dårlig skjevhet for mange kollisjoner og dårlig fordeling, den bryter på de fleste smashasher kvalitetstester: Se github.com/rurban/smhasher/blob/master/doc/bernstein Hans cdb-database bruker den, men jeg vil ikke ‘ ikke bruke den med offentlig tilgang.
- DJB er ganske ille fra et ytelses- og distribusjonssynspunkt. Jeg vil ikke ‘ ikke bruke den i dag.
- @ConradMeyer Jeg ‘ satset, DJB kan bli spurt opp av en faktor på tre akkurat som i dette spørsmålet mitt og da slo det sannsynligvis ‘ d mest brukbare algoritmer. Når det gjelder distribusjonen, er jeg enig. En hasj som produserer kollisjoner selv for to bokstavstrenger, kan ‘ ikke være veldig bra.
- Gutter, jeg er i tvil. Du sier at
djb2
er dårlig, men testresultatene i det aksepterte svaret viser at det er bra. - Du kan i det minste bruke en fornuftig prime som gir mindre kollisjoner i stedet for 33. stackoverflow.com/a/2816747/21499
Svar
CityHash av Google er algoritmen du leter etter. Det er ikke bra for kryptografi, men er bra for å generere unike hashes.
Les bloggen for mer informasjon og -koden er tilgjengelig her .
CityHash er skrevet i C ++. Det er også en vanlig C-port .
Alle CityHash-funksjonene er innstilt for 64-biters prosessorer. Når det er sagt, vil de kjøre (bortsett fra de nye som bruker SSE4.2) i 32-biters kode. De vil ikke være veldig raske. Det kan være lurt å bruke Murmur eller noe annet i 32-biters kode.
Kommentarer
- Er CityHash uttalt lik » City Sushi? »
- Har du en se på SipHash også, det er ment å erstatte MurmurHash / CityHash / etc.: 131002.net/siphash
- Se også FarmHash, en etterfølger av CitHash. code.google.com/p/farmhash
- xxHash hevder å være fem ganger raskere enn CityHash.
-
plain C port
link er ødelagt
Svar
Jeg har tegnet en kort hastighetssammenligning av forskjellige hashingalgoritmer ved hashing av filer.
De enkelte plottene skiller seg bare litt ut i lesemetoden og kan ignoreres her, siden alle filene ble lagret i en tmpfs. Derfor var ikke referanseindeksen IO-bundet hvis du lurer på.
Algoritmer inkluderer: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}
.
Konklusjoner:
- Ikke-kryptografiske hashfunksjoner som Murmur3, Cityhash og Spooky er ganske tett sammen. Man bør merke seg at Cityhash kan være raskere på CPUer med SSE 4.2s
CRC
instruksjon, som min CPU ikke har. SpookyHash var i mitt tilfelle alltid en liten bit før CityHash. - MD5 ser ut til å være en god kompromiss når du bruker kryptografiske hashfunksjoner, selv om SHA256 kan være sikrere for kollisjonssårbarheter av MD5 og SHA1.
- Kompleksiteten til alle algoritmer er lineær – noe som egentlig ikke er overraskende siden de fungerer blokkvis. (Jeg ønsket å se om lesemetoden gjør en forskjell, så du kan bare sammenligne verdiene til høyre).
- SHA256 var tregere enn SHA512.
- Jeg undersøkte ikke tilfeldigheten til hash-funksjonene. Men her er en god sammenligning av hashfunksjonene som mangler i Ian Boyds svar . Dette påpeker at CityHash har noen problemer i hjørnesaker.
Kilden som ble brukt til tomtene:
- https://github.com/sahib/rmlint/tree/gh-pages/plots (beklager den stygge koden)
Kommentarer
- Grafen for lineær skala kutter av y-akse-etiketten som sier hvilken mengde den plotter. Jeg antar at det sannsynligvis ville være » tid i sekunder «, samme som den logaritmiske skalaen. Det er ‘ det er verdt å fikse.
Svar
Jeg vet at det er ting som SHA-256 og slikt, men disse algoritmene er designet å være sikker , noe som vanligvis betyr at de er langsommere enn algoritmer som er mindre unike .
Antagelsen om at kryptografiske hashfunksjoner er mer unike, er feil, og faktisk kan det vises at den ofte er baklengs i praksis. I sannhet:
- Kryptografiske hashfunksjoner bør ideelt sett være som ikke kan skilles fra tilfeldig ;
- Men med ikke-kryptografiske hashfunksjoner er det ønskelig for dem å samhandle gunstig med sannsynlige innganger .
Hvilket betyr at en ikke-kryptografisk hash-funksjon godt kan ha færre kollisjoner kryptografisk for «godt» datasett — datasett det ble designet for.
Vi kan faktisk demonstrere dette med dataene i Ian Boyds svar og litt matte: Bursdagsproblem . Formelen for forventet antall kolliderende par hvis du velger n
heltall fra settet [1, d]
er dette (hentet fra Wikipedia):
n - d + d * ((d - 1) / d)^n
Koble til n
= 216,553 og d
= 2 ^ 32 får vi ca 5.5 forventede kollisjoner . Ians tester viser for det meste resultater rundt det nabolaget, men med ett dramatisk unntak: de fleste funksjonene fikk null kollisjoner i fortløpende talltester. Sannsynligheten for å velge 216 553 32-bits tall tilfeldig og få null kollisjoner er omtrent 0,43%. Og det er bare for en funksjon – her har vi fem forskjellige hashfunksjonsfamilier med null kollisjoner!
Så det vi ser her er at hasjene som Ian testet samhandler gunstig med det påfølgende talldatasettet – dvs. de spres minimalt forskjellige innganger bredere enn en ideell kryptografisk hash-funksjon ville gjort. (Sideanmerkning: dette betyr at Ians grafiske vurdering av at FNV-1a og MurmurHash2 «ser tilfeldig ut» for ham i tallene datasettet kan tilbakevises fra hans egne data. Null kollisjon på et datasett av den størrelsen, for begge hashfunksjonene, er slående ikke tilfeldig!)
Dette er ikke en overraskelse fordi dette er en ønskelig oppførsel for mange bruksområder for hashfunksjoner. For eksempel er hash-tabellnøkler ofte veldig like; Ians svar nevner et problem MSN en gang hadde med postnummer hash-tabeller . Dette er en bruk der kollisjons unngåelse på sannsynlige innganger vinner over tilfeldig oppførsel.
En annen lærerik sammenligning her er kontrasten i designmålene mellom CRC og kryptografiske hashfunksjoner:
- CRC er designet for å fange feil som skyldes støyende kommunikasjonskanaler , som sannsynligvis vil være et lite antall bitflips;
- Crypto-hashes er designet for å fange modifikasjoner gjort av ondsinnede angripere , som er tildelt begrensede beregningsressurser, men vilkårlig mye kløkt.
Så for CRC er det igjen bra å ha færre kollisjoner enn tilfeldig i minimalt forskjellige innganger. Med kryptohash er dette nei-nei!
Svar
SHA-algoritmene (inkludert SHA-256) er designet for å være rask .
Faktisk kan hastigheten deres være et problem noen ganger. Spesielt er en vanlig teknikk for lagring av et passordavledet token å kjøre en standard hurtig hash-algoritme 10 000 ganger (lagring av hasj av hasj av hash av hash av … passord).
#!/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
Utgang:
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 raskt, sikkert, for en kryptografisk hashingalgoritme . Men OP vil bare lagre verdier i en hashtable, og jeg tror ikke ‘ at en kryptografisk hashfunksjon virkelig er passende for det.
- Spørsmålet som ble tatt opp (tangentielt ser det nå ut) emnet for de kryptografiske hashfunksjonene. At ‘ er den biten jeg svarer på.
- Bare for å sette folk utenfor ideen om » Spesielt , er en vanlig teknikk for lagring av et passordavledet token å kjøre en standard hurtig hash-algoritme 10 000 ganger » – mens det er vanlig, at ‘ er bare dumt. Det er algoritmer designet for disse scenariene, f.eks.
bcrypt
. Bruk de riktige verktøyene. - Kryptografiske hashes er designet for å ha høy gjennomstrømning, men det betyr ofte at de har høye oppsett, nedrivning,
.rodata
og / eller statlige kostnader .Når du vil ha en algoritme for en hashtable, har du vanligvis veldig korte nøkler, og mange av dem, men trenger ikke tilleggsgarantiene til en kryptografisk har. Jeg bruker en finjustert Jenkins en om gangen selv. - @ChrisMorgan: i stedet for å bruke en kryptografisk sikker hash, kan HashTable DoS løses mye mer effektivt ved hjelp av hash-randomisering, slik at hvert løp av programmene eller til og med på hver hashtable, så dataene ‘ blir ikke gruppert i samme bøtte hver gang.
Svar
Bruk SipHash . Den har mange ønskelige egenskaper:
-
Rask. En optimalisert implementering tar omtrent 1 syklus per byte.
-
Sikker. SipHash er en sterk PRF (pseudorandom-funksjon). Dette betyr at det ikke kan skilles fra en tilfeldig funksjon (med mindre du kjenner den 128-biters hemmelige nøkkelen). Derfor:
-
Ingen grunn til å bekymre deg for at hash-bordsondene dine blir lineære på grunn av kollisjoner. Med SipHash vet du at du vil oppnå gjennomsnittlig ytelse i gjennomsnitt, uavhengig av innganger.
-
Immunitet mot hash-basert nektelse av tjenesteangrep.
-
Du kan bruke SipHash (spesielt versjonen med 128-bits utdata) som MAC (Melding godkjenningskode). Hvis du mottar en melding og en SipHash-tag, og taggen er den samme som fra å kjøre SipHash med den hemmelige nøkkelen din, vet du at den som opprettet hash også var i besittelse av din hemmelige nøkkel, og at verken meldingen hash har blitt endret siden.
-
Kommentarer
- Er ikke ‘ t SipHash overkill med mindre du trenger sikkerhet? Krever en 128-bit nøkkel som bare er et glorifisert hashfrø. For ikke å nevne at MurmurHash3 har 128-biters utgang og SipHash bare har en 64-biters utgang. Åpenbart har den større fordøyelsen en lavere kollisjonssjanse.
- @bryc Forskjellen er at SipHash vil fortsette å være veloppdragen, selv på ondsinnede innspill. En hash-tabell basert på SipHash kan brukes til data fra potensielt fiendtlige kilder, og kan bruke en algoritme som lineær sondering som er veldig følsom for detaljene i hash-funksjonen.
- Siphash (og relatert nyere prng stilfunksjoner) er mitt standardvalg for sikkerhet. For ytelse er xxhash vanskelig å slå. Det er mange dårlige råd om internett, selv i diskusjonene her. God ytelse på tilfeldige eller semi-tilfeldige innganger er meningsløs. Hva er worst case-ytelsen, med innspill fra den virkelige verden? Hva er resultatet med ondsinnede innganger? Hashtabellen din vil til slutt bli en angrepsvektor.
Svar
Det avhenger av dataene du hasher. Noen hashing fungerer bedre med spesifikke data som tekst. Noen hashingalgoritmer var spesifikt designet for å være gode for spesifikke data.
Paul Hsieh laget en gang rask hash . Han lister opp kildekode og forklaringer. Men den var allerede slått. 🙂
Svar
Java bruker dette enkelt multiplisere -og-legg til algoritme:
Hash-koden for et strengobjekt beregnes som
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
ved hjelp av int-aritmetikk, der
s[i]
er i -strengen,n
er lengden på strengen, og^
indikerer eksponentiering. (Hashverdien til den tomme strengen er null.)
Det er sannsynligvis mye bedre der ute, men dette er ganske utbredt og ser ut til å være bra kompromiss mellom hastighet og unikhet.
Kommentarer
- Jeg vil ikke ‘ ikke bruke nøyaktig det samme en brukt her, da det ‘ fortsatt er relativt lett å produsere kollisjoner med dette. Det ‘ er definitivt ikke forferdelig, men det er mye bedre der ute. Og hvis det ‘ ikke er noen vesentlig grunn til å være kompatibel med Java, bør det ikke velges.
- Hvis du fortsatt velger dette av hash av en eller annen grunn, kan du i det minste bruke en bedre prime som 92821 som en multiplikator. Det reduserer kollisjoner mye. stackoverflow.com/a/2816747/21499
- Du kan like gjerne bruke FNV1a i stedet. Den ‘ er også en enkel multiplikasjonsbasert hash, men bruker en større multiplikator, som sprer hashen bedre.
- Du trenger ikke ‘ t vil gjøre
s[0]*31^3 + s[1]*31^2 + s[2]*31 + s[3]
. Unngå kraftoperatøren (^) og gjør det på denne måten:((s[0]*31 + s[1])*31 + s[2])*31 + s[3]
. - @LeopoldoSanczyk Ja, i koden er det (og bør gjøres) iterativt, det var bare lettere å forstå i en lukket formel.
Svar
Først og fremst, hvorfor trenger du å implementere din egen hashing? For de fleste oppgaver bør du få gode resultater med datastrukturer fra et standardbibliotek, forutsatt at det er en implementering tilgjengelig (med mindre du bare gjør dette for din egen utdannelse).
Så langt som faktiske hashingalgoritmer går, er min personlige favoritt FNV. 1
Her er et eksempel på implementering av 32-biters versjonen 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 litt bedre med tilfeldighet. Bytt rekkefølgen på
*
og^
:h = (h * 16777619) ^ p[i]
== >h = (h ^ p[i]) * 16777619