Quel algorithme de hachage est le meilleur pour l'unicité et la vitesse?


1388

Quel algorithme de hachage est le meilleur pour l'unicité et la vitesse? Les exemples (bons) utilisations incluent les dictionnaires de hachage.

Je sais qu'il existe des éléments tels que SHA-256 et autres, mais ces algorithmes sont conçus pour être sécurisés , ce qui signifie généralement qu'ils sont plus lents que des algorithmes moins uniques . Je veux un algorithme de hachage conçu pour être rapide, tout en restant assez unique pour éviter les collisions.


9
Dans quel but, sécurité ou autre?
Orbling

19
@Orbling, pour l'implémentation d'un dictionnaire de hachage. Les collisions doivent donc être réduites au minimum, mais elles n’ont aucun objectif de sécurité.
Earlz

4
Notez que vous devez vous attendre à au moins quelques collisions dans votre table de hachage, sinon la table devra être énorme pour pouvoir gérer même un nombre relativement petit de clés ...
Dean Harding

19
Très bonne publication! Pourriez-vous également vérifier le xxHash de Yann Collet (créateur ou LZ4), qui est deux fois plus rapide que Murmur? Page d'accueil: code.google.com/p/xxhash Plus d'informations: fastcompression.blogspot.fr/2012/04/…

24
@zvrba Dépend de l'algorithme. bcrypt est conçu pour être lent.
Izkata

Réponses:


2461

J'ai testé différents algorithmes, mesurant la vitesse et le nombre de collisions.

J'ai utilisé trois jeux de clés différents:

Pour chaque corpus, le nombre de collisions et le temps moyen de hachage ont été enregistrés.

J'ai testé:

Résultats

Chaque résultat contient le temps de hachage moyen et le nombre de collisions

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

Notes :

Les collisions se produisent-elles réellement?

Oui. J'ai commencé à écrire mon programme de test pour voir si les collisions de hachage se produisaient réellement - et ne constituaient pas simplement un concept théorique. Ils se produisent effectivement:

Collisions FNV-1

  • creamwove entre en collision avec quists

Collisions FNV-1a

  • costarring entre en collision avec liquid
  • declinate entre en collision avec macallums
  • altarage entre en collision avec zinke
  • altarages entre en collision avec zinkes

Collisions Murmur2

  • cataract entre en collision avec periti
  • roquette entre en collision avec skivie
  • shawl entre en collision avec stormbound
  • dowlases entre en collision avec tramontane
  • cricketings entre en collision avec twanger
  • longans entre en collision avec whigs

Collisions DJB2

  • hetairas entre en collision avec mentioner
  • heliotropes entre en collision avec neurospora
  • depravement entre en collision avec serafins
  • stylist entre en collision avec subgenera
  • joyful entre en collision avec synaphea
  • redescribed entre en collision avec urites
  • dram entre en collision avec vivency

Collisions DJB2a

  • haggadot entre en collision avec loathsomenesses
  • adorablenesses entre en collision avec rentability
  • playwright entre en collision avec snush
  • playwrighting entre en collision avec snushing
  • treponematoses entre en collision avec waterbeds

Collisions CRC32

  • codding entre en collision avec gnu
  • exhibiters entre en collision avec schlager

Collisions SuperFastHash

  • dahabiah entre en collision avec drapability
  • encharm entre en collision avec enclave
  • grahams entre en collision avec gramary
  • ... coupez 79 collisions ...
  • night entre en collision avec vigil
  • nights entre en collision avec vigils
  • finks entre en collision avec vinic

Aléatoire

L’autre mesure subjective est la distribution aléatoire des hachages. Le mappage des tables de hachage obtenues montre comment les données sont distribuées. Toutes les fonctions de hachage montrent une bonne distribution lors du mappage linéaire de la table:

Entrez la description de l'image ici

Ou comme une carte de Hilbert ( XKCD est toujours pertinent ):

