Estou usando esta linha para gerar um ID sha1 para node.js:
crypto.createHash('sha1').digest('hex');
O problema é que ele está retornando o mesmo ID todas as vezes.
É possível gerar uma identificação aleatória a cada vez para que eu possa usá-la como identificação de documento de banco de dados?
Respostas:
Dê uma olhada aqui: Como uso o node.js Crypto para criar um hash HMAC-SHA1? Eu criaria um hash do timestamp atual + um número aleatório para garantir a exclusividade do hash:
fonte
243.583.606.221.817.150.598.111.409x mais entropia
Eu recomendo usar crypto.randomBytes . Não é
sha1
, mas para fins de identificação, é mais rápido e tão "aleatório".A sequência resultante será duas vezes maior que os bytes aleatórios que você gerar; cada byte codificado em hexadecimal tem 2 caracteres. 20 bytes terão 40 caracteres hexadecimais.
Usando 20 bytes, temos
256^20
ou 1.461.501.637.330.902.918.203.684.832.716.283.019.655.932.542.976 valores de saída exclusivos. Isso é idêntico às saídas possíveis de 160 bits (20 bytes) do SHA1.Sabendo disso, não é realmente significativo para nós
shasum
nossos bytes aleatórios. É como jogar um dado duas vezes, mas apenas aceitar o segundo lançamento; não importa o que aconteça, você tem 6 resultados possíveis a cada lançamento; portanto, o primeiro lançamento é suficiente.Por que isso é melhor?
Para entender por que isso é melhor, primeiro precisamos entender como as funções de hash funcionam. As funções de hash (incluindo SHA1) sempre geram a mesma saída se a mesma entrada for fornecida.
Digamos que queremos gerar IDs, mas nossa entrada aleatória é gerada por um sorteio. Nós temos
"heads"
ou"tails"
Se
"heads"
surgir novamente, a saída SHA1 será a mesma da primeira vezOk, então um sorteio não é um ótimo gerador de ID aleatório, porque só temos 2 saídas possíveis.
Se usarmos um dado de 6 lados padrão, teremos 6 entradas possíveis. Adivinha quantas saídas SHA1 possíveis? 6!
É fácil nos iludir pensando apenas porque o resultado de nossa função parece muito aleatório, que é muito aleatória.
Nós dois concordamos que um sorteio ou um dado de 6 lados seria um gerador de identificação aleatória ruim, porque nossos possíveis resultados SHA1 (o valor que usamos para o ID) são muito poucos. Mas e se usarmos algo que tem muito mais resultados? Como um carimbo de data / hora com milissegundos? Ou JavaScript
Math.random
? Ou mesmo uma combinação desses dois ?!Vamos calcular quantos IDs únicos obteríamos ...
A exclusividade de um carimbo de data / hora com milissegundos
Ao usar
(new Date()).valueOf().toString()
, você recebe um número de 13 caracteres (por exemplo,1375369309741
). No entanto, como esse é um número atualizado seqüencialmente (uma vez por milissegundo), as saídas são quase sempre as mesmas. Vamos dar uma olhadaPara ser justo, para fins de comparação, em um determinado minuto (um tempo de execução da operação generoso), você terá
60*1000
ou será60000
único.A singularidade de
Math.random
Agora, ao usar
Math.random
, devido à maneira como o JavaScript representa números de ponto flutuante de 64 bits, você obterá um número com comprimento entre 13 e 24 caracteres. Um resultado mais longo significa mais dígitos, o que significa mais entropia. Primeiro, precisamos descobrir qual é o comprimento mais provável.O script abaixo determinará qual comprimento é mais provável. Fazemos isso gerando 1 milhão de números aleatórios e incrementando um contador com base no
.length
número de cada número.Ao dividir cada contador por 1 milhão, obtemos a probabilidade do tamanho do número retornado
Math.random
.Portanto, mesmo que não seja totalmente verdade, sejamos generosos e digamos que você obtém uma saída aleatória de 19 caracteres;
0.1234567890123456789
. Os primeiros caracteres sempre serão0
e.
, na verdade, estamos recebendo apenas 17 caracteres aleatórios. Isso nos deixa com10^17
+1
(para possível0
; veja as notas abaixo) ou 100.000.000.000.000.001 únicos.Então, quantas entradas aleatórias podemos gerar?
Ok, calculamos o número de resultados para um carimbo de data / hora de milissegundo e
Math.random
Esse é um dado de 6.000.000.000.000.000.060.000 lados. Ou, para tornar este número mais humanamente digerível, esse é aproximadamente o mesmo número que
Parece muito bom, certo? Bem, vamos descobrir ...
SHA1 produz um valor de 20 bytes, com possíveis 256 ^ 20 resultados. Portanto, não estamos realmente usando o SHA1 em todo o seu potencial. Bem, quanto estamos usando?
Um registro de data e hora em milissegundos e Math.random usam apenas 4,11 e 27 por cento do potencial de 160 bits do SHA1!
Gatos sagrados, cara! Veja todos esses zeros. Então, quanto melhor é
crypto.randomBytes(20)
? 243.583.606.221.817.150.598.111.409 vezes melhor.Notas sobre
+1
e frequência de zerosSe você está se perguntando sobre o
+1
possível, é possívelMath.random
retornar um, o0
que significa que há mais um resultado único possível que devemos considerar.Com base na discussão que aconteceu a seguir, eu estava curioso sobre a frequência de um
0
viria para cima. Aqui está um pequeno scriptrandom_zero.js
, eu fiz para obter alguns dadosEm seguida, executei-o em 4 threads (eu tenho um processador de 4 núcleos), anexando a saída a um arquivo
Acontece que
0
não é tão difícil de obter. Após 100 valores registrados, a média foiLegal! Mais pesquisas seriam necessárias para saber se esse número está a par com uma distribuição uniforme da
Math.random
implementação da v8fonte
Date
terrível a produção de boas sementes.Math.random
que nunca iria produzir um0.
crypto.randomBytes
é definitivamente o caminho a seguir ^^Faça isso também no navegador!
Você pode fazer isso do lado do cliente em navegadores modernos, se desejar
Requisitos do navegador
fonte
Number.toString(radix)
nem sempre garante um valor de 2 dígitos (ex:(5).toString(16)
= "5", não "05"). Isso não importa, a menos que você esteja dependendo de sua saída final com exatamentelen
caracteres. Nesse caso, você pode usarreturn ('0'+n.toString(16)).slice(-2);
dentro da sua função de mapa.id
atributo, verifique se o ID começa com uma letra: [A-Za-z].