Введение: «Состояние греха» фон Неймана и парадокс детерминированной случайности
В 1951 году Джон фон Нейман произнёс фразу, навсегда вошедшую в историю информатики: «Всякий, кто рассматривает арифметические методы получения случайных цифр, разумеется, пребывает в состоянии греха (in a state of sin)». Цифровой компьютер — это строго детерминированный конечный автомат: при заданном начальном состоянии и инструкции каждый следующий бит предопределён на 100%. Тем не менее от моделирования методом Монте-Карло в ядерной физике и процедурной генерации миров в играх до ключей TLS, SSH и подписей ECDSA современная цивилизация потребляет триллионы случайных чисел каждую секунду.
Как жёсткий алгоритм может порождать непредсказуемость? И почему статистически безупречный генератор вроде вихря Мерсенна (MT19937) оказывается катастрофически уязвимым при генерации токенов сброса пароля, позволяя атакующему по 624 последовательным выходам на 100% предсказать все будущие и прошлые значения?
Глава 1: Математическая анатомия ГПСЧ ── Зерно (Seed), конечное пространство состояний и принцип Дирихле
Формально генератор псевдослучайных чисел (ГПСЧ / PRNG) — это детерминированный автомат \((\mathcal{S}, \mathcal{O}, f, g, s_0)\) с конечным внутренним пространством состояний \(\mathcal{S}\) размера \(|\mathcal{S}| = 2^b\), начальным зерном (Seed) \(s_0 \in \mathcal{S}\), функцией перехода \(f: \mathcal{S} \to \mathcal{S}\) и функцией вывода \(g: \mathcal{S} \to \mathcal{O}\):
\[s_{i+1} = f(s_i), \qquad r_i = g(s_i) \qquad \left(|\mathcal{S}| = 2^b \implies \text{Period } P \le 2^b\right)\]Как только зерно \(s_0\) зафиксировано, вся последовательность \(r_0, r_1, r_2, \dots\) полностью предопределена. Эта воспроизводимость бесценна при отладке научных расчётов. Однако по принципу Дирихле (Pigeonhole Principle) автомат неизбежно повторит одно из предыдущих состояний \(s_{k+P} = s_k\) не более чем через \(2^b\) шагов, замкнувшись в периодический цикл периода \(P \le 2^b\).
flowchart LR
S0["Начальное зерно s0"] --> S1["Состояние s1 = f(s0)"]
S1 --> S2["Состояние s2 = f(s1)"]
S2 -. "Предпериод (Tail)" .-> Sk["Вход в цикл sk"]
Sk --> Sk1["Состояние s(k+1)"]
Sk1 -. "Периодический цикл P <= 2^b" .-> Skm1["Состояние s(k+P-1)"]
Skm1 -- "f(s(k+P-1)) = sk" --> Sk
Предложенный фон Нейманом в 1949 году метод серединных квадратов (Middle-Square Method) (возведение \(2k\)-значного числа в квадрат и извлечение средних \(2k\) цифр) без алгебраической структуры быстро вырождается в 0000 или короткие циклы длины 4.
Глава 2: Линейные конгруэнтные генераторы (LCG) и теорема Марсальи ── Трагедия 15 плоскостей IBM RANDU
В 1949 году Д. Г. Лемер предложил линейный конгруэнтный генератор (LCG): \(X_{n+1} = (a X_n + c) \bmod m\). Согласно теореме Халла — Добелла (1962), LCG достигает полного периода \(P = m\) тогда и только тогда, когда: (1) \(\gcd(c, m) = 1\), (2) каждый простой делитель \(p\) числа \(m\) делит \(a-1\), и (3) если \(4 \mid m\), то \(4 \mid (a-1)\).
В 1968 году статистик Джордж Марсалья (George Marsaglia) опубликовал знаменитую статью «Random numbers fall mainly in the planes», доказав, что \(d\)-мерные точки \((X_n, \dots, X_{n+d-1})\) любого LCG ложатся не более чем на \((d! \cdot m)^{1/d}\) параллельных гиперплоскостей кристаллической решётки!
Самым печально известным примером стал стандартный генератор RANDU корпорации IBM (\(m = 2^{31}, c = 0, a = 65539 = 2^{16} + 3\)) на мейнфреймах System/360:
Из-за тождества \(X_{n+2} \equiv 6 X_{n+1} - 9 X_n \pmod{2^{31}}\) все 3D-точки RANDU в единичном кубе оказались заперты всего на 15 параллельных плоскостях с огромными пустыми промежутками, что исказило тысячи расчётов методом Монте-Карло в 1960–70-х годах!
Глава 3: Вихрь Мерсенна (MT19937) и современные статистические ГПСЧ (PCG64, Xoshiro256++)
В 1997 году японские математики Макото Мацумото и Такудзи Нисимура создали вихрь Мерсенна (MT19937) на основе скрученного обобщённого регистра сдвига с обратной связью (TGFSR) над полем \(\mathbb{F}_2 = \{0, 1\}\) (стандарт в Python random, R, MATLAB, C++ std::mt19937):
- Гигантский период и 623-мерная равномерность: Массив состояния из \(624\) 32-битных слов (\(19\,937\) активных бит) обеспечивает период, равный простому числу Мерсенна \(P = 2^{19937} - 1 \approx 4{,}315 \times 10^{6001}\), и строгую равномерность распределения вплоть до размерности 623!
- Закалка (Tempering): Перед выводом каждое слово состояния \(x\) умножается на обратимую битовую матрицу \(32\times 32\) над \(\mathbb{F}_2\):
Чтобы преодолеть большой объём состояния MT19937 (\(2{,}5\text{ КБ}\)) и провал двух тестов на \(\mathbb{F}_2\)-линейность в пакете TestU01 (BigCrush), в 2010-х годах были созданы PCG64 (Мелисса О’Нил, 2014: 128-битный LCG с вращением битов, зависящим от данных; стандарт в NumPy) и Xoshiro256++ (Блэкман и Винья, 2018: 256-битное состояние с нелинейным скремблером; используется в Rust и Java), проходящие 100% тестов BigCrush.
Глава 4: Почему статистическое совершенство \(\neq\) криптостойкость ── Взлом MT19937 по 624 выходам и КГПСЧ
4.1 Обращение Tempering: клонирование MT19937 по 624 выходам
Использование MT19937 для генерации токенов сессий или паролей — фатальная ошибка: каждый из четырёх шагов Tempering является обратимой линейной биекцией над \(\mathbb{F}_2^{32}\) за время \(O(1)\)!
| |
Атакующий, увидевший всего 624 последовательных 32-битных выхода (\(2\,496\text{ байт}\)) сервера на MT19937, применяет untemper(z) к каждому числу и на 100% восстанавливает внутренний массив из 624 слов! С этого момента он может со 100%-ной точностью предсказывать все будущие числа и вычислять прошлые.
4.2 Теорема Эндрю Яо (1982) и криптографически стойкие генераторы (КГПСЧ / CSPRNG)
В криптографии необходим криптографически стойкий ГПСЧ (CSPRNG), удовлетворяющий трём аксиомам:
- Непредсказуемость следующего бита \(\iff\) Вычислительная неотличимость (Теорема Яо, 1982 / Блюм — Микали): Никакой полиномиальный алгоритм \(\mathcal{A}\), зная первые \(k\) бит, не может угадать бит \(r_{k+1}\) существенно лучше, чем подбрасыванием монеты (\(1/2\)):
- Прямая секретность (Forward Secrecy / Защита от ретроспективного взлома): После каждой выдачи внутренний ключ немедленно перезаписывается односторонней функцией (Fast-Key-Erasure), поэтому даже при утечке текущего состояния невозможно восстановить прошлые ключи.
- Обратная секретность (Backward Secrecy / Защита от предсказания): Периодическое подмешивание свежей аппаратной энтропии (Reseeding) восстанавливает безопасность после компрометации.
flowchart TD
subgraph Insecure ["Статистический ГПСЧ (LCG / MT19937 / Xoshiro)"]
StateM["Внутреннее состояние s_i (624 слова)"] -- "Обратимый F2-линейный Tempering" --> OutM["Выход r_i"]
OutM -- "untemper() клонирует состояние по 624 выходам!" --> StateM
end
subgraph Secure ["Криптостойкий КГПСЧ (ChaCha20 / AES-CTR_DRBG)"]
Entropy["Аппаратные источники энтропии<br/>(Тепловой шум / RDSEED)"] -- "Периодический Reseeding (Backward Secrecy)" --> StateC["256-битный секретный ключ и счётчик"]
StateC -- "Односторонний шифр (ChaCha20 / AES)<br/>[Обращение требует 2^256 операций!]" --> OutC["Криптостойкий поток r_i"]
StateC -- "Fast-Key-Erasure Key' = PRF(Key)<br/>[Forward Secrecy!]" --> StateC_Next["Обновлённый ключ Key'"]
end
Современные CSPRNG строятся на потоковых и блочных шифрах ChaCha20-RNG (ядро Linux, OpenBSD, Rust) и AES-CTR_DRBG (NIST SP 800-90A), либо на теоретико-числовой задаче факторизации в Blum-Blum-Shub (\(x_{n+1} = x_n^2 \bmod M\)). Напротив, стандартизированный NIST в 2006 году генератор на эллиптических кривых Dual_EC_DRBG содержал клептографический бэкдор АНБ (подтверждённый документами Сноудена в 2013 году: знание секретного дискретного логарифма \(d\) в \(P = d \cdot Q\) позволяло по 32 байтам выхода вычислить внутреннее состояние и расшифровать TLS-трафик).
| Класс генератора | Примеры алгоритмов | Размер состояния | Период \(P\) | Тест BigCrush | Криптостойкость | Применение |
|---|---|---|---|---|---|---|
| Классический LCG | RANDU, C rand() | 32–64 бит | \(\le 2^{64}\) | Провал (Гиперплоскости) | Взломан | Устаревший код |
| Современный стат. ГПСЧ | MT19937, PCG64, Xoshiro256++ | 128 бит – 2,5 КБ | \(2^{128} \sim 2^{19937}-1\) | Проходит | Взломан (624 выхода / Z3) | Монте-Карло, симуляции, игры |
| Криптостойкий (CSPRNG) | ChaCha20-RNG, AES-CTR_DRBG | 256–512 бит | \(\ge 2^{256}\) | 100% Проходит | Безопасен (Forward/Backward) | Ключи TLS/SSH, пароли, токены |
| Физический ГСЧ (TRNG) | Тепловой шум, лавинный пробой, генератор (RDSEED) | Физический континуум | Апериодичен (\(\infty\)) | После отбеливания | Истинная физическая энтропия | Инициализация и Reseeding CSPRNG |
Глава 5: Физические генераторы (TRNG), мин-энтропия (\(H_\infty\)) и пулы энтропии ОС
Начальное зерно CSPRNG поступает от аппаратных генераторов истинно случайных чисел (TRNG / HRNG), улавливающих физический хаос: тепловой шум Джонсона — Найквиста в проводниках, квантовый дробовой шум лавинного пробоя стабилитронов и фазовый джиттер кольцевых осцилляторов (инструкции RDSEED/RDRAND в процессорах Intel/AMD). В криптографии (NIST SP 800-90B) непредсказуемость в худшем случае оценивается через мин-энтропию (\(H_\infty\)), а не среднюю энтропию Шеннона \(H_1\):
«Сырой» физический шум проходит отбеливание (Whitening) методом фон Неймана или криптографическими хеш-экстракторами (BLAKE2s в ядре Linux согласно Leftover Hash Lemma) перед подачей в CSPRNG.
В современном Linux (5.6+) /dev/random и /dev/urandom используют один и тот же ядерный CSPRNG на базе ChaCha20; разработчикам следует всегда вызывать getrandom(2) (или Python secrets, JS crypto.getRandomValues(), Rust OsRng/ThreadRng, Go crypto/rand). Катастрофа Debian OpenSSL 2008 года (CVE-2008-0166) — когда из-за закомментированной ради Valgrind строки энтропия всех генерируемых в мире ключей RSA/SSH на два года сжалась до 15-битного идентификатора процесса PID (\(32\,768\) вариантов!) — и ошибка со статическим одноразовым числом \(k\) в ECDSA на Sony PlayStation 3 (2010) напоминают железный закон: стойкость любой криптосистемы никогда не превышает энтропию генератора случайных чисел, создавшего её ключи.
