Qual algoritmo de hash é melhor para exclusividade e velocidade?

Qual algoritmo de hash é melhor para exclusividade e velocidade? Exemplos de uso (bons) incluem dicionários hash.

Eu sei que existem coisas como SHA-256 e tal, mas esses algoritmos são projetado para ser seguro , o que geralmente significa que são mais lentos que algoritmos que são menos únicos . Eu quero um algoritmo de hash projetado para ser rápido, mas permanecer bastante exclusivo para evitar colisões.

Comentários

  • Para qual propósito, segurança ou outro?
  • @Orbling, para implementação de um dicionário hash. Portanto, as colisões devem ser mínimas, mas não tem nenhum propósito de segurança.
  • Observe que você precisará esperar pelo menos algumas colisões em sua tabela de hash, caso contrário, a mesa deverá ser enorme para ser capaz de lidar até mesmo com um número relativamente pequeno de teclas …
  • Excelente postagem! Você também pode verificar ‘ s Yann Collet ‘ s xxHash (criador ou LZ4), que é duas vezes mais rápido que Murmur? Página inicial: code.google.com/p/xxhash Mais informações: fastcompression.blogspot.fr/2012/ 04 / …
  • @zvrba Depende do algoritmo. bcrypt foi projetado para ser lento.

Resposta

Testei alguns algoritmos diferentes, medindo a velocidade e o número de colisões .

Usei três conjuntos de chaves diferentes:

Para cada corpus, o número de colisões e o tempo médio gasto com hash foi gravado.

Eu testei:

Resultados

Cada resultado contém o tempo médio de hash e o número de colisões

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 

Observações :

As colisões realmente acontecem?

Sim. Comecei a escrever meu programa de teste para ver se as colisões de hash realmente acontecem – e não são apenas uma construção teórica.Eles realmente acontecem:

Colisões FNV-1

  • creamwove colide com quists

FNV -1a colisões

  • costarring colide com liquid
  • declinate colide com macallums
  • altarage colide com zinke
  • altarages colide com zinkes

Colisões Murmur2

  • cataract colide com periti
  • roquette colide com skivie
  • shawl colide com stormbound
  • dowlases colide com tramontane
  • cricketings colide com twanger
  • longans colide com whigs

colisões DJB2

  • hetairas colide com mentioner
  • heliotropes colide com neurospora
  • depravement colide com serafins
  • stylist colide com subgenera
  • joyful colide com synaphea
  • redescribed colide com urites
  • dram colide com vivency

Colisões DJB2a

  • haggadot colide com loathsomenesses
  • adorablenesses colide com rentability
  • playwright colide com snush
  • playwrighting colide com snushing
  • treponematoses colide com waterbeds

Colisões CRC32

  • codding colide com gnu
  • exhibiters colide com schlager

Colisões SuperFastHash

  • dahabiah colide com drapability
  • encharm colide com enclave
  • grahams colide com gramary
  • … corta 79 colisões …
  • night colide com vigil
  • colide com vigils
  • finks colide com vinic

Randomnessification

A outra medida subjetiva é o quão aleatoriamente os hashes são distribuídos. O mapeamento das HashTables resultantes mostra como os dados são distribuídos uniformemente. Todas as funções hash mostram boa distribuição ao mapear a tabela linearmente:

Insira a descrição da imagem aqui

Ou como um Mapa de Hilbert ( XKCD é sempre relevante ):

Insira a descrição da imagem aqui

Exceto ao hash de strings de número ("1", "2", …, "216553") (por exemplo, códigos postais ), onde os padrões começam para emergir na maioria dos algoritmos de hash:

SDBM :

Insira a descrição da imagem aqui

DJB2a :

Insira a descrição da imagem aqui

FNV-1 :

Insira a descrição da imagem aqui

Todos, exceto

FNV-1a , que ainda me parecem bastante aleatórios:

Insira a descrição da imagem aqui

Na verdade, Murmur2 parece ter uma aleatoriedade ainda melhor com Numbers do que FNV-1a:

Insira a descrição da imagem aqui

Quando olho para o mapa FNV-1a “número”, eu pense Vejo padrões verticais sutis. Com Murmur, não vejo nenhum padrão. O que você acha?


