Hash più veloce per usi non crittografici?


154

Sto essenzialmente preparando le frasi da inserire nel database, potrebbero essere malformate, quindi preferisco memorizzarne un breve hash (mi limiterò a confrontare se esistono o no, quindi l'hash è l'ideale).

Presumo che MD5 sia abbastanza lento su oltre 100.000 richieste, quindi volevo sapere quale sarebbe il metodo migliore per eseguire l'hashing delle frasi, magari implementando la mia funzione hash o usando hash('md4', '...' sarebbe più veloce alla fine?

So che MySQL ha MD5 (), quindi completerebbe un po 'di velocità alla fine della query, ma forse c'è ancora una funzione di hashing più veloce in MySQL di cui non so che funzionerebbe con PHP ..


6
Cosa ti impedisce di confrontare gli hash?
NullUserException

3
NullUserException: hai ragione, li proverò con frasi di lunghezza casuale. Volevo solo approfondire quale sarebbe stata la norma se qualcuno gestisse questo genere di cose.
Giovanni,

5
MD5 non è poi così lento ...
Amber

25
sei sicuro che la funzione di hashing sia un collo di bottiglia dell'intera applicazione? Ne dubito
Il tuo buon senso

4
Questa è un'ottima domanda da porre, e i commenti implicanti che non lo sono, o non sono importanti, e / o dovrebbero essere ovvi e / o intuitivi - sono deludenti e frustranti. (E anche per niente inaspettato.)
michael

Risposte:


56

CRC32 è piuttosto veloce e c'è una funzione per esso: http://www.php.net/manual/en/function.crc32.php

Ma dovresti essere consapevole che CRC32 avrà più collisioni rispetto agli hash MD5 o SHA-1, semplicemente a causa della lunghezza ridotta (32 bit rispetto a 128 bit rispettivamente 160 bit). Ma se vuoi solo verificare se una stringa memorizzata è danneggiata, con CRC32 starai bene.


1
Caspita, solo il tipo di dati richiesto è un numero intero senza segno, questo sarà significativamente più veloce di altri hash.
Giovanni,

2
@John: o no. CRC32 risulta essere più lento di MD4 e non molto più veloce di MD5 sui processori ARM. Inoltre, CRC32 utilizza un tipo intero a 32 bit senza segno, che è esattamente tutto ciò di cui MD5 ha bisogno ...
Thomas Pornin,

3
se hai il vantaggio / lusso di una nuova CPU Intel, c'è un comando assembly crc32c che è ... probabilmente molto veloce (anche se non è il tradizionale valore crc32). Vedi anche xxhash code.google.com/p/xxhash
rogerdpack il

146
fcn     time  generated hash
crc32:  0.03163  798740135
md5:    0.0731   0dbab6d0c841278d33be207f14eeab8b
sha1:   0.07331  417a9e5c9ac7c52e32727cfd25da99eca9339a80
xor:    0.65218  119
xor2:   0.29301  134217728
add:    0.57841  1105

E il codice utilizzato per generare questo è:

 $loops = 100000;
 $str = "ana are mere";

 echo "<pre>";

 $tss = microtime(true);
 for($i=0; $i<$loops; $i++){
  $x = crc32($str);
 }
 $tse = microtime(true);
 echo "\ncrc32: \t" . round($tse-$tss, 5) . " \t" . $x;

 $tss = microtime(true);
 for($i=0; $i<$loops; $i++){
  $x = md5($str);
 }
 $tse = microtime(true);
 echo "\nmd5: \t".round($tse-$tss, 5) . " \t" . $x;

 $tss = microtime(true);
 for($i=0; $i<$loops; $i++){
  $x = sha1($str);
 }
 $tse = microtime(true);
 echo "\nsha1: \t".round($tse-$tss, 5) . " \t" . $x;

 $tss = microtime(true);
 for($i=0; $i<$loops; $i++){
  $l = strlen($str);
  $x = 0x77;
  for($j=0;$j<$l;$j++){
   $x = $x xor ord($str[$j]);
  }
 }
 $tse = microtime(true);
 echo "\nxor: \t".round($tse-$tss, 5) . " \t" . $x;

 $tss = microtime(true);
 for($i=0; $i<$loops; $i++){
  $l = strlen($str);
  $x = 0x08;
  for($j=0;$j<$l;$j++){
   $x = ($x<<2) xor $str[$j];
  }
 }
 $tse = microtime(true);
 echo "\nxor2: \t".round($tse-$tss, 5) . " \t" . $x;

 $tss = microtime(true);
 for($i=0; $i<$loops; $i++){
  $l = strlen($str);
  $x = 0;
  for($j=0;$j<$l;$j++){
   $x = $x + ord($str[$j]);
  }
 }
 $tse = microtime(true);
 echo "\nadd: \t".round($tse-$tss, 5) . " \t" . $x;