Entrez la description de l'image ici

Sauf lorsque les chaînes numériques (hashing "1", "2", ..., "216553") (par exemple, des codes postaux ), où commencent à émerger des modèles dans la plupart des algorithmes de hachage:

SDBM :

Entrez la description de l'image ici

DJB2a :

Entrez la description de l'image ici

FNV-1 :

Entrez la description de l'image ici

Tous sauf FNV-1a , qui me semble toujours assez aléatoire:

Entrez la description de l'image ici

En fait, Murmur2 semble avoir encore mieux son caractère aléatoire avec Numbersque FNV-1a:

Entrez la description de l'image ici

Quand je regarde la FNV-1acarte "nombre", je pense voir des motifs verticaux subtils. Avec Murmur, je ne vois aucune tendance. Qu'est-ce que tu penses?


Le supplément *dans le tableau indique à quel point le caractère aléatoire est mauvais. Avec FNV-1aêtre le meilleur, et DJB2xétant le pire:

      Murmur2: .
       FNV-1a: .
        FNV-1: ▪
         DJB2: ▪▪
        DJB2a: ▪▪
         SDBM: ▪▪▪
SuperFastHash: .
          CRC: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
     Loselose: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
                                        ▪
                                 ▪▪▪▪▪▪▪▪▪▪▪▪▪
                        ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
          ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪

Au départ, j’avais écrit ce programme pour décider si je devais même me soucier des collisions: c’est le cas.

Et ensuite, il s’est assuré que les fonctions de hachage étaient suffisamment aléatoires.

Algorithme FNV-1a

Le hachage FNV1 est proposé dans des variantes qui renvoient des hachages de 32, 64, 128, 256, 512 et 1024 bits.

L' algorithme FNV-1a est:

hash = FNV_offset_basis
for each octetOfData to be hashed
    hash = hash xor octetOfData
    hash = hash * FNV_prime
return hash

Où les constantes FNV_offset_basiset FNV_primedépendent de la taille de hachage de retour souhaitée:

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

Voir la page principale FNV pour plus de détails.

Tous mes résultats sont avec la variante 32 bits.

FNV-1 meilleur que FNV-1a?

FNV-1a est tout à fait mieux. Il y avait plus de collisions avec FNV-1a en utilisant le mot anglais corpus:

Hash    Word Collisions
======  ===============
FNV-1   1
FNV-1a  4

Maintenant, comparez les minuscules et les majuscules:

Hash    lowercase word Collisions  UPPERCASE word collisions
======  =========================  =========================
FNV-1   1                          9
FNV-1a  4                          11

Dans ce cas, FNV-1a n'est pas "400%" pire que FN-1, seulement 20% pire.

Je pense que le point le plus important à retenir est qu’il existe deux classes d’algorithmes en matière de collision:

  • collisions rares : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
  • collisions communes : SuperFastHash, Loselose

Et puis il y a la façon dont les hachages sont distribués uniformément:

  • distribution exceptionnelle: Murmur2, FNV-1a, SuperFastHas
  • excellente distribution: FNV-1
  • bonne distribution: SDBM, DJB2, DJB2a
  • distribution horrible: Loselose

Mise à jour

Murmure? Bien sûr, pourquoi pas


Mise à jour

@whatshisname s'est demandé comment se comporterait un CRC32 , ajoutait des chiffres à la table.

CRC32 est très bon . Peu de collisions, mais plus lentes, et les frais généraux d’une table de recherche 1k.

Snip tous les trucs erronés sur la distribution du CRC - mon mauvais


Jusqu'à aujourd'hui, j'allais utiliser FNV-1a comme algorithme de hachage de facto de table de hachage. Mais maintenant je passe à Murmur2:

  • plus rapide
  • Meilleure randomisation de toutes les classes d'entrées

Et j'espère vraiment qu'il y a quelque chose qui ne va pas avec l' SuperFastHashalgorithme que j'ai trouvé ; c'est dommage d'être aussi populaire que ça.

