J'utilise cette ligne pour générer un identifiant sha1 pour node.js:
crypto.createHash('sha1').digest('hex');
Le problème est qu'il renvoie le même identifiant à chaque fois.
Est-il possible de le faire générer un identifiant aléatoire à chaque fois afin que je puisse l'utiliser comme identifiant de document de base de données?
Réponses:
Jetez un oeil ici: Comment utiliser la crypto node.js pour créer un hachage HMAC-SHA1? Je créerais un hachage de l'horodatage actuel + un nombre aléatoire pour assurer l'unicité du hachage:
la source
243,583,606,221,817,150,598,111,409x plus d'entropie
Je recommanderais d'utiliser crypto.randomBytes . Ce n'est pas le cas
sha1
, mais pour des raisons d'identification, c'est plus rapide et tout aussi "aléatoire".La chaîne résultante sera deux fois plus longue que les octets aléatoires que vous générez; chaque octet codé en hexadécimal est de 2 caractères. 20 octets seront 40 caractères hexadécimaux.
En utilisant 20 octets, nous avons
256^20
ou 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976 valeurs de sortie uniques. Ceci est identique aux sorties possibles de 160 bits (20 octets) de SHA1.Sachant cela,
shasum
nos octets aléatoires ne sont pas vraiment significatifs pour nous . C'est comme lancer un dé deux fois mais n'accepter que le deuxième lancer; quoi qu'il arrive, vous avez 6 résultats possibles à chaque jet, donc le premier jet est suffisant.Pourquoi est-ce mieux?
Pour comprendre pourquoi c'est mieux, nous devons d'abord comprendre comment fonctionnent les fonctions de hachage. Les fonctions de hachage (y compris SHA1) généreront toujours la même sortie si la même entrée est donnée.
Disons que nous voulons générer des identifiants, mais notre entrée aléatoire est générée par un tirage au sort. Nous avons
"heads"
ou"tails"
Si
"heads"
revient, la sortie SHA1 sera la même que la première foisOk, donc un tirage au sort n'est pas un bon générateur d'ID aléatoires car nous n'avons que 2 sorties possibles.
Si nous utilisons une matrice standard à 6 faces, nous avons 6 entrées possibles. Devinez combien de sorties SHA1 possibles? 6!
Il est facile de se leurrer en pensant simplement parce que la sortie de notre fonction semble très aléatoire, qu'elle est très aléatoire.
Nous sommes tous les deux d'accord qu'un tirage au sort ou un dé à 6 faces ferait un mauvais générateur d'identifiant aléatoire, car nos résultats SHA1 possibles (la valeur que nous utilisons pour l'identifiant) sont très peu nombreux. Mais que faire si nous utilisons quelque chose qui a beaucoup plus de sorties? Comme un horodatage avec des millisecondes? Ou JavaScript
Math.random
? Ou même une combinaison de ces deux?!Calculons le nombre d'identifiants uniques que nous obtiendrions ...
L'unicité d'un horodatage en millisecondes
Lors de l'utilisation
(new Date()).valueOf().toString()
, vous obtenez un numéro à 13 caractères (par exemple,1375369309741
). Cependant, comme il s'agit d'un nombre de mise à jour séquentielle (une fois par milliseconde), les sorties sont presque toujours les mêmes. Nous allons jeter un coup d'oeilPour être juste, à des fins de comparaison, dans une minute donnée (un temps d'exécution d'opération généreux), vous aurez
60*1000
ou60000
uniques.Le caractère unique de
Math.random
Maintenant, lors de l'utilisation
Math.random
, en raison de la façon dont JavaScript représente les nombres à virgule flottante 64 bits, vous obtiendrez un nombre d'une longueur comprise entre 13 et 24 caractères. Un résultat plus long signifie plus de chiffres, ce qui signifie plus d'entropie. Tout d'abord, nous devons savoir quelle est la longueur la plus probable.Le script ci-dessous déterminera la longueur la plus probable. Nous faisons cela en générant 1 million de nombres aléatoires et en incrémentant un compteur basé sur le
.length
de chaque nombre.En divisant chaque compteur par 1 million, nous obtenons la probabilité de la longueur du nombre retourné
Math.random
.Donc, même si ce n'est pas tout à fait vrai, soyons généreux et disons que vous obtenez une sortie aléatoire de 19 caractères;
0.1234567890123456789
. Les premiers personnages seront toujours0
et.
, donc en réalité, nous n'obtenons que 17 caractères aléatoires. Cela nous laisse avec10^17
+1
(pour possible0
; voir les notes ci-dessous) ou 100 000 000 000 000 001 uniques.Alors, combien d'entrées aléatoires pouvons-nous générer?
Ok, nous avons calculé le nombre de résultats pour un horodatage en millisecondes et
Math.random
C'est un seul dé à 6 000 000 000 000 000 060 000 faces. Ou, pour rendre ce nombre plus digestible humainement, c'est à peu près le même nombre que
Ça sonne plutôt bien, non? Eh bien, découvrons ...
SHA1 produit une valeur de 20 octets, avec un possible 256 ^ 20 résultats. Nous n'utilisons donc vraiment pas SHA1 à son plein potentiel. Eh bien, combien utilisons-nous?
Un horodatage à la milliseconde et Math.random n'utilise que 4,11e-27% du potentiel 160 bits de SHA1!
Saints chats, mec! Regardez tous ces zéros. Alors, à quel point c'est mieux
crypto.randomBytes(20)
? 243,583,606,221,817,150,598,111,409 fois mieux.Remarques sur la
+1
fréquence et la fréquence des zérosSi vous vous interrogez sur le
+1
, il est possibleMath.random
de renvoyer un,0
ce qui signifie qu'il y a 1 autre résultat unique possible que nous devons prendre en compte.Sur la base de la discussion qui s'est déroulée ci-dessous, j'étais curieux de savoir à quelle fréquence un
0
allait arriver. Voici un petit scriptrandom_zero.js
, j'ai fait pour obtenir des donnéesEnsuite, je l'ai exécuté en 4 threads (j'ai un processeur à 4 cœurs), en ajoutant la sortie à un fichier
Il s'avère donc que ce
0
n'est pas si difficile à obtenir. Après l' enregistrement de 100 valeurs , la moyenne étaitCool! Des recherches supplémentaires seraient nécessaires pour savoir si ce nombre correspond à une distribution uniforme de la
Math.random
mise en œuvre de la v8la source
Date
mal la production de bonnes graines.Math.random
cela produirait jamais un0.
crypto.randomBytes
est définitivement la voie à suivre ^^Faites-le aussi dans le navigateur!
Vous pouvez faire ce côté client dans les navigateurs modernes, si vous le souhaitez
Exigences du navigateur
la source
Number.toString(radix)
ne garantit pas toujours une valeur à 2 chiffres (ex:(5).toString(16)
= "5", pas "05"). Cela n'a pas d'importance, sauf si vous comptez sur votre sortie finale pour contenir exactement deslen
caractères. Dans ce cas, vous pouvez utiliser à l'return ('0'+n.toString(16)).slice(-2);
intérieur de votre fonction de carte.id
attribut, assurez-vous que l'ID commence par une lettre: [A-Za-z].