3
Ah, grazie per questa intuizione in realtà, rafforza il mio uso del CRC32 in modo più veloce.
Giovanni,

@ John - È possibile recuperare i algoritmi di hashing utilizzando: hash_algos(). Il seguente codice di benchmark hash era nei commenti PHP ==> codepad.viper-7.com/5Wdhw6
Peter Ajtai

Grazie per il tuo codice L'ho migliorato un po '. Non penso che dovremmo confrontare funzioni come md5 () che elaborano l'intera stringa e i loop che eseguono byte per byte come hai fatto con xor. In PHP, questi loop sono molto lenti e persino più lenti dello stesso md5. Dovremmo confrontare un hases con un altro, tutti implementati come funzioni.
Maxim Masiutin,

1
Solo una breve nota: l'ho provato con una stringa molto più lunga (~ 5000 caratteri) e CRC32 era più lento di MD5 e SHA1 sulla mia macchina (i7-6650U, 16GB). CRC32 - 1.7s, MD5 - 1.4s, SHA1 - 1.5s. Metti sempre alla prova te stesso.
Sam Tolton,

4
@Quam è un test piacevole ma potrebbe essere fuorviante - come notato da @samTolton, i risultati sono diversi ed md5è più veloce. Un test migliore sarà randomizzare anche il contenuto e la lunghezza delle stringhe. in questo modo abbiamo un'idea migliore della performance reale del mondo reale. Ciò eviterà anche la memorizzazione nella cache. Dai un'occhiata: php hashing checksum performance
Shlomi Hassid

43

Elenco classificato in cui ogni loop condivide la stessa cosa per crittografare come tutti gli altri.

<?php

set_time_limit(720);

$begin = startTime();
$scores = array();


foreach(hash_algos() as $algo) {
    $scores[$algo] = 0;
}

for($i=0;$i<10000;$i++) {
    $number = rand()*100000000000000;
    $string = randomString(500);

    foreach(hash_algos() as $algo) {
        $start = startTime();

        hash($algo, $number); //Number
        hash($algo, $string); //String

        $end = endTime($start);

        $scores[$algo] += $end;
    }   
}


asort($scores);

$i=1;
foreach($scores as $alg => $time) {
    print $i.' - '.$alg.' '.$time.'<br />';
    $i++;
}

echo "Entire page took ".endTime($begin).' seconds<br />';

echo "<br /><br /><h2>Hashes Compared</h2>";

foreach($scores as $alg => $time) {
    print $i.' - '.$alg.' '.hash($alg,$string).'<br />';
    $i++;
}

function startTime() {
   $mtime = microtime(); 
   $mtime = explode(" ",$mtime); 
   $mtime = $mtime[1] + $mtime[0]; 
   return $mtime;   
}

function endTime($starttime) {
   $mtime = microtime(); 
   $mtime = explode(" ",$mtime); 
   $mtime = $mtime[1] + $mtime[0]; 
   $endtime = $mtime; 
   return $totaltime = ($endtime - $starttime); 
}

function randomString($length) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
    $string = '';    
    for ($p = 0; $p < $length; $p++) {
        $string .= $characters[mt_rand(0, strlen($characters) - 1)];
    }
    return $string;
}

?>

E l'output

