Как кратко, портативно и тщательно засеять ГПСЧ mt19937?

113

Кажется, я вижу много ответов, в которых кто-то предлагает использовать <random>для генерации случайных чисел, обычно вместе с таким кодом:

std::random_device rd;  
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);

Обычно это заменяет какую-то «нечестивую мерзость» типа:

srand(time(NULL));
rand()%6;

Мы могли бы критиковать старый способ, утверждая, что он time(NULL)обеспечивает низкую энтропию, time(NULL)предсказуемость и конечный результат неоднороден.

Но все это верно в отношении нового способа: у него просто более блестящий внешний вид.

  • rd()возвращает сингл unsigned int. Он имеет как минимум 16 бит, а возможно, 32. Этого недостаточно для заполнения 19937 бит состояния MT.

  • Использование std::mt19937 gen(rd());gen()(заполнение 32 битами и просмотр первого вывода) не дает хорошего распределения вывода. 7 и 13 никогда не могут быть первым выходом. Два семени дают 0. Двенадцать семян дают 1226181350. ( Ссылка )

  • std::random_deviceможет быть, а иногда и реализуется как простой ГПСЧ с фиксированным начальным значением. Следовательно, при каждом запуске может производиться одна и та же последовательность. ( Ссылка ) Это даже хуже чем time(NULL).

Что еще хуже, очень легко скопировать и вставить приведенные выше фрагменты кода, несмотря на проблемы, которые они содержат. Некоторые решения этой проблемы требуют приобретения обширных библиотек, которые могут не подходить всем.

В свете этого, мой вопрос: как можно кратко, портативно и тщательно засеять mt19937 PRNG в C ++?

Учитывая вышеперечисленные проблемы, хороший ответ:

  • Необходимо полностью засеять mt19937 / mt19937_64.
  • Нельзя полагаться только на источник энтропии std::random_deviceили time(NULL)как на ее источник.
  • Не следует полагаться на Boost или другие библиотеки.
  • Должен уместиться в небольшом количестве строк, чтобы он выглядел хорошо вставленным в ответ.

мысли

  • Моя текущая мысль заключается в том, что выходные данные std::random_deviceможно объединить (возможно, с помощью XOR) со time(NULL)значениями, полученными в результате рандомизации адресного пространства , и жестко запрограммированной константой (которая может быть установлена ​​во время распределения), чтобы получить максимальную отдачу от энтропии.

  • std::random_device::entropy() не дает четкого представления о том, что std::random_deviceможет или не может сделать.

Ричард
источник
24
@Fabien: Что в этом портативного? Это вопрос C ++, а не Linux.
Гонки
6
Моя личная мысль, что , возможно , значения могут быть взяты из std::random_device, time(NULL)и адреса функций, затем выполняется XOR вместе , чтобы произвести своего рода источник энтропии максимальных усилий.
Ричард
5
Было бы неплохо, если бы была такая функция, как does_random_device_actually_work (), чтобы можно было хотя бы изящно деградировать или выдавать предупреждения или ошибки для пользователя.
4
Правильное решение не короткое, короткое решение не будет правильным. Мой подход, который я использую в своей библиотеке seed11, в основном заключается в std::random_deviceправильной реализации на платформах, на которых вы планируете запускать свою программу, и предоставлении вспомогательной функции, которая создает генератор с засеянными seed11::make_seeded<std::mt19937>()
milleniumbug
5
Кроме того: ваша вторая пуля не добавляет ничего нового. Неудивительно, что вы нашли значение, которое встречается 12 раз. Вы должны ожидать, что будет чуть более трех значений, которые появятся ровно 12 раз , если у вас есть 2 ^ 32 независимых, равномерно случайных выборки.

Ответы:

58

Я бы сказал, что самый большой недостаток std::random_deviceзаключается в том, что разрешен детерминированный откат, если CSPRNG недоступен. Уже одно это является хорошей причиной не заполнять ГПСЧ с помощью std::random_device, поскольку производимые байты могут быть детерминированными. К сожалению, он не предоставляет API, чтобы узнать, когда это происходит, или запросить сбой вместо случайных чисел низкого качества.

То есть полностью переносимого решения нет: зато есть достойный, минималистичный подход. Вы можете использовать минимальную оболочку вокруг CSPRNG (определенного sysrandomниже) для заполнения PRNG.

Windows


Вы можете положиться на CryptGenRandomCSPRNG. Например, вы можете использовать следующий код:

