¿Qué algoritmo de hash es mejor para la unicidad y la velocidad? Los ejemplos (buenos) usos incluyen diccionarios hash.
Sé que hay cosas como SHA-256 y similares, pero estos algoritmos están diseñados para ser seguros , lo que generalmente significa que son más lentos que los algoritmos que son menos únicos . Quiero un algoritmo hash diseñado para ser rápido, pero que siga siendo bastante único para evitar colisiones.
algorithms
hashing
Earlz
fuente
fuente

Respuestas:
Probé algunos algoritmos diferentes, midiendo la velocidad y el número de colisiones.
Usé tres conjuntos de teclas diferentes:
"1"para"216553"(piense en los códigos postales y cómo un hash pobre eliminó msn.com )Para cada corpus, se registró el número de colisiones y el tiempo promedio empleado en el hashing.
Probé:
xorlugar de+)Resultados
Cada resultado contiene el tiempo promedio de hash y el número de colisiones
Notas :
¿Las colisiones suceden realmente?
Si. Comencé a escribir mi programa de prueba para ver si realmente ocurren colisiones de hash , y no son solo una construcción teórica. De hecho suceden:
Colisiones FNV-1
creamwovechoca conquistsColisiones FNV-1a
costarringchoca conliquiddeclinatechoca conmacallumsaltaragechoca conzinkealtarageschoca conzinkesMurmurio2 colisiones
cataractchoca conperitiroquettechoca conskivieshawlchoca constormbounddowlaseschoca contramontanecricketingschoca contwangerlonganschoca conwhigsColisiones DJB2
hetairaschoca conmentionerheliotropeschoca conneurosporadepravementchoca conserafinsstylistchoca consubgenerajoyfulchoca consynaphearedescribedchoca conuritesdramchoca convivencyDJB2a colisiones
haggadotchoca conloathsomenessesadorablenesseschoca conrentabilityplaywrightchoca consnushplaywrightingchoca consnushingtreponematoseschoca conwaterbedsColisiones CRC32
coddingchoca congnuexhibiterschoca conschlagerColisiones SuperFastHash
dahabiahchoca condrapabilityencharmchoca conenclavegrahamschoca congramarynightchoca convigilnightschoca convigilsfinkschoca convinicAleatorización
La otra medida subjetiva es la distribución aleatoria de los hashes. La asignación de las HashTables resultantes muestra cuán uniformemente se distribuyen los datos. Todas las funciones hash muestran una buena distribución al mapear la tabla linealmente:
O como un mapa de Hilbert ( XKCD siempre es relevante ):
Excepto cuando hash cadenas de números (
"1","2", ...,"216553") (por ejemplo, códigos postales ), donde los patrones comienzan a surgir en la mayoría de los algoritmos de hash:SDBM :
DJB2a :
FNV-1 :
Todos excepto FNV-1a , que todavía me parecen bastante aleatorios:
De hecho, Murmur2 parece tener una aleatoriedad aún mejor con
NumbersqueFNV-1a:El extra
*en la tabla denota cuán mala es la aleatoriedad. ConFNV-1aser el mejor yDJB2xser el peor:Originalmente escribí este programa para decidir si incluso tenía que preocuparme por colisiones: lo hago.
Y luego se convirtió en asegurarse de que las funciones hash fueran lo suficientemente aleatorias.
Algoritmo FNV-1a
El hash FNV1 viene en variantes que devuelven hashes de 32, 64, 128, 256, 512 y 1024 bits.
El algoritmo FNV-1a es:
Donde las constantes
FNV_offset_basisyFNV_primedependen del tamaño de hash de retorno que desee:Vea la página principal de FNV para más detalles.
Todos mis resultados son con la variante de 32 bits.
FNV-1 mejor que FNV-1a?
No. FNV-1a es mucho mejor. Hubo más colisiones con FNV-1a al usar la palabra inglesa corpus:
Ahora compare minúsculas y mayúsculas:
En este caso, FNV-1a no es "400%" peor que FN-1, solo 20% peor.
Creo que lo más importante es que hay dos clases de algoritmos cuando se trata de colisiones:
Y luego está la distribución uniforme de los hashes:
Actualizar
¿Murmullo? Seguro Por qué no
Actualizar
@whatshisname se preguntó cómo funcionaría un CRC32 , agregó números a la tabla.
CRC32 es bastante bueno . Pocas colisiones, pero más lentas, y la sobrecarga de una tabla de búsqueda de 1k.
Recorte todas las cosas erróneas sobre la distribución de CRC - my bad
Hasta hoy iba a usar FNV-1a como mi algoritmo de hash de tabla hash de facto . Pero ahora me estoy cambiando a Murmur2:
Y realmente, realmente espero que haya algo mal con el
SuperFastHashalgoritmo que encontré ; Es una pena ser tan popular como es.Actualización: desde la página de inicio de MurmurHash3 en Google :
Así que supongo que no soy solo yo.
Actualización: me di cuenta de por qué
Murmures más rápido que los demás. MurmurHash2 opera en cuatro bytes a la vez. La mayoría de los algoritmos son byte a byte :Esto significa que a medida que las teclas se alargan, Murmur tiene la oportunidad de brillar.
Actualizar
Los GUID están diseñados para ser únicos, no aleatorios
Una publicación oportuna de Raymond Chen reitera el hecho de que los GUID "aleatorios" no deben usarse para su aleatoriedad. Ellos, o un subconjunto de ellos, no son adecuados como una clave hash:
Aleatoriedad no es lo mismo que evitar colisiones; por eso sería un error intentar inventar su propio algoritmo de "hashing" tomando algún subconjunto de un guid "aleatorio":
Nota : Nuevamente, pongo "GUID aleatorio" entre comillas, porque es la variante "aleatoria" de GUID. Una descripción más precisa sería
Type 4 UUID. Pero nadie sabe qué son los tipos 4 o 1, 3 y 5. Por lo tanto, es más fácil llamarlos GUID "aleatorios".Todas las palabras inglesas reflejan
fuente
Si desea crear un mapa hash a partir de un diccionario que no cambia, puede considerar el hashing perfecto https://en.wikipedia.org/wiki/Perfect_hash_function : durante la construcción de la función hash y la tabla hash, puede garantizar, para un conjunto de datos dado, que no habrá colisiones.
fuente
Aquí hay una lista de funciones hash, pero la versión corta es:
fuente
CityHash by Google es el algoritmo que estás buscando. No es bueno para la criptografía, pero es bueno para generar hashes únicos.
Lea el blog para más detalles y el código está disponible aquí .
CityHash está escrito en C ++. También hay un puerto C simple .
Acerca del soporte de 32 bits:
fuente
plain C portel enlace está rotoHe trazado una comparación de velocidad corta de diferentes algoritmos de hash cuando hashing archivos.
Las parcelas individuales solo difieren ligeramente en el método de lectura y pueden ignorarse aquí, ya que todos los archivos se almacenaron en un archivo tmpfs. Por lo tanto, el punto de referencia no estaba sujeto a IO si se está preguntando.
Algoritmos incluyen:
SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}.Conclusiones:
CRCinstrucción SSE 4.2 , que mi CPU no tiene. SpookyHash estuvo en mi caso siempre un poquito antes de CityHash.La fuente utilizada para las parcelas:
fuente
Los algoritmos SHA (incluido SHA-256) están diseñados para ser rápidos .
De hecho, su velocidad puede ser un problema a veces. En particular, una técnica común para almacenar un token derivado de contraseña es ejecutar un algoritmo de hash rápido estándar 10.000 veces (almacenar el hash del hash del hash del hash de la ... contraseña).
Salida:
fuente
bcrypt. Usa las herramientas adecuadas..rodatacostos de instalación, desmontaje y / o estado. Cuando desea un algoritmo para una tabla hash, generalmente tiene claves muy cortas y muchas de ellas, pero no necesita las garantías adicionales de una cuenta criptográfica. Yo uso un Jenkins modificado uno por uno.La suposición de que las funciones hash criptográficas son más únicas es errónea, y de hecho se puede demostrar que a menudo es al revés en la práctica. En verdad:
Lo que significa que una función hash no criptográfica puede tener menos colisiones que una criptográfica para un "buen" conjunto de datos: conjuntos de datos para los que fue diseñada.
De hecho, podemos demostrar esto con los datos en la respuesta de Ian Boyd y un poco de matemática: el problema del cumpleaños . La fórmula para el número esperado de pares de colisión si selecciona
nenteros al azar del conjunto[1, d]es la siguiente (tomada de Wikipedia):Plugging
n= 216,553 yd= 2 ^ 32 obtenemos aproximadamente 5.5 colisiones esperadas . Las pruebas de Ian muestran principalmente resultados en ese vecindario, pero con una excepción dramática: la mayoría de las funciones obtuvieron cero colisiones en las pruebas de números consecutivos. La probabilidad de elegir al azar 216,553 números de 32 bits y obtener colisiones cero es de aproximadamente 0,43%. Y eso es solo para una función: ¡aquí tenemos cinco familias distintas de funciones hash con cero colisiones!Entonces, lo que estamos viendo aquí es que los hash que Ian probó están interactuando favorablemente con el conjunto de datos de números consecutivos, es decir, están dispersando entradas mínimamente diferentes más ampliamente de lo que lo haría una función hash criptográfica ideal. (Nota al margen: esto significa que la evaluación gráfica de Ian de que FNV-1a y MurmurHash2 "le parecen aleatorios" en el conjunto de datos de números se puede refutar a partir de sus propios datos. Cero colisiones en un conjunto de datos de ese tamaño, para ambas funciones hash, es sorprendentemente no aleatorio!)
Esto no es una sorpresa porque es un comportamiento deseable para muchos usos de las funciones hash. Por ejemplo, las claves de tabla hash son a menudo muy similares; La respuesta de Ian menciona un problema que MSN tuvo una vez con las tablas hash de código postal . Este es un uso donde la prevención de colisiones en entradas probables gana sobre el comportamiento aleatorio.
Otra comparación instructiva aquí es el contraste en los objetivos de diseño entre CRC y las funciones hash criptográficas:
Entonces, para CRC, nuevamente es bueno tener menos colisiones que aleatorias en entradas mínimamente diferentes. Con cripto hashes, este es un no-no!
fuente
Usa SipHash . Tiene muchas propiedades deseables:
Rápido. Una implementación optimizada toma alrededor de 1 ciclo por byte.
Seguro. SipHash es un fuerte PRF (función pseudoaleatoria). Esto significa que no se puede distinguir de una función aleatoria (a menos que conozca la clave secreta de 128 bits). Por lo tanto:
No es necesario preocuparse de que las sondas de la tabla hash se conviertan en tiempo lineal debido a colisiones. Con SipHash, sabe que obtendrá un rendimiento promedio de caso en promedio, independientemente de las entradas.
Inmunidad a los ataques de denegación de servicio basados en hash.
Puede usar SipHash (especialmente la versión con una salida de 128 bits) como MAC (Código de autenticación de mensaje). Si recibe un mensaje y una etiqueta SipHash, y la etiqueta es la misma que la de ejecutar SipHash con su clave secreta, entonces sabe que quien creó el hash también estaba en posesión de su clave secreta, y que ni el mensaje ni el hash ha sido alterado desde entonces.
fuente
Depende de los datos que esté procesando. Algunos hash funcionan mejor con datos específicos como texto. Algunos algoritmos de hash se diseñaron específicamente para ser buenos para datos específicos.
Paul Hsieh una vez hizo hash rápido . Enumera el código fuente y las explicaciones. Pero ya estaba vencido. :)
fuente
Java utiliza este algoritmo simple de multiplicar y agregar:
Probablemente hay muchos mejores, pero esto está bastante extendido y parece ser una buena compensación entre velocidad y singularidad.
fuente
En primer lugar, ¿por qué necesita implementar su propio hash? Para la mayoría de las tareas, debe obtener buenos resultados con las estructuras de datos de una biblioteca estándar, suponiendo que haya una implementación disponible (a menos que solo lo haga para su propia educación).
En cuanto a los algoritmos de hash reales, mi favorito personal es FNV. 1
Aquí hay un ejemplo de implementación de la versión de 32 bits en C:
fuente
*y^:h = (h * 16777619) ^ p[i]==>h = (h ^ p[i]) * 16777619