मैं इस लाइन का उपयोग कर रहा हूँ।
crypto.createHash('sha1').digest('hex');
समस्या यह है कि यह हर बार एक ही आईडी लौटा रहा है।
क्या यह संभव है कि यह हर बार एक यादृच्छिक आईडी उत्पन्न करे ताकि मैं इसे डेटाबेस दस्तावेज़ आईडी के रूप में उपयोग कर सकूं?
मैं इस लाइन का उपयोग कर रहा हूँ।
crypto.createHash('sha1').digest('hex');
समस्या यह है कि यह हर बार एक ही आईडी लौटा रहा है।
क्या यह संभव है कि यह हर बार एक यादृच्छिक आईडी उत्पन्न करे ताकि मैं इसे डेटाबेस दस्तावेज़ आईडी के रूप में उपयोग कर सकूं?
जवाबों:
यहाँ एक नज़र है: मैं एक HMAC-SHA1 हैश बनाने के लिए नोड.जेएस क्रिप्टो का उपयोग कैसे करूँ? मैं वर्तमान टाइमस्टैम्प का एक हैश बनाऊंगा + हैश विशिष्टता सुनिश्चित करने के लिए एक यादृच्छिक संख्या:
var current_date = (new Date()).valueOf().toString();
var random = Math.random().toString();
crypto.createHash('sha1').update(current_date + random).digest('hex');
मैं crypto.randomBytes का उपयोग करने की सलाह दूंगा । यह नहीं है sha1
, लेकिन आईडी उद्देश्यों के लिए, यह तेज है, और बस "यादृच्छिक" के रूप में।
var id = crypto.randomBytes(20).toString('hex');
//=> f26d60305dae929ef8640a75e70dd78ab809cfe9
परिणामी स्ट्रिंग आपके द्वारा उत्पन्न यादृच्छिक बाइट्स से दोगुनी होगी; प्रत्येक बाइट हेक्स को एन्कोडेड 2 अक्षर है। 20 बाइट्स हेक्स के 40 अक्षर होंगे।
20 बाइट्स का उपयोग करना, हमारे पास 256^20
या 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976 अनूठे आउटपुट मान हैं। यह वह जगह है समान SHA1 के 160-बिट (20-बाइट) संभव आउटपुट से।
यह जानना, यह वास्तव में shasum
हमारे यादृच्छिक बाइट्स के लिए सार्थक नहीं है । यह दो बार मरने की तरह है लेकिन केवल दूसरे रोल को स्वीकार करना; कोई बात नहीं, आपके पास प्रत्येक रोल के 6 संभावित परिणाम हैं, इसलिए पहला रोल पर्याप्त है।
यह बेहतर क्यों है?
यह समझने के लिए कि यह बेहतर क्यों है, हमें पहले यह समझना होगा कि हैशिंग कार्य कैसे करते हैं। यदि समान इनपुट दिया जाता है, तो हाशिंग फ़ंक्शंस (SHA1 सहित) हमेशा वही आउटपुट उत्पन्न करेगा।
मान लें कि हम आईडी जनरेट करना चाहते हैं, लेकिन हमारा रैंडम इनपुट एक सिक्का टॉस द्वारा उत्पन्न होता है। हमारे पास "heads"
या है"tails"
% echo -n "heads" | shasum
c25dda249cdece9d908cc33adcd16aa05e20290f -
% echo -n "tails" | shasum
71ac9eed6a76a285ae035fe84a251d56ae9485a4 -
यदि "heads"
फिर से आता है, तो SHA1 आउटपुट वही होगा जो पहली बार था
% echo -n "heads" | shasum
c25dda249cdece9d908cc33adcd16aa05e20290f -
ठीक है, इसलिए एक सिक्का टॉस एक महान यादृच्छिक आईडी जनरेटर नहीं है क्योंकि हमारे पास केवल 2 संभावित आउटपुट हैं।
अगर हम मानक 6-पक्षीय डाई का उपयोग करते हैं, तो हमारे पास 6 संभावित इनपुट हैं। लगता है कि कितने संभव SHA1 आउटपुट? 6!
input => (sha1) => output
1 => 356a192b7913b04c54574d18c28d46e6395428ab
2 => da4b9237bacccdf19c0760cab7aec4a8359010b0
3 => 77de68daecd823babbb58edb1c8e14d7106e83bb
4 => 1b6453892473a467d07372d45eb05abc2031647a
5 => ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
6 => c1dfd96eea8cc2b62785275bca38ac261256e278
हम दोनों सहमत हैं कि एक सिक्का टॉस या 6-पक्षीय मृत्यु एक बुरा यादृच्छिक आईडी जनरेटर बना देगा, क्योंकि हमारे संभावित SHA1 परिणाम (आईडी के लिए हम जो मूल्य का उपयोग करते हैं) बहुत कम हैं। लेकिन क्या होगा अगर हम किसी ऐसी चीज का उपयोग करें जिसमें बहुत अधिक आउटपुट हैं? मिलीसेकंड के साथ टाइमस्टैम्प की तरह? या जावास्क्रिप्ट है Math.random
? या उन दो का एक संयोजन भी ?!
आइए गणना करें कि हमें कितनी अनोखी आईडी मिलेगी ...
मिलीसेकंड के साथ एक टाइमस्टैम्प की विशिष्टता
उपयोग करते समय (new Date()).valueOf().toString()
, आपको एक 13-वर्ण संख्या (जैसे, 1375369309741
) मिल रही है । हालाँकि, यह क्रमिक रूप से अद्यतन करने वाली संख्या (एक बार मिलीसेकंड के बाद) के बाद से, आउटपुट लगभग हमेशा समान होते हैं। चलो एक नज़र डालते हैं
for (var i=0; i<10; i++) {
console.log((new Date()).valueOf().toString());
}
console.log("OMG so not random");
// 1375369431838
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431839
// 1375369431840
// 1375369431840
// OMG so not random
तुलनात्मक उद्देश्यों के लिए, निष्पक्ष होने के लिए, दिए गए मिनट में (एक उदार संचालन निष्पादन समय), आपके पास 60*1000
या 60000
अप्रकाशित होंगे।
की विशिष्टता Math.random
अब, जब Math.random
जावास्क्रिप्ट 64-बिट फ्लोटिंग पॉइंट संख्याओं का प्रतिनिधित्व करता है, तो जिस तरह से, आप 13 से 24 वर्णों के बीच कहीं भी लंबाई के साथ एक नंबर प्राप्त करेंगे। एक लंबे परिणाम का अर्थ है अधिक अंक जिसका अर्थ अधिक एन्ट्रापी है। सबसे पहले, हमें यह पता लगाने की आवश्यकता है कि सबसे संभावित लंबाई कौन सी है।
नीचे दी गई स्क्रिप्ट निर्धारित करेगी कि कौन सी लंबाई सबसे अधिक संभावित है। हम 1 मिलियन यादृच्छिक संख्याओं को उत्पन्न करके और .length
प्रत्येक संख्या के आधार पर एक काउंटर बढ़ाते हैं ।
// get distribution
var counts = [], rand, len;
for (var i=0; i<1000000; i++) {
rand = Math.random();
len = String(rand).length;
if (counts[len] === undefined) counts[len] = 0;
counts[len] += 1;
}
// calculate % frequency
var freq = counts.map(function(n) { return n/1000000 *100 });
प्रत्येक काउंटर को 1 मिलियन से विभाजित करने पर, हमें उस नंबर की लंबाई की संभावना मिलती है, जहां से लौटा है Math.random
।
len frequency(%)
------------------
13 0.0004
14 0.0066
15 0.0654
16 0.6768
17 6.6703
18 61.133 <- highest probability
19 28.089 <- second highest probability
20 3.0287
21 0.2989
22 0.0262
23 0.0040
24 0.0004
इसलिए, भले ही यह पूरी तरह से सच नहीं है, आइए उदार बनें और कहें कि आपको एक 19-चरित्र-लंबा यादृच्छिक आउटपुट मिलता है; 0.1234567890123456789
। पहले वर्ण हमेशा रहेंगे 0
और .
इसलिए, वास्तव में हम केवल 17 यादृच्छिक वर्ण प्राप्त कर रहे हैं। यह हमें 10^17
+1
(संभव के लिए 0
नीचे देखें नोट्स) या 100,000,000,000,000,001 uniques के साथ छोड़ देता है ।
तो हम कितने यादृच्छिक इनपुट उत्पन्न कर सकते हैं?
ठीक है, हमने एक मिलीसेकंड टाइमस्टैम्प और के लिए परिणामों की संख्या की गणना की Math.random
100,000,000,000,000,001 (Math.random)
* 60,000 (timestamp)
-----------------------------
6,000,000,000,000,000,060,000
यह एक एकल 6,000,000,000,000,000,060,000-पक्षीय मृत्यु है। या, इस संख्या को अधिक मानवीय रूप से सुपाच्य बनाने के लिए, यह लगभग उतनी ही संख्या है जितनी कि
input outputs
------------------------------------------------------------------------------
( 1×) 6,000,000,000,000,000,060,000-sided die 6,000,000,000,000,000,060,000
(28×) 6-sided die 6,140,942,214,464,815,497,21
(72×) 2-sided coins 4,722,366,482,869,645,213,696
बहुत अच्छा लगता है, है ना? खैर, आइए जानें ...
SHA1 संभावित 20 ^ 20 परिणामों के साथ, 20-बाइट मान का उत्पादन करता है। तो हम वास्तव में पूरी क्षमता तक SHA1 का उपयोग नहीं कर रहे हैं। वैसे हम कितना उपयोग कर रहे हैं?
node> 6000000000000000060000 / Math.pow(256,20) * 100
generator sha1 potential used
-----------------------------------------------------------------------------
crypto.randomBytes(20) 100%
Date() + Math.random() 0.00000000000000000000000000411%
6-sided die 0.000000000000000000000000000000000000000000000411%
A coin 0.000000000000000000000000000000000000000000000137%
पवित्र बिल्लियों, आदमी! उन सभी शून्य को देखो। तो कितना बेहतर है crypto.randomBytes(20)
? 243,583,606,221,817,150,598,111,409 गुना बेहतर।
+1
और शून्य की आवृत्ति के बारे में नोट्स
आप के बारे में सोच रहे हैं +1
, यह संभव है के लिए Math.random
एक वापस जाने के लिए 0
जो वहाँ 1 और अधिक संभव अद्वितीय परिणाम हम के लिए खाते में राशि का मतलब है।
नीचे हुई चर्चा के आधार पर, मैं इस बात के बारे में उत्सुक था कि आवृत्ति 0
क्या होगी। यहां थोड़ी स्क्रिप्ट है random_zero.js
, मैंने कुछ डेटा प्राप्त करने के लिए बनाया है
#!/usr/bin/env node
var count = 0;
while (Math.random() !== 0) count++;
console.log(count);
फिर, मैंने इसे 4 थ्रेड्स में चलाया (मेरे पास 4-कोर प्रोसेसर है), आउटपुट को एक फाइल में जोड़ता है
$ yes | xargs -n 1 -P 4 node random_zero.js >> zeroes.txt
तो यह पता चला है कि एक 0
मुश्किल नहीं है। 100 मान दर्ज किए जाने के बाद , औसत था
3,164,854,823 में 1 रैंडम 0 है
ठंडा! यह जानने के लिए अधिक शोध की आवश्यकता होगी कि क्या वह संख्या v8 के Math.random
कार्यान्वयन के समान वितरण के साथ चालू है
Date
अच्छे बीजों के उत्पादन में भयानक है।
Math.random
कि कभी भी एक उत्पादन होगा0.
crypto.randomBytes
निश्चित रूप से जाने के लिए रास्ता है ^ ^
संपादित करें: यह वास्तव में मेरे पिछले उत्तर के प्रवाह में फिट नहीं था। मैं इसे यहां लोगों के लिए एक दूसरे उत्तर के रूप में छोड़ रहा हूं जो शायद ब्राउज़र में ऐसा करना चाह रहा है।
यदि आप चाहें तो आप इस क्लाइंट को आधुनिक ब्राउज़रों में कर सकते हैं
// str byteToHex(uint8 byte)
// converts a single byte to a hex string
function byteToHex(byte) {
return ('0' + byte.toString(16)).slice(-2);
}
// str generateId(int len);
// len - must be an even number (default: 40)
function generateId(len = 40) {
var arr = new Uint8Array(len / 2);
window.crypto.getRandomValues(arr);
return Array.from(arr, byteToHex).join("");
}
console.log(generateId())
// "1e6ef8d5c851a3b5c5ad78f96dd086e4a77da800"
console.log(generateId(20))
// "d2180620d8f781178840"
ब्राउज़र आवश्यकताएँ
Browser Minimum Version
--------------------------
Chrome 11.0
Firefox 21.0
IE 11.0
Opera 15.0
Safari 5.1
Number.toString(radix)
हमेशा 2 अंकीय मान की गारंटी नहीं देता (उदा: (5).toString(16)
= "5", "05" नहीं)। यह तब तक मायने नहीं रखता जब तक कि आप अपने अंतिम आउटपुट पर निर्भर न हों कि वास्तव में len
वर्ण लंबे हों। इस मामले में आप return ('0'+n.toString(16)).slice(-2);
अपने मानचित्र फ़ंक्शन के अंदर उपयोग कर सकते हैं ।
id
विशेषता के मूल्य के लिए उपयोग करने जा रहे हैं , तो सुनिश्चित करें कि आईडी एक पत्र से शुरू होती है: [ए-ज़-ज़]।