bool acquire_context(HCRYPTPROV *ctx)
{
    if (!CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, 0)) {
        return CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET);
    }
    return true;
}


size_t sysrandom(void* dst, size_t dstlen)
{
    HCRYPTPROV ctx;
    if (!acquire_context(&ctx)) {
        throw std::runtime_error("Unable to initialize Win32 crypt library.");
    }

    BYTE* buffer = reinterpret_cast<BYTE*>(dst);
    if(!CryptGenRandom(ctx, dstlen, buffer)) {
        throw std::runtime_error("Unable to generate random bytes.");
    }

    if (!CryptReleaseContext(ctx, 0)) {
        throw std::runtime_error("Unable to release Win32 crypt library.");
    }

    return dstlen;
}

Unix-подобный


Во многих Unix-подобных системах по возможности следует использовать / dev / urandom (хотя это не гарантируется в POSIX-совместимых системах).

size_t sysrandom(void* dst, size_t dstlen)
{
    char* buffer = reinterpret_cast<char*>(dst);
    std::ifstream stream("/dev/urandom", std::ios_base::binary | std::ios_base::in);
    stream.read(buffer, dstlen);

    return dstlen;
}

Другой


Если CSPRNG недоступен, вы можете полагаться на него std::random_device. Однако я бы по возможности избегал этого, поскольку различные компиляторы (в первую очередь, MinGW) реализуют его как ГПСЧ (фактически, каждый раз создавая одну и ту же последовательность, чтобы предупредить людей о том, что она не является должным образом случайной).

Посев


Теперь, когда у нас есть части с минимальными накладными расходами, мы можем сгенерировать желаемые биты случайной энтропии для заполнения нашего ГПСЧ. В примере используются (явно недостаточные) 32 бита для заполнения PRNG, и вам следует увеличить это значение (которое зависит от вашего CSPRNG).

std::uint_least32_t seed;    
sysrandom(&seed, sizeof(seed));
std::mt19937 gen(seed);

Сравнение с Boost


Мы можем увидеть параллели с boost :: random_device (настоящий CSPRNG) после беглого просмотра исходного кода . Boost используется MS_DEF_PROVв Windows, это тип поставщика для PROV_RSA_FULL. Единственное, чего не хватает, - это проверки криптографического контекста, что можно сделать с помощью CRYPT_VERIFYCONTEXT. На * Nix Boost использует /dev/urandom. IE, это решение портативно, хорошо протестировано и простое в использовании.

Специализация Linux


Если вы готовы пожертвовать краткостью ради безопасности, getrandomэто отличный выбор для Linux 3.17 и новее, а также для недавней версии Solaris. getrandomведет себя идентично /dev/urandom, за исключением того, что блокируется, если ядро ​​еще не инициализировало свой CSPRNG после загрузки. Следующий фрагмент кода определяет getrandom, доступен ли Linux , и, если нет, возвращается к /dev/urandom.

#if defined(__linux__) || defined(linux) || defined(__linux)
#   // Check the kernel version. `getrandom` is only Linux 3.17 and above.
#   include <linux/version.h>
#   if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
#       define HAVE_GETRANDOM
#   endif
#endif

// also requires glibc 2.25 for the libc wrapper
#if defined(HAVE_GETRANDOM)
#   include <sys/syscall.h>
#   include <linux/random.h>

