Как правильно генерировать случайную ошибку в haskell
Я новичок в haskell и хотел бы написать функцию для генерации случайных байтовых строк.
С моей точки зрения Crypto.Random
(из crypto-api v0.3.1), кажется, лучший модуль для использования, но я не могу понять это.
Я хотел бы сделать что-то вроде следующего:
let size = 2048
let bytestring = randomByteString size
Ответы
Ответ 1
- Вы можете использовать любой экземпляр
CryptoRandomGen
, поскольку Ganesh показывает
- Вы можете использовать
System.Random
для незащищенных случайных значений (см. ответ jamshidh)
- Вы можете просто получить энтропию, предоставляемую платформой, лежащей в основе генератора (это то, что
SystemRandom
делает под обложками).
Вариант 3. Получение энтропии с вашей платформы
Последний метод является самым легким, но имеет более высокие накладные расходы на системах без инструкции RDRAND - он должен открыть файл, прочитать и закрыть файл. Это использует пакет entropy
:
import System.Entropy
someFunc = do
randBytes <- getEntropy 2048
....
Вариант 1: Использование экземпляра CryptoRandomGen
Если вы хотите получить чистый генератор, но засеяли семенами с высокой энтропией, вы можете использовать любые из CryptoRandomGen
экземпляров из DRBG
пакет:
import Crypto.Random.DRBG
Затем просто пример Ganesh (воспроизведенный здесь) с другой подписью на newGenIO
:
do
g <- newGenIO :: IO CtrDRBG
case genBytes size g of
Left err -> error $ show err
Right (result, g2) -> return result
Для любопытных я просмотрел несколько доступных безопасных RNG в моем блоге - большинство из них не соответствуют ни одному стандарту ( которые не являются хорошими, они, по-видимому, полностью исключены из изобретения манжеты программиста), за исключением RDRAND
, HashDRBG
и HmacDRBG
.
Ответ 2
Вам нужно сделать это в монаде IO
, чтобы инициализировать энтропию для генератора. Что-то вроде этого фрагмента сделает для простого примера, хотя в более сложном коде вам, вероятно, следует держать генератор g2
и повторно использовать его позже.
do
g <- newGenIO :: IO SystemRandom
case genBytes size of
Left err -> error $ show err
Right (result, g2) -> return result
Ответ 3
Здесь много, поэтому я опишу, как все это работает ниже. Но на данный момент вот код
import Data.ByteString
import Data.Word8
import System.Random
randomBytes::Int->StdGen->[Word8]
randomBytes 0 _ = []
randomBytes count g = fromIntegral value:randomBytes (count - 1) nextG
where (value, nextG) = next g
randomByteString::Int->StdGen->ByteString
randomByteString count g = pack $ randomBytes count g
main = do
g <- getStdGen
let bytestring = randomByteString 2048 g
print bytestring
Прежде всего, обратите внимание, что вам нужно предоставить случайный генератор. Все компьютерные программы, которые генерируют псевдослучайные числа, нуждаются в генераторе случайных чисел, но большинство скрывают это за кулисами, используя побочные эффекты. Поскольку в Haskell нет побочных эффектов, вам нужно управлять самим собой (есть монодальная генератор случайных чисел, которая может сделать это для вас, если вы хотите вернуться и скрыть некоторые детали, но поскольку это упражнение, Я оставлю это явным).
Все случайные генераторы должны быть засеяны.... Вы можете создать случайный генератор, предоставив свое собственное семя, но это считается небезопасным, потому что любой может переделать ваш код и увидеть семя. Помните, что псевдослучайные генераторы на самом деле не являются случайными, но представляют собой четко определенные воспроизводимые серии, которые следуют из математической формулы и заданного семени. (числа являются только случайными в том смысле, что ничего статистического не может быть предсказано о результирующих значениях, не запустив сам алгоритм).
В большинстве ОС есть какой-то вызов API, который будет генерировать что-то непредсказуемое во время компиляции (т.е. более реальное случайное число), но они выполняются медленно, поэтому обычной стратегией является выполнение этого один раз, чтобы засеять случайный генератор. Выполнение getStdGen
сделает это за вас, но поскольку ему необходимо установить связь с ОС, его тип - IO a. Я сделал это в основном, это уже тип IO().
Функция next
возвращает две вещи: случайный Int и следующий случайный генератор (если вы запускаете следующий на том же случайном генераторе, вы получаете тот же результат... Попробуйте). Вам нужно добавить это значение в результирующий список и снова включить следующий генератор в функцию, чтобы получить следующее значение в списке.
Обратите внимание, что ByteString представляет список значений Word8, а затем возвращает Int, поэтому нам нужно преобразовать из Int в Word8 с помощью fromIntegral
. Затем он преобразуется в байтовую строку, используя пакет.