Mise à jour: depuis la page d'accueil MurmurHash3 sur Google :

(1) - SuperFastHash a de très mauvaises propriétés de collision, qui ont été documentées ailleurs.

Donc je suppose que ce n'est pas juste moi.

Mise à jour: j'ai compris pourquoi Murmurc'est plus rapide que les autres. MurmurHash2 fonctionne sur quatre octets à la fois. La plupart des algorithmes sont octets par octets :

for each octet in Key
   AddTheOctetToTheHash

Cela signifie que lorsque les touches s'allongent, Murmur a la chance de briller.


Mise à jour

Les GUID sont conçus pour être uniques et non aléatoires

Dans un article opportun de Raymond Chen, on réitère le fait que les GUID "aléatoires" ne sont pas destinés à être utilisés pour leur caractère aléatoire. Ils, ou un sous-ensemble d’entre eux, ne conviennent pas comme clé de hachage:

Même l’algorithme GUID de la version 4 n’est pas toujours imprévisible, car il ne spécifie pas la qualité du générateur de nombres aléatoires. L'article de Wikipedia pour GUID contient des recherches principales qui suggèrent que les GUID futurs et antérieurs peuvent être prédits sur la base de la connaissance de l'état du générateur de nombres aléatoires, car le générateur n'est pas cryptographiquement puissant.

Le hasard n'est pas la même chose que d'éviter les collisions; C'est pourquoi ce serait une erreur d'essayer d'inventer votre propre algorithme de "hachage" en prenant un sous-ensemble d'un guid "aléatoire":

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);
}

Note : Encore une fois, je mets "GUID aléatoire" entre guillemets, car c'est la variante "aléatoire" des GUID. Une description plus précise serait Type 4 UUID. Mais personne ne sait ce que sont le type 4 ou les types 1, 3 et 5. Il est donc plus simple de les appeler des GUID "aléatoires".

Tous les mots anglais miroirs


41
Il serait vraiment intéressant de voir comment SHA se compare, pas parce que c'est un bon candidat pour un algorithme de hachage ici, mais il serait vraiment intéressant de voir comment tout hachage cryptographique se compare à ceux conçus pour les algorithmes de vitesse.
Michael

8
Un nouveau hash du nom de 'xxHash', de Yann Collet, faisait récemment le tour. Je me méfie toujours d'un nouveau hash. Il serait intéressant de le voir dans votre comparaison (si vous n'êtes pas fatigué de personnes suggérant d'ajouter des hachages aléatoires dont ils ont entendu parler ...)
th_in_gs

7
En effet. Les chiffres de performance annoncés par la page du projet xxHash sont impressionnants, peut-être trop pour être vrais. Au moins, c'est un projet open-source: code.google.com/p/xxhash
ATTracker

9
Bonjour Ian, mon implémentation de SuperFastHash à Delphi est correcte. Lors de la mise en œuvre, j'ai créé un ensemble de tests en C et Delphi pour comparer les résultats de mon implémentation et de l'implémentation de référence. Il n'y a pas de différences. Donc, ce que vous voyez est la mauvaise qualité du hachage ... (C’est pourquoi j’ai également publié une implémentation de MurmurHash : landman-code.blogspot.nl/2009/02/… )
Davy Landman

19
Est-ce que l'affiche est consciente que ce n'est pas simplement une réponse géniale - qu'il s'agit de la ressource de référence de facto sur le sujet? Chaque fois que je dois faire face à des hachages, cela résout mon problème si rapidement et avec autorité que je n'ai jamais besoin d'autre chose.
MaiaVictor

59

Si vous souhaitez créer une carte de hachage à partir d'un dictionnaire immuable, envisagez un hachage parfait https://en.wikipedia.org/wiki/Perfect_hash_function - lors de la construction de la fonction de hachage et de la table de hachage, vous pouvez garantir, pour un ensemble de données donné, il n'y aura pas de collision.


2
En savoir plus sur (minimum) Perfect Hashing burtleburtle.net/bob/hash/perfect.html, y compris les données de performance, bien qu'il n'utilise pas le processeur le plus récent, etc.
Ellie Kesselman

4
C'est assez évident, mais il convient de souligner que pour éviter les collisions, les clés doivent avoir la même taille que les valeurs, à moins que des contraintes sur les valeurs que l'algorithme puisse exploiter.
devios1

1
@ devios1 Votre déclaration n'a pas de sens. Tout d'abord, les valeurs d'une table de hachage, parfaite ou non, sont indépendantes des clés. Deuxièmement, une table de hachage parfaite est simplement un tableau linéaire de valeurs, indexé par le résultat d'une fonction conçue de manière à ce que tous les index soient uniques.
Jim Balter

1
@MarcusJ Le hachage parfait est généralement utilisé avec moins de 100 clés, mais jetez un coup d'œil à cmph.sourceforge.net ... encore loin de votre portée.
Jim Balter

1
@ DavidCary Rien sur votre lien n'appuie votre demande. Vous avez peut-être confondu O (1) avec "pas de collision", mais ce n'est pas du tout la même chose. Bien sûr, un hachage parfait ne garantit aucune collision, mais il nécessite que toutes les clés soient connues à l'avance et qu'il en existe relativement peu. (Mais voir le lien vers cmph ci-dessus.)
Jim Balter

34

Voici une liste des fonctions de hachage, mais la version courte est:

Si vous voulez juste avoir une bonne fonction de hachage, et ne pouvez pas attendre, djb2est l’une des meilleures fonctions de hachage de chaîne que je connaisse. Il offre une excellente distribution et vitesse sur de nombreux jeux de clés et de tailles de table

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;
}

6
En réalité, djb2 est sensible au zéro, comme la plupart des fonctions de hachage simples, vous pouvez donc facilement casser ces hachages. Il a un mauvais biais, trop de collisions et une mauvaise distribution, il tombe sur la plupart des tests de qualité: voir github.com/rurban/smhasher/blob/master/doc/bernstein Sa base de données cdb l'utilise, mais je ne l'utilise pas avec accès public.
rurban

2
DJB est plutôt mauvais du point de vue des performances et de la distribution. Je ne l'utiliserais pas aujourd'hui.
Conrad Meyer

@ ConradMeyer Je parierais que DJB peut être multiplié par trois, comme dans cette question, et qu'il batrait probablement la plupart des algorithmes utilisables. En ce qui concerne la distribution, je suis d'accord. Un hachage produisant des collisions même pour deux chaînes de lettres ne peut pas être vraiment bon.
Maaartinus

28

CityHash de Google est l'algorithme que vous recherchez. Ce n'est pas bon pour la cryptographie, mais c'est bon pour générer des hachages uniques.

Lisez le blog pour plus de détails et le code est disponible ici .

CityHash est écrit en C ++. Il y a aussi un port C simple .

À propos du support 32 bits:

Toutes les fonctions CityHash sont adaptées aux processeurs 64 bits. Cela dit, ils fonctionneront (à l'exception des nouveaux qui utilisent SSE4.2) en code 32 bits. Ils ne seront pas très rapides cependant. Vous voudrez peut-être utiliser Murmur ou autre chose en code 32 bits.


11
CityHash se prononce-t-il de manière similaire à "City Sushi?"
Eric

2
Regardez aussi SipHash, il est destiné à remplacer MurmurHash / CityHash / etc. : 131002.net/siphash
Török Edwin

3
Voir également FarmHash, un successeur de CitHash. code.google.com/p/farmhash
stevendaniels

7
xxHash prétend être 5 fois plus rapide que CityHash.
Clay Bridges

plain C portle lien est cassé
fabricantj

20

J'ai tracé une comparaison rapide de différents algorithmes de hachage lors du hachage de fichiers.

Les tracés individuels ne diffèrent que légèrement par la méthode de lecture et peuvent être ignorés ici, car tous les fichiers ont été stockés dans un fichier tmpfs. Par conséquent, le repère n'était pas lié aux entrées-sorties si vous vous posez la question.

Les algorithmes comprennent: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}.

Conclusions:

  • Les fonctions de hachage non cryptographiques telles que Murmur3, Cityhash et Spooky sont assez proches les unes des autres. Il convient de noter que Cityhash est peut-être plus rapide sur les CPU avec l’ CRCinstruction SSE 4.2s , que mon CPU n’a pas. SpookyHash était dans mon cas toujours un peu avant CityHash.
  • MD5 semble être un bon compromis lors de l’utilisation de fonctions de hachage cryptographiques, bien que SHA256 puisse être plus sûr face aux vulnérabilités de collision de MD5 et SHA1.
  • La complexité de tous les algorithmes est linéaire - ce qui n’est vraiment pas surprenant dans la mesure où ils fonctionnent par blocs. (Je voulais voir si la méthode de lecture faisait une différence, vous pouvez donc comparer les valeurs les plus à droite).
  • SHA256 était plus lent que SHA512.
  • Je n'ai pas étudié le caractère aléatoire des fonctions de hachage. Mais voici une bonne comparaison des fonctions de hachage qui manquent dans la réponse de Ian Boyds . Cela indique que CityHash a quelques problèmes dans certains cas.

La source utilisée pour les parcelles:


1
Le graphique à échelle linéaire coupe l'étiquette de l'axe des y, qui indique la quantité à tracer. Je suppose que ce serait probablement "le temps en secondes", identique à l'échelle logarithmique. Cela vaut la peine de réparer.
Craig McQueen

18

Les algorithmes SHA (y compris SHA-256) sont conçus pour être rapides .

En fait, leur vitesse peut parfois être un problème. En particulier, une technique courante pour stocker un jeton dérivé d'un mot de passe consiste à exécuter un algorithme de hachage rapide standard 10 000 fois (stocker le hachage du hachage du hachage du hachage du mot de passe ...).

#!/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

Sortie:

Rehearsal ------------------------------------
   1.480000   0.000000   1.480000 (  1.391229)
--------------------------- total: 1.480000sec

       user     system      total        real
   1.400000   0.000000   1.400000 (  1.382016)

57
C'est relativement rapide, bien sûr, pour un algorithme de hachage cryptographique . Mais l'OP veut simplement stocker les valeurs dans une table de hachage, et je ne pense pas qu'une fonction de hachage cryptographique soit vraiment appropriée pour cela.
Dean Harding

6
La question a soulevé (tangentiellement, il apparaît maintenant) le sujet des fonctions de hachage cryptographique. C'est le peu que je réponds à.
Yfeldblum

15
Juste pour dissuader les gens de "En particulier, une technique courante pour stocker un jeton dérivé d'un mot de passe consiste à exécuter un algorithme standard de hachage rapide 10 000 fois" - bien que cela soit courant, c'est tout simplement stupide. Il existe des algorithmes conçus pour ces scénarios, par exemple bcrypt. Utilisez les bons outils.
TC1

3
Les hachages cryptographiques sont conçus pour avoir un débit élevé, mais cela signifie souvent qu'ils impliquent des .rodatacoûts d' installation, de démontage et / ou d'état élevés. Lorsque vous voulez un algorithme pour une table de hachage, vous avez généralement des clés très courtes et un grand nombre d’entre elles, mais vous n’avez pas besoin des garanties supplémentaires que vous offre un cryptographique. J'utilise moi-même un Jenkins modifié.
mirabilos

