Take the 2-minute tour ×
Cryptography Stack Exchange is a question and answer site for software developers, mathematicians and others interested in cryptography. It's 100% free, no registration required.

Using node.js crypto library I can generate cryptographically strong bytes. How can I use this to generate a random number between 0 and 9999 (both inclusive)?

share|improve this question
    
As an aside, randomBytes and pseudoRandomBytes are named terribly. randomBytes is actually pseudo-random (and cryptographically secure) while pseudoRandomBytes is not cryptographically secure? –  Reid Jun 24 '13 at 14:42
    
There are several very similar question on stackoverflow. For example my own enerating uniform random integers with a certain maximum –  CodesInChaos Jun 24 '13 at 15:57

2 Answers 2

up vote 5 down vote accepted

I would personally recommend this simple procedure for selecting random values from 0 to N:

Step 1: ask your cryptographically secure RNG for a sample M that is large enough to cover the interval between 0 and N

In your case, if your CSRNG outputs bytes, then you would ask it for 2 bytes; that gives you a random value M between 0 and 65535

Step 2: modulo reduce M by the smallest power of 2 that is larger than N

In your case, the smallest power of two larger than N is 16384; hence, you take M (the value between 0 and 65535), and modulo reduce that by 16384, giving you a value between 0 and 16383;

M = M % 16384;

(language note: the above assumes that the result will always be in the range of 0 through 16383; if the programming language does something funny with the modulo of negative numbers, you might either avoid negative numbers altogether, or handle negative numbers as a special case)

Step 3: check if the value M is in the range you want, that is, no more than N; if it is not, then go back to step 1

In your case, you're looking for values between 0 and 9999; if M is outside the range, we discard it, and go back to step 1.

if (M > 9999) goto step_1;

Step 4: return the value M

Properties of the above algorithm:

  • It is unbiased. The only nonobvious point behind this is step 2; by modulo reducing M by a power of 2, it remains an unbiased value (only with a smaller range). This step is effectively masking off the higher order bits; leaving the lower order bits undisturbed.

  • It is cryptographically secure (assuming that the original RNG used in step 1 was cryptographically secure); any method that can be used on the output of this algorithm to distinguish it from random could be used against the original source to distinguish that from random.

  • It is moderately efficient; we'll run steps 1 through 3 (at most) an expected 2 times for every generated value. Now, there are alternative algorithms that use fewer expected random bits from your rng, however (IMHO) those methods aren't as easy to get right, and wringing the last bit of efficiency is less important than getting a method that we are confident is good.

share|improve this answer

First, how not to do it. You could generate 2 bytes, treat it as a 16 bit number and compute it modulo 10000. That would give you a number between 0 and 9999, but would not be cryptographically secure. It would have bias. For example, using python random.randint(0,65535) % 10000, I generated 1,000,000 random numbers and plotted the following histogram:

Bad PRNG

The proper way to do it would be to generate 2 random bytes and treat them as a 16 bit number, say $x$. Then compute $x' = x\mod 16384$ (note $16384 = 2^{14}$, i.e., the next power of two just bigger than 10000). Then, if $x'$ is less than 10000, return that number, otherwise start over. Using this process gives the following histogram on 1,000,000 random numbers.

Good PRNG

share|improve this answer
    
A more efficient approach is to take the problem modulo 65536 and divide by 6 when less than 60000, you will waste less entropy this way. This question is actually a duplicate of a couple crypto.SE questions, in particular crypto.stackexchange.com/questions/5708/… and crypto.stackexchange.com/questions/6175/… –  Thomas Jun 24 '13 at 16:07

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.