やりたいこと
0.0~1.0の間で小数の乱数をセキュアに生成したいです
以下のMDNによるとMath.random()
はセキュアじゃないです。
Math.random() の提供する乱数は、暗号に使用可能な安全性を備えていません。セキュリティに関連する目的では使用しないで下さい。代わりにWeb Crypto API(より正確にはwindow.crypto.getRandomValues()メソッド)を使用して下さい。
なので、Math.random()
のセキュア版を作りたいです。
セキュアな乱数生成
以下のsecureRandom()
がセキュアなMath.random()
のつもりです。
// cryptoをインポート
const crypto = require('crypto');
// crypto.randomBytes()で生成するときのバイト数
const nBytes = 4;
// nBytesの整数の最大値
const maxValue = 4294967295
// [0.0, 1.0]区間でセキュアな乱数を生成する
function secureRandom() {
// nBytesバイトのランダムなバッファを生成する
const randomBytes = crypto.randomBytes(nBytes);
// ランダムなバッファを整数値に変換する
const r = randomBytes.readUIntBE(0, nBytes);
// 最大値で割ることで、[0.0, 1.0]にする
return r / maxValue;
}
動かしてみる
以下で動作確認できます([run▶]を押してください)
https://repl.it/@nwtgck/secure-random-number
maxValue
の算出について
maxValue
はnBytes
を使えば生成できるはずなのです。JavaScriptでmaxValue == (1 << 8*nBytes) - 1
なはずなので、ビット演算をしてみたのですが、うまく行かなかったので、ハードコーディングしています。長くなりますが、以下のように書くと、うまくnBytes
からmaxValue
を算出できました(なにかいい案があったら教えてもらえると嬉しいです)。
// (計算できるけど、ちょっと長い)
const maxValue = new Buffer(Array(nBytes).fill(0xff)).readUIntBE(0, nBytes);
Math.random()
との違い
Math.random()
は「[0, 1)(0以上、1未満)」らしいですが、secureRandom()
は[0, 1]なので、そこが違うところだと思います。