1
@ChrisMorgan: au lieu d'utiliser un hachage cryptographiquement sécurisé, HashTable DoS peut être résolu beaucoup plus efficacement en utilisant la randomisation du hachage, de sorte que chaque exécution des programmes ou même chaque hachage, afin que les données ne soient pas regroupées dans le même seau .
Lie Ryan

14

Je sais qu'il existe des éléments tels que SHA-256 et autres, mais ces algorithmes sont conçus pour être sécurisés , ce qui signifie généralement qu'ils sont plus lents que des algorithmes moins uniques .

L'hypothèse selon laquelle les fonctions de hachage cryptographiques sont plus uniques est fausse et, en fait, on peut démontrer qu'elle est souvent rétrograde dans la pratique. En vérité:

  1. Les fonctions de hachage cryptographique devraient idéalement ne pas être distinguées de manière aléatoire ;
  2. Mais avec les fonctions de hachage non cryptographiques, il est souhaitable qu’elles interagissent favorablement avec les entrées probables .

Ce qui signifie qu'une fonction de hachage non cryptographique risque d'avoir moins de collisions qu'une fonction cryptographique pour de "bons" ensembles de données - ensembles de données pour lesquels elle a été conçue.

Nous pouvons en faire la démonstration avec les données de la réponse de Ian Boyd et un peu de calcul: le problème de l' anniversaire . La formule pour le nombre attendu de paires en collision si vous choisissez des nentiers au hasard dans l'ensemble [1, d]est la suivante (tirée de Wikipedia):

n - d + d * ((d - 1) / d)^n

Branchement n= 216553 et d= 2 ^ 32 nous obtenons environ 5,5 collisions attendues . Les tests de Ian montrent principalement des résultats dans ce quartier, à une exception près: la plupart des fonctions n'ont eu aucune collision lors des tests de nombres consécutifs. La probabilité de choisir au hasard 216 553 nombres de 32 bits et d'obtenir zéro collision est d'environ 0,43%. Et ce n'est que pour une fonction - nous avons ici cinq familles de fonctions de hachage distinctes avec zéro collision!

Nous constatons donc ici que les hachages testés par Ian interagissent favorablement avec l'ensemble de données de nombres consécutifs, c'est-à-dire qu'ils dispersent très peu d'entrées différentes plus largement qu'une fonction de hachage cryptographique idéale. (Note latérale: cela signifie que l'évaluation graphique de Ian selon laquelle FNV-1a et MurmurHash2 lui "semblent aléatoires" dans l'ensemble de données numériques peut être réfuté à partir de ses propres données. Zéro collisions sur un ensemble de données de cette taille, pour les deux fonctions de hachage, est remarquablement non-aléatoire!)

Ce n'est pas une surprise, car il s'agit d'un comportement souhaitable pour de nombreuses utilisations des fonctions de hachage. Par exemple, les clés de table de hachage sont souvent très similaires. La réponse de Ian mentionne un problème que MSN a déjà rencontré avec les tables de hachage par code postal . Il s'agit d'une utilisation dans laquelle la prévention des collisions sur des entrées probables l' emporte sur un comportement aléatoire.

Une autre comparaison intéressante est le contraste entre les objectifs de conception des fonctions CRC et de hachage cryptographique:

  • Le CRC est conçu pour détecter les erreurs résultant de canaux de communication bruyants , qui sont généralement constitués d’un petit nombre de retournements de bits;
  • Les hachages cryptographiques sont conçus pour détecter les modifications apportées par des attaquants malveillants , à qui des ressources de calcul limitées sont allouées, mais dont l'intelligence est arbitraire.

Pour le CRC, il est donc bon d’avoir moins de collisions que de hasard dans des entrées très différentes. Avec crypto hashes, c'est un non-non!


10

