SORU
23 ŞUBAT 2012, PERŞEMBE


Nasıl node.js KİMLİĞİ olarak kullanmak için rastgele SHA1 hash oluşturmak için?

Bu hat node.js sha1 için bir kimlik oluşturmak için kullanıyorum:

crypto.createHash('sha1').digest('hex');

Sorun aynı kimliği her zaman dönüyor.

Bu veritabanı belge numarası olarak kullanabilirsiniz böylece rastgele bir kimliği her zaman oluşturmak mümkün mü?

CEVAP
14 ŞUBAT 2013, PERŞEMBE


Daha fazla entropi 14,615,016,373,300,259,879,912,540,705,229 x

crypto.randomBytes kullanmanızı tavsiye ediyorum. sha1 ama kimliği amaçlar için, daha hızlı ve adil olarak değil"". rasgele

var id = crypto.randomBytes(20).toString('hex');
//=> bb5dc8842ca31d4603d6aa11448d1654

Sonuç dizesi rasgele bayt oluşturmak için iki kat daha uzun olacak; her bayt 2 karakter hex kodlanmış. 20 bayt hex 40 karakter olacak.

20 bayt kullanarak, ** 16 yaşında ya var1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976benzersiz çıkış değerleri. BuaynıSHA1 160 bit (20 byte) Olası çıkışları için.

Bunu bilerek, bize 17 ** rasgele bayt bizim için gerçekten çok anlamlı değildir. İki kez ölmek haddeleme ama sadece ikinci rulo;, 6 rulo Olası sonucu her ne olursa olsun kabul etmek gibi bir şey, ilk rulo yeterlidir.


Neden bu daha mı iyi?

Bu daha iyi anlamak için, biz ilk karma fonksiyonların nasıl çalıştığını anlamak zorunda. Fonksiyonlar (SHA1 dahil) karma hep aynı giriş verilirse aynı çıktıyı üretecektir.

Kimliklerini oluşturmak istiyoruz ama rastgele girdiğimiz bir yazı tura ile oluşturulur söylüyorlar. "heads" "tails" var

% echo -n "heads" | shasum
c25dda249cdece9d908cc33adcd16aa05e20290f  -

% echo -n "tails" | shasum
71ac9eed6a76a285ae035fe84a251d56ae9485a4  -

"heads" tekrar gelirse, SHA1 çıktıaynıilk seferinde olduğu gibi

% echo -n "heads" | shasum
c25dda249cdece9d908cc33adcd16aa05e20290f  -

Tamam, yazı tura atmak, böylece biz sadece 2 Olası çıkışları var çünkü büyük rasgele bir KİMLİK oluşturucu değildir.

Eğer 6 taraflı kalıp standart kullanırsak, 6 Olası girişler var. Kaç Olası SHA1 çıkışları sanırım? 6!

input => (sha1) => output
1 => 356a192b7913b04c54574d18c28d46e6395428ab
2 => da4b9237bacccdf19c0760cab7aec4a8359010b0
3 => 77de68daecd823babbb58edb1c8e14d7106e83bb
4 => 1b6453892473a467d07372d45eb05abc2031647a
5 => ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
6 => c1dfd96eea8cc2b62785275bca38ac261256e278

Kolay sadece bizim işlevin çıktı çünkü düşünerek kendimizi kandırırızgörünüyorçok rastgele, o kadarçok rastgele.

İkimiz de bir yazı-tura veya 6-taraflı kalıp Olası SHA1 sonuçları (KİMLİĞİ için kullandığımız değer) çok az olduğu için kötü rasgele kimliği bir jeneratör yapmak konusunda hemfikirler. Ama eğer çok fazla çıkışları olan bir şey kullansak nasıl olur? Milisaniye ile bir zaman damgası gibi? Veya JavaScript Math.random? Hatta birkombinasyonuiki? o!

Bakalım kaç tane almak istiyorsunuz ... hesaplamak


Milisaniye zaman damgası ile bir teklik

(new Date()).valueOf().toString(), kullanırken 13 karakterlik bir sayı (örneğin, 1375369309741) alıyoruz. Ancak, bu yana sırayla numara güncelleme (milisaniye başına bir kez) çıkışlar, hemen hemen her zaman aynıdır. Bir bakalım

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

Adil olmak gerekirse, karşılaştırma amacıylaverilen bir dakika içinde(cömert operasyon yürütme zamanı), 60*1000 60000 tekil olacak.


Math.random teklik

JavaScript 64-bit kayan nokta sayılarını temsil eder, çünkü Math.random, kullanırken, uzunluğu ile bir sayı arasında herhangi bir yerde 13 ve 24 karakter uzunluğunda alacaksın. Uzun bir sonucu daha fazla entropi anlamına gelir daha fazla basamak anlamına gelir. İlk olarak, en olası uzunluğu olduğunu öğrenmek için ihtiyacımız var.

Aşağıdaki komut dosyası en olası olduğunu belirlemek olacaktır. 1 milyon rastgele sayılar üreten bir sayaç her sayı .length göre artan isteriz.

// 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 milyon tarafından her sayaç bölerek, numara uzunluğu Math.random döndü olasılığını elde ederiz.

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

Tamamen doğru olmasa da, cömert olalım ve 19 karakterlik rastgele bir çıkış; 0.1234567890123456789 olsun diyorum. İlk karakter her zaman 0 17 rasgele karakterler alıyoruz yani gerçekten ., olacaktır. 10^17 1 (Olası 0; notlara bakın) bize bırakıyor bu ya100,000,000,000,000,001tekil.


Kaç tane rasgele girişler oluşturabilir miyiz?

Tamam, milisaniyelik bir zaman damgası ve Math.random için sonuç sayısını hesapladık

                   60,000 (timestamp)
  100,000,000,000,000,001 (Math.random)
-------------------------
  100,000,000,000,060,001

Bu 100,000,000,000,060,001 taraflı tek bir kalıp. Veya, bu sayı daha fazla yapmak insanca sindirilebilir, bu periyodik olarak aynı sayıda kabaca10x50-taraflı zar. Kulağa hoş geliyor, değil mi?

SHA1 20-bayt bir değer, 256^20 olası sonuçlar üretir. Gerçekten tam potansiyeline için SHA1 kullanmıyoruz. Peki ne kadar kullanıyoruz?

node> 100000000000060001 / (Math.pow(256,20)) * 100

Milisaniyelik bir zaman damgası ve Matematik.rastgele kullanır sadece 6.84 e-30 SHA1 160 bit % potansiyel!

generator               sha1 potential used
-----------------------------------------------------------------------------
crypto.randomBytes(20)  100%
Date()   Math.random()    0.00000000000000000000000000000684%
6-sided die               0.000000000000000000000000000000000000000000000411%
A coin                    0.000000000000000000000000000000000000000000000137%

Aman Tanrım! Şu sıfırlara bak. Ne kadar iyi crypto.randomBytes(20)?14,615,016,373,300,259,879,912,540,705,229kat daha iyi.


Sıfır 1 ve sıklığı hakkında notlar

1 merak ediyorsan Math.random hesap var 1 yok 50 ** daha olası benzersiz bir sonuca dönmek mümkün.

Aşağıda yaşanan tartışma dayalı, 0 gelip bir frekansı merak ettim. Burada küçük bir script, random_zero.js, bazı veriler elde ettim

#!/usr/bin/env node
var count = 0;
while (Math.random() !== 0) count  ;
console.log(count);

Daha sonra, 4 iş parçacığı (4 çekirdekli işlemci var), çıktıyı bir dosyaya ekleme yaptım

$ yes | xargs -n 1 -P 4 node random_zero.js >> zeroes.txt

Bir 0 bu zor çıkıyor. 100 values kaydedildikten sonra, ortalama oldu

13,164,854,823ortasında bir 0

Serin! Daha fazla araştırma ise bu sayı on-par v8 Math.random uygulama tekdüze dağılıma sahip olup olmadığını öğrenmek için gerekli olacaktır

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BroadCity

    BroadCity

    10 ŞUBAT 2010
  • Jonah Penna

    Jonah Penna

    11 EYLÜL 2005
  • Matt Steffanina

    Matt Steffan

    1 EYLÜL 2011