size_t sysrandom(void* dst, size_t dstlen)
{
    int bytes = syscall(SYS_getrandom, dst, dstlen, 0);
    if (bytes != dstlen) {
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    return dstlen;
}

#elif defined(_WIN32)

// Windows sysrandom here.

#else

// POSIX sysrandom here.

#endif

OpenBSD


Есть еще одно последнее предостережение: в современной OpenBSD его нет /dev/urandom. Вместо этого вы должны использовать getentropy .

#if defined(__OpenBSD__)
#   define HAVE_GETENTROPY
#endif

#if defined(HAVE_GETENTROPY)
#   include <unistd.h>

size_t sysrandom(void* dst, size_t dstlen)
{
    int bytes = getentropy(dst, dstlen);
    if (bytes != dstlen) {
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    return dstlen;
}

#endif

другие мысли


Если вам нужны криптографически безопасные случайные байты, вам, вероятно, следует заменить fstream на небуферизованные open / read / close POSIX. Это потому , что , как basic_filebufи FILEсодержит внутренний буфер, который будет выделен с помощью стандартного распределителя (и , следовательно , не стер из памяти).

Это легко сделать, изменив sysrandomна:

size_t sysrandom(void* dst, size_t dstlen)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd == -1) {
        throw std::runtime_error("Unable to open /dev/urandom.");
    }
    if (read(fd, dst, dstlen) != dstlen) {
        close(fd);
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    close(fd);
    return dstlen;
}

Спасибо


Особая благодарность Бену Фойгту за указание на FILEиспользование буферизованного чтения, поэтому его не следует использовать.

Я также хотел бы поблагодарить Питера Кордеса за упоминание getrandomи отсутствие в OpenBSD /dev/urandom.

Александр Хусзаг
источник
11
Это то, что я делал в прошлом, но вопрос или, по крайней мере, вопрос в том, что WTF, не могут ли разработчики библиотек для этих платформ сделать это за нас? Я ожидаю, что доступ к файлам и потоки (например) будут абстрагированы реализациями библиотеки, так почему бы не генерировать случайные числа?
2
ОП здесь: Было бы неплохо, если бы этот ответ немного лучше продемонстрировал посев. Насколько это возможно, я надеюсь на ответы, которые генерируют копируемый код, который выполняет свою работу лучше, чем простой пример, который я опубликовал в моем вопросе, не требуя особой технической интерпретации или размышлений со стороны кодировщика.
Ричард
4
Я думал, /dev/randomчто это будет лучший выбор для заполнения ГСЧ, но, по-видимому, /dev/urandomон по-прежнему считается безопасным с точки зрения вычислений, даже когда /dev/randomблокируется из-за низкой доступной энтропии, поэтому urandomэто рекомендуемый выбор для всего, кроме, возможно, одноразовых прокладок. См. Также unix.stackexchange.com/questions/324209/… . Однако остерегайтесь предсказуемых семян с urandomсамого начала после загрузки.
Питер Кордес
2
getrandom(2)Системный вызов Linux похож на открытие и чтение /dev/urandom, за исключением того, что он блокируется, если источники случайности ядра еще не инициализированы. Я думаю, это избавит вас от проблемы ранней загрузки с низким качеством случайности без блокировки в других случаях, как это /dev/randomпроисходит.
Питер Кордес
1
@PeterCordes, конечно, и это отличный вариант, когда он доступен. Однако он не работает с BSD или другими * Nix'ами, с которыми /dev/urandomобычно работает. Я обычно подписываюсь на обсуждение этого вопроса в списке рассылки Python: bugs.python.org/issue27266
Alexander Huszagh
22

В некотором смысле это невозможно сделать портативно. Таким образом, можно представить себе действительную полностью детерминированную платформу, работающую на C ++ (скажем, симулятор, который детерминированно изменяет синхронизацию машинных часов и с «детерминированным» вводом-выводом), в которой нет источника случайности для заполнения ГПСЧ.

einpoklum
источник
1
@kbelder: 1. Кто назвал пользователя человеком? 2. Не все программы имеют взаимодействие с пользователем, и вы, конечно, не можете предположить, что всегда есть пользователь ...
einpoklum
8
Я ценю такой ответ, но также считаю, что программа должна предпринять разумные усилия.
Ричард
3
@Richard Согласен, но проблема в том, что разработчики стандартов C ++ должны (или, по крайней мере, изо всех сил стараться) приспособиться к такого рода странным ситуациям. Вот почему вы получаете такого рода безвкусные стандартные определения, в которых вы можете получить достойные результаты, но компилятор по-прежнему может соответствовать стандартам, даже если он возвращает что-то, что функционально бесполезно. - Таким образом, ваши ограничения («короткие и не могут полагаться на другие библиотеки») исключают любой ответ, поскольку вам действительно нужен специальный корпус для каждой платформы / компилятора за компилятором. (например, что такое Boost.)
RM
2
@Richard, однако, объясняет, что вы получаете то, что получаете в стандарте, потому что нет портативного способа сделать лучше. Если вы хотите добиться большего (а это благородная цель), вам придется смириться с большим или меньшим количеством мерзости :)
hobbs
1
@Richard: Иногда вам просто нужно признать, что можно создать совместимую со стандартами реализацию C ++, которая бесполезна. Поскольку реализации, которые люди используют для всего, что имеет значение , предназначены для того, чтобы быть полезными, вам иногда приходится жить с аргументами типа «любая разумная реализация сделает что-то разумное». Я бы надеялся, что std::random_deviceэто будет в этой категории, но, очевидно, это не так, если в некоторых реальных реализациях используется ГПСЧ с фиксированным начальным числом! Это выходит далеко за рамки аргументов Эйнпоклума.
Питер Кордес
14

Вы можете использовать a std::seed_seqи заполнить его, по крайней мере, до требуемого размера состояния для генератора, используя метод Александра Хусзага для получения энтропии:

size_t sysrandom(void* dst, size_t dstlen); //from Alexander Huszagh answer above

void foo(){

    std::array<std::mt19937::UIntType, std::mt19937::state_size> state;
    sysrandom(state.begin(), state.length*sizeof(std::mt19937::UIntType));
    std::seed_seq s(state.begin(), state.end());

    std::mt19937 g;
    g.seed(s);
}

Если бы существовал правильный способ заполнения или создания SeedSequence из UniformRandomBitGenerator в стандартной библиотеке, использование std::random_deviceдля правильного заполнения было бы намного проще.

храповой урод
источник
1
У seed_seq есть проблемы, pcg-random.org/posts/developing-a-seed_seq-alternative.html
etarion
Ни в стандарте C ++, ни в каком-либо другом нет ничего, что могло бы гарантировать, что генератор случайных чисел будет использовать весь массив при заполнении из seed_seq. Этот метод приведет к неудаче, если вы используете rng для научного моделирования и, очевидно, также для криптографии. Единственный вариант использования для этого - рандомизация видеоигры, но это было бы излишним.
Костас
5

Реализация, над которой я работаю, использует state_sizeсвойство mt19937PRNG, чтобы решить, сколько семян предоставить при инициализации:

using Generator = std::mt19937;

inline
auto const& random_data()
{
    thread_local static std::array<typename Generator::result_type, Generator::state_size> data;
    thread_local static std::random_device rd;

    std::generate(std::begin(data), std::end(data), std::ref(rd));

    return data;
}

inline
Generator& random_generator()
{
    auto const& data = random_data();

    thread_local static std::seed_seq seeds(std::begin(data), std::end(data));
    thread_local static Generator gen{seeds};

    return gen;
}

template<typename Number>
Number random_number(Number from, Number to)
{
    using Distribution = typename std::conditional
    <
        std::is_integral<Number>::value,
        std::uniform_int_distribution<Number>,
        std::uniform_real_distribution<Number>
    >::type;

    thread_local static Distribution dist;

    return dist(random_generator(), typename Distribution::param_type{from, to});
}

Я думаю, что есть возможности для улучшения, потому что они std::random_device::result_typeмогут отличаться std::mt19937::result_typeпо размеру и диапазону, поэтому это действительно следует учитывать.

Замечание о std :: random_device .

Согласно C++11(/14/17)стандарту (-ам):

26.5.6 Класс random_device [ rand.device ]

2 Если ограничения реализации не позволяют генерировать недетерминированные случайные числа, реализация может использовать механизм случайных чисел.

Это означает, что реализация может генерировать детерминированные значения только в том случае, если ей не позволяют генерировать недетерминированные значения из - за некоторых ограничений.

MinGWКомпилятор на Windowsлихе не обеспечивает недетерминированное значение своего std::random_device, несмотря на их быть легко доступны из операционной системы. Поэтому я считаю это ошибкой, которая вряд ли часто встречается в разных реализациях и на разных платформах.

Галик
источник
1
Это может заполнить состояние MT, но по-прежнему полагается исключительно на него std::random_deviceи, следовательно, уязвимо для связанных с ним проблем.
Ричард
1
Думаю, я достаточно четко сформулировал их в вопросе. Однако рад уточнить / обсудить.
Ричард
2
@Richard Есть ли какие-нибудь реальные системы, которые на самом деле не реализуют разумного std::random_device? Я знаю, что стандарт допускает такой PRNGже откат, но я чувствую, что это только для прикрытия, поскольку трудно требовать, чтобы каждое используемое устройство C++имело недетерминированный случайный источник. А если они этого не сделают, что вы можете с этим поделать?
Галик
5
@AlexanderHuszagh Я не уверен. Я намерен сделать свое «портативное решение» зависимым от устройства, потому что, если устройство поддерживает недетерминированные генераторы, то и должно std::random_device. Я считаю, что это дух стандарта. Итак, я искал и могу найти только MinGWто, что сломано в этом отношении. Кажется, никто не сообщает об этой проблеме ни с чем другим, что я нашел. Итак, в моей библиотеке я просто помечен MinGWкак неподдерживаемый. Если бы была более широкая проблема, я бы ее переосмыслил. Я просто не вижу доказательств этого прямо сейчас.
Галик
5
Я действительно разочарован тем, что MinGW разрушает std::random_deviceвсех, делая его доступным в форме, не обеспечивающей возможности случайности платформы. Низкокачественные реализации противоречат цели существующего API. Было бы лучше, ИМО, если бы они просто не реализовали его, пока он не заработал. (Или лучше, если бы API предоставлял способ запроса сбоя, если высококачественная случайность недоступна, поэтому MinGW мог бы избежать угроз безопасности, при этом давая разные начальные значения для игр или чего-то еще.)
Питер Кордес
2

Нет ничего плохого в раздаче с использованием времени, если это вам не нужно для обеспечения безопасности (и вы не говорили, что это было необходимо). Понимание состоит в том, что вы можете использовать хеширование, чтобы исправить неслучайность. Я обнаружил, что это работает адекватно во всех случаях, включая, в частности, тяжелое моделирование методом Монте-Карло.

Одной из приятных особенностей этого подхода является то, что он обобщается на инициализацию из других не совсем случайных наборов начальных чисел. Например, если вы хотите, чтобы каждый поток имел свой собственный RNG (для обеспечения безопасности потоков), вы можете просто инициализировать его на основе хешированного идентификатора потока.

Ниже приведен SSCCE , полученный из моей кодовой базы (для простоты; некоторые структуры поддержки OO опущены):

#include <cstdint> //`uint32_t`
#include <functional> //`std::hash`
#include <random> //`std::mt19937`
#include <iostream> //`std::cout`

static std::mt19937 rng;

static void seed(uint32_t seed) {
    rng.seed(static_cast<std::mt19937::result_type>(seed));
}
static void seed() {
    uint32_t t = static_cast<uint32_t>( time(nullptr) );
    std::hash<uint32_t> hasher; size_t hashed=hasher(t);
    seed( static_cast<uint32_t>(hashed) );
}

int main(int /*argc*/, char* /*argv*/[]) {
    seed();
    std::uniform_int_distribution<> dis(0, 5);
    std::cout << dis(rng);
}
imallett
источник
1
Я согласен с вашей точкой зрения, что посев по времени, вероятно, достаточно хорош на практике, если он вам не нужен для обеспечения безопасности. Но я не могу согласиться с остальной частью вашего ответа. Посев хешем времени ничем не лучше посевного значения самого времени.
DW
@DW Эмпирически это намного лучше. Причина в том, что хэш является прерывистым и охватывает гораздо более широкий диапазон значений (попробуйте сами: начните с 1и 2и обратите внимание, что последовательность сгенерированных ими чисел с плавающей запятой требует времени, чтобы действительно расходиться).
imallett
Я не понимаю, почему это важно. Мы работаем только с одним семенем за раз. Пространство возможных значений семени (энтропия семени) в любом случае одинаково - хеширование не увеличивает энтропию. Возможно, вы могли бы отредактировать вопрос, чтобы объяснить, почему хеширование лучше?
DW
0

Вот мой собственный ответ на вопрос:

#include <random>
#include <chrono>
#include <cstdint>
#include <algorithm>
#include <functional>
#include <iostream>

uint32_t LilEntropy(){
  //Gather many potential forms of entropy and XOR them
  const  uint32_t my_seed = 1273498732; //Change during distribution
  static uint32_t i = 0;        
  static std::random_device rd; 
  const auto hrclock = std::chrono::high_resolution_clock::now().time_since_epoch().count();
  const auto sclock  = std::chrono::system_clock::now().time_since_epoch().count();
  auto *heap         = malloc(1);
  const auto mash = my_seed + rd() + hrclock + sclock + (i++) +
    reinterpret_cast<intptr_t>(heap)    + reinterpret_cast<intptr_t>(&hrclock) +
    reinterpret_cast<intptr_t>(&i)      + reinterpret_cast<intptr_t>(&malloc)  +
    reinterpret_cast<intptr_t>(&LilEntropy);
  free(heap);
  return mash;
}

//Fully seed the mt19937 engine using as much entropy as we can get our
//hands on
void SeedGenerator(std::mt19937 &mt){
  std::uint_least32_t seed_data[std::mt19937::state_size];
  std::generate_n(seed_data, std::mt19937::state_size, std::ref(LilEntropy));
  std::seed_seq q(std::begin(seed_data), std::end(seed_data));
  mt.seed(q);
}

int main(){
  std::mt19937 mt;
  SeedGenerator(mt);

  for(int i=0;i<100;i++)
    std::cout<<mt()<<std::endl;
}

Идея здесь состоит в том, чтобы использовать XOR для объединения многих потенциальных источников энтропии (быстрое время, медленное время std::random-device, местоположения статических переменных, местоположения кучи, местоположения функций, местоположения библиотек, значения, специфичные для программы), чтобы предпринять максимальную попытку инициализировать mt19937. Если хотя бы один раз источник будет «хорошим», результат будет не менее «хорошим».

Этот ответ не такой короткий, как хотелось бы, и может содержать одну или несколько логических ошибок. Так что я считаю это незавершенным. Прокомментируйте, если у вас есть отзыв.

Ричард
источник
3
Адреса могут иметь очень небольшую случайность. У вас всегда одни и те же распределения, поэтому в небольших встроенных системах, где у вас есть доступ ко всей памяти, вероятно, каждый раз будут получены одни и те же результаты. Я бы сказал, что этого вполне достаточно для большой системы, но с микроконтроллером он может не справиться.
Meneldal
1
Я предполагаю, &i ^ &myseedчто энтропия должна быть значительно меньше, чем у любого из них по отдельности, поскольку оба являются объектами со статической продолжительностью хранения в одной и той же единице перевода и, следовательно, могут быть довольно близко друг к другу. И вы, кажется, на самом деле не используете специальное значение из инициализации myseed?
aschepler
7
Преобразование освобожденных указателей в целые числа является неопределенным поведением; сделай это, пока он еще существует. ^ужасный сумматор хешей; если два значения имеют много энтропии, но мало по сравнению друг с другом, она удаляется. +обычно лучше (поскольку x + x сжигает только 1 бит энтропии в x, а x ^ x сжигает их все). Я подозреваю, что функция небезопасна ( rd())
Yakk - Adam Nevraumont
2
Ну и +я имею в виду на неподписанном ( +на подписанном - это UB-приманка). Хотя это несколько нелепые случаи UB, вы сказали портативные. Также рассмотрите возможность получения адреса функции в виде целого значения, если возможно (не уверены, есть ли это?)
Якк - Адам Неврамонт
1
@meneldal: даже на полноценном ПК, хотя распределения могут иметь разные физические местоположения (в зависимости от состояния машины, внешней по отношению к процессу), указатели абстрагируются виртуальным адресным пространством процесса и, вероятно, имеют высокую повторяемость, особенно ASLR не действует.
Ben Voigt
0
  • Используйте getentropy () для заполнения генератора псевдослучайных чисел (PRNG).
  • Используйте getrandom (), если вам нужны случайные значения (вместо, скажем, /dev/urandomили /dev/random).

Они доступны в современных UNIX-подобных системах, таких как Linux, Solaris и OpenBSD.

Дэн Андерсон
источник
-2

Данная платформа может иметь источник энтропии, например /dev/random. Наносекунды с начала эпохи, std::chrono::high_resolution_clock::now()вероятно, являются лучшим начальным значением в стандартной библиотеке.

Раньше я использовал что-то вроде того, (uint64_t)( time(NULL)*CLOCKS_PER_SEC + clock() )чтобы получить больше бит энтропии для приложений, которые не критичны с точки зрения безопасности.

Davislor
источник
2
Вам действительно стоит использовать /dev/urandom, особенно в таком случае. /dev/randomблоков, и часто без веских причин для этого ([вставьте длинное объяснение о том, сколько разных ОС оценивают случайность байтов, созданных / dev / random]).
Alexander Huszagh
2
@AlexanderHuszagh Верно, хотя мне приходилось кодировать в системах, которых /dev/urandomне было, и альтернативой блокировке был детерминизм. Коробка может иметь /dev/hwrngили /dev/hw_randomтоже, что должно быть даже лучше.
Davislor
Хорошо, я сказал: «например, как /dev/random», и это, похоже, вызвало священную войну /dev/randomпротив /dev/urandomLinux, чего я не имел в
виду,