O * na tabela denota quão ruim é a aleatoriedade. Com FNV-1a sendo o melhor e DJB2x sendo o pior:

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

Eu originalmente escrevi este programa para decidir se eu tinha que me preocupar com colisões: Sim.

E então passou a ter certeza de que as funções hash eram suficientemente aleatórias.

Algoritmo FNV-1a

O hash FNV1 vem em variantes que retornar hashes de 32, 64, 128, 256, 512 e 1024 bits.

O algoritmo FNV-1a é:

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

Onde as constantes FNV_offset_basis e FNV_prime dependem do tamanho do hash de retorno que você deseja :

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 a página principal do FNV para obter detalhes.

Todos os meus resultados estão com a variante de 32 bits.

FNV-1 melhor que FNV-1a?

Não. O FNV-1a é totalmente melhor. Houve mais colisões com FNV-1a ao usar a palavra em inglês corpus:

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

Agora compare letras minúsculas e maiúsculas:

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

Neste caso, o FNV-1a não é ” 400% “ pior do que o FN-1, apenas 20% pior.

Acho que o o mais importante é que existem duas classes de algoritmos quando se trata de colisões:

  • colisões raras : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
  • colisões comuns : SuperFastHash, Loselose

E então há como os hashes são distribuídos uniformemente:

  • distribuição excelente: Murmur2, FNV-1a, SuperFastHas
  • distribuição excelente: FNV-1
  • boa distribuição: SDBM, DJB2, DJB2a
  • distribuição horrível: Loselose


Atualizar

Murmur? Claro, por que não


Atualizar

@whatshisname questionou o desempenho de um CRC32 , adicionando números à tabela.

CRC32 é muito bom . Poucas colisões, mas mais lentas, e a sobrecarga de uma tabela de pesquisa de 1k.

Corte todas as coisas erradas sobre distribuição CRC – meu mal


Up até hoje eu ia usar o FNV-1a como meu algoritmo hash de hash de facto . Mas agora estou mudando para Murmur2:

  • Mais rápido
  • Melhor randomnessification de todas as classes de entrada

E eu realmente, realmente espero que haja algo errado com o SuperFastHash algoritmo que encontrei ; é uma pena ser tão popular quanto é.

Atualização: De a página inicial MurmurHash3 no Google :

(1) – SuperFastHash tem propriedades de colisão muito pobres, que foram documentados em outro lugar.

Então eu acho que “não sou só eu.

Atualização: Percebi por que Murmur é mais rápido que os outros. MurmurHash2 opera em quatro bytes por vez. A maioria dos algoritmos são byte por byte :

for each octet in Key AddTheOctetToTheHash 

Isso significa que conforme as chaves ficam mais longas, o Murmur tem sua chance de brilhar.


Atualização

GUIDs são projetados para serem únicos, não aleatórios

Uma postagem oportuna de Raymond Chen reitera o fato de que GUIDs “aleatórios” não devem ser usados para seus aleatoriedade. Eles, ou um subconjunto deles, são inadequados como chave hash:

Mesmo o algoritmo GUID da Versão 4 não é garantido como imprevisível, porque o algoritmo não especifica a qualidade do gerador de números aleatórios. O artigo da Wikipedia para GUID contém pesquisas primárias que sugerem que GUIDs futuros e anteriores podem ser previstos com base no conhecimento do estado do gerador de número aleatório, uma vez que o gerador não é criptograficamente Forte.

Aleatoriedade não é o mesmo que prevenção de colisão; é por isso que seria um erro tentar inventar seu próprio algoritmo de “hashing” pegando algum subconjunto de um guid “aleatório”:

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

Observação : Novamente, coloco “random GUID” entre aspas, porque é “aleatório” variante dos GUIDs. Uma descrição mais precisa seria Type 4 UUID. Mas ninguém sabe o que são os tipos 4 ou 1, 3 e 5. Portanto, é mais fácil chamá-los de aleatório “GUIDs.

Espelhos de todas as palavras em inglês

