Node.js – 如何使用crypto.randomBytes在特定范围内生成随机数字

如何使用crypto.randomBytes在特定范围内生成随机数字?

我想能够生成一个像这样的随机数字:

console.log(random(55, 956)); // where 55 is minimum and 956 is maximum 

而且我仅限于在随机函数内部使用crypto.randomBytes来为此范围生成随机数。

我知道如何将生成的字节从randomBytes转换为hex或十进制,但我不知道如何从math上随机字节的特定范围内获得一个随机数。

要生成范围[55 .. 956]中的数字,首先在[0 .. 901]范围内生成一个随机数,其中901 = 956 – 55。然后,将55添加到刚生成的数字中。

要生成范围[0 .. 901]中的数字,请选取两个随机字节并屏蔽掉6位。 这将给你一个10位的随机数在[0 .. 1023]的范围内。 如果这个数字<= 901,那么你就完成了。 如果它大于901,则丢弃它并得到两个更多的随机字节。 不要尝试使用MOD,将数字置于正确的范围内,这会使输出变得非随机。

ETA:减less丢弃生成号码的机会。

由于我们从RNG中取出两个字节,我们得到一个范围在[0 .. 65535]的数​​字。 现在65535 MOD 902是591.因此,如果我们的双字节随机数小于(65535 – 591),即小于64944,我们可以安全地使用MOD算子,因为每个数字的范围[0 .. 901]现在同样可能。 任何双字节数> = 64944仍然必须被丢弃,因为使用它会使输出失去随机性。 之前,不得不拒绝的几率是(1024 – 901)/ 1024 = 12%。 现在拒绝的机会是(65535 – 64944)/ 65535 = 1%。 我们不太可能不得不拒绝随机生成的数字。

 running <- true while running num <- two byte random if (num < 64944) result <- num MOD 902 running <- false endif endwhile return result + 55 

要在一定范围内生成随机数,可以使用下面的公式

 Math.random() * (high - low) + low 

但是你想用crypto.randomBytes而不是Math.random()这个函数返回一个随机生成的字节的缓冲区。 反过来,你需要把这个函数的结果从字节转换成十进制。 这可以使用biguint格式的包来完成。 要安装这个软件包,只需使用以下命令:

 npm install biguint-format --save 

现在你需要将crypto.randomBytes的结果转换为十进制,你可以这样做:

 var x= crypto.randomBytes(1); return format(x, 'dec'); 

现在你可以创build你的随机函数,如下所示:

 var crypto = require('crypto'), format = require('biguint-format'); function randomC (qty) { var x= crypto.randomBytes(qty); return format(x, 'dec'); } function random (low, high) { return randomC(4)/Math.pow(2,4*8-1) * (high - low) + low; } console.log(random(50,1000)); 

感谢来自@Mustafamg的回答以及@CodesInChaos的巨大帮助,我设法解决了这个问题。 我做了一些调整,把范围增加到最大256 ^ 6-1或者281,474,976,710,655。 范围可以增加更多,但你需要使用额外的库大整数,因为256 ^ 7-1超出Number.MAX_SAFE_INTEGER限制。

如果任何人有相同的问题随时使用它。

 var crypto = require('crypto'); /* Generating random numbers in specific range using crypto.randomBytes from crypto library Maximum available range is 281474976710655 or 256^6-1 Maximum number for range must be equal or less than Number.MAX_SAFE_INTEGER (usually 9007199254740991) Usage examples: cryptoRandomNumber(0, 350); cryptoRandomNumber(556, 1250425); cryptoRandomNumber(0, 281474976710655); cryptoRandomNumber((Number.MAX_SAFE_INTEGER-281474976710655), Number.MAX_SAFE_INTEGER); Tested and working on 64bit Windows and Unix operation systems. */ function cryptoRandomNumber(minimum, maximum){ var distance = maximum-minimum; if(minimum>=maximum){ console.log('Minimum number should be less than maximum'); return false; } else if(distance>281474976710655){ console.log('You can not get all possible random numbers if range is greater than 256^6-1'); return false; } else if(maximum>Number.MAX_SAFE_INTEGER){ console.log('Maximum number should be safe integer limit'); return false; } else { var maxBytes = 6; var maxDec = 281474976710656; // To avoid huge mathematical operations and increase function performance for small ranges, you can uncomment following script /* if(distance<256){ maxBytes = 1; maxDec = 256; } else if(distance<65536){ maxBytes = 2; maxDec = 65536; } else if(distance<16777216){ maxBytes = 3; maxDec = 16777216; } else if(distance<4294967296){ maxBytes = 4; maxDec = 4294967296; } else if(distance<1099511627776){ maxBytes = 4; maxDec = 1099511627776; } */ var randbytes = parseInt(crypto.randomBytes(maxBytes).toString('hex'), 16); var result = Math.floor(randbytes/maxDec*(maximum-minimum+1)+minimum); if(result>maximum){ result = maximum; } return result; } }