¿Qué algoritmo de hash es mejor para la singularidad y la velocidad?

¿Qué algoritmo hash es mejor para la singularidad y la velocidad? Ejemplos de usos (buenos) incluyen diccionarios hash.

Sé que hay cosas como SHA-256 y cosas así, pero estos algoritmos son diseñado para ser seguro , 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.

Comentarios

  • ¿Con qué propósito, seguridad u otro?
  • @Orbling, para la implementación de un diccionario hash. Por lo tanto, las colisiones deben mantenerse al mínimo, pero no tiene ningún propósito de seguridad.
  • Tenga en cuenta que deberá esperar al menos algunas colisiones en su tabla hash; de lo contrario, el La tabla deberá ser enorme para poder manejar incluso un número relativamente pequeño de claves …
  • ¡Excelente publicación! ¿Podrías también comprobar ‘ s Yann Collet ‘ s xxHash (creator o LZ4), que es dos veces más rápido que Murmur? Página de inicio: code.google.com/p/xxhash Más información: fastcompression.blogspot.fr/2012/ 04 / …
  • @zvrba Depende del algoritmo. bcrypt está diseñado para ser lento.

Respuesta

Probé algunos algoritmos diferentes, midiendo la velocidad y el número de colisiones .

Usé tres conjuntos de claves diferentes:

Para cada corpus, el número de colisiones y el tiempo medio empleado en el hash fue grabado.

Probé:

Resultados

Cada resultado contiene el tiempo hash promedio y el número de colisiones

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 

Notas :

¿Se producen realmente las colisiones?

Sí. Comencé a escribir mi programa de prueba para ver si las colisiones hash realmente ocurren, y no son solo una construcción teórica.De hecho, ocurren:

Colisiones FNV-1

  • creamwove choca con quists

FNV -1a colisiones

  • costarring colisiona con liquid
  • declinate choca con macallums
  • altarage choca con zinke
  • altarages choca con zinkes

Murmur2 colisiones

  • cataract choca con periti
  • roquette choca con skivie
  • shawl choca con stormbound
  • dowlases choca con tramontane
  • cricketings choca con twanger
  • longans choca con whigs

colisiones DJB2

  • hetairas choca con mentioner
  • heliotropes choca con neurospora
  • depravement choca con serafins
  • stylist choca con subgenera
  • joyful choca con synaphea
  • redescribed choca con urites
  • dram choca con vivency

DJB2a collisions

  • haggadot choca con loathsomenesses
  • adorablenesses colisiona con rentability
  • playwright colisiona con snush
  • playwrighting choca con snushing
  • treponematoses choca con waterbeds

colisiones CRC32

  • codding choca con gnu
  • exhibiters choca con schlager

colisiones SuperFastHash

  • dahabiah choca con drapability
  • encharm choca con enclave
  • grahams choca con gramary
  • … snip 79 colisiones …
  • night choca con vigil
  • choca con vigils
  • finks choca con vinic

Aleatoriedad

La otra medida subjetiva es la distribución aleatoria de los hashes. El mapeo 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:

Ingrese la descripción de la imagen aquí

O como Hilbert Map ( XKCD siempre es relevante ):

Ingrese la descripción de la imagen aquí

Excepto cuando se procesan cadenas de números ("1", "2", …, "216553") (por ejemplo, códigos postales ), donde comienzan los patrones para emerger en la mayoría de los algoritmos hash:

SDBM :

Ingrese la descripción de la imagen aquí

DJB2a :

Ingrese la descripción de la imagen aquí

FNV-1 :

Ingrese la descripción de la imagen aquí

Todos excepto

FNV-1a , que todavía me parecen bastante aleatorios:

Ingrese la descripción de la imagen aquí

De hecho, Murmur2 parece tener una aleatoriedad aún mejor con Numbers que FNV-1a:

Ingrese la descripción de la imagen aquí

Cuando miro el mapa de FNV-1a «number», yo piensa Veo patrones verticales sutiles. Con Murmur no veo ningún patrón en absoluto. ¿Qué piensas?


El * en la tabla indica qué tan mala es la aleatoriedad. Con FNV-1a siendo el mejor y DJB2x siendo el peor:

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

Originalmente escribí este programa para decidir si tenía que preocuparme por las colisiones: Sí.

Y luego se convirtió en asegurarnos de que las funciones hash fueran lo suficientemente aleatorias.

Algoritmo FNV-1a

El hash FNV1 viene en variantes que devuelve hashes de 32, 64, 128, 256, 512 y 1024 bits.

El algoritmo FNV-1a es:

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

Donde las constantes FNV_offset_basis y FNV_prime dependen del tamaño de hash de retorno que desee :

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 

Consulte la página principal de FNV para obtener 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:

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

Ahora compare minúsculas y mayúsculas:

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

En este caso, FNV-1a no es» t «400%» peor que FN-1, solo un 20% peor.

Creo que La conclusión más importante es que hay dos clases de algoritmos cuando se trata de colisiones:

  • colisiones raras : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
  • colisiones comunes : SuperFastHash, Loselose

Y luego está la distribución uniforme de los hash:

  • excelente distribución: Murmur2, FNV-1a, SuperFastHas
  • excelente distribución: FNV-1
  • buena distribución: SDBM, DJB2, DJB2a
  • distribución horrible: Loselose


Actualizar

¿Murmullo? Claro, ¿por qué no?


Actualización

@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 – mi mal


Arriba hasta hoy iba a usar FNV-1a como mi algoritmo hash de tabla hash de facto . Pero ahora estoy cambiando a Murmur2:

  • Más rápido
  • Mejor aleatoriedad de todas las clases de entrada

Y yo realmente, realmente espero que haya algo mal con el SuperFastHash algoritmo que encontré ; es una lástima que sea tan popular como es.

Actualización: De la página principal de MurmurHash3 en Google :

(1) – SuperFastHash tiene propiedades de colisión muy deficientes, que se han documentado en otro lugar.

Así que supongo que no soy solo yo.

Actualización: Me di cuenta de por qué Murmur es 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 :

for each octet in Key AddTheOctetToTheHash 

Esto significa que a medida que las teclas se alargan, Murmur tiene la oportunidad de brillar.


Actualización

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 están destinados a ser utilizados para sus aleatoriedad. Ellos, o un subconjunto de ellos, no son adecuados como clave hash:

Ni siquiera se garantiza que el algoritmo GUID de la versión 4 sea impredecible, porque el algoritmo no especifica la calidad del generador de números aleatorios. El artículo de Wikipedia para GUID contiene una investigación primaria que sugiere que los GUID anteriores y futuros se pueden predecir en función del conocimiento del estado del generador de números aleatorios, ya que el generador no es criptográfico fuerte.

Aleatoriedad no es lo mismo que evitar colisiones; por eso sería un error intentar inventar su propio algoritmo «hash» tomando algún subconjunto de un guid «aleatorio»:

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

Nota : De nuevo, pongo «GUID aleatorio» entre comillas, porque «es el» aleatorio » variante de GUID. Una descripción más precisa sería Type 4 UUID. Pero nadie sabe qué tipo 4, o los tipos 1, 3 y 5 son. Por lo tanto, es más fácil llamarlos «aleatorios «GUID.

Todas las palabras en inglés reflejan

Comentarios

  • Sería realmente interesante ver cómo se compara SHA, no porque ‘ sea un buen candidato para un algoritmo hash aquí, pero Sería realmente interesante ver cómo se compara cualquier hash criptográfico con estos algoritmos de velocidad.
  • Un nuevo hash del nam e de ‘ xxHash ‘, de Yann Collet, estaba circulando recientemente. ‘ siempre sospecho de un nuevo hash. Sería interesante verlo en tu comparación (si no ‘ t cansado de que la gente sugiera hashes aleatorios de los que ‘ han oído hablar) para ser agregado …)
  • De hecho. Las cifras de rendimiento anunciadas por la página del proyecto xxHash parecen impresionantes, tal vez demasiado para ser verdad. Bueno, al menos, ‘ es un proyecto de código abierto: code.google.com/p/xxhash
  • Hola Ian, mi implementación Delphi de SuperFastHash es correcta. Al implementar, creé un conjunto de pruebas en C y Delphi para comparar los resultados de mi implementación y la implementación de referencia. No hay diferencias. Entonces, lo que ves es la maldad real del hash … (Por eso también publiqué una implementación de MurmurHash: landman-code.blogspot.nl/2009/02/ … )
  • ¿El autor sabe que esto no es solo una respuesta asombrosa? Este es el mundo ‘ ¿Es un recurso de referencia de facto sobre el tema? Cada vez que necesito lidiar con hashes, eso resuelve mi problema tan rápido y con tanta autoridad que no ‘ nunca necesito nada más.

Respuesta

Si desea crear un mapa hash a partir de un diccionario que no cambia, puede considerar el hash 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 determinado, que no habrá colisiones.