Comentários

  • Seria realmente interessante ver como o SHA se compara, não porque ‘ um bom candidato para um algoritmo de hashing aqui, mas é seria realmente interessante ver como qualquer hash criptográfico se compara a esses feitos para algoritmos de velocidade.
  • Um novo hash pelo nam e de ‘ xxHash ‘, de Yann Collet, estava circulando recentemente. Eu ‘ Sempre suspeito de um novo hash. Seria interessante ver em sua comparação (se você não ‘ t cansado de pessoas sugerindo hashes aleatórios que ‘ já ouviram falar a ser adicionado …)
  • Certamente. Os números de desempenho anunciados pela página do projeto xxHash parecem impressionantes, talvez até demais para ser verdade. Bem, pelo menos, é ‘ um projeto de código aberto: code.google.com/p/xxhash
  • Olá Ian, minha implementação Delphi do SuperFastHash está correta. Ao implementar, criei um conjunto de testes em C e Delphi para comparar os resultados da minha implementação e a implementação de referência. Não existem diferenças. Então, o que você vê é a verdadeira maldade do hash … (É por isso que também publiquei uma implementação de MurmurHash: landman-code.blogspot.nl/2009/02/ … )
  • O autor da postagem está ciente de que esta não é apenas uma resposta incrível – este é o mundo ‘ s recurso de referência de fato sobre o assunto? Sempre que preciso lidar com hashes, isso resolve meu problema com tanta rapidez e autoridade que não ‘ nunca preciso de mais nada.

Resposta

Se você deseja criar um mapa hash a partir de um dicionário imutável, pode considerar o hash perfeito https://en.wikipedia.org/wiki/Perfect_hash_function – durante a construção da função hash e da tabela hash, você pode garantir, para um determinado conjunto de dados, que não haverá colisões.

Comentários

  • Aqui ‘ s mais sobre Hashing perfeito (mínimo) burtleburtle.net/bob/hash/perfect.html incluindo dados de desempenho, embora não ‘ não use o processador mais atual, etc.
  • É ‘ bastante óbvio, mas vale ressaltar que, para garantir que não haja colisões, as chaves teriam que ser do mesmo tamanho que os valores, a menos que th Existem restrições sobre os valores que o algoritmo pode capitalizar.
  • @ devios1 Sua declaração não tem sentido. Primeiro, os valores em uma tabela hash, perfeitos ou não, são independentes das chaves. Em segundo lugar, uma tabela de hash perfeita é apenas uma matriz linear de valores, indexada pelo resultado da função que foi criada para que todos os índices sejam únicos.
  • @MarcusJ Hashing perfeito é geralmente usado com menos de 100 mas dê uma olhada em cmph.sourceforge.net … ainda muito aquém do seu alcance.
  • @DavidCary Nada em seu o link apóia sua reivindicação. Possivelmente você confundiu O (1) com ” sem colisões “, mas eles não estão ‘ t absolutamente a mesma coisa. Obviamente, o hashing perfeito não garante colisões, mas requer que todas as chaves sejam conhecidas com antecedência e que haja relativamente poucas delas. (Mas veja o link para cmph acima.)

Resposta

Aqui está uma lista de funções hash, mas a versão curta é:

Se você deseja apenas ter uma boa função hash e não pode esperar, djb2 é uma das melhores funções hash de string que conheço. Possui excelente distribuição e velocidade em muitos conjuntos diferentes de chaves e tamanhos de tabela

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

Comentários

  • Na verdade, djb2 é sensível a zero, como a maioria dessas funções de hash simples, então você pode facilmente quebrar esses hashes.Tem um viés ruim, muitas colisões e uma distribuição ruim, ele quebra na maioria dos testes de qualidade smhasher: Veja github.com/rurban/smhasher/blob/master/doc/bernstein Seu banco de dados cdb o usa, mas eu não ‘ não o usaria com acesso público.
  • DJB é muito ruim do ponto de vista de desempenho e distribuição. Eu não ‘ não o usaria hoje.
  • @ConradMeyer I ‘ d aposto que DJB pode ser acelerado por um fator de três, exatamente como esta minha pergunta e então ‘ d provavelmente superou a maioria dos algoritmos utilizáveis. Quanto à distribuição, eu concordo. Um hash que produz colisões, mesmo para strings de duas letras, pode ‘ não ser muito bom.
  • Pessoal, tenho dúvidas. Você está dizendo que djb2 é ruim, mas os resultados do teste da resposta aceita mostram que é bom.
  • Você pode pelo menos usar um primo sensível que produza menos colisões em vez de 33. stackoverflow.com/a/2816747/21499

