Как правильно генерировать случайную ошибку в 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. Затем он преобразуется в байтовую строку, используя пакет.