Comentarios

  • Aquí ‘ s más sobre (mínimo) Perfect Hashing burtleburtle.net/bob/hash/perfect.html incluidos los datos de rendimiento, aunque no ‘ no utiliza el procesador más actual, etc.
  • Es ‘ bastante obvio, pero vale la pena señalar que para garantizar que no haya colisiones, las claves tendrían que ser del mismo tamaño que los valores, a menos que Hay restricciones sobre los valores que el algoritmo puede aprovechar.
  • @ devios1 Su declaración no tiene sentido. Primero, los valores en una tabla hash, perfectos o no, son independientes de las claves. En segundo lugar, una tabla hash perfecta es solo una matriz lineal de valores, indexados por el resultado de la función que ha sido diseñada para que todos los índices sean únicos.
  • @MarcusJ El hash perfecto se usa generalmente con menos de 100 claves, pero eche un vistazo a cmph.sourceforge.net … todavía muy por debajo de su rango.
  • @DavidCary Nada en su enlace apoya su reclamo. Posiblemente haya confundido O (1) con » sin colisiones «, pero no son ‘ t en todo lo mismo. Por supuesto, el hash perfecto garantiza que no haya colisiones, pero requiere que todas las claves se conozcan de antemano y que sean relativamente pocas. (Pero vea el enlace a cmph arriba.)

Respuesta

Aquí hay una lista de funciones hash, pero la versión corta es:

Si solo desea tener una buena función hash , y no puedo esperar, djb2 es una de las mejores funciones de hash de cadenas que conozco. Tiene una excelente distribución y velocidad en muchos conjuntos diferentes de claves y tamaños de tabla

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

Comentarios

  • En realidad, djb2 es sensible a cero, como la mayoría de las funciones hash simples, por lo que puede romper fácilmente dichos hash.Tiene un sesgo incorrecto, demasiadas colisiones y una mala distribución, se rompe en la mayoría de las pruebas de calidad de smhasher: consulte github.com/rurban/smhasher/blob/master/doc/bernstein Su base de datos cdb lo usa, pero yo no ‘ no lo usaría con acceso público.
  • DJB es bastante malo desde el punto de vista de rendimiento y distribución. Yo no ‘ no lo usaría hoy.
  • @ConradMeyer Apuesto ‘, DJB puede acelerarse si un factor de tres como en esta pregunta mía y luego ‘ probablemente superará a la mayoría de los algoritmos utilizables. En cuanto a la distribución, estoy de acuerdo. Un hash que produzca colisiones incluso para cadenas de dos letras no puede ‘ ser realmente bueno.
  • Chicos, tengo dudas. Estás diciendo que djb2 es malo, pero los resultados de la prueba de la respuesta aceptada muestran que es bueno.
  • Al menos podrías usar un primo sensible que produzca menos colisiones en lugar de 33. stackoverflow.com/a/2816747/21499

Respuesta

CityHash de Google es el algoritmo que está buscando. No es bueno para la criptografía, pero es bueno para generar hash únicos.

Lea el blog para obtener más detalles y el El código está disponible aquí .

CityHash está escrito en C ++. También hay un puerto C simple .

Acerca de la compatibilidad con 32 bits:

Todas las funciones de CityHash están ajustadas para procesadores de 64 bits. Dicho esto, se ejecutarán (excepto los nuevos que usan SSE4.2) en código de 32 bits. Sin embargo, no serán muy rápidos. Es posible que desee utilizar Murmur o algo más en código de 32 bits.

Comentarios

  • ¿CityHash se pronuncia de forma similar a » City Sushi? »
  • Tiene un mire también SipHash, está destinado a reemplazar MurmurHash / CityHash / etc.: 131002.net/siphash
  • Consulte también FarmHash, un sucesor de CitHash. code.google.com/p/farmhash
  • xxHash afirma ser 5 veces más rápido que CityHash.
  • plain C port enlace roto

Respuesta

He trazado una comparación de velocidad corta de diferentes algoritmos de hash al hacer hash de archivos.

Los gráficos individuales solo difieren ligeramente en el método de lectura y se pueden ignorar aquí, ya que todos los archivos se almacenaron en un tmpfs. Por lo tanto, el punto de referencia no estaba limitado por IO si se lo estaba preguntando.

Los algoritmos incluyen: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}.