Resposta

CityHash do Google é o algoritmo que você está procurando. Não é bom para criptografia, mas é bom para gerar hashes únicos.

Leia o blog para obter mais detalhes e o o código está disponível aqui .

CityHash é escrito em C ++. Também existe uma porta C simples .

Sobre o suporte de 32 bits:

Todas as funções CityHash são ajustadas para processadores de 64 bits. Dito isso, eles serão executados (exceto para os novos que usam SSE4.2) em código de 32 bits. No entanto, eles não serão muito rápidos. Você pode usar Murmur ou outra coisa em código de 32 bits.

Comentários

  • CityHash é pronunciado de forma semelhante a ” City Sushi? ”
  • veja SipHash também, ele deve substituir MurmurHash / CityHash / etc.: 131002.net/siphash
  • Consulte também FarmHash, a sucessor do CitHash. code.google.com/p/farmhash
  • xxHash afirma ser 5x mais rápido do que CityHash.
  • plain C port link quebrado

Resposta

Eu plotei uma pequena comparação de velocidade de diferentes algoritmos de hash ao fazer hash de arquivos.

Os gráficos individuais diferem apenas ligeiramente no método de leitura e podem ser ignorados aqui, uma vez que todos os arquivos foram armazenados em um tmpfs. Portanto, o benchmark não foi limitado por IO, se você estiver se perguntando.

Os algoritmos incluem: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}.

Conclusões:

  • Funções hash não criptográficas como Murmur3, Cityhash e Spooky são muito próximas. Deve-se notar que Cityhash pode ser mais rápido em CPUs com instrução SSE 4.2s CRC, que minha CPU não possui. No meu caso, o SpookyHash sempre foi um pouco antes do CityHash.
  • MD5 parece ser uma boa opção ao usar funções de hash criptográficas, embora SHA256 possa ser mais seguro para o vulnerabilidades de colisão de MD5 e SHA1.
  • A complexidade de todos os algoritmos é linear – o que realmente não é surpreendente, já que funcionam em blocos. (Eu queria ver se o método de leitura faz alguma diferença, para que você possa comparar os valores mais à direita).
  • SHA256 era mais lento que SHA512.
  • Não investiguei a aleatoriedade de as funções hash. Mas aqui é uma boa comparação das funções hash que estão faltando na resposta de Ian Boyds . Isso indica que o CityHash tem alguns problemas em casos extremos.

A fonte usada para os gráficos:

Comentários

  • O gráfico de escala linear corta o rótulo do eixo y que diz a quantidade que está traçando. Eu acho que provavelmente seria ” tempo em segundos “, o mesmo que a escala logarítmica. ‘ Vale a pena corrigir.

Resposta

Eu sei que existem coisas como SHA-256 e tal, mas esses algoritmos são projetados para ser seguro , o que geralmente significa que eles são mais lentos do que algoritmos menos exclusivos .

A suposição de que as funções de hash criptográficas são mais exclusivas está errada e, na verdade, pode ser demonstrado que muitas vezes está invertida na prática. Na verdade:

  1. funções de hash criptográficas idealmente devem ser indistinguíveis de aleatórias ;
  2. Mas com funções hash não criptográficas, é desejável que interaja favoravelmente com entradas prováveis .

O que significa que uma função hash não criptográfica pode muito bem ter menos colisões do que um criptográfico para “bom” conjunto de dados – conjuntos de dados para os quais foi projetado.

Podemos realmente demonstrar isso com os dados da resposta de Ian Boyd e um pouco de matemática: o Problema de aniversário . A fórmula para o número esperado de pares em colisão se você escolher n inteiros aleatórios do conjunto [1, d] é esta (retirada da Wikipedia):

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