Utilisez SipHash . Il possède de nombreuses propriétés souhaitables:

  • Vite. Une mise en œuvre optimisée prend environ 1 cycle par octet.

  • Sécurise. SipHash est une PRF forte (fonction pseudo-aléatoire). Cela signifie qu'il est impossible de distinguer une fonction aléatoire (à moins que vous ne connaissiez la clé secrète de 128 bits). Par conséquent:

    • Inutile de vous inquiéter de ce que vos sondes de table de hachage deviennent des heures linéaires en raison de collisions. Avec SipHash, vous savez que vous obtiendrez une performance de cas moyen en moyenne, indépendamment des entrées.

    • Immunité aux attaques par déni de service basées sur le hachage.

    • Vous pouvez utiliser SipHash (en particulier la version avec une sortie 128 bits) en tant que MAC (code d’authentification de message). Si vous recevez un message et une balise SipHash, et que cette balise est identique à celle obtenue en exécutant SipHash avec votre clé secrète, vous savez que le créateur du hachage était également en possession de votre clé secrète et que ni le message, ni le le hash a été modifié depuis.


1
SipHash n’est-il pas excessif sauf si vous avez besoin de sécurité? Nécessite une clé de 128 bits qui est juste une graine de hachage glorifiée. Sans oublier MurmurHash3 a une sortie 128 bits et SipHash n’a qu’une sortie 64 bits. De toute évidence, le plus gros condensé a moins de chance de collision.
bryc

@bryc La différence est que SipHash continuera à bien se comporter, même avec des entrées malveillantes. Une table de hachage basée sur SipHash peut être utilisée pour les données de sources potentiellement hostiles et peut utiliser un algorithme tel que le sondage linéaire qui est très sensible aux détails de la fonction de hachage.
Demi

9

Cela dépend des données que vous hachez. Certains hachages fonctionnent mieux avec des données spécifiques telles que le texte. Certains algorithmes de hachage ont été spécifiquement conçus pour être utiles pour des données spécifiques.

Paul Hsieh a déjà fait du hasch rapide . Il énumère le code source et les explications. Mais c'était déjà battu. :)


6

Java utilise cet algorithme simple multiplier-ajouter:

Le code de hachage pour un objet String est calculé comme suit:

 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

en utilisant arithmétique int, où s[i]est le caractère i- th de la chaîne, nest la longueur de la chaîne et ^indique une exponentiation. (La valeur de hachage de la chaîne vide est zéro.)

Il y en a probablement de bien meilleurs, mais ceci est assez répandu et semble constituer un bon compromis entre vitesse et unicité.


12
Je ne voudrais pas utiliser exactement le même que celui utilisé ici, car il est encore relativement facile de produire des collisions avec cela. Ce n'est certainement pas terrible, mais il y en a beaucoup mieux. Et s’il n’ya aucune raison importante d’être compatible avec Java, vous ne devez pas le choisir.
Joachim Sauer

4
Si vous choisissez toujours cette méthode de hachage pour une raison quelconque, vous pouvez au moins utiliser un meilleur nombre premier, comme 92821, comme multiplicateur. Cela réduit beaucoup les collisions. stackoverflow.com/a/2816747/21499
Hans-Peter Störr

1
Vous pourriez aussi bien utiliser FNV1a à la place. C'est aussi un hachage simple basé sur la multiplication, mais qui utilise un multiplicateur plus grand, qui disperse mieux le hachage.
bryc

4

Tout d’abord, pourquoi avez-vous besoin de mettre en œuvre votre propre hachage? Pour la plupart des tâches, vous devriez obtenir de bons résultats avec les structures de données d'une bibliothèque standard, en supposant qu'une implémentation soit disponible (à moins que vous ne le fassiez pour votre propre formation).

En ce qui concerne les algorithmes de hachage, mon préféré est FNV. 1

Voici un exemple d'implémentation de la version 32 bits en 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;
}

2
La variante FNV-1a est légèrement meilleure avec le caractère aléatoire. Échangez l'ordre des *et ^: h = (h * 16777619) ^ p[i]==>h = (h ^ p[i]) * 16777619
Ian Boyd le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.