25

この関数を使用して、範囲内で JavaScript で乱数を生成できることを理解しています。

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

Ionuț G. Stanの 厚意により掲載。

私が知りたいのは、Math.random()の代わりに crypto.getRandomValues( ) を使用して範囲内でより良い乱数を生成できるかどうかです。0 から 10 まで、または 0 から 1 まで、さらには 10 から 5000 までの数値を生成できるようにしたいと考えています。

Math.random() が0.8565239671015732のような数値を生成することに注意してください。

getRandomValues API は、次のようなものを返す場合があります。

  • 231Uint8Array(1)
  • 54328Uint16Array(1)
  • 355282741Uint32Array(1)

では、上記と同じ範囲アルゴリズムを維持できるように、それを 10 進数に変換する方法を教えてください。それとも、新しいアルゴリズムが必要ですか?

これが私が試したコードですが、うまく機能しません。

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) では、1 よりも多くの 0 を返します。getRandomValues() でそれを行う最善の方法は何ですか?

どうもありがとう

4

6 に答える 6

2

ネクロマンシング。
さて、これは簡単に解決できます。

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

したがって、必要なことは Math.random を crypt からのランダムに置き換えることだけです。

では、Math.random は何をするのでしょうか? MDN
に よると、 Math.random() 関数は、0 から 1 未満 (0 を含むが 1 は含まない) の範囲の浮動小数点の疑似乱数を返します。

したがって、暗号乱数 >= 0 かつ< 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 になるようにする必要があります
。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 を使用してランダム バイトを取得する場合、これらの値を真に暗号学的に安全なエントロピーのソースと見なすべきではないことに注意してください。

于 2020-07-08T10:20:34.430 に答える