Help us understand the problem. What is going on with this article?

Node.jsでセキュアな乱数を生成したい!(0.0 ~ 1.0)

More than 1 year has passed since last update.

やりたいこと

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の算出について

maxValuenBytesを使えば生成できるはずなのです。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]なので、そこが違うところだと思います。

参考

nwtgck
最近はScrapbox → https://scrapbox.io/nwtgck
https://scrapbox.io/nwtgck
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away