Узел безопасных реализаций рандоме


Я пытаюсь создать безопасную случайности в узел как личный вызов. Мне было интересно, если следующим реализациям правильно случайных или у них есть некоторые недостатки.

const crypto = require('crypto');

const secureRandomFloat = (bytes = 6) => {
  const size = Math.pow(2, bytes * 8);
  const hexString = crypto.randomBytes(bytes).toString('hex');
  const randInt = parseInt(hexString, 16);
  return randInt / size;
}

export const secureRandomIntRange = (min, max) => {
  const range = max - min; // max is the first not included integer [min, max)
  if (range > Number.MAX_SAFE_INTEGER) return null;
  // use an amount of bytes that will cover the range we need
  const bytes = Math.ceil(Math.log(range) / Math.log(256));
  const size = Math.pow(2, bytes * 8);
  // this is the "tail" of possible numbers. Using them that would
  // give us more chances to get lower values when using modulo
  const excess = size % range;

  let validRand = false;
  let hexString;
  let randInt;
  while (!validRand) {
    hexString = crypto.randomBytes(bytes).toString('hex');
    randInt = parseInt(hexString, 16);
    validRand = randInt + excess < size;
  }

  return min + randInt % range;
}

const secureRandomChoice = arr => {
  // This is to check that the "arr" is iterable, like an array
  // or a string, etc.
  if (arr == null) return null;
  if (typeof arr[Symbol.iterator] !== 'function') return null;
  if (!arr.hasOwnProperty('length')) return null;

  // use an amount of bytes that will cover the range we need
  const bytes = Math.ceil(Math.log(arr.length) / Math.log(256));

  const randIdx = secureRandomIntRange(0, arr.length);
  if (randIdx === null) return null;
  return arr[randIdx];
}

Я сделал некоторые испытания с миллионом итераций и результаты кажутся случайными, но я не знаю, если я что-то упускаю.

Эти реализации даст мне псевдо-рандоме?

Выбраковка

@Blindman67 отметил, что выбраковка, которую я делаю в цикл while в secureRandomIntRangeне собираетесь дать мне случайные значения. Я не есть сильный аргумент, чтобы сказать, что выбраковка даст мне случайных чисел, но я не вижу, почему это не так.

Я использовал выбраковки, потому что я вспомнил, когда мне нужно для генерации случайных точек на сфере. Для этого я взял случайную точку в кубе (гораздо проще), и отбрасывается, если это было вне сферы. Я думаю, он дал мне случайное распределение точек на сфере.

Я пытался применить эту же идею к этой проблеме. Если у меня есть 1 байта можно получить 256 возможные комбинации в случайном порядке, скажем, от 0 до 255. Если я хочу выбрать целое число от 0 до 99 (100 номеров), наивный способ, используя остаток от деления даст мне следующие отношения:

randomByte:     0   1   2 ... 99 100 101 ... 199 200 201 ... 254 255
secureRandInt:  0   1   2 ... 99   0   1 ...  99   0   1 ...  54  55

Но таким образом все числа от 0-55 можно сделать из 3 разных байтов, в то время как цифры от 56-99 могут только быть сделаны из 2 разных байтов. Тогда, как я думал, могли бы дать мне случайное распределение в диапазоне было назначение цифр следующим образом:

randomByte:     0   1   2 ... 99 100 101 ... 199 200 201 ... 254 255
secureRandInt:  0   1   2 ... 99   0   1 ...  99   x   x ...   x   x

Где x означает, что байт не является допустимым (!validRand) и мне придется отбросить его и сделать новый байт в случайном порядке.

В этом примере значения для различных переменных будет выглядеть следующим образом:

range = 100
size = 256
excess = 56
isValid = randInt + excess < size
// isValid = randInt + 56 < 256 --> isValid = randInt < 200
// T for true and F for false
randomByte:  0   1   2 ... 99 100 101 ... 199 200 201 ... 254 255
isValid:     T   T   T ...  T   T   T ...   T   F   F ...   F   F

Как вы думаете, такой подход недопустим для получения случайных чисел?



Комментарии