Як швидко, переносно та ретельно висіяти PRNG mt19937?


112

Здається, я бачу багато відповідей, в яких хтось пропонує використовувати <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 біт.

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

  • std::random_deviceможе бути, а іноді і реалізується як звичайний PRNG з фіксованим насінням. Таким чином, він може створювати однакову послідовність на кожному запуску. ( Посилання ) Це навіть гірше , ніж 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)та функціональних адрес, а потім XORed разом, щоб створити своєрідне джерело ентропії з найкращих зусиль.
Річард

5
Було б добре, якби була така функція, як did_random_device_actual_work (), щоб можна було принаймні витончено погіршити або створити попередження або помилки для користувача.

4
Правильне рішення не є коротким, коротке рішення не буде правильним. Мій підхід, який я використовую у своїй бібліотеці seed11, полягає в основному для std::random_deviceналежного впровадження на платформах, на яких ви плануєте запускати свою програму, та надання допоміжної функції, яка створює генератор висіву ( seed11::make_seeded<std::mt19937>())
milleniumbug

5
Убік: ваша друга куля не додає нічого нового. Не дивно, що ви знайшли якесь значення, яке з’являється 12 разів. Ви повинні очікувати, що там буде трохи більше трьох значень, які з’являються рівно 12 разів , припускаючи, що у вас є 2 ^ 32 незалежних, рівномірно випадкових вибірки.

Відповіді:


58

Я б заперечував, що найбільшим недоліком std::random_deviceє те, що дозволено детермінований запасний варіант, якщо немає CSPRNG. Це одне є вагомою причиною не засівати PRNG, використовуючи 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-Like


У багатьох системах, схожих на 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) реалізують це як PRNG (насправді, щоразу створюючи ту саму послідовність, щоб попереджати людей про те, що це не належним чином випадково).

Висівання насіння


Тепер, коли у нас є шматки з мінімальними накладними витратами, ми можемо генерувати бажані біти випадкової ентропії для насіння нашого PRNG. У прикладі використовується (очевидно недостатньо) 32-біт для виведення PRNG, і ви повинні збільшити це значення (яке залежить від вашого CSPRNG).

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

Порівняння для підвищення


Ми можемо побачити паралелі для підвищення :: 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. Натомість слід використовувати гетентропію .

#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 на розблоковане відкрите / читання / закриття 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що буде кращим вибором для висіву RNG, але, мабуть /dev/urandom, все ще вважається безпечним для обчислень, навіть коли /dev/randomблокується через низьку ентропію, тому urandomрекомендується вибір для всіх, крім, можливо, разових колодок. Дивіться також unix.stackexchange.com/questions/324209/… . urandomОднак остерігайтеся передбачуваних насіння дуже рано після завантаження.
Пітер Кордес

2
getrandom(2)Системний виклик Linux схожий на відкриття та читання /dev/urandom, за винятком того, що він блокується, якщо джерела випадковості ядра ще не ініціалізовані. Я думаю, що це позбавить вас від проблеми раннього завантаження з низькою якістю випадковості, не блокуючи в інших випадках, як /dev/randomце робиться.
Пітер Кордес

1
@PeterCordes, безумовно, і це чудовий варіант, коли він доступний. Однак він не працює на BSD або інших * Nixes, на чому /dev/urandomвзагалі працює щось . Обговорення в цьому списку розсилки Python - це те, на що я зазвичай підписуюся: bugs.python.org/issue27266
Alexander Huszagh

22

У певному сенсі це неможливо зробити портативно. Тобто, можна уявити дійсну повністю детерміновану платформу, що працює на C ++ (скажімо, тренажер, який керує машинним годинником детерміновано, та з "визначеним" введенням-виведенням), в якому немає джерела випадковості висаджувати PRNG.


1
@kbelder: 1. Хто каже, що користувач - це людина? 2. Не всі програми мають взаємодію з користувачем, і ви, звичайно, не можете припустити, що навколо завжди знайдеться користувач ...
einpoklum

8
Я ціную цю відповідь, але також вважаю, що програма повинна зробити розумну спробу найкращих зусиль.
Річард

3
@ Річард погодився, але проблема полягає в тому, що стандартні письменники C ++ повинні (або принаймні спробувати їх найдивовижніші) для вирішення подібних химерних ситуацій. Ось чому ви отримуєте такі різновиди загадливих стандартних визначень, де ви можете отримати гідні результати, але компілятор все ще може відповідати стандартам, навіть якщо він повертає щось, що функціонально нічого не варте. - Тож ваші обмеження ("короткі та не можуть покладатися на інші бібліотеки") виключають будь-яку відповідь, оскільки вам фактично потрібен спеціальний корпус "платформа за платформою / компілятор за компілятором". (наприклад, що Boost робить так добре.)
RM

2
@ Richard, що це пояснює, це те, що ви отримуєте те, що отримуєте в стандарті, оскільки немає портативного способу зробити краще. Якщо ви хочете зробити краще (що є благородною метою), вам доведеться прийняти деяку більшу або меншу кількість гидоти :)
hobbs

1
@Richard: Іноді потрібно просто погодитися з можливістю зробити стандартну C ++ реалізацію, що не відповідає стандартам. Оскільки реалізація, яку люди використовують для будь-чого, що має значення , призначена для корисного, іноді доводиться жити з аргументами на кшталт "будь-яка розумна реалізація зробить щось розумне". Я би сподівався, що std::random_deviceце буде в цій категорії, але, мабуть, це не так, якщо деякі реальні реалізації використовують PRNG з фіксованим набором! Це виходить за рамки аргументу einpoklum.
Пітер Кордес

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

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);
}

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
Перетворення розділених покажчиків у ints - це невизначена поведінка; робіть це, поки він все ще існує. ^- жахливий хеш-комбайнер; якщо обидва значення мають велику кількість ентропії, але мало порівняно один з одним, це усуває її. +зазвичай краще (так як x + x спалює лише 1 біт ентропії в x, тоді як x ^ x спалює їх усі). Підозрюю, що функція не є безпечною для теда ( rd())
Як - Адам Невраумон

2
О, і +я маю на увазі неподписаний ( +на підписі є UB-приманка). Хоча це дещо смішні випадки UB, ви сказали, що вони переносні. Також розгляньте можливість отримання адреси функції як цілісного значення, якщо можливо (невизначено, чи є це?)
Yakk - Adam Nevraumont

1
@meneldal: Навіть на ПК з повною силою, хоча розподіли можуть отримувати різні фізичні місця (залежно від стану машини поза процесом), покажчики абстрагуються віртуальним адресним простором процесу та, ймовірно, дуже повторювані, зокрема це ASLR не діє.
Бен Войгт

0
  • Використовуйте гетентропію () для посіву генератора псевдовипадкових чисел (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() )щоб отримати більше біт ентропії для додатків, які не є критичними для безпеки.


2
Вам справді слід користуватися /dev/urandom, особливо у такому випадку. /dev/randomблоки, і часто без поважних причин для цього ([вставити довге пояснення про те, скільки різних ОС оцінюють випадковість байтів, вироблених / dev / random]).
Олександр Хузаг

2
@AlexanderHuszagh Правда, хоча мені довелося кодувати системи, де /dev/urandomїх не було, і альтернативою блокуванню був детермінізм. У коробці може бути /dev/hwrngабо /dev/hw_randomтак само, що має бути ще краще.
Девіслор

Гаразд, я сказав: "такі як /dev/random", і це, здається, спричинило святу війну /dev/randomпроти /dev/urandomLinux, яку я не мав наміру, коли дав цей приклад ..
Davislor
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.