diff --git a/lib/internal/crypto/random.js b/lib/internal/crypto/random.js index 8ea9f4cee76a48..f89bd198ade1ce 100644 --- a/lib/internal/crypto/random.js +++ b/lib/internal/crypto/random.js @@ -176,20 +176,20 @@ function randomInt(min, max, callback) { `<= ${RAND_MAX}`, range); } - const excess = RAND_MAX % range; - const randLimit = RAND_MAX - excess; + // For (x % range) to produce an unbiased value greater than or equal to 0 and + // less than range, x must be drawn randomly from the set of integers greater + // than or equal to 0 and less than randLimit. + const randLimit = RAND_MAX - (RAND_MAX % range); if (isSync) { // Sync API while (true) { const x = randomBytes(6).readUIntBE(0, 6); - // If x > (maxVal - (maxVal % range)), we will get "modulo bias" - if (x > randLimit) { - // Try again + if (x >= randLimit) { + // Try again. continue; } - const n = (x % range) + min; - return n; + return (x % range) + min; } } else { // Async API @@ -197,9 +197,8 @@ function randomInt(min, max, callback) { randomBytes(6, (err, bytes) => { if (err) return callback(err); const x = bytes.readUIntBE(0, 6); - // If x > (maxVal - (maxVal % range)), we will get "modulo bias" - if (x > randLimit) { - // Try again + if (x >= randLimit) { + // Try again. return pickAttempt(); } const n = (x % range) + min;