Conectando n = 216.553 e d = 2 ^ 32 obtemos cerca de 5,5 colisões esperadas . Os testes de Ian mostram principalmente resultados em torno dessa vizinhança, mas com uma exceção dramática: a maioria das funções obteve zero colisões no testes de números consecutivos. A probabilidade de escolher 216.553 números de 32 bits aleatoriamente e obter zero colisões é de cerca de 0,43%. E isso é apenas para uma função – aqui temos cinco famílias de funções hash distintas com zero colisões!

Então, o que estamos vendo aqui é que os hashes que Ian testou estão interagindo favoravelmente com o conjunto de dados de números consecutivos, ou seja, eles estão se dispersando minimamente diferentes entradas mais amplamente do que uma função de hash criptográfica ideal faria. (Observação: isso significa que a avaliação gráfica de Ian de que FNV-1a e MurmurHash2 “parecem aleatórios” para ele no conjunto de dados de números pode ser refutada a partir de seus próprios dados. Zero colisões em um conjunto de dados desse tamanho, para ambas funções hash, é surpreendentemente não aleatório!)

Isso não é uma surpresa porque este é um comportamento desejável para muitos usos de funções hash. Por exemplo, as chaves da tabela hash são frequentemente muito semelhantes; A resposta de Ian menciona um problema que o MSN já teve com tabelas de hash de código postal . Este é um uso em que a prevenção de colisão em entradas prováveis vence o comportamento de tipo aleatório.

Outra comparação instrutiva aqui é o contraste nos objetivos de design entre CRC e funções hash criptográficas:

  • CRC é projetado para capturar erros resultantes de canais de comunicação ruidosos , que provavelmente serão um pequeno número de mudanças de bits;
  • Os hashes criptográficos são projetados para capturar modificações feitas por atacantes maliciosos , a quem são atribuídos recursos computacionais limitados, mas arbitrariamente muita inteligência.

Portanto, para o CRC, é novamente bom ter menos colisões do que aleatórias em entradas minimamente diferentes. Com criptografia hashes, isso é impossível!

Resposta

Os algoritmos SHA (incluindo SHA-256) são projetado para ser rápido .

Na verdade, sua velocidade pode ser um problema às vezes. Em particular, uma técnica comum para armazenar um token derivado de senha é executar um algoritmo de hash rápido padrão 10.000 vezes (armazenando o hash do hash do hash do hash da … senha).

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

Comentários

  • É ‘ relativamente rápido, claro, para um algoritmo de hash criptográfico . Mas o OP deseja apenas armazenar valores em uma tabela de hash e eu não ‘ não acho que uma função de hash criptográfica seja realmente apropriada para isso.
  • A questão levantada (tangencialmente, parece agora) o assunto das funções hash criptográficas. Esse ‘ é a parte a que estou respondendo.
  • Apenas para afastar as pessoas da ideia de ” Em particular , uma técnica comum para armazenar um token derivado de senha é executar um algoritmo de hash rápido padrão 10.000 vezes ” – embora comum, que ‘ é simplesmente estúpido. Existem algoritmos projetados para esses cenários, por exemplo, bcrypt. Use as ferramentas certas.
  • Hashes criptográficos são projetados para ter um alto rendimento, mas isso geralmente significa que eles têm alta configuração, desmontagem, .rodata e / ou custos de estado .Quando você quer um algoritmo para uma tabela de hash, normalmente você tem chaves muito curtas, e muitas delas, mas não precisa das garantias adicionais de uma criptografia. Eu mesmo uso um Jenkins de cada vez ajustado.
  • @ChrisMorgan: em vez de usar um hash criptograficamente seguro, o HashTable DoS pode ser resolvido com muito mais eficiência usando a randomização de hash, para que cada execução de os programas ou até mesmo em cada hashtable, de modo que os dados não ‘ sejam agrupados no mesmo intervalo todas as vezes.

Resposta

Use SipHash . Possui muitas propriedades desejáveis:

  • Rápido. Uma implementação otimizada leva cerca de 1 ciclo por byte.

  • Seguro. SipHash é uma PRF (função pseudo-aleatória) forte. Isso significa que é indistinguível de uma função aleatória (a menos que você conheça a chave secreta de 128 bits). Portanto:

    • Não há necessidade de se preocupar com os testes da tabela hash se tornando lineares devido às colisões. Com o SipHash, você sabe que obterá desempenho médio, independentemente das entradas.

    • Imunidade a ataques de negação de serviço baseados em hash.

    • Você pode usar SipHash (especialmente a versão com saída de 128 bits) como um MAC (Código de autenticação de mensagem). Se você receber uma mensagem e uma tag SipHash, e a tag for a mesma de executar SipHash com sua chave secreta, você saberá que quem criou o hash também estava em posse de sua chave secreta e que nem a mensagem nem o hash foram alterados desde então.

