Skip to content

Instantly share code, notes, and snippets.

@kawaz
Last active Sep 5, 2021
Embed
What would you like to do?
ブラウザのJavascriptで暗号論的にセキュアな疑似乱数を使って指定範囲の整数の乱数を得る方法。
/**
* a以上b以下の整数の乱数を生成する
* @param {number|bigint} a
* @param {number|bigint} b
* @returns {number|bigint}
*/
function getRandomIntBetween(a, b) {
if (b < a) {
// [a, b] = [b, a]
const t = a; a = b; b = t;
}
if(typeof a === 'bigint' || typeof b === 'bigint') {
return getRandomBigUint64(b - a) + a
} else {
return getRandomUint(b - a) + a
}
}
/**
* 0以上max以下の整数の乱数を生成する
* @param {number|bigint} max
* @returns {number|bigint}
*/
function getRandomUint(max = 0xFFFFFFFF) {
if (max === 0xFFFFFFFF) {
return crypto.getRandomValues(new Uint32Array(1))[0]
}
if (max < 0xFFFFFFFF) {
const validMax = 0xFFFFFFFF - 0xFFFFFFFF % (max + 1)
while (true) {
const r = crypto.getRandomValues(new Uint32Array(8)).find(i => i <= validMax)
if (r !== undefined) {
return r % (max + 1)
}
}
}
if (typeof max == 'number') {
return Number(getRandomBigUint64(BigInt(max)))
}
return getRandomBigUint64(BigInt(max))
}
/**
* 0以上max以下の整数の乱数を生成する
* @param {bigint} max
* @returns {bigint}
*/
function getRandomBigUint64(max = 2n ** 64n - 1n) {
if (max === 2n ** 64n - 1n) {
return crypto.getRandomValues(new BigUint64Array(1))[0]
}
if (max < 2n ** 64n - 1n) {
const validMax = (2n ** 64n - 1n) - (2n ** 64n - 1n) % (max + 1n)
while (true) {
const r = crypto.getRandomValues(new BigUint64Array(8)).find(i => i <= validMax)
if (r !== undefined) {
return r % (max + 1n)
}
}
}
}
@kawaz
Copy link
Author

kawaz commented Sep 5, 2021

ブラウザが対応してないならしゃーない。

// crypto.getRandomValues が使えないなら諦めて Math.random にフォールバックする
if(!window.crypto || !typeof window.crypto.getRandomValues === 'function') {
    function getRandomUint(max) {
        return Math.floor(Math.random(max + 1))
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment