Ich benutze diese Zeile, um eine sha1-ID für node.js zu generieren:
crypto.createHash('sha1').digest('hex');
Das Problem ist, dass jedes Mal dieselbe ID zurückgegeben wird.
Ist es möglich, dass jedes Mal eine zufällige ID generiert wird, damit ich sie als Datenbankdokument-ID verwenden kann?
Antworten:
Schauen Sie hier: Wie verwende ich node.js Crypto, um einen HMAC-SHA1-Hash zu erstellen? Ich würde einen Hash des aktuellen Zeitstempels + eine Zufallszahl erstellen, um die Eindeutigkeit des Hash sicherzustellen:
quelle
243.583.606.221.817.150.598.111.409x mehr Entropie
Ich würde empfehlen, crypto.randomBytes zu verwenden . Es ist nicht
sha1
, aber für ID-Zwecke ist es schneller und genauso "zufällig".Die resultierende Zeichenfolge ist doppelt so lang wie die von Ihnen generierten zufälligen Bytes. Jedes in Hex codierte Byte besteht aus 2 Zeichen. 20 Bytes sind 40 hexadezimale Zeichen.
Bei Verwendung von 20 Bytes haben wir
256^20
oder 1.461.501.637.330.902.918.203.684.832.716.283.019.655.932.542.976 eindeutige Ausgabewerte. Dies ist identisch mit den möglichen 160-Bit-Ausgängen (20 Byte) von SHA1.Wenn wir das wissen, ist es für uns für
shasum
unsere zufälligen Bytes nicht wirklich bedeutungsvoll . Es ist, als würde man zweimal einen Würfel werfen, aber nur den zweiten Wurf akzeptieren. Egal was passiert, Sie haben 6 mögliche Ergebnisse pro Wurf, also ist der erste Wurf ausreichend.Warum ist das besser?
Um zu verstehen, warum dies besser ist, müssen wir zuerst verstehen, wie Hashing-Funktionen funktionieren. Hashing-Funktionen (einschließlich SHA1) erzeugen immer die gleiche Ausgabe, wenn die gleiche Eingabe gegeben wird.
Angenommen, wir möchten IDs generieren, aber unsere zufällige Eingabe wird durch einen Münzwurf generiert. Wir haben
"heads"
oder"tails"
Wenn
"heads"
es erneut angezeigt wird, ist der SHA1-Ausgang derselbe wie beim ersten MalOk, ein Münzwurf ist also kein großartiger Zufallsgenerator, da wir nur zwei mögliche Ausgaben haben.
Wenn wir einen standardmäßigen 6-seitigen Würfel verwenden, haben wir 6 mögliche Eingänge. Ratet mal, wie viele mögliche SHA1-Ausgänge? 6!
Es ist einfach , sie zu täuschen , indem nur weil die Leistung unserer Funktion Denken sieht sehr zufällig, dass es ist sehr zufällig.
Wir sind uns beide einig, dass ein Münzwurf oder ein 6-seitiger Würfel einen schlechten Zufallsgenerator erzeugen würde, da unsere möglichen SHA1-Ergebnisse (der Wert, den wir für die ID verwenden) sehr gering sind. Aber was ist, wenn wir etwas verwenden, das viel mehr Ausgänge hat? Wie ein Zeitstempel mit Millisekunden? Oder JavaScript
Math.random
? Oder sogar eine Kombination dieser beiden?!Berechnen wir, wie viele eindeutige IDs wir erhalten würden ...
Die Einzigartigkeit eines Zeitstempels mit Millisekunden
Bei Verwendung erhalten
(new Date()).valueOf().toString()
Sie eine 13-stellige Nummer (z1375369309741
. B. ). Da dies jedoch eine fortlaufend aktualisierte Zahl ist (einmal pro Millisekunde), sind die Ausgänge fast immer gleich. Lass uns mal sehenUm zu Vergleichszwecken fair zu sein, haben Sie in einer bestimmten Minute (eine großzügige Ausführungszeit für Operationen)
60*1000
oder haben Sie60000
Unikate.Die Einzigartigkeit von
Math.random
Bei Verwendung
Math.random
von JavaScript erhalten Sie aufgrund der Darstellung von 64-Bit-Gleitkommazahlen eine Zahl mit einer Länge zwischen 13 und 24 Zeichen. Ein längeres Ergebnis bedeutet mehr Ziffern, was mehr Entropie bedeutet. Zuerst müssen wir herausfinden, welche Länge am wahrscheinlichsten ist.Das folgende Skript bestimmt, welche Länge am wahrscheinlichsten ist. Dazu generieren wir 1 Million Zufallszahlen und erhöhen einen Zähler basierend auf der
.length
von jeder Zahl.Durch Teilen jedes Zählers durch 1 Million erhalten wir die Wahrscheinlichkeit der Länge der zurückgegebenen Zahl
Math.random
.Also, auch wenn es nicht ganz stimmt, lassen Sie uns großzügig sein und sagen, Sie erhalten eine 19 Zeichen lange zufällige Ausgabe;
0.1234567890123456789
. Die ersten Zeichen werden immer0
und sein.
, also bekommen wir wirklich nur 17 zufällige Zeichen. Dies lässt uns10^17
+1
(für möglich0
; siehe Anmerkungen unten) oder 100.000.000.000.000.001 Unikate.Wie viele zufällige Eingaben können wir also generieren?
Ok, wir haben die Anzahl der Ergebnisse für einen Millisekunden-Zeitstempel berechnet und
Math.random
Das ist ein einzelner 6.000.000.000.000.000.000.060.000-seitiger Würfel. Oder, um diese Zahl menschlicher verdaulich zu machen, ist dies ungefähr die gleiche Zahl wie
Klingt ziemlich gut, oder? Nun, lass es uns herausfinden ...
SHA1 erzeugt einen 20-Byte-Wert mit möglichen 256 ^ 20 Ergebnissen. Wir nutzen SHA1 also wirklich nicht in vollem Umfang. Wie viel verbrauchen wir?
Ein Millisekunden-Zeitstempel und Math.random nutzen nur 4,11 bis 27 Prozent des 160-Bit-Potenzials von SHA1!
Heilige Katzen, Mann! Schau dir all diese Nullen an. Wie viel besser ist es also
crypto.randomBytes(20)
? 243.583.606.221.817.150.598.111.409 mal besser.Hinweise zur
+1
und Häufigkeit von NullenWenn Sie sich über das wundern
+1
, können SieMath.random
ein zurückgeben,0
was bedeutet, dass wir noch 1 mögliches eindeutiges Ergebnis berücksichtigen müssen.Aufgrund der Diskussion, die unten stattfand, war ich neugierig auf die Häufigkeit, mit der a
0
auftauchen würde. Hier ist ein kleines Skriptrandom_zero.js
, das ich erstellt habe, um einige Daten zu erhaltenDann habe ich es in 4 Threads ausgeführt (ich habe einen 4-Core-Prozessor) und die Ausgabe an eine Datei angehängt
Es stellt sich also heraus, dass a
0
nicht so schwer zu bekommen ist. Nachdem 100 Werte aufgezeichnet wurden, betrug der DurchschnittCool! Weitere Untersuchungen wären erforderlich, um zu wissen, ob diese Zahl einer gleichmäßigen Verteilung der
Math.random
Implementierung von v8 entsprichtquelle
Date
schrecklich macht , gute Samen zu produzieren.Math.random
dass jemals ein0.
crypto.randomBytes
ist definitiv der richtige Weg ^^Mach es auch im Browser!
Sie können diese Client-Seite in modernen Browsern ausführen, wenn Sie möchten
Browseranforderungen
quelle
Number.toString(radix)
garantiert nicht immer einen zweistelligen Wert (Beispiel:(5).toString(16)
= "5", nicht "05"). Dies spielt keine Rolle, es sei denn, Sie sind darauf angewiesen, dass Ihre endgültige Ausgabe genaulen
Zeichen lang ist. In diesem Fall können Siereturn ('0'+n.toString(16)).slice(-2);
innerhalb Ihrer Kartenfunktion verwenden.id
Attributs verwenden möchten, stellen Sie sicher, dass die ID mit einem Buchstaben beginnt: [A-Za-z].