Comentários

  • Isn ‘ t Exagero do SipHash, a menos que você precise de segurança? Requer uma chave de 128 bits que é apenas uma semente de hash glorificada. Sem mencionar que MurmurHash3 tem saída de 128 bits e SipHash só tem saída de 64 bits. Obviamente, o resumo maior tem uma chance de colisão menor.
  • @bryc A diferença é que o SipHash continuará a se comportar bem, mesmo com entrada maliciosa. Uma tabela de hash baseada em SipHash pode ser usada para dados de fontes potencialmente hostis e pode usar um algoritmo como a análise linear que é muito sensível aos detalhes da função de hash.
  • Siphash (e prng mais recente relacionado funções de estilo) é minha escolha padrão para segurança. Em termos de desempenho, xxhash é difícil de vencer. Há toneladas de conselhos ruins sobre hash na Internet, mesmo nas discussões aqui. O bom desempenho em entradas aleatórias ou semi-aleatórias não faz sentido. Qual é o pior caso de desempenho, com entradas do mundo real? Qual é o resultado com entradas maliciosas? Sua tabela de hash eventualmente se tornará um vetor de ataque.

Resposta

Depende dos dados que você está fazendo hash. Alguns hash funcionam melhor com dados específicos, como texto. Alguns algoritmos de hash foram projetados especificamente para serem bons para dados específicos.

Paul Hsieh uma vez fez hash rápido . Ele lista o código-fonte e as explicações. Mas já foi derrotado. 🙂

Resposta

Java usa esta multiplicação simples -e-adicionar algoritmo:

O código hash para um objeto String é calculado como

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

usando int aritmética, onde s[i] é o i ​ -ésimo caractere da string, n é o comprimento da string e ^ indica exponenciação. (O valor hash da string vazia é zero.)

Provavelmente existem outros muito melhores por aí, mas isso é bastante difundido e parece ser um bom compensação entre velocidade e exclusividade.

Comentários

  • Eu não ‘ não usaria exatamente o mesmo um usado aqui, pois ‘ ainda é relativamente fácil de produzir colisões com ele. Não ‘ é definitivamente terrível, mas existem muitos melhores por aí. E se não ‘ s nenhuma razão significativa para ser compatível com Java, ele não deve ser escolhido.
  • Se você ainda escolher este forma de hash por algum motivo, você poderia pelo menos usar um número primo melhor, como 92821, como multiplicador. Isso reduz muito as colisões. stackoverflow.com/a/2816747/21499
  • Você também pode usar FNV1a. Ele ‘ s também um hash simples baseado em multiplicação, mas usa um multiplicador maior, que dispersa melhor o hash.
  • Você não ‘ t quero fazer s[0]*31^3 + s[1]*31^2 + s[2]*31 + s[3]. Evite o operador de potência (^) e faça desta forma: ((s[0]*31 + s[1])*31 + s[2])*31 + s[3].
  • @LeopoldoSanczyk Sim, no código é (e deve ser) feito iterativamente, era apenas mais fácil de entender em uma fórmula fechada.

Resposta

Em primeiro lugar, por que você precisa implementar seu próprio hashing? Para a maioria das tarefas, você deve obter bons resultados com estruturas de dados de uma biblioteca padrão, presumindo que haja uma implementação disponível (a menos que você esteja fazendo isso apenas para sua própria educação).

No que diz respeito aos algoritmos de hash reais, meu favorito pessoal é FNV. 1

Aqui está um exemplo de implementação da versão de 32 bits em 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; } 

Comentários

  • A variante FNV-1a é ligeiramente melhor com aleatoriedade. Troque a ordem de * e ^: h = (h * 16777619) ^ p[i] == > h = (h ^ p[i]) * 16777619

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *