Объясните чем отличаются случайные числа от псевдослучайных почему в компьютере
Что общего у любителей проходить видеоигры на скорость, азартных игроков и криптографов? Они зависят от случайных чисел. От перетасовки музыки до шифрования интернета, случайные числа — важнейшая часть современной жизни. И мы, как правило, полагаемся на компьютеры, которые генерируют их.
Это заставляет задуматься: как именно компьютеры это делают? Скорее всего, вы когда-либо использовали генератор случайных чисел. Языки программирования очень упрощают это действие. Например, в Ruby достаточно вызвать rand .
На первый взгляд, создание случайных чисел может показаться простым. В конце концов, числа на компьютере — это набор единиц и нулей. Компьютеру просто нужно случайным образом выбрать 1 или 0 и повторить это столько раз, сколько необходимо.
Человеку не составит труда сделать это:
Примечание: ведутся споры о том, может ли человек демонстрировать по-настоящему случайное поведение. Но это выходит за рамки данной статьи.
Тем не менее, все еще остается вопрос: как компьютер случайно выбирает между нулем и единицей? Ответ оказывается довольно сложным. Он коренится в таких темах, как рекурсивные алгоритмы, компьютерное оборудование и немного — теория хаоса.
Если это звучит для вас интересно, тогда погрузимся глубже.
Как используют случайные числа
Случайные числа использовались в течение многих тысяч лет. Независимо от того, подкидывали ли монету или бросали кости, цель заключалась в том, чтобы получить случайный результат. Генераторы случайных чисел на компьютерах похожи – они пытаются достичь непредсказуемого случайного результата.
Генераторы случайных чисел полезны для разных целей. Помимо очевидных приложений, таких как генерация случайных чисел для азартных игр или создания непредсказуемых результатов в компьютерной игре, случайность важна для криптографии.
NSA и аппаратный генератор случайных чисел Intel
Чтобы упростить работу разработчиков и помочь генерировать безопасные случайные числа, чипы Intel включают аппаратный генератор случайных чисел, известный как RdRand. Этот чип использует источник энтропии на процессоре и предоставляет случайные числа для программного обеспечения, когда программное обеспечение запрашивает их.
Проблема здесь в том, что генератор случайных чисел – это, по сути, «черный ящик», и мы не знаем, что происходит внутри него. Если RdRand содержит бэкдор NSA, правительство сможет получить ключи шифрования, которые были сгенерированы с данными, предоставленными этим генератором случайных чисел.
Как компьютеры генерируют случайные числа?
Простой ответ на этот вопрос заключается в том, что они не могут. По крайней мере, не сами по себе.
Люди создали компьютеры, чтобы они были тем, чем не являемся мы, — полностью логическими машинами. Случайность не в их природе. В конце концов, вы же не хотите, чтобы сервер спонтанно решил не следовать логике приложения.
По своей сути компьютеры — простые машины, которые принимают данные и выдают их обратно. Чтобы компьютеры могли генерировать случайные числа, им нужен внешний источник случайности. И этот источник будет варьироваться в зависимости от того, каким генератором случайных чисел вы решите воспользоваться.
Вероятно, последнее предложение вызвало несколько растерянных взглядов. Что подразумевается под “своего рода генератором случайных чисел”? Разве они не все одинаковы?
Не совсем. Существует два основных типа генераторов случайных чисел.
Примечание: далее названия генераторов случайных чисел будут использоваться в сокращении.
Seed: основа псевдослучайных алгоритмов
Первые алгоритмы формирования случайных чисел выполняли ряд основных арифметических действий: умножить, разделить, добавить, вычесть, взять средние числа и т.д. Сегодня такие мощные алгоритмы, как Fortuna и Yarrow (используется в FreeBSD, AIX, Mac OS X, NetBSD) выглядят как генераторы случайных чисел для параноиков. Fortuna, например, это криптографический генератор, в котором для защиты от дискредитации после выполнения каждого запроса на случайные данные в размере 220 байт генерируются еще 256 бит псевдослучайных данных и используются в качестве нового ключа шифрования — старый ключ при этом каждый раз уничтожается.
Прошли годы, прежде чем простейшие алгоритмы эволюционировали до криптографически стойких генераторов псевдослучайных чисел. Частично этот процесс можно проследить на примере работы одной математической функции в языке С.
Функция rand () является простейшей из функций генерации случайных чисел в C.
В этом примере рандома используется вложенный цикл для отображения 100 случайных значений. Функция rand () хороша при создании множества случайных значений, но они являются предсказуемыми. Чтобы сделать вывод менее предсказуемым, вам нужно добавить seed в генератор случайных чисел — это делается с помощью функции srand ().
Seed — это стартовое число, точка, с которой начинается последовательность псевдослучайных чисел. Генератор псевдослучайных чисел использует единственное начальное значение, откуда и следует его псевдослучайность. Генератор истинных случайных чисел всегда имеет в начале высококачественную случайную величину, предоставленную различными источниками энтропии.
srand() принимает число и ставит его в качестве отправной точки. Если seed не выставить, то при каждом запуске программы мы будем получать одинаковые случайные числа.
Вот пример простой формулы случайного числа из «классики» — книги «Язык программирования C» Кернигана и Ричи, первое издание которой вышло аж в 1978 году:
Эта формула предполагает существование переменной, называемой random_seed, изначально заданной некоторым числом. Переменная random_seed умножается на 1 103 535 245, а затем 12 345 добавляется к результату; random_seed затем заменяется этим новым значением. Это на самом деле довольно хороший генератор псевдослучайных чисел. Если вы используете его для создания случайных чисел от 0 до 9, то первые 20 значений, которые он вернет при seed = 10, будут такими:
Если у вас есть 10 000 значений от 0 до 9, то распределение будет следующим:
0 — 10151 — 10242 — 10483 — 9964 — 9885 — 10016 — 9967 — 10068 — 9659 — 961
Любая формула псевдослучайных чисел зависит от начального значения. Если вы предоставите функции rand() seed 10 на одном компьютере, и посмотрите на поток чисел, которые она производит, то результат будет идентичен «случайной последовательности», созданной на любом другом компьютере с seed 10.
К сожалению, у генератора случайных чисел есть и другая слабость: вы всегда можете предсказать, что будет дальше, основываясь на том, что было раньше. Чтобы получить следующее число в последовательности, мы должны всегда помнить последнее внутреннее состояние генератора — так называемый state. Без state мы будем снова делать одну и ту же математическую операцию с одинаковыми числами, чтобы получить тот же ответ.
Как сделать seed уникальным для каждого случая? Самое очевидное решение — добавить в вычисления текущее системное время. Сделать это можно с помощью функции time().
Функция time() возвращает информацию о текущем времени суток, значение, которое постоянно изменяется. При этом метод typecasting гарантирует, что значение, возвращаемое функцией time(), является целым числом.
Итак, в результате добавления «случайного» системного времени функция rand() генерирует значения, которые являются более случайными, чем мы получили в первом примере.
Однако в этом случае seed можно угадать, зная системное время или время запуска приложения. Как правило, для приложений, где случайные числа являются абсолютно критичными, лучше всего найти альтернативное решение.
- ID текущего процесса;
- текущий ID потока;
- количество отсчетов с момента загрузки;
- текущее время;
- различные высокоточные счетчики производительности процессора;
- MD4-хэш среды пользователя (имя пользователя, имя компьютера и т.д.).
Но опять же, все эти числа не случайны.
Лучшее, что вы можете сделать с детерминированными генераторами псевдослучайных чисел — добавить энтропию физических явлений.
Генератор истинно случайных чисел (ГИСЧ)
Как вы можете догадаться, истинно случайные числа непредсказуемы и не следуют шаблону.
Но как компьютер может достичь этого? Как было указано ранее, компьютерам требуется внешний источник случайности. В случае ГПСЧ, это было семя. В случае ГИСЧ, это энтропия .
Теория хаоса и термодинамика выходят далеко за рамки данной статьи. Достаточно сказать, что энтропия — это чистый нефильтрованный хаос. И лучший источник этого хаоса — сам компьютер.
Компьютер не может функционировать случайным образом, но составляющие его части — могут. Компьютер — это сложная система со множеством движущихся частей и изменчивостью. Тепловой шум , фотоэффект и другие квантовые явления происходят постоянно.
Компьютерное оборудование — не единственный источник энтропии. Также можно использовать движения мыши и клавиатуры пользователя.
Но хаос был бы бесполезен, если бы его нельзя было обуздать. К счастью, инженеры-аппаратчики придумали, как это сделать. Посредством сложной схемы аппаратных микросхем и компонентов , компьютеры могут преобразовывать этот физический шум в цифровые нули и единицы.
Один из наиболее очевидных вариантов применения ГИСЧ — цифровые азартные игры. Бросание костей, перетасовка карт и вращение колеса рулетки — все это зависит от того, чтобы быть неопределимым. Хотя он часто используется при опросах общественного мнения, призыве на военную службу и отборе присяжных, а также там, где случайность используется как метод справедливости.
В действительности сферы применения ГИСЧ довольно ограничены, поскольку у них есть свой набор недостатков. Во-первых, они медлительны. Хотя это варьируется, ГИСЧ может выдавать только небольшое количество бит в секунду.
Кроме того, ГИСЧ не всегда надежны. Компьютерам требуется достаточное количество энтропии для производства истинно случайных чисел. Но суть случайности в том, что она возникает случайным образом. Простаивающий или новый сервер не сможет генерировать числа настолько же качественно, как активный.
Эта ненадежность создает угрозу безопасности при использовании ГИСЧ для создания криптографических ключей. В 2012 году в исследовательской работе под названием Ron was Wrong, Whit is Right обнаружилось, что тысячи SSL-ключей небезопасны. Хотя основная причина неизвестна, обычно считается, что это результат ошибочной генерации случайных чисел.
Завершающие мысли
Многие разработчики программного обеспечения не понимают сложности, связанной с генерацией случайных чисел. Это свидетельствует в пользу архитекторов, которые создали существующую систему. От инженеров-аппаратчиков, которые разрабатывали чипы для преобразования шума в данные, до разработчиков ядра и языков программирования, которые преобразовали эти данные в простые для использования API.
Возможно, в следующий раз, когда вы будете играть в видеоигру, слушать музыку в случайном порядке или просто генерировать произвольное число у себя в коде, вы лучше станете понимать волшебство, которое происходит под капотом.
Случайности преследуют нас всю жизнь и никогда не задумываешься, есть ли у нее какая-то формула или нет. Если обратиться к научной литературе, то можно прочитать такое вот определение случайности:
Настоящие случайные числа возможно генерировать измеряя случайные величины, которые называются шумом. В результате измерения шума в выборке и перевода его в числа, получается случайная числовая последовательность , которая никогда не повторится.
К примеру, если измерить статическое электричество от экрана телевизора, можно получить настоящую случайную последовательность.
Эту случайную последовательность легко визуализировать, построив путь, направление которого изменяется в зависимости от каждого числа.
Т.к. это - настоящая случайность, здесь мы не увидим ни одного повторяющегося шаблона.
Вычислительная техника, машины - детерминированы , т.к. операции, которыми они оперирую предсказуемы и повторяемы.
Тем не менее, на компьютерах также получают случайные числа , но они - менее случайны, или, скажем так, случайны, но не до конца - псевдослучайны .
В компьютере, псевдослучайные последовательности генерируются с помощью специальных алгоритмов и требуют для работы изначального числа.
Если попытаться визуализировать случайные и псевдослучайные последовательности чисел, то получится такая картина:
Отлично видно, что рано или поздно псевдослучайная последовательность начинает повторяться . Это происходит потому как алгоритм доходит до начального числа, которое использовалось для генерации последовательности и круг замыкается.
Начальное число последовательности или " Зерно " в компьютере берется из текущего времени или счетчика тактов процессора, или из иных мест, где можно получить хоть какую-то величину "случайно", а затем алгоритм генерирует последовательность. И чем больше зерно, тем больше чисел до начала повторения.
На данный момент, генерировать действительно случайные числа на компьютере довольно затруднительно. Даже измеряя какие-то физические величины, такие как шум звуковой карт, такты процесса, размер свободной памяти жесткого диска и другие, мы сильно теряем в производительности, потому, на выручку приходят псевдослучайные числа, которые генерируются куда быстрее.
Надеюсь, Вам было хоть немного интересно и познавательно! Подписывайтесь на мой канал и не забывайте поставить лайк!
(с)
Случайные числа постоянно генерируются каждой машиной, которая может обмениваться данными. И даже если она не обменивается данными, каждый компьютер нуждается в случайности для распределения программ в памяти. При этом, конечно, компьютер, как детерминированная система, не может создавать истинные случайные числа.
Когда речь заходит о генераторах случайных (или псевдослучайных) чисел, рассказ всегда строится вокруг поиска истинной случайности. Пока серьезные математики десятилетиями ведут дискуссии о том, что считать случайностью, в практическом отношении мы давно научились использовать «правильную» энтропию. Впрочем, «шум» — это лишь вершина айсберга.
С чего начать, если мы хотим распутать клубок самых сильных алгоритмов PRNG и TRNG? На самом деле, с какими бы алгоритмами вы не имели дело, все сводится к трем китам: seed, таблица предопределенных констант и математические формулы.
Каким бы ни был seed, еще есть алгоритмы, участвующие в генераторах истинных случайных чисел, и такие алгоритмы никогда не бывают случайными.
Как компьютеры генерируют случайные числа?
Простой ответ на этот вопрос заключается в том, что они не могут. По крайней мере, не сами по себе.
Люди создали компьютеры, чтобы они были тем, чем не являемся мы, — полностью логическими машинами. Случайность не в их природе. В конце концов, вы же не хотите, чтобы сервер спонтанно решил не следовать логике приложения.
По своей сути компьютеры — простые машины, которые принимают данные и выдают их обратно. Чтобы компьютеры могли генерировать случайные числа, им нужен внешний источник случайности. И этот источник будет варьироваться в зависимости от того, каким генератором случайных чисел вы решите воспользоваться.
Вероятно, последнее предложение вызвало несколько растерянных взглядов. Что подразумевается под “своего рода генератором случайных чисел”? Разве они не все одинаковы?
Не совсем. Существует два основных типа генераторов случайных чисел.
Примечание: далее названия генераторов случайных чисел будут использоваться в сокращении.
Истинная случайность бит
Итак, получив seed с примесью данных от реальных физических явлений (либо максимально усложнив жизнь будущему взломщику самым большим набором потоков программного мусора, который только сможем придумать), установив state для защиты от ошибки повтора значений и добавив криптографических алгоритмов (или сложных математических задач), мы получим некоторый набор данных, который будем считать случайной последовательностью. Что дальше?
Дальше мы возвращаемся к самому началу, к одному из фундаментальных требований — тестам.
Национальный институт стандартов и технологий США вложил в «Пакет статистических тестов для случайных и псевдослучайных генераторов чисел для криптографических приложений» 15 базовых проверок. Ими можно и ограничиться, но этот пакет вовсе не является «вершиной» проверки случайности.
Одни из самых строгих статистических тестов предложил профессор Джордж Марсалья из Университета штата Флорида. «Тесты diehard» включают 17 различных проверок, некоторые из них требуют очень длинных последовательностей: минимум 268 мегабайт.
Случайность можно проверить с помощью библиотеки TestU01, представленной Пьером Л’Экуйе и Ричардом Симардом из Монреальского университета, включающей классические тесты и некоторые оригинальные, а также посредством общедоступной библиотеки SPRNG.
На Хабре и в сети часто начали появляться статьи, посвященные уязвимостям генераторов случайных чисел. Данная тема крайне обширна и является одной из основных в криптографии. Под катом находится описание случайных чисел от A до Z. Статья является результатом свободного перевода цикла статей из одного западного блога и личных дополнений автора. Основная цель — получить feedback и поделиться знаниями.
Введение
- Генераторы сессий (PHPSESSID)
- Генерация текста для капчи
- Шифрование
- Генерация соли для хранения паролей в необратимом виде
- Генератор паролей
- Порядок раздачи карт в интернет казино
Как отличить случайную последовательность чисел от неслучайной?
Пусть есть последовательность чисел: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 . Является ли она случайной? Есть строгое определение для случайной величины. Случайная величина — это величина, которая принимает в результате опыта одно из множества значений, причём появление того или иного значения этой величины до её измерения нельзя точно предсказать. Но оно не помогает ответить на наш вопрос, так как нам не хватает информации для ответа. Теперь скажем, что данные числа получились набором одной из верхних строк клавиатуры. «Конечно не случайная» — воскликните Вы и тут же назовете следующие число и будете абсолютно правы. Последовательность будет случайной только если между символами, нету зависимости. Например, если бы данные символы появились в результате вытягивания бочонков в лото, то последовательность была бы случайной.
Чуть более сложный пример или число Пи
Последовательность цифры в числе Пи считается случайной. Пусть генератор основывается на выводе бит представления числа Пи, начиная с какой-то неизвестной точки. Такой генератор, возможно и пройдет «тест на следующий бит», так как ПИ, видимо, является случайной последовательностью. Однако этот подход не является критографически надежным — если криптоаналитик определит, какой бит числа Пи используется в данный момент, он сможет вычислить и все предшествующие и последующие биты.
Данный пример накладывает ещё одно ограничение на генераторы случайных чисел. Криптоаналитик не должен иметь возможности предсказать работу генератора случайных чисел.
Отличие генератора псевдослучайных чисел (ГПСЧ) от генератора случайных чисел (ГСЧ)
Источники энтропии используются для накопления энтропии с последующим получением из неё начального значения (initial value, seed), необходимого генераторам случайных чисел (ГСЧ) для формирования случайных чисел. ГПСЧ использует единственное начальное значение, откуда и следует его псевдослучайность, а ГСЧ всегда формирует случайное число, имея в начале высококачественную случайную величину, предоставленную различными источниками энтропии.
Энтропия – это мера беспорядка. Информационная энтропия — мера неопределённости или непредсказуемости информации.
Можно сказать, что ГСЧ = ГПСЧ + источник энтропии.
Уязвимости ГПСЧ
- Предсказуемая зависимость между числами.
- Предсказуемое начальное значение генератора.
- Малая длина периода генерируемой последовательности случайных чисел, после которой генератор зацикливается.
Линейный конгруэнтный ГПСЧ (LCPRNG)
Распространённый метод для генерации псевдослучайных чисел, не обладающий криптографической стойкостью. Линейный конгруэнтный метод заключается в вычислении членов линейной рекуррентной последовательности по модулю некоторого натурального числа m, задаваемой следующей формулой:
где a (multiplier), c (addend), m (mask) — некоторые целочисленные коэффициенты. Получаемая последовательность зависит от выбора стартового числа (seed) X0 и при разных его значениях получаются различные последовательности случайных чисел.
Для выбора коэффициентов имеются свойства позволяющие максимизировать длину периода(максимальная длина равна m), то есть момент, с которого генератор зациклится [1].
Пусть генератор выдал несколько случайных чисел X0, X1, X2, X3. Получается система уравнений
Решив эту систему, можно определить коэффициенты a, c, m. Как утверждает википедия [8], эта система имеет решение, но решить самостоятельно или найти решение не получилось. Буду очень признателен за любую помощь в этом направлении.
Предсказание результатов линейно-конгруэнтного метода
Основным алгоритмом предсказания чисел для линейно-конгруэнтного метода является Plumstead’s — алгоритм, реализацию, которого можно найти здесь [4](есть онлайн запуск) и здесь [5]. Описание алгоритма можно найти в [9].
Простая реализация конгруэнтного метода на Java.
Отправив 20 чисел на сайт [4], можно с большой вероятностью получить следующие. Чем больше чисел, тем больше вероятность.
Взлом встроенного генератора случайных чисел в Java
Многие языки программирования, например C(rand), C++(rand) и Java используют LСPRNG. Рассмотрим, как можно провести взлом на примере java.utils.Random. Зайдя в исходный код (jdk1.7) данного класса можно увидеть используемые константы
Метод java.utils.Randon.nextInt() выглядит следующим образом (здесь bits == 32)
Пусть мы знаем два подряд сгенерированных числа x1 и x2. Тогда необходимо перебрать 2^16 = 65536 вариантов oldseed и применять к x1 формулу:
до тех пор, пока она не станет равной x2. Код для brute-force может выглядеть так
Несложно понять, что мы нашли не самый первый seed, а seed, используемый при генерации второго числа. Для нахождения первоначального seed необходимо провести несколько операций, которые Java использовала для преобразования seed, в обратном порядке.
И теперь в исходном коде заменим
crackingSeed.set(seed);
на
crackingSeed.set(getPreviousSeed(seed));
И всё, мы успешно взломали ГПСЧ в Java.
Взлом ГПСЧ Mersenne twister в PHP
Рассмотрим ещё один не криптостойкий алгоритм генерации псевдослучайных чисел Mersenne Twister. Основные преимущества алгоритма — это скорость генерации и огромный период 2^19937 − 1, На этот раз будем анализировать реализацию алгоритма mt_srand() и mt_rand() в исходном коде php версии 5.4.6.
Можно заметить, что php_mt_reload вызывается при инициализации и после вызова php_mt_rand 624 раза. Начнем взлом с конца, обратим трансформации в конце функции php_mt_rand(). Рассмотрим (s1 ^ (s1 >> 18)). В бинарном представление операция выглядит так:
10110111010111100111111001110010 s1
00000000000000000010110111010111100111111001110010 s1 >> 18
10110111010111100101001110100101 s1 ^ (s1 >> 18)
Видно, что первые 18 бит (выделены жирным) остались без изменений.
Напишем две функции для инвертирования битового сдвига и xor
Тогда код для инвертирования последних строк функции php_mt_rand() будет выглядеть так
Если у нас есть 624 последовательных числа сгенерированных Mersenne Twister, то применив этот алгоритм для этих последовательных чисел, мы получим полное состояние Mersenne Twister, и сможем легко определить каждое последующее значение, запустив php_mt_reload для известного набора значений.
Область для взлома
Если вы думаете, что уже нечего ломать, то Вы глубоко заблуждаетесь. Одним из интересных направлений является генератор случайных чисел Adobe Flash(Action Script 3.0). Его особенностью является закрытость исходного кода и отсутствие задания seed'а. Основной интерес к нему, это использование во многих онлайн-казино и онлайн-покере.
Есть много последовательностей чисел, начиная от курса доллара и заканчивая количеством времени проведенным в пробке каждый день. И найти закономерность в таких данных очень не простая задача.
Задание распределения для генератора псевдослучайных чисел
Для любой случайной величины можно задать распределение. Перенося на пример с картами, можно сделать так, чтобы тузы выпадали чаще, чем девятки. Далее представлены несколько примеров для треугольного распределения и экспоненциального распределения.
Треугольное распределение
Приведем пример генерации случайной величины с треугольным распределением [7] на языке C99.
В данном случае мы берем случайную величину rand() и задаем ей распределение, исходя из функции треугольного распределения. Для параметров a = -40, b = 100, c = 50 график 10000000 измерений будет выглядеть так
Экспоненциальное распределение
Пусть требуется получить датчик экспоненциально распределенных случайных величин. В этом случае F(x) = 1 – exp(-lambda * x). Тогда из решения уравнения y = 1 – exp(-lambda * x) получаем x = -log(1-y)/lambda.
Можно заметить, что выражение под знаком логарифма в последней формуле имеет равномерное распределение на отрезке [0,1), что позволяет получать другую, но так же распределённую последовательность по формуле: x = -log(y)/lambda, где y есть случайная величина(rand()).
Тесты ГПСЧ
Некоторые разработчики считают, что если они скроют используемый ими метод генерации или придумают свой, то этого достаточно для защиты. Это очень распространённое заблуждение. Следует помнить, что есть специальные методы и приемы для поиска зависимостей в последовательности чисел.
Одним из известных тестов является тест на следующий бит — тест, служащий для проверки генераторов псевдослучайных чисел на криптостойкость. Тест гласит, что не должно существовать полиномиального алгоритма, который, зная первые k битов случайной последовательности, сможет предсказать k+1 бит с вероятностью большей ½.
В теории криптографии отдельной проблемой является определение того, насколько последовательность чисел или бит, сгенерированных генератором, является случайной. Как правило, для этой цели используются различные статистические тесты, такие как DIEHARD или NIST. Эндрю Яо в 1982 году доказал, что генератор, прошедший «тест на следующий бит», пройдет и любые другие статистические тесты на случайность, выполнимые за полиномиальное время.
В интернете [10] можно пройти тесты DIEHARD и множество других, чтобы определить критостойкость алгоритма.
Компьютеры могут генерировать поистине случайные числа, наблюдая за некоторыми внешними данными, такими как движения мыши или шум вентилятора, который не предсказуем и создают данные из него. Это называется энтропией. В других случаях они генерируют «псевдослучайные» числа, используя алгоритм, поэтому результаты кажутся случайными, хотя таковыми не являются.
Эта тема становится всё более спорной в последнее время, и вызывает сомнение у большого количества людей. Чтобы понять, почему это может быть ненадежным, вам нужно понять, как используются случайные числа и для чего они нужны.
Период (цикл) генератора
Одними из наиболее часто используемых методов генерации псевдослучайных чисел являются различные модификации линейного конгруэнтного метода, схема которого была предложена Дерриком Лемером еще в 1949 году:
Xn+1 = (aXn + c) mod m, где m — модуль, a — множитель, c — приращение, mod — операция взятия остатка от деления. Причем m > 0, 0 < a ≤ m, 0 < c ≤ m, также задается начальное значение X0: 0 < X0 ≤ m.
Линейный конгруэнтный метод дает нам повторяющиеся последовательности — конгруэнтная последовательность всегда образует «петли». Этот цикл (период), повторяющийся бесконечное число раз — свойство всех последовательностей вида Xn+1 = f(n).
В языке С линейно-конгруэнтный метод реализован в уже знакомой вам функции rand():
Что вообще такое цикл с точки зрения случайных чисел? Период — это количество чисел, которое генерируется до того, как они вернутся в той же последовательности. Для примера число периодов в шифре А5 в среднем составляет 2 23 , а сложность атаки 240, что позволяет взломать его на любом персональном компьютере.
Рассмотрим случай, когда seed равен 1, а период — 100 (на языке Haskell):
В результате мы получим следующий ответ:
Это лишь пример и подобную структуру в реальной жизни не используют. В Haskell, если вы хотите построить случайную последовательность, можно воспользоваться следующим кодом:
Выбор случайного Int дает вам обратно Int и новый StdGen, который вы можете использовать для получения более псевдослучайных чисел. Многие языки программирования, включая Haskell, имеют генераторы случайных чисел, которые автоматически запоминают свое состояние (в Haskell это randomIO).
Чем больше величина периода, тем выше надежность создания хороших случайных значений, однако даже с миллиардами циклов крайне важно использовать надежный seed. Реальные генераторы случайных чисел обычно используют атмосферный шум (поставьте сюда любое физическое явление — от движения мыши пользователя до радиоактивного распада), но мы можем и схитрить программным методом, добавив в seed асинхронные потоки различного мусора, будь то длины интервалов между последними heartbeat потоками или временем ожидания mutual exclusion (а лучше добавить все вместе).
Псевдослучайные числа
Псевдослучайные числа являются альтернативой «истинным» случайным числам. Компьютер может использовать начальное значение и алгоритм для генерации чисел, которые кажутся случайными, но которые, на самом деле, предсказуемы. Компьютер не собирает никаких случайных данных из среды.
Это не обязательно плохо. Например, если вы играете в видеоигру, не имеет значения, связаны ли события, происходящие в этой игре, с «истинными» случайными числами или псевдослучайными числами. С другой стороны, если вы используете шифрование, вряд ли Вам захочется использовать псевдослучайные числа, которые может угадать злоумышленник.
Например, злоумышленник знает алгоритм и начальное значение, которое использует генератор псевдослучайных чисел. Предположим, что алгоритм шифрования получает псевдослучайное число из этого алгоритма и использует его для генерации ключа шифрования без добавления дополнительной случайности. Если злоумышленник знает достаточно, он сможет «повернуть процесс вспять» и определять псевдослучайное число, вмешавшись в шифрование.
Криптографически стойкий генератор псевдослучайных чисел (КСГПЧ)
Из-за недостатков ГИСЧ и ГПСЧ криптографы разработали гибридный подход, называемый криптографически защищенной генерацией псевдослучайных чисел . Этот метод направлен на обеспечение скорости ГПСЧ с гарантией безопасности ГИСЧ.
КСГПЧ прост в теории. В нем применяется высококачественный источник энтропии для получения начального значения, которое дальше вводится в алгоритм, а тот затем выдает безопасные случайные числа.
Проще говоря, он задействует ГИСЧ при создании начального значения для ГПСЧ. Если все сделано правильно, КСГПЧ гарантирует, что начальное значение действительно случайное, и ГПСЧ не может быть скомпрометирован или изменен.
Пример этому — /dev/random в системах Unix и Linux.
Несмотря на преимущества КСГПЧ, здесь, как и везде в технологической отрасли, нельзя гарантировать полную безопасность.
Истинные случайные числа
Возможно, вам интересно, как компьютер может генерировать случайное число. Откуда возникает эта «случайность». Если это всего лишь фрагмент компьютерного кода, возможно ли, что числа, которые генерирует компьютер, могут быть непредсказуемыми?
Обычно мы группируем случайные числа, создаваемые компьютером, в два типа, в зависимости от того, как они генерируются: «истинные» случайные числа и псевдослучайные числа.
Для генерации «истинного» случайного числа компьютер измеряет некоторый тип физического явления, которое происходит за пределами компьютера. Например, компьютер может измерять радиоактивный распад атома. Согласно квантовой теории, нет никакого способа точно знать, когда произойдет радиоактивный распад, так что это «чистая случайность». Злоумышленник не сможет предсказать, когда произойдет радиоактивный распад, поэтому они не будут знать случайное значение.
В бытовом случае компьютер может опираться на атмосферный шум или просто использовать точное время нажатия клавиш на клавиатуре в качестве источника непредсказуемых данных или энтропии. Например, ваш компьютер может заметить, что вы нажали клавишу ровно в 0,23423523 секунды после 2 часов дня. Это достаточный источник энтропии, который можно использовать для создания «истинного» случайного числа. Вы не предсказуемая машина, поэтому злоумышленник не сможет угадать точный момент, когда вы нажимаете эти клавиши.
Что такое случайность
Первое подходящее определение случайной последовательности дал в 1966 году шведский статистик Пер Мартин-Лёф, ученик одного из крупнейших математиков XX века Андрея Колмогорова. Ранее исследователи пытались определить случайную последовательность как последовательность, которая проходила все тесты на случайность.
Основная идея Мартина-Лёфа заключалась в том, чтобы использовать теорию вычислимости для формального определения понятия теста случайности. Это контрастирует с идеей случайности в вероятности; в этой теории ни один конкретный элемент пространства выборки не может быть назван случайным.
«Случайная последовательность» в представлениях Мартина-Лёфа должна быть типичной, т.е. не должна обладать индивидуальными отличительными особенностями.
Было показано, что случайность Мартина-Лёфа допускает много эквивалентных характеристик, каждая из которых удовлетворяет нашему интуитивному представлению о свойствах, которые должны иметь случайные последовательности:
- несжимаемость;
- прохождение статистических тестов для случайности;
- сложность создания прогнозов.
Существование множественных определений рандомизации Мартина-Лёфа и устойчивость этих определений при разных моделях вычислений свидетельствуют о том, что случайность Мартина-Лёфа является фундаментальным свойством математики.
Генератор псевдослучайных чисел (ГПСЧ)
Наиболее распространенный тип — генератор псевдослучайных чисел . Он называется псевдослучайным, потому что не создает “по-настоящему” случайных чисел.
“ГПСЧ — это алгоритмы, которые могут автоматически создавать длинные ряды чисел с хорошими случайными свойствами, но в конечном итоге последовательность повторяется”.
Несмотря на то, что ГПСЧ следуют определенной схеме, эта схема не прослеживается людьми. Поэтому они “достаточно хороши” для большинства случаев, к примеру для видеоигр.
Генераторам псевдослучайных чисел для работы необходимы две составляющие:
- алгоритм генерации случайных чисел;
- семя.
Первоначально в качестве алгоритмов ГПСЧ применялись линейные конгруэнтные генераторы . Это рекурсивные алгоритмы, которые генерируют следующую величину на основе предыдущей. Вот почему этим алгоритмам требуется “семя” (seed) или начальное значение. О семени можно думать как о фрагменте случайности.
Однако со временем на смену линейным конгруэнтным генераторам пришел вихрь Мерсенна , и он по сей день остается самым популярным алгоритмом ГПСЧ.
Хотя псевдослучайные числа на самом деле не случайные, есть множество причин ими пользоваться. Во-первых, они быстры и дешевы в создании. Кроме того, поскольку ГПСЧ — всего лишь алгоритмы, их можно протестировать и убедиться, что они всегда будут работать правильно.
Вот почему в большинстве, если не во всех, языках программирования случайные числа по умолчанию генерируются именно через ГПСЧ.
Но у генерации псевдослучайных чисел есть и свои недостатки. ГСПЧ работают, потому что случайны для неподготовленного глаза. Однако, если бы вы знали начальное значение для определенной последовательности ГПСЧ, то могли бы предсказать, какие числа будут следующими.
Этой уязвимостью часто пользуются любители ускоренного прохождения видеоигр — они называют это манипулированием ГСЧ. Они заставляют игру работать предсказуемо, чтобы пройти ее как можно быстрее. К счастью, если семя видеоигры будет скомпрометировано, ничего особенного не случится. В этом нет ни вреда, ни зла.
Но бывают случаи, когда предсказание случайных чисел имеет гораздо большее значение. Например, создание ключей безопасности.
Если злоумышленник выяснит исходное значение, используемое для создания ключей RSA в сертификатах TLS, он потенциально может расшифровать сетевой трафик. Это означает, что он сможет получать пароли и другую личную информацию, передаваемую через интернет.
В таких ситуациях нужен более безопасный способ получения случайных чисел.
Читайте также: