← Назад до блогу

Чи справний ваш генератор випадкових чисел? Контрольний список практичного аудиту

Інструменти та справедливість30 березня 2026·7 хвилин прочитати
Random number generator fairness audit

Коли ви проводите розіграш, обираєте команди випадковим чином або призначаєте завдання за допомогою лотереї, справедливість не є обов’язковою — це вся суть. Але «випадкове» не означає автоматично «чесне». Приховані зміщення в генераторах випадкових чисел (ГВЧ) можуть спотворювати результати непомітними способами, якщо ви не знаєте, де шукати.

Ця стаття містить практичний контрольний список для перевірки будь-якого RNG на справедливість, незалежно від того, використовуєте ви наш Генератор випадкових чисел чи створюєте власний.

Що означає чесність для розіграшів, призначених для користувачів

Чесний RNG дає результати, де:

Пропуск будь-якого з цих порушує довіру, навіть якщо результати «виглядають» випадковими.

Поширені джерела упередженості

Bad Seeds

A PRNG (генератор псевдовипадкових чисел) настільки ж непередбачуваний, як і його початкове значення. Поширені погані насіння:

Завжди завантажуйте з криптографічного джерела: crypto.getRandomValues() у браузерах, /dev/urandom в Linux або crypto.randomBytes() у Node.js.

Modulo Bias

Тонка та поширена помилка: використання оператора modulo для зменшення випадкового числа до діапазону.

// BIASED — якщо діапазон RNG не кратний 6,
// деякі результати є трохи більш імовірними
const roll = randomUint32() % 6; // ПРАВИЛЬНО — вибірка відхилення
функція fairDiceRoll() { const max = Math.floor(0xFFFFFFFF / 6) * 6; нехай значення; do { value = crypto.getRandomValues(new Uint32Array(1))[0]; } while (значення >= max); повернення значення % 6;

Для 6-сторонньої матриці зміщення за модулем із 32-бітним цілим числом становить лише ~0,00000009%. Але для більших діапазонів або 8-бітних значень це стає значущим.

Приховані фільтри

Деякі системи розіграшу мовчки виключають певні результати (наприклад, відфільтровують «останніх переможців» або повторюють результати, які не подобаються оператору). Це порушує справедливість, навіть якщо основний RNG ідеальний. Задокументуйте та розкрийте всі правила фільтрації перед розіграшем.

Контрольний список аудиту для операторів

  1. Джерело ентропії — RNG завантажується з криптографічного джерела? (Не Math.random, не мітки часу)
  2. Тест однорідності — Виконайте понад 10 000 зразків і застосуйте тест хі-квадрат. p-value має бути > 0,05
  3. Modulo bias — чи використовує код вибірку відхилень чи метод неупередженого зіставлення?
  4. Independence — Чи пов’язані послідовні розіграші? Виконайте тест автокореляції на великих вибірках
  5. Перегляд коду — Чи код розіграшу є відкритим кодом чи доступним для перевірки? Прихований код може містити бекдори
  6. Відкриття фільтрації — Чи відфільтровано, повторно згорнуто чи виключено будь-які результати? Це має бути розкрито
  7. Timing — Чи може оператор переглянути результати перед публікацією? Якщо так, вони можуть вибірково відкидати несприятливі розіграші

Шаблон прозорості для публічних розіграшів

Для розіграшів із високими ставками (призи, завдання, вибір) використовуйте схему фіксації-розкриття:

  1. Перед розіграшем: Згенеруйте випадкове початкове число. Опублікуйте його хеш SHA-256 («зобов’язання») — наприклад, у соціальних мережах або документі з міткою часу
  2. Запустіть розіграш: Використовуйте початковий код, щоб створити результати за допомогою детермінованого алгоритму
  3. Після жеребкування: Опублікуйте початковий код. Будь-хто може підтвердити, що:
    • Початковий код створює опублікований хеш
    • Початковий код + алгоритм дає оголошені результати

Використовуйте наш Генератор хешів, щоб створити та перевірити хеш зобов’язань.

// Фаза зобов’язань
const seed = crypto.randomBytes(32).toString('hex');
const commitment = sha256(seed); // опублікувати це перед розіграшем // Етап малювання
const result = deterministicDraw(seed, учасників); // Фаза розкриття
// опублікувати вихідний код — будь-хто може перевірити sha256(seed) === commitment

Повідомлення користувачів про чесність

Довіра вимагає прозорості. Під час публічних розіграшів:

FAQ

Чи достатньо Math.random?

Math.random() використовує генератор псевдовипадкових чисел (PRNG), який не є криптографічно захищеним. Його вихід можна передбачити, якщо відомий внутрішній стан. Для чесних розіграшів використовуйте crypto.getRandomValues() у браузері або crypto.randomInt() у Node.js.

Як я можу довести, що розіграш не був підроблений?

Використовуйте схему виявлення фіксації: перед розіграшем опублікуйте хеш випадкового початкового числа (зобов’язання). Після розіграшу розкрийте насіння. Будь-хто може переконатися, що вихідний код створює опублікований хеш і оголошені результати.

Скільки зразків мені потрібно для базової перевірки упередженості?

Для простої перевірки однорідності за N результатами вам потрібно принаймні 100 × N зразків (наприклад, 1000 зразків для жеребкування з 10 варіантами). Застосуйте тест хі-квадрат: якщо p-значення вище 0,05, розподіл достатньо рівномірний. Для серйозних перевірок використовуйте понад 10 000 зразків.

Пов’язані інструменти та статті