Javascript:使用crypto.getRandomValues在一个范围内生成一个随机数

时间:2013-08-14 11:14:01

标签: javascript random cryptography range

我知道你可以使用这个函数在一个范围内的JavaScript中生成一个随机数:

function getRandomInt (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

IonuţG。Stan提供 here

我想知道的是,如果您可以使用crypto.getRandomValues()而不是Math.random()在范围内生成更好的随机数。我希望能够生成一个0到10之间的数字,或0到1,甚至10 - 5000(含)。

你会注意到Math.random()产生的数字如下: 0.8565239671015732

getRandomValues API可能会返回类似于:

的内容
  • 231 Uint8Array(1)
  • 54328 Uint16Array(1)
  • 355282741 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;
}

在低端(范围0 - 1),它返回0比1更多。使用getRandomValues()的最佳方法是什么?

非常感谢

6 个答案:

答案 0 :(得分:13)

最简单的方法可能是拒绝抽样(见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);
}

答案 1 :(得分:7)

恕我直言,here描述了[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;
}

答案 2 :(得分:1)

不断创新。
好吧,这很容易解决。

考虑random number in ranges without crypto-random

// 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;
}

因此,您所需要做的就是用来自crypt的随机数替换Math.random。

那么Math.random做什么?
根据{{​​3}},Math.random()函数返回一个浮点伪随机数,范围为0到小于1(包括0,但不包括1)

因此我们需要一个密码随机数> = 0和 << / strong> 1(不是<= )。

因此,我们需要getRandomValues中的一个非负(也称为UNSIGNED)整数。
我们该怎么做?

简单: 不用获取整数,然后执行Math.abs,我们只需获取UInt:

var randomBuffer = new Int8Array(4); // Int8Array = byte, 1 int = 4 byte = 32 bit 
window.crypto.getRandomValues(randomBuffer);
var dataView = new DataView(array.buffer);
var uint = dataView.getUint32();

简写为

var randomBuffer = new Uint32Array(1);
(window.crypto || window.msCrypto).getRandomValues(randomBuffer);
var uint = randomBuffer[0];

现在,我们要做的就是将uint除以uint32.MaxValue(也称为0xFFFFFFFF)以获得浮点数。而且由于结果集中不能有1,因此需要除以(uint32.MaxValue + 1)以确保结果为<1。
除以(UInt32.MaxValue +1)是可行的,因为JavaScript整数在内部是64位浮点数,因此它不限于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;
}

简写为

function cryptoRand()
{
    const randomBuffer = new Uint32Array(1);
    (window.crypto || window.msCrypto).getRandomValues(randomBuffer);
    return ( randomBuffer[0] / (0xffffffff + 1) );
}

现在您需要做的就是在上述函数中将Math.random()替换为cryptoRand()。

请注意,如果crypto.getRandomValues使用Windows上的Windows-CryptoAPI来获取随机字节,则MDN

答案 3 :(得分:0)

Rando.js使用AttributeError: 'set' object has no attribute 'items'基本上为您完成

dask.config.set(temporary_directory='/path/to/tmp')
crypto.getRandomValues

如果您想看一下幕后故事,这些摘录自源代码:

console.log(rando(5, 10));

答案 4 :(得分:0)

其中许多答案都会产生有偏见的结果。这是一个公正的解决方案。

@override
Widget build(BuildContext context) {
  connectivity();
  print("value${isoffline}");
  return YourWidget();
}

答案 5 :(得分:0)

如果您使用的是 Node.js,则使用加密安全的伪随机 crypto.randomInt 会更安全。如果你不知道自己在做什么,没有同行评审,不要去写这种敏感的方法。

Official documentation

crypto.randomInt([min, ]max[, callback])

加入:v14.10.0、v12.19.0

  • min <integer> 随机范围的开始(包括)。默认值:0。
  • max <integer> 随机范围结束(独占)。
  • callback <Function> function(err, n) {}

返回一个随机整数 n 使得 min <= n < max。此实现避免了 modulo bias

范围 (max - min) 必须小于 2^48。 minmax 必须是 safe integers

如果没有提供回调函数,则同步生成随机整数。

// Asynchronous
crypto.randomInt(3, (err, n) => {
  if (err) throw err;
  console.log(`Random number chosen from (0, 1, 2): ${n}`);
});
// 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}`);