1 - crc32b 0.111036300659
2 - crc32 0.112048864365
3 - md4 0.120795726776
4 - md5 0.138875722885
5 - sha1 0.146368741989
6 - adler32 0.15501332283
7 - tiger192,3 0.177447080612
8 - tiger160,3 0.179498195648
9 - tiger128,3 0.184012889862
10 - ripemd128 0.184052705765
11 - ripemd256 0.185411214828
12 - salsa20 0.198500156403
13 - salsa10 0.204956293106
14 - haval160,3 0.206098556519
15 - haval256,3 0.206891775131
16 - haval224,3 0.206954240799
17 - ripemd160 0.207638263702
18 - tiger192,4 0.208125829697
19 - tiger160,4 0.208438634872
20 - tiger128,4 0.209359407425
21 - haval128,3 0.210256814957
22 - sha256 0.212738037109
23 - ripemd320 0.215386390686
24 - haval192,3 0.215610980988
25 - sha224 0.218329429626
26 - haval192,4 0.256464719772
27 - haval160,4 0.256565093994
28 - haval128,4 0.257113456726
29 - haval224,4 0.258928537369
30 - haval256,4 0.259262084961
31 - haval192,5 0.288433790207
32 - haval160,5 0.290239810944
33 - haval256,5 0.291721343994
34 - haval224,5 0.294484138489
35 - haval128,5 0.300224781036
36 - sha384 0.352449893951
37 - sha512 0.354603528976
38 - gost 0.392376661301
39 - whirlpool 0.629067659378
40 - snefru256 0.829529047012
41 - snefru 0.833986997604
42 - md2 1.80192279816
Entire page took 22.755341053 seconds


Hashes Compared

1 - crc32b 761331d7
2 - crc32 7e8c6d34
3 - md4 1bc8785de173e77ef28a24bd525beb68
4 - md5 9f9cfa3b5b339773b8d6dd77bbe931dd
5 - sha1 ca2bd798e47eab85655f0ce03fa46b2e6e20a31f
6 - adler32 f5f2aefc
7 - tiger192,3 d11b7615af06779259b29446948389c31d896dee25edfc50
8 - tiger160,3 d11b7615af06779259b29446948389c31d896dee
9 - tiger128,3 d11b7615af06779259b29446948389c3
10 - ripemd128 5f221a4574a072bc71518d150ae907c8
11 - ripemd256 bc89cd79f4e70b73fbb4faaf47a3caf263baa07e72dd435a0f62afe840f5c71c
12 - salsa20 91d9b963e172988a8fc2c5ff1a8d67073b2c5a09573cb03e901615dc1ea5162640f607e0d7134c981eedb761934cd8200fe90642a4608eacb82143e6e7b822c4
13 - salsa10 320b8cb8498d590ca2ec552008f1e55486116257a1e933d10d35c85a967f4a89c52158f755f775cd0b147ec64cde8934bae1e13bea81b8a4a55ac2c08efff4ce
14 - haval160,3 27ad6dd290161b883e614015b574b109233c7c0e
15 - haval256,3 03706dd2be7b1888bf9f3b151145b009859a720e3fe921a575e11be801c54c9a
16 - haval224,3 16706dd2c77b1888c29f3b151745b009879a720e4fe921a576e11be8
17 - ripemd160 f419c7c997a10aaf2d83a5fa03c58350d9f9d2e4
18 - tiger192,4 112f486d3a9000f822c050a204d284d52473f267b1247dbd
19 - tiger160,4 112f486d3a9000f822c050a204d284d52473f267
20 - tiger128,4 112f486d3a9000f822c050a204d284d5
21 - haval128,3 9d9155d430218e4dcdde1c62962ecca3
22 - sha256 6027f87b4dd4c732758aa52049257f9e9db7244f78c132d36d47f9033b5c3b09
23 - ripemd320 9ac00db553b51662826267daced37abfccca6433844f67d8f8cfd243cf78bbbf86839daf0961b61d
24 - haval192,3 7d706dd2d37c1888eaa53b154948b009e09c720effed21a5
25 - sha224 b6395266d8c7e40edde77969359e6a5d725f322e2ea4bd73d3d25768
26 - haval192,4 d87cd76e4c8006d401d7068dce5dec3d02dfa037d196ea14
27 - haval160,4 f2ddd76e156d0cd40eec0b8d09c8f23d0f47a437
28 - haval128,4 f066e6312b91e7ef69f26b2adbeba875
29 - haval224,4 1b7cd76ea97c06d439d6068d7d56ec3d73dba0373895ea14e465bc0e
30 - haval256,4 157cd76e8b7c06d432d6068d7556ec3d66dba0371c95ea14e165bc0ec31b9d37
31 - haval192,5 05f9ea219ae1b98ba33bac6b37ccfe2f248511046c80c2f0
32 - haval160,5 e054ec218637bc8b4bf1b26b2fb40230e0161904
33 - haval256,5 48f6ea210ee1b98be835ac6b7dc4fe2f39841104a37cc2f06ceb2bf58ab4fe78
34 - haval224,5 57f6ea2111e1b98bf735ac6b92c4fe2f43841104ab7cc2f076eb2bf5
35 - haval128,5 ccb8e0ac1fd12640ecd8976ab6402aa8
36 - sha384 bcf0eeaa1479bf6bef7ece0f5d7111c3aeee177aa7990926c633891464534cd8a6c69d905c36e882b3350ef40816ed02
37 - sha512 8def9a1e6e31423ef73c94251d7553f6fe3ed262c44e852bdb43e3e2a2b76254b4da5ef25aefb32aae260bb386cd133045adfa2024b067c2990b60d6f014e039
38 - gost ef6cb990b754b1d6a428f6bb5c113ee22cc9533558d203161441933d86e3b6f8
39 - whirlpool 54eb1d0667b6fdf97c01e005ac1febfacf8704da55c70f10f812b34cd9d45528b60d20f08765ced0ab3086d2bde312259aebf15d105318ae76995c4cf9a1e981
40 - snefru256 20849cbeda5ddec5043c09d36b2de4ba0ea9296b6c9efaa7c7257f30f351aea4
41 - snefru 20849cbeda5ddec5043c09d36b2de4ba0ea9296b6c9efaa7c7257f30f351aea4
42 - md2 d4864c8c95786480d1cf821f690753dc