Conclusiones:

  • Las funciones hash no criptográficas como Murmur3, Cityhash y Spooky están bastante próximas. Se debe tener en cuenta que Cityhash puede ser más rápido en CPU con instrucción SSE 4.2s CRC, que mi CPU no tiene. SpookyHash fue en mi caso siempre un poquito antes que CityHash.
  • MD5 parece ser una buena compensación cuando se usan funciones de hash criptográficas, aunque SHA256 puede ser más seguro para vulnerabilidades de colisión de MD5 y SHA1.
  • La complejidad de todos los algoritmos es lineal, lo que realmente no es sorprendente, ya que funcionan en bloques. (Quería ver si el método de lectura hace una diferencia, para que pueda comparar los valores más a la derecha).
  • SHA256 era más lento que SHA512.
  • No investigué la aleatoriedad de las funciones hash. Pero aquí es una buena comparación de las funciones hash que faltan en la respuesta de Ian Boyds . Esto señala que CityHash tiene algunos problemas en casos de esquina.

La fuente utilizada para los gráficos:

Comentarios

  • El gráfico de escala lineal corta la etiqueta del eje y que dice qué cantidad está trazando. Supongo que probablemente sería » tiempo en segundos «, igual que la escala logarítmica. Vale la pena arreglarlo ‘.

Respuesta

Sé que hay cosas como SHA-256 y cosas así, pero estos algoritmos están diseñados para ser seguros , lo que normalmente significa que son más lentos que los algoritmos que son menos únicos .

La suposición de que las funciones de hash criptográficas son más únicas es incorrecta y, de hecho, se puede demostrar que a menudo es al revés en la práctica. En realidad:

  1. Las funciones de hash criptográficas idealmente deberían ser indistinguibles de ;
  2. Pero con funciones hash no criptográficas, es deseable que interactúen favorablemente con las posibles entradas .

Lo que significa que una función hash no criptográfica puede tener menos colisiones que una criptográfico para un conjunto de datos «bueno»: conjuntos de datos para los que fue diseñado.

De hecho, podemos demostrar esto con los datos de la respuesta de Ian Boyd y un poco de matemáticas: el Problema de cumpleaños . La fórmula para el número esperado de pares en colisión si eliges n enteros al azar del conjunto [1, d] es la siguiente (tomada de Wikipedia):

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

Conectando n = 216,553 y d = 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 el pruebas de números consecutivos. La probabilidad de elegir 216,553 números de 32 bits al azar y obtener cero colisiones 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, «se están dispersando mínimamente diferentes entradas 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 «parecen aleatorios» para él en el conjunto de datos numéricos puede refutarse a partir de sus propios datos. Cero colisiones en un conjunto de datos de ese tamaño, por 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 teclas de la 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 en el que la prevención de colisiones en entradas probables gana sobre el comportamiento similar al azar.

Otra comparación instructiva aquí es el contraste en los objetivos de diseño entre CRC y funciones hash criptográficas:

  • CRC está diseñado para detectar errores resultantes de canales de comunicación ruidosos , que probablemente una pequeña cantidad de cambios de bits;
  • Los hash de cifrado están diseñados para detectar modificaciones realizadas por atacantes maliciosos , a quienes se les asignan recursos computacionales limitados pero arbitrariamente mucha inteligencia.

Entonces, para CRC nuevamente es bueno tener menos colisiones que aleatorias en entradas mínimamente diferentes. Con cripto hashes, ¡esto es un no-no!

Respuesta

Los algoritmos SHA (incluido SHA-256) son diseñado para ser rápido .

De hecho, su velocidad a veces puede ser un problema. En particular, una técnica común para almacenar un token derivado de una contraseña es ejecutar un algoritmo hash rápido estándar 10,000 veces (almacenando el hash del hash del hash del hash de la … contraseña).

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

Resultado:

Rehearsal ------------------------------------ 1.480000 0.000000 1.480000 ( 1.391229) --------------------------- total: 1.480000sec user system total real 1.400000 0.000000 1.400000 ( 1.382016) 

Comentarios

  • Es ‘ relativamente rápido, seguro, para un algoritmo hash criptográfico . Pero el OP solo quiere almacenar valores en una tabla hash, y yo ‘ no creo que una función hash criptográfica sea realmente apropiada para eso.
  • La pregunta que surgió (tangencialmente, ahora aparece) el tema de las funciones hash criptográficas. Esa ‘ es la parte a la que estoy respondiendo.
  • Solo para disuadir a la gente de la idea de » En particular , una técnica común para almacenar un token derivado de una contraseña es ejecutar un algoritmo hash rápido estándar 10,000 veces » – aunque es común, que ‘ s simplemente estúpido. Hay algoritmos diseñados para estos escenarios, p. Ej., bcrypt. Use las herramientas adecuadas.
  • Los hash criptográficos están diseñados para tener un alto rendimiento, pero eso a menudo significa que tienen altos costos de configuración, desmontaje, .rodata y / o estatales .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 un criptográfico. Yo mismo utilizo un Jenkins modificado de uno en uno.
  • @ChrisMorgan: en lugar de usar un hash criptográficamente seguro, HashTable DoS se puede resolver de manera mucho más eficiente usando la aleatorización de hash, de modo que cada ejecución de los programas o incluso en cada tabla hash, por lo que los datos no ‘ no se agrupan en el mismo grupo cada vez.

