Node: Generate 6 digits random number using crypto.randomBytes

空扰寡人 提交于 2020-08-18 16:25:26

问题


What is the correct way to generate exact value from 0 to 999999 randomly since 1000000 is not a power of 2?

This is my approach:

  1. use crypto.randomBytes to generate 3 bytes and convert to hex
  2. use the first 5 characters to convert to integer (max is fffff == 1048575 > 999999)
  3. if the result > 999999, start from step 1 again

It will somehow create a recursive function. Is it logically correct and will it cause a concern of performance?


回答1:


There are several way to extract random numbers in a range from random bits. Some common ones are described in NIST Special Publication 800-90A revision 1: Recommendation for Random Number Generation Using Deterministic Random Bit Generators

Although this standard is about deterministic random bit generations there is a helpful appendix called A.5 Converting Random Bits into a Random Number which describes three useful methods.

The methods described are:

  • A.5.1 The Simple Discard Method
  • A.5.2 The Complex Discard Method
  • A.5.3 The Simple Modular Method

The first two of them are not deterministic but generate a number with no bias at all. They are based on rejection sampling. The last one is time constant and deterministic but has non-zero (but negligible) bias. It requires a relatively large amount of additional randomness to achieve the negligible bias though.

Your algorithm is clearly a version of the Simple Discard Method (more generally called "rejection sampling"), so it is fine.


Of course you should rather use a generic method that is efficient given any value of N. In that case the Complex Discard Method or Simple Modular Method should be considered over the Simple Discard Method. There are other, much more complex algorithms that are even more efficient, but generally you're fine when using either of these two.

Note that it is often beneficial to first check if N is a power of two when generating a random in the range [0, N). If N is a power of two then there is no need to use any of these possibly expensive computations; just use the bits you need from the random bit or byte generator.




回答2:


It's a correct algorithm (https://en.wikipedia.org/wiki/Rejection_sampling), though you could consider using bitwise operations instead of converting to hex. It can run forever if the random number generator is malfunctioning -- you could consider trying a fixed number of times and then throwing an exception instead of looping forever.




回答3:


The main possible performance problem is that on some platforms, crypto.randomBytes can block if it runs out of entropy. So you don't want to waste any randomness if you're using it.

Therefore instead of your string comparison I would use the following integer operation.

if (random_bytes < 16700000) {
    return random_bytes = random_bytes - 100000 * Math.floor(random_bytes/100000);
}

This has about a 99.54% chance of producing an answer from the first 3 bytes, as opposed to around 76% odds with your approach.




回答4:


I would suggest the following approach:

private generateCode(): string {
    let code: string = "";

    do {
        code += randomBytes(3).readUIntBE(0, 3);
        // code += Number.parseInt(randomBytes(3).toString("hex"), 16);
    } while (code.length < 6);

    return code.slice(0, 6);
}

This returns the numeric code as string, but if it is necessary to get it as a number, then change to return Number.parseInt(code.slice(0, 6))




回答5:


I call it the random_6d algo. Worst case just a single additional loop.

var random_6d = function(n2){
    var n1 = crypto.randomBytes(3).readUIntLE(0, 3) >>> 4;

    if(n1 < 1000000)
        return n1;

    if(typeof n2 === 'undefined')
        return random_6d(n1);

    return Math.abs(n1 - n2);
};

loop version:

var random_6d = function(){
    var n1, n2;

    while(true){
        n1 = crypto.randomBytes(3).readUIntLE(0, 3) >>> 4;

        if(n1 < 1000000)
            return n1;

        if(typeof n2 === 'undefined')
            n2 = n1;
        else
            return Math.abs(n1 - n2);
    };
};


来源:https://stackoverflow.com/questions/51325338/node-generate-6-digits-random-number-using-crypto-randombytes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!