4
Alla fine c'è un errore off-by-one minimo. strlen($characters)dovrebbe essere strlen($characters) - 1:)
MM.

29

C'è un confronto di velocità sul sito xxhash. Copia incollandolo qui:

 Name            Speed       Q.Score   Author
 xxHash          5.4 GB/s     10
 MumurHash 3a    2.7 GB/s     10       Austin Appleby
 SpookyHash      2.0 GB/s     10       Bob Jenkins
 SBox            1.4 GB/s      9       Bret Mulvey
 Lookup3         1.2 GB/s      9       Bob Jenkins
 CityHash64      1.05 GB/s    10       Pike & Alakuijala
 FNV             0.55 GB/s     5       Fowler, Noll, Vo
 CRC32           0.43 GB/s     9
 MD5-32          0.33 GB/s    10       Ronald L. Rivest
 SHA1-32         0.28 GB/s    10

Quindi sembra che xxHash sia di gran lunga il più veloce, mentre molti altri battono hash più vecchi, come CRC32, MD5 e SHA.

https://code.google.com/p/xxhash/

Si noti che questo è l'ordinamento su una compilation a 32 bit. In una compilation a 64 bit, l'ordine delle prestazioni è probabilmente molto diverso. Alcuni hash sono fortemente basati su moltiplicazioni e recuperi a 64 bit.


17
+-------------------+---------+------+--------------+
|       NAME        |  LOOPS  | TIME |     OP/S     |
+-------------------+---------+------+--------------+
| sha1ShortString   | 1638400 | 2.85 | 574,877.19   |
| md5ShortString    | 2777680 | 4.11 | 675,834.55   |
| crc32ShortString  | 3847980 | 3.61 | 1,065,922.44 |
| sha1MediumString  | 602620  | 4.75 | 126,867.37   |
| md5MediumString   | 884860  | 4.69 | 188,669.51   |
| crc32MediumString | 819200  | 4.85 | 168,907.22   |
| sha1LongString    | 181800  | 4.95 | 36,727.27    |
| md5LongString     | 281680  | 4.93 | 57,135.90    |
| crc32LongString   | 226220  | 4.95 | 45,701.01    |
+-------------------+---------+------+--------------+

Sembra che crc32 sia più veloce per i messaggi piccoli (in questo caso 26 caratteri) mentre md5 per i messaggi più lunghi (in questo caso> 852 caratteri).


17

