Estoy usando esta línea para generar una identificación sha1 para node.js:
crypto.createHash('sha1').digest('hex');
El problema es que está devolviendo la misma identificación cada vez.
¿Es posible que genere una identificación aleatoria cada vez para que pueda usarla como una identificación de documento de base de datos?
Respuestas:
Eche un vistazo aquí: ¿Cómo uso el cifrado node.js para crear un hash HMAC-SHA1? Crearía un hash de la marca de tiempo actual + un número aleatorio para garantizar la unicidad del hash:
fuente
243,583,606,221,817,150,598,111,409x más entropía
Recomiendo usar crypto.randomBytes . No lo es
sha1
, pero para fines de identificación, es más rápido e igual de "aleatorio".La cadena resultante tendrá el doble de longitud que los bytes aleatorios que genere; cada byte codificado para hexadecimal tiene 2 caracteres. 20 bytes serán 40 caracteres de hexadecimal.
El uso de 20 bytes, tenemos
256^20
o 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976 valores de salida únicas. Esto es idéntico a las posibles salidas de 160 bits (20 bytes) de SHA1.Sabiendo esto, no es realmente significativo para nosotros para
shasum
nuestros bytes aleatorios. Es como lanzar un dado dos veces, pero solo aceptar el segundo lanzamiento; pase lo que pase, tiene 6 resultados posibles en cada lanzamiento, por lo que el primer lanzamiento es suficiente.¿Por qué es esto mejor?
Para entender por qué esto es mejor, primero tenemos que entender cómo funcionan las funciones de hash. Las funciones de hash (incluido SHA1) siempre generarán la misma salida si se proporciona la misma entrada.
Digamos que queremos generar ID pero nuestra entrada aleatoria es generada por un lanzamiento de moneda. Tenemos
"heads"
o"tails"
Si
"heads"
vuelve a aparecer, la salida SHA1 será la misma que la primera vez.Ok, entonces lanzar una moneda no es un gran generador de ID aleatorio porque solo tenemos 2 salidas posibles.
Si usamos un dado estándar de 6 lados, tenemos 6 entradas posibles. Adivina cuántas salidas SHA1 posibles? 6!
Es fácil engañarse pensando simplemente porque la salida de nuestra función parece muy aleatoria, que es muy aleatoria.
Ambos acordamos que un lanzamiento de moneda o un dado de 6 caras sería un generador de identificación aleatorio incorrecto, porque nuestros posibles resultados SHA1 (el valor que usamos para la ID) son muy pocos. Pero, ¿qué pasa si usamos algo que tiene muchos más resultados? ¿Como una marca de tiempo con milisegundos? ¿O JavaScript
Math.random
? ¿O incluso una combinación de esos dos?Calculemos cuántos ID únicos obtendríamos ...
La singularidad de una marca de tiempo con milisegundos
Al usarlo
(new Date()).valueOf().toString()
, obtienes un número de 13 caracteres (por ejemplo,1375369309741
). Sin embargo, dado que este es un número de actualización secuencial (una vez por milisegundo), las salidas son casi siempre las mismas. Vamos a verPara ser justos, para fines de comparación, en un minuto dado (un tiempo de ejecución de operación generoso), tendrá
60*1000
o60000
únicos.La singularidad de
Math.random
Ahora, cuando se usa
Math.random
, debido a la forma en que JavaScript representa números de coma flotante de 64 bits, obtendrá un número con una longitud de entre 13 y 24 caracteres. Un resultado más largo significa más dígitos, lo que significa más entropía. Primero, necesitamos averiguar cuál es la longitud más probable.El siguiente script determinará qué longitud es más probable. Hacemos esto generando 1 millón de números aleatorios e incrementando un contador basado en el
.length
de cada número.Al dividir cada contador por 1 millón, obtenemos la probabilidad de la longitud del número devuelto
Math.random
.Entonces, aunque no es del todo cierto, seamos generosos y digamos que obtienes una salida aleatoria de 19 caracteres;
0.1234567890123456789
. Los primeros caracteres siempre serán0
y.
, por lo tanto, realmente solo obtendremos 17 caracteres aleatorios. Esto nos deja con10^17
+1
(para posible0
; vea las notas a continuación) o 100,000,000,000,000,001 únicos.Entonces, ¿cuántas entradas aleatorias podemos generar?
Ok, calculamos el número de resultados para una marca de tiempo de milisegundos y
Math.random
Eso es un solo dado de 6,000,000,000,000,000,060,000 lados. O, para que este número sea más digerible humanamente, es aproximadamente el mismo número que
Suena bastante bien, ¿verdad? Bueno, descubramos ...
SHA1 produce un valor de 20 bytes, con posibles 256 ^ 20 resultados. Así que realmente no estamos usando SHA1 para su potencial completo. Bueno, ¿cuánto estamos usando?
¡Una marca de tiempo de milisegundos y Math.random usa solo 4.11e-27 por ciento del potencial de 160 bits de SHA1!
¡Santos gatos, hombre! Mira todos esos ceros. Entonces, ¿cuánto mejor es
crypto.randomBytes(20)
? 243,583,606,221,817,150,598,111,409 veces mejor.Notas sobre la
+1
frecuencia y los cerosSi se está preguntando acerca de
+1
esto, es posibleMath.random
devolver un, lo0
que significa que hay 1 resultado único más posible que debemos tener en cuenta.Basado en la discusión que sucedió a continuación, tenía curiosidad sobre la frecuencia con la que
0
surgiría. Aquí hay un pequeño scriptrandom_zero.js
que hice para obtener algunos datosLuego, lo ejecuté en 4 hilos (tengo un procesador de 4 núcleos), agregando la salida a un archivo
Entonces resulta que a
0
no es tan difícil de conseguir. Después de registrar 100 valores , el promedio fue¡Frio! Se requeriría más investigación para saber si ese número está a la par con una distribución uniforme de v8
Math.random
implementaciónfuente
Date
horrible producir buenas semillas.Math.random
que produzca un0.
crypto.randomBytes
es definitivamente el camino a seguir ^^¡Hazlo también en el navegador!
Puede hacer este lado del cliente en los navegadores modernos, si lo desea
Requisitos del navegador
fuente
Number.toString(radix)
no siempre garantiza un valor de 2 dígitos (ej .:(5).toString(16)
= "5", no "05"). Esto no importa a menos que dependa de que su salida final tenga exactamente unalen
longitud de caracteres. En este caso, puede usarreturn ('0'+n.toString(16)).slice(-2);
dentro de su función de mapa.id
atributo, asegúrese de que la ID comience con una letra: [A-Za-z].