Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node: Generate 6 digits random number using crypto.randomBytes

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?

like image 578
wdetac Avatar asked Jul 13 '18 12:07

wdetac


People also ask

How do I generate a random number in node?

Calculate a random number between the min and max values like this:use Math. random() to generate a random number, multiply this random number with the difference of min and max and ultimately add min to it. This random number is between min and max , but not an integer. Finally, round the number with Math.

What does crypto randomBytes do?

The crypto. randomBytes() generates cyprtographically strong pseudo-random data. This method will not be completed until there is sufficient entropy in the bytes created. But even after this it does not takes more than a few milliseconds.

Is crypto randomBytes secure?

crypto.randomBytes(size[, callback]) Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate. This means that the random data is secure enough to use for encryption purposes.

Is Nodejs crypto safe?

The core of Node. js is secure, but third-party packages may require additional security measures to protect your web applications. According to this analysis, 14% of the Node Package Manager (NPM) ecosystem is affected.


2 Answers

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 with regards to running time but generate a number with no bias at all. They are based on rejection sampling.

The complex discard method discusses a more optimal scheme for generating large quantities of random numbers in a range. I think it is too complex for almost any normal use; I would look at the Optimized Simple Discard method described below if you require additional efficiency instead.

The Simple Modular Method 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; basically to have a bias of one out of 2^128 you need 128 bits on top of the bit size of the range required. This is probably not the method to choose for smaller numbers.

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


I've myself thought of a very efficient algorithm based on the Simple Discard Method called the "Optimized Simple Discard Method" or RNG-BC where "BC" stands for "binary compare". It is based on the observation that comparison only looks at the most significant bits, which means that the least significant bits should still be considered random and can therefore be reused. Beware that this method has not been officially peer reviewed; I do present an informal proof of equivalence with the Simple Discard Method.


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.

like image 141
Maarten Bodewes Avatar answered Nov 21 '22 22:11

Maarten Bodewes


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))

like image 30
alexojegu Avatar answered Nov 22 '22 00:11

alexojegu