Aggiornamento 2019: questa risposta è la più aggiornata. Le biblioteche a supporto del soffio sono in gran parte disponibili per tutte le lingue.

La raccomandazione attuale è quella di utilizzare la famiglia Hash Murmur (vedi in particolare le varianti murmur2 o murmur3 ).

Gli hash Murmur sono stati progettati per un hashing veloce con collisioni minime (molto più veloce di CRC, MDx e SHAx). È perfetto per cercare duplicati e molto appropriato per gli indici HashTable.

In effetti è utilizzato da molti dei database moderni (Redis, ElastisSearch, Cassandra) per calcolare tutti i tipi di hash per vari scopi. Questo algoritmo specifico è stato la fonte principale di numerosi miglioramenti delle prestazioni nell'ultimo decennio.

Viene anche utilizzato nelle implementazioni dei filtri Bloom . Dovresti essere consapevole del fatto che se stai cercando "hash veloci", probabilmente stai affrontando un problema tipico che viene risolto dai filtri Bloom. ;-)

Nota : il soffio è un hash generico, che significa NON crittografico. Non impedisce di trovare il "testo" di origine che ha generato un hash. NON è appropriato per le password di hash.

Qualche dettaglio in più: MurmurHash - che cos'è?


2
C'è una richiesta aperta qui per aggiungere murmurhash a php, su cui puoi votare.
keune,

8

Invece di supporre che MD5 sia "abbastanza lento", provalo. Una semplice implementazione basata su C di MD5 su un semplice PC (il mio, un Core2 a 2,4 GHz, che utilizza un singolo core) può eseguire l'hashing di 6 milioni di piccoli messaggi al secondo . Un piccolo messaggio contiene fino a 55 byte. Per i messaggi più lunghi, la velocità di hashing MD5 è lineare con la dimensione del messaggio, ovvero riduce i dati a circa 400 megabyte al secondo. Si può notare che questa è quattro volte la velocità massima di un buon disco rigido o di una scheda di rete Ethernet Gigabit.

Poiché il mio PC ha quattro core, ciò significa che l'hashing dei dati è veloce quanto il mio hard disk può fornire o ricevere usi al massimo il 6% della potenza di elaborazione disponibile. Ci vuole una situazione molto speciale perché la velocità di hashing diventi un collo di bottiglia o addirittura induca un notevole costo su un PC.

Su architetture molto più piccole in cui la velocità di hashing può diventare in qualche modo rilevante, è possibile utilizzare MD4. MD4 va bene per scopi non crittografici (e per scopi crittografici, non dovresti usare MD5 comunque). È stato riferito che MD4 è persino più veloce di CRC32 su piattaforme basate su ARM.


C'è un punto da considerare. MD5 richiede 128 bit anziché 32. Ciò significa che l'archiviazione del database occupa 4 volte più spazio e quindi 4 volte più lentamente per cercare gli hash di confronto ( credo ). Ciò di cui mi preoccupo (per i miei usi) è la velocità con cui sarà necessario interrogare il database in seguito quando è pieno di hash.
Camilo Martin,

3
Se non si utilizza un output sufficientemente ampio, si otterranno collisioni casuali, il che sarà negativo poiché l'obiettivo è quello di interrogare un database per sapere se una determinata "frase" è già nota; le collisioni qui si trasformano in falsi positivi. Con 32 bit, inizierai a vedere le collisioni non appena avrai circa 60000 frasi. Questo vale per tutte le funzioni hash, crittografiche o meno. Detto questo, puoi sempre prendere l'output di una funzione hash e troncarla a qualsiasi lunghezza che ritieni appropriata, entro i limiti spiegati sopra.
Thomas Pornin,

@ThomasPornin Se andiamo per il verso troncato, non affronteremmo di nuovo il problema della collisione, intendo l'unica ragione per cui md5 non dovrebbe ottenere una facile collisione è il numero extra di personaggi che ha rispetto a CRC32, giusto?
Mohd Abdul Mujib,

4

Avvertimento

La risposta che segue non risponde alla domanda, poiché non raccomanda le funzioni hash. Ricorda, "Una funzione di hash è qualsiasi funzione che può essere utilizzata per mappare dati di dimensioni arbitrarie su valori di dimensioni fisse". (Wikipedia) La risposta seguente raccomanda trasformazioni che non garantiscono risultati di dimensioni fisse.

Se sei disposto a rilassare la necessità di utilizzare una funzione hash , continua a leggere ...

Risposta originale

Suggerisco urlencode () o base64_encode () per questi motivi:

  • Non hai bisogno di crittografia
  • Vuoi velocità
  • Volete un modo per identificare stringhe uniche mentre ripulite le stringhe "malformate"

Adattando il codice di riferimento altrove in queste risposte, ho dimostrato che uno di questi è molto più veloce di qualsiasi algoritmo di hash. A seconda dell'applicazione, potresti essere in grado di utilizzare urlencode () o base64_encode () per ripulire qualsiasi stringa "non valida" che desideri memorizzare.


Ri: "Vuoi un modo per identificare stringhe uniche mentre ripulisci le stringhe" malformate ": elaboreresti per favore?
David J.

È difficile ricordare cosa stavo pensando più di sei anni fa ... Avrei potuto alludere al fatto che non si ottengono collisioni con urlencode o base64_encode, quindi i risultati sarebbero unici come le stringhe originali.
Anacronista il

2

Fase 1: installa libsodium (o assicurati di utilizzare PHP 7.2+)

Passaggio 2: utilizzare uno dei seguenti:

  1. sodium_crypto_generichash(), che è BLAKE2b , una funzione hash più sicura di MD5 ma più veloce di SHA256. (Link ha benchmark, ecc.)
  2. sodium_crypto_shorthash(), che è SipHash-2-4 , che è appropriato per le tabelle hash ma non dovrebbe essere invocato per la resistenza alle collisioni.

_shorthashè circa 3 volte più veloce _generichash, ma hai bisogno di una chiave e hai un rischio piccolo ma realistico di collisioni. Con _generichash, probabilmente non devi preoccuparti delle collisioni e non devi usare una chiave (ma potresti volerlo comunque).


1
domanda è "quanto è veloce questa cosa"?
My1

1
sodium_crypto_generichash(), which is BLAKE2b, a hash function more secure than MD5 but faster than SHA256. (Link has benchmarks, etc.)- blake2b sì, ma un'implementazione PHP di blake2b negli Stati Uniti sarà molto più lenta della sha256 implementata in C per PHP ... vorrei che PHP potesse adottare blake2b nella suite hash_algos () ..
hanshenrik

La pura implementazione di PHP non è stata suggerita qui.
Scott Arciszewski,

1

Se stai cercando veloce e unico, ti consiglio xxHash o qualcosa che utilizza il comando integrato crc32c della CPU più recente, vedi https://stackoverflow.com/a/11422479/32453 . Collega anche lì a hash forse anche più veloci se non ti interessa la possibilità di collisione.


1

Adler32 funziona meglio sulla mia macchina. E md5()si è rivelato più veloce di crc32().


3
Se MD5 è più veloce di una funzione CRC32 generica, c'è qualcosa che non va.
nxasdf

0

L'implementazione per md5 all'interno dell'hash è un po 'più veloce di md5 (). Quindi questa può essere un'opzione o qualcun altro, per favore prova:

echo '<pre>';

$run = array();

function test($algo)
{
  #static $c = 0;
  #if($c>10) return;
  #$c++;

 $tss = microtime(true);
 for($i=0; $i<100000; $i++){
  $x = hash($algo, "ana are mere");
 }
 $tse = microtime(true);

 $GLOBALS['run'][(string)round($tse-$tss, 5)] = "\nhash({$algo}): \t".round($tse-$tss, 5) . " \t" . $x;
 #echo "\n$i nhash({$algo}): \t".round($tse-$tss, 5) . " \t" . $x;
}
array_map('test', hash_algos());
ksort($run);
print_r($run);
echo '</pre>';

Puoi vedere su http://www.dozent.net/Tipps-Tricks/PHP/hash-performance


0

CRC32 è più veloce, ma meno sicuro di MD5 e SHA1. Non c'è molta differenza di velocità tra MD5 e SHA1.


MD5 è ora considerato insicuro. È molto più insicuro di SHA1. Leggi la pagina wiki MD5.
Ahmed,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.