Respuesta

Utilice SipHash . Tiene muchas propiedades deseables:

  • Rápido. Una implementación optimizada toma alrededor de 1 ciclo por byte.

  • Seguro. SipHash es un PRF fuerte (función pseudoaleatoria). Esto significa que es indistinguible de una función aleatoria (a menos que conozca la clave secreta de 128 bits). Por lo tanto:

    • No hay necesidad de preocuparse de que las sondas de su tabla hash se conviertan en tiempo lineal debido a las colisiones. Con SipHash, sabe que obtendrá un rendimiento promedio de casos en promedio, independientemente de las entradas.

    • Inmunidad a 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 mensajes). 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 se han modificado desde entonces.

Comentarios

  • Isn ‘ t ¿Exceso de SipHash a menos que necesite seguridad? Requiere una clave de 128 bits que es solo una semilla hash glorificada. Sin mencionar que MurmurHash3 tiene una salida de 128 bits y SipHash solo tiene una salida de 64 bits. Obviamente, el resumen más grande tiene una menor probabilidad de colisión.
  • @bryc La diferencia es que SipHash seguirá comportándose bien, incluso con entradas maliciosas. Una tabla hash basada en SipHash se puede usar para datos de fuentes potencialmente hostiles y puede usar un algoritmo como el sondeo lineal que es muy sensible a los detalles de la función hash.
  • Siphash (y prng más reciente relacionado funciones de estilo) es mi opción predeterminada para la seguridad. En rendimiento, xxhash es difícil de superar. Hay toneladas de malos consejos sobre hash en Internet, incluso en los debates aquí. Un buen rendimiento en entradas aleatorias o semi aleatorias no tiene sentido. ¿Cuál es el peor rendimiento de caso, con entradas del mundo real? ¿Cuál es el resultado con entradas maliciosas? Su tabla hash eventualmente se convertirá en un vector de ataque.

Respuesta

Depende de los datos que esté hash. Algunos hash funcionan mejor con datos específicos como texto. Algunos algoritmos de hash fueron diseñados 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. 🙂

Responder

Java usa este simple multiplicar -y-agregar algoritmo:

El código hash para un objeto String se calcula como

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

usando aritmética int, donde s[i] es el i ​ -ésimo carácter de la cadena, n es la longitud de la cadena y ^ indica exponenciación. (El valor hash de la cadena vacía es cero.)

Probablemente haya otros mucho mejores, pero esto está bastante extendido y parece ser un buen equilibrio entre velocidad y singularidad.

Comentarios

  • Yo no ‘ t usaría exactamente el mismo uno usado aquí, ya que ‘ sigue siendo relativamente fácil producir colisiones con esto. ‘ s definitivamente no es terrible, pero hay mucho mejores por ahí. Y si ‘ no hay una razón importante para ser compatible con Java, no debe elegirse.
  • Si aún elige esta forma de hash por alguna razón, al menos podría usar un número primo mejor como 92821 como multiplicador. Eso reduce mucho las colisiones. stackoverflow.com/a/2816747/21499
  • También puede usar FNV1a en su lugar. También ‘ es un hash simple basado en la multiplicación, pero utiliza un multiplicador más grande, que dispersa mejor el hash.
  • No ‘ no quiero hacer s[0]*31^3 + s[1]*31^2 + s[2]*31 + s[3]. Evite el operador de energía (^) y hágalo de esta manera: ((s[0]*31 + s[1])*31 + s[2])*31 + s[3].
  • @LeopoldoSanczyk Sí, en el código se hace (y debería) hacerse iterativamente, era más fácil de entender en una fórmula cerrada.

Respuesta

En primer lugar, ¿por qué necesita implementar su propio hash? Para la mayoría de las tareas, debería obtener buenos resultados con estructuras de datos de una biblioteca estándar, asumiendo que hay una implementación disponible (a menos que solo esté haciendo esto para su propia educación).

En lo que respecta a los algoritmos hash reales, mi favorito personal es FNV. 1

A continuación, se muestra un ejemplo de implementación de la versión de 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; } 

Comentarios

  • La variante FNV-1a es ligeramente mejor con aleatoriedad. Cambia el orden de * y ^: h = (h * 16777619) ^ p[i] == > h = (h ^ p[i]) * 16777619

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *