您的位置:首页 > Web前端 > Node.js

node-haystack Episode - 12 : A Better Random Generator

2016-09-19 05:53 423 查看
The built-in random generator of JavaScript does not look like so random. Anyway, even if there are so many random generator in js/C++/nodejs, I still decide to write my own one.

I found GNU org gives a lot of random generating algorithms(reference). I peeked the one of gls_rng_taus:

Generator: gsl_rng_taus

Generator: gsl_rng_taus2

This is a maximally equidistributed combined Tausworthe generator by L’Ecuyer. The sequence is,

x_n = (s1_n ^^ s2_n ^^ s3_n)

where,

s1_{n+1} = (((s1_n&4294967294)<<12)^^(((s1_n<<13)^^s1_n)>>19))
s2_{n+1} = (((s2_n&4294967288)<< 4)^^(((s2_n<< 2)^^s2_n)>>25))
s3_{n+1} = (((s3_n&4294967280)<<17)^^(((s3_n<< 3)^^s3_n)>>11))

computed modulo 2^32. In the formulas above ^^ denotes “exclusive-or”. Note that the algorithm relies on the properties of 32-bit unsigned integers and has been implemented using a bitmask of 0xFFFFFFFF to make it work on 64 bit machines.

The period of this generator is 2^88 (about 10^26). It uses 3 words of state per generator. For more information see,

P. L’Ecuyer, “Maximally Equidistributed Combined Tausworthe Generators”, Mathematics of Computation, 65, 213 (1996), 203–213.

The generator gsl_rng_taus2 uses the same algorithm as gsl_rng_taus but with an improved seeding procedure described in the paper,

P. L’Ecuyer, “Tables of Maximally Equidistributed Combined LFSR Generators”, Mathematics of Computation, 68, 225 (1999), 261–269

The generator gsl_rng_taus2 should now be used in preference to gsl_rng_taus.


It looks symmetric. I like it. And so on, here comes the C++ code:

/*!
\brief Random number/uuid generator.
*/
class Random {
public:
Random(){
m_seed1 = std::time(nullptr);
m_seed2 = std::time(nullptr);
m_seed3 = std::time(nullptr);
}

Random(const Random&) = delete;

/*!
\brief Generate a random number in range of (0, 2^31]
*/
inline u32 Next() {
m_seed1 = (((m_seed1 & 4294967294) << 12) ^ (((m_seed1 << 13) ^ m_seed1) >> 19));
m_seed2 = (((m_seed2 & 4294967288) << 4) ^ (((m_seed2 << 2) ^ m_seed2) >> 25));
m_seed3 = (((m_seed3 & 4294967280) << 17) ^ (((m_seed3 << 3) ^ m_seed3) >> 11));

return m_seed1 ^ m_seed2 ^ m_seed3;
}

/*!
\brief Generate a random value in range of (0, rng].
*/
inline u32 Next(u32 rng) {
return ((u64)Next() * rng) / 0xFFFFFFFF;
}
private:
u32 m_seed1;
u32 m_seed2;
u32 m_seed3;
}; // class Random


And story goes on, now for node.js add-on:

class RandomObject : public NodeObjectTemplate<Random> {
public:
using self_t = RandomObject;
using random_t = shared_t<wrapped_t>;
public:
explicit RandomObject(Random* rand):Base(rand) {}

IMPL_INIT_FUNC("Random", {
{ "next", Next }
}, {
/* No props */
})

IMPL_NEW_FUNC(DEFAULT_NEW_FUNC())

private:
~RandomObject() {
}

/*!
\brief Get a random value.
\return unsigned 32 bits integer with no range specified; otherwise,
return a random value in range of [0, specified rang).
*/
static void Next(const js_arg_t& args) {
PREPARE_FUNC(args, 0, rand)
u64 val = rand ? rand->Next() : 0;

if (args.Length() > 0 && args[0]->IsNumber()) {
val = (val * args[0]->Int32Value()) / 0xFFFFFFFF;
}

args.GetReturnValue().Set(static_cast<u32>(val));
}

private:
DECL_CTOR()
}; // cls RandomObject


And then the testing code:

var rand = require('../node-random');

var i = 10240;
var count = 0;
while(i-- > 0) {
if ( 100 === rand.next(100)) {
count++;
}
} // while

if (count > 0) {
console.log('Getcha! ', count);
} else {
console.log('Not found');
}


According to a testing before, the duplication is about 0.2% when generating 10M random numbers. It’s good enough for our project. I plan to apply it for block’s cookie field. The cookie field exists for avoiding the attack by guessing the url. As same as the description of Facebook’s paper, an url like http://site.address/key/cookie will dramatically increase the difficulty of attacking.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript random