use*_*552 12 javascript random cryptography range
我知道你可以使用这个函数在一个范围内的JavaScript中生成一个随机数:
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Run Code Online (Sandbox Code Playgroud)
感谢IonuţG.Stan 在这里.
我想知道的是你是否可以使用crypto.getRandomValues()而不是Math.random()在一个范围内生成一个更好的随机数.我希望能够生成0到10之间的数字,或0到1,甚至10 - 5000(含).
你会注意到Math.random()产生一个如下数字:0.8565239671015732.
getRandomValues API可能会返回以下内容:
Uint8Array(1)Uint16Array(1)Uint32Array(1).那么如何将其转换回十进制数,以便我可以使用上面相同的范围算法?或者我需要一个新的算法?
这是我尝试的代码,但它不能很好地工作.
function getRandomInt(min, max) {
// Create byte array and fill with 1 random number
var byteArray = new Uint8Array(1);
window.crypto.getRandomValues(byteArray);
// Convert to decimal
var randomNum = '0.' + byteArray[0].toString();
// Get number in range
randomNum = Math.floor(randomNum * (max - min + 1)) + min;
return randomNum;
}
Run Code Online (Sandbox Code Playgroud)
在低端(范围0 - 1),它返回0比1更多.使用getRandomValues()执行此操作的最佳方法是什么?
非常感谢
小智 14
最简单的方法可能是拒绝抽样(参见http://en.wikipedia.org/wiki/Rejection_sampling).例如,假设max - min小于256:
function getRandomInt(min, max) {
// Create byte array and fill with 1 random number
var byteArray = new Uint8Array(1);
window.crypto.getRandomValues(byteArray);
var range = max - min + 1;
var max_range = 256;
if (byteArray[0] >= Math.floor(max_range / range) * range)
return getRandomInt(min, max);
return min + (byteArray[0] % range);
}
Run Code Online (Sandbox Code Playgroud)
小智 8
恕我直言,这里描述了在[min..max]范围内生成随机数的最简单方法.window.crypto.getRandomValues()
ECMAScript 2015语法代码,以防链接为TL; TR:
function getRandomIntInclusive(min, max) {
const randomBuffer = new Uint32Array(1);
window.crypto.getRandomValues(randomBuffer);
let randomNumber = randomBuffer[0] / (0xffffffff + 1);
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(randomNumber * (max - min + 1)) + min;
}
Run Code Online (Sandbox Code Playgroud)
其中许多答案都会产生有偏见的结果。这是一个无偏见的解决方案。
function random(min, max) {
const range = max - min + 1
const bytes_needed = Math.ceil(Math.log2(range) / 8)
const cutoff = Math.floor((256 ** bytes_needed) / range) * range
const bytes = new Uint8Array(bytes_needed)
let value
do {
crypto.getRandomValues(bytes)
value = bytes.reduce((acc, x, n) => acc + x * 256 ** n, 0)
} while (value >= cutoff)
return min + value % range
}
Run Code Online (Sandbox Code Playgroud)
如果您使用 Node.js,那么使用加密安全的伪随机 crypto.randomInt 会更安全。如果您不知道自己在做什么并且没有经过同行评审,请不要编写这种敏感方法。
添加于:v14.10.0、v12.19.0
min <integer>随机范围的开始(含)。默认值:0。max <integer>随机范围结束(不包括)。callback <Function> function(err, n) {}。返回一个随机整数 n,使得 min <= n < max。该实现避免了模偏差。
范围 ( max - min) 必须小于 2^48。min并且max必须是安全整数。
如果不提供回调函数,则同步生成随机整数。
// Asynchronous
crypto.randomInt(3, (err, n) => {
if (err) throw err;
console.log(`Random number chosen from (0, 1, 2): ${n}`);
});
Run Code Online (Sandbox Code Playgroud)
// Synchronous
const n = crypto.randomInt(3);
console.log(`Random number chosen from (0, 1, 2): ${n}`);
// With `min` argument
const n = crypto.randomInt(1, 7);
console.log(`The dice rolled: ${n}`);
Run Code Online (Sandbox Code Playgroud)
死灵术。
嗯,这很容易解决。
// Returns a random number between min (inclusive) and max (exclusive)
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Run Code Online (Sandbox Code Playgroud)
因此,您需要做的就是将 Math.random 替换为来自 crypt 的随机数。
那么 Math.random 有什么作用呢?
根据MDN,Math.random() 函数返回 0 到小于 1 范围内的浮点伪随机数(包括 0,但不包括 1)
所以我们需要一个加密随机数 >= 0 且< 1 (而不是 <=)。
因此,我们需要来自 getRandomValues 的非负(也称为 UNSIGNED)整数。
我们如何做到这一点?
简单:我们只得到一个 UInt,而不是获取一个整数,然后执行 Math.abs:
var randomBuffer = new Int8Array(4); // Int8Array = byte, 1 int = 4 byte = 32 bit
window.crypto.getRandomValues(randomBuffer);
var dataView = new DataView(randomBuffer.buffer);
var uint = dataView.getUint32();
Run Code Online (Sandbox Code Playgroud)
其简写版本是
var randomBuffer = new Uint32Array(1);
(window.crypto || window.msCrypto).getRandomValues(randomBuffer);
var uint = randomBuffer[0];
Run Code Online (Sandbox Code Playgroud)
现在我们需要做的就是将 uint 除以 uint32.MaxValue(又名 0xFFFFFFFF)以获得浮点数。因为结果集中不能有 1,所以我们需要除以 (uint32.MaxValue+1) 以确保结果 < 1。
除以 (UInt32.MaxValue + 1) 是有效的,因为 JavaScript 整数是 64-内部为bit浮点数,因此不限于32位。
function cryptoRand()
{
var array = new Int8Array(4);
(window.crypto || window.msCrypto).getRandomValues(array);
var dataView = new DataView(array.buffer);
var uint = dataView.getUint32();
var f = uint / (0xffffffff + 1); // 0xFFFFFFFF = uint32.MaxValue (+1 because Math.random is inclusive of 0, but not 1)
return f;
}
Run Code Online (Sandbox Code Playgroud)
其简写是
function cryptoRand()
{
const randomBuffer = new Uint32Array(1);
(window.crypto || window.msCrypto).getRandomValues(randomBuffer);
return ( randomBuffer[0] / (0xffffffff + 1) );
}
Run Code Online (Sandbox Code Playgroud)
现在您需要做的就是将上述函数中的 Math.random() 替换为 cryptoRand() 。
请注意,如果 crypto.getRandomValues 在 Windows 上使用 Windows-CryptoAPI 来获取随机字节,则不应将这些值视为真正的加密安全熵源。