Por que std :: hash não é garantido como determinístico?

28

A seguir, usamos o N4140 (C ++ 14 Standard).


De acordo com o § 17.6.3.4 Requisitos de hash ,

O valor retornado dependerá apenas do argumento k durante a duração do programa .

[Nota: Assim, todas as avaliações da expressão h(k)com o mesmo valor para kproduzem o mesmo resultado para uma determinada execução do programa . - nota final]

e § 20.9.12 o hash do modelo de classe diz

...

a instanciação hash<Key>deve:

(1.1) - satisfazer os requisitos de Hash (17.6.3.4) ...

(1,2) - ...


Isso significa que um valor de hash de value(ou seja hash<decltype(value)>(value)) pode assumir um valor diferente se você reiniciar o programa.

Mas por que? Essa limitação não estava no padrão de C ++ 11, mas no padrão de C ++ 14, C ++ 17 e C ++ 20. Como usuário (não desenvolvedor de STL), seria bastante útil se std::hashfosse determinístico. Existem dificuldades matemáticas na implementação de uma função hash determinística? Mas as funções de hash que usamos diariamente (por exemplo, obsoletas md5sumou mais seguras sha256) são todas determinísticas. Existe um problema de eficiência?

ynn
fonte
7
"... As funções de hash são necessárias apenas para produzir o mesmo resultado para a mesma entrada em uma única execução de um programa; isso permite hashes salgados que evitam ataques de negação de serviço por colisão ". Fonte: pt.cppreference.com/w/cpp/utility/hash
Richard Critten
5
Ele permite que um algoritmo determinístico receba entradas não determinísticas. Valores de ponteiro, por exemplo. Uma estrutura de dados imutável pode fazer o hash dos endereços de seus dados internos, o que pode ser muito mais rápido que o conteúdo.
John Kugelman 6/03
4
Esta resposta tem alguns links interessantes para você não querer determinismo.
NathanOliver 6/03
3
Não ameace isso como limitação, mas torne as restrições padrão um pouco menos rígidas.
Marek R
4
Aqui está uma explicação completa por que as restrições foram relaxadas.
Marek R

Respostas:

17

Não é necessário que a função hash seja determinística entre as execuções, mas você ainda pode fornecer seu próprio hash, por exemplo, para contêineres não ordenados, se for um comportamento em que você confia.

Quanto ao porquê, a cppreference diz:

As funções de hash são necessárias apenas para produzir o mesmo resultado para a mesma entrada em uma única execução de um programa; isso permite hashes salgados que impedem ataques de negação de serviço de colisão.

Se os Hashrequisitos indicarem que é determinístico, você não poderá fornecer um hash salgado sem violar o requisito.

Aqui está a explicação real por que

Geoffroy
fonte
7

Esta resposta (e links) sugerida por @NathanOliver é finalmente útil. Deixe-me citar partes importantes.

Para uma função hash não criptográfica, é possível pré-calcular entradas massivas com o mesmo valor de hash para desacelerar algoritmicamente os contêineres não ordenados e resultar em um ataque de negação de serviço.

(da edição 2291. std :: hash é vulnerável a ataques de colisão do DoS )

Por esse motivo, os designers de idiomas estão migrando para o hash aleatório. No hash aleatório, o valor do hash da string "a" pode mudar toda vez que você executa seu programa. O hash aleatório agora é o padrão em Python (a partir da versão 3.3), Ruby (a partir da versão 1.9) e Perl (a partir da versão 5.18).

(de Você percebe que está usando hash aleatório? )

Mude para Pronto, em vez de Imediato, pois até a permissão foi controversa na discussão do refletor

(da edição 2291. std :: hash é vulnerável a ataques de colisão do DoS )

Na prática, tanto quanto eu entendo, nenhuma implementação de std::hashimplementa hash aleatório, mas você pode escrever o seu próprio my::secure_hash.

( desta resposta )


PS

Acabei de pesquisar no "hash table dos" e encontrei uma página informativa: o momento em que você percebe que todos os servidores do mundo são vulneráveis .

ynn
fonte