Come seminare in modo succinto, portatile e completo il PRNG mt19937?


112

Mi sembra di vedere molte risposte in cui qualcuno suggerisce di utilizzare <random>per generare numeri casuali, di solito insieme a codice come questo:

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

Di solito questo sostituisce una sorta di "abominio empio" come:

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

Potremmo criticare il vecchio modo sostenendo che time(NULL)fornisce bassa entropia, time(NULL)è prevedibile e il risultato finale non è uniforme.

Ma tutto questo è vero per il nuovo modo: ha solo un rivestimento più brillante.

  • rd()restituisce un singolo unsigned int. Questo ha almeno 16 bit e probabilmente 32. Non è sufficiente per seminare i 19937 bit di stato di MT.

  • L'utilizzo std::mt19937 gen(rd());gen()(seeding con 32 bit e guardando il primo output) non fornisce una buona distribuzione dell'output. 7 e 13 non possono mai essere la prima uscita. Due semi producono 0. Dodici semi producono 1226181350. ( Link )

  • std::random_devicepuò essere, e talvolta lo è, implementato come un semplice PRNG con un seed fisso. Potrebbe quindi produrre la stessa sequenza in ogni esecuzione. ( Link ) Questo è anche peggio di time(NULL).

Peggio ancora, è molto facile copiare e incollare gli snippet di codice precedenti, nonostante i problemi che contengono. Alcune soluzioni a questo richiedono l'acquisizione di biblioteche di grandi dimensioni che potrebbero non essere adatte a tutti.

Alla luce di ciò, la mia domanda è: come si può seminare in modo succinto, portabile e completo il PRNG mt19937 in C ++?

Dati i problemi di cui sopra, una buona risposta:

  • Deve seminare completamente il mt19937 / mt19937_64.
  • Non posso fare affidamento esclusivamente su std::random_deviceo time(NULL)come fonte di entropia.
  • Non dovrebbe fare affidamento su Boost o altre biblioteche.
  • Dovrebbe rientrare in un piccolo numero di righe in modo tale da sembrare piacevole da copiare e incollare in una risposta.

Pensieri

  • Il mio pensiero attuale è che gli output di std::random_devicepossono essere combinati (forse tramite XOR) con time(NULL)valori derivati ​​dalla randomizzazione dello spazio degli indirizzi e una costante hard-coded (che potrebbe essere impostata durante la distribuzione) per ottenere il massimo sforzo con l'entropia.

  • std::random_device::entropy() non fornisce una buona indicazione di ciò che std::random_devicepotrebbe o non potrebbe fare.


24
@Fabien: cosa c'è di portatile in questo? Questa è una domanda C ++, non una domanda Linux.
Gare di leggerezza in orbita

6
Il mio pensiero personale era che forse si potevano trarre valori da std::random_device, time(NULL)e indirizzi di funzioni, quindi XOR insieme per produrre una sorta di fonte di entropia di massimo sforzo.
Richard

5
Sarebbe bello se ci fosse una funzione come does_random_device_actually_work () in modo che si possa almeno degradare con garbo, o produrre avvisi o errori per l'utente.

4
La soluzione corretta non è breve, la soluzione breve non sarà corretta. Il mio approccio che utilizzo nella mia libreria seed11 è fondamentalmente quello di implementare std::random_devicecorrettamente sulle piattaforme su cui prevedi di eseguire il tuo programma e fornire una funzione di supporto che crea un generatore seeded ( seed11::make_seeded<std::mt19937>())
milleniumbug

5
A parte: il tuo secondo proiettile non aggiunge nulla di nuovo. Non sorprende che tu abbia trovato un valore che appare 12 volte. Dovresti aspettarti che ci siano poco più di tre valori che appaiono esattamente 12 volte , assumendo che tu abbia 2 ^ 32 campioni indipendenti e uniformemente casuali .

Risposte:


58

Direi che il più grande difetto std::random_deviceè che è consentito un fallback deterministico se non è disponibile CSPRNG. Questo da solo è un buon motivo per non seminare un PRNG utilizzando std::random_device, poiché i byte prodotti possono essere deterministici. Sfortunatamente non fornisce un'API per scoprire quando ciò accade o per richiedere un errore invece di numeri casuali di bassa qualità.

Cioè, non esiste una soluzione completamente portabile : tuttavia, esiste un approccio decente e minimo. È possibile utilizzare un wrapper minimo attorno a un CSPRNG (definito come di sysrandomseguito) per eseguire il seeding del PRNG.

finestre


Puoi fare affidamento su CryptGenRandomun CSPRNG. Ad esempio, puoi utilizzare il codice seguente:

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


Su molti sistemi Unix-like, dovresti usare / dev / urandom quando possibile (sebbene non sia garantito che esista su sistemi conformi a 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;
}

Altro


Se nessun CSPRNG è disponibile, potresti scegliere di fare affidamento su std::random_device. Tuttavia, lo eviterei se possibile, poiché vari compilatori (in particolare, MinGW) lo implementano come PRNG (in effetti, producendo la stessa sequenza ogni volta per avvisare gli umani che non è propriamente casuale).

Semina


Ora che abbiamo i nostri pezzi con un sovraccarico minimo, possiamo generare i bit desiderati di entropia casuale per seminare il nostro PRNG. L'esempio utilizza 32 bit (ovviamente insufficienti) per inizializzare il PRNG e dovresti aumentare questo valore (che dipende dal tuo CSPRNG).

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

Confronto con Boost


Possiamo vedere parallelismi con boost :: random_device (un vero CSPRNG) dopo una rapida occhiata al codice sorgente . Boost utilizza MS_DEF_PROVsu Windows, che è il tipo di provider per PROV_RSA_FULL. L'unica cosa che manca sarebbe la verifica del contesto crittografico, che può essere fatto con CRYPT_VERIFYCONTEXT. Su * Nix, Boost utilizza /dev/urandom. IE, questa soluzione è portatile, ben testata e facile da usare.

Specializzazione Linux


Se sei disposto a sacrificare la concisione per la sicurezza, getrandomè una scelta eccellente su Linux 3.17 e versioni successive e su Solaris recente. getrandomsi comporta in modo identico a /dev/urandom, tranne che si blocca se il kernel non ha ancora inizializzato il suo CSPRNG dopo l'avvio. Il frammento di codice seguente rileva se Linux getrandomè disponibile e, in caso contrario, ricade su /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


C'è un ultimo avvertimento: il moderno OpenBSD non ha /dev/urandom. Dovresti invece usare 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

Altri pensieri


Se hai bisogno di byte casuali crittograficamente sicuri, dovresti probabilmente sostituire fstream con l'apertura / lettura / chiusura senza buffer di POSIX. Questo perché entrambi basic_filebufe FILEcontengono un buffer interno, che verrà allocato tramite un allocatore standard (e quindi non cancellato dalla memoria).

Questo potrebbe essere fatto facilmente cambiando sysrandomin:

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

Grazie


Un ringraziamento speciale a Ben Voigt per aver sottolineato che FILEutilizza letture bufferizzate, e quindi non dovrebbe essere utilizzato.

Vorrei anche ringraziare Peter Cordes per aver menzionato getrandome la mancanza di OpenBSD /dev/urandom.


11
Questo è quello che ho fatto in passato, ma la domanda, o almeno una, è: WTF non possono fare gli scrittori di biblioteche per queste piattaforme per noi? Mi aspetto che l'accesso ai file e i thread (ad esempio) vengano astratti dalle implementazioni della libreria, quindi perché non la generazione di numeri casuali?

2
OP qui: Sarebbe bello se questa risposta dimostrasse un po 'meglio il seeding. Per quanto possibile, spero in risposte che generino codice copiabile che faccia il lavoro meglio del semplice esempio che ho pubblicato nella mia domanda senza richiedere molta interpretazione tecnica o pensiero da parte del programmatore.
Richard

4
Ho pensato che /dev/randomsarebbe stata la scelta migliore per il seeding di un RNG, ma a quanto pare /dev/urandomè ancora considerato computazionalmente sicuro anche quando /dev/randomsi bloccherebbe a causa della bassa entropia disponibile, quindi urandomè la scelta consigliata per tutto tranne forse per i pad monouso. Vedi anche unix.stackexchange.com/questions/324209/… . Fai attenzione ai semi prevedibili fin urandomdall'inizio, però.
Peter Cordes

2
La getrandom(2)chiamata di sistema di Linux è come l'apertura e la lettura /dev/urandom, tranne che si bloccherà se le fonti di casualità del kernel non sono state ancora inizializzate. Penso che questo ti salvi dal problema della casualità di bassa qualità di avvio iniziale senza bloccare in altri casi come /dev/randomfa.
Peter Cordes

1
@ PeterCordes, di sicuro, e questa è un'ottima opzione quando disponibile. Tuttavia, non funziona su BSD o altri * Nix, che è qualcosa su cui /dev/urandomgeneralmente funziona. La discussione sulla mailing list Python su questo è qualcosa a cui generalmente mi iscrivo: bugs.python.org/issue27266
Alexander Huszagh

22

In un certo senso, questo non può essere fatto in modo portabile. Cioè, si può concepire una valida piattaforma completamente deterministica che esegue C ++ (diciamo, un simulatore che fa avanzare il clock della macchina in modo deterministico e con I / O "determinizzato") in cui non vi è alcuna fonte di casualità per seminare un PRNG.


1
@kbelder: 1. Chi dice che l'utente è una persona? 2. Non tutti i programmi hanno l'interazione dell'utente e di certo non puoi presumere che ci sia sempre un utente in giro ...
einpoklum

8
Apprezzo questa risposta, ma sento anche che un programma dovrebbe fare un ragionevole tentativo di miglior sforzo.
Richard

3
@Richard era d'accordo, ma il problema è che gli scrittori standard del C ++ devono (o almeno provano a fare del loro meglio per) accogliere questo tipo di situazioni bizzarre. Ecco perché ottieni questo tipo di definizioni standard insignificanti, in cui potresti ottenere risultati decenti, ma il compilatore può comunque essere conforme agli standard anche se restituisce qualcosa di funzionalmente inutile. - Quindi le tue restrizioni ("brevi e non possono fare affidamento su altre librerie") escludono qualsiasi risposta, poiché hai effettivamente bisogno di un involucro speciale piattaforma per piattaforma / compilatore per compilatore. (ad es. cosa fa Boost così bene.)
RM

2
@Richard ciò che spiega, però, è che ottieni ciò che ottieni nello standard perché non esiste un modo portatile per fare di meglio. Se vuoi fare meglio (che è un obiettivo nobile) dovrai accettare una quantità maggiore o minore di abominio :)
hobbs

1
@Richard: A volte devi solo accettare che è possibile realizzare un'implementazione C ++ conforme agli standard che non è utile. Poiché le implementazioni che le persone usano per qualsiasi cosa importante sono progettate per essere utili, a volte devi convivere con argomenti come "qualsiasi implementazione sana farà qualcosa di ragionevole". Avrei sperato che std::random_devicefosse in quella categoria, ma a quanto pare non lo è se alcune implementazioni reali utilizzano un PRNG a seme fisso! Questo va ben oltre l'argomento di einpoklum.
Peter Cordes

14

Puoi usare un std::seed_seqe riempirlo almeno fino alla dimensione dello stato richiesto per il generatore usando il metodo di Alexander Huszagh per ottenere l'entropia:

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

Se ci fosse un modo corretto per riempire o creare una SeedSequence da un UniformRandomBitGenerator nella libreria standard, usare std::random_deviceper il seeding correttamente sarebbe molto più semplice.



Non c'è niente nello standard C ++ o altro per garantire che il generatore di numeri casuali utilizzerà l'intero array quando si inizializza da seed_seq. Questo metodo porterà al fallimento se stai usando rng per una simulazione scientifica, e ovviamente anche per la crittografia. L'unico caso d'uso per questo sarà quello di randomizzare un videogioco, ma sarebbe eccessivo.
Kostas

5

L'implementazione su cui sto lavorando sfrutta la state_sizeproprietà del mt19937PRNG per decidere quanti seed fornire in fase di inizializzazione:

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

Penso che ci siano margini di miglioramento perché std::random_device::result_typepotrebbero differire dalle std::mt19937::result_typedimensioni e dalla gamma, quindi dovrebbero essere davvero presi in considerazione.

Una nota su std :: random_device .

Secondo lo C++11(/14/17)standard (s):

26.5.6 Classe random_device [ rand.device ]

2 Se le limitazioni di implementazione impediscono di generare numeri casuali non deterministici, l'implementazione può utilizzare un motore di numeri casuali.

Ciò significa che l'implementazione può generare valori deterministici solo se le è impedito di generare valori non deterministici da qualche limitazione.

Il MinGWcompilatore Windowsnotoriamente non fornisce valori non deterministici dai suoi std::random_device, nonostante siano facilmente disponibili dal sistema operativo. Quindi lo considero un bug e probabilmente non un evento comune tra implementazioni e piattaforme.


1
Questo può riempire lo stato di traduzione automatica, ma si basa ancora esclusivamente su std::random_deviceed è quindi vulnerabile ai problemi che ne derivano.
Richard

1
Penso di averli dichiarati abbastanza chiaramente nella domanda. Felice di chiarire / discutere, però.
Richard

2
@Richard Esistono sistemi reali che in realtà non implementano un ragionevole std::random_device? So che lo standard consente un PRNGripiego ma ritengo che sia solo per coprirsi poiché è difficile pretendere che ogni dispositivo che utilizza C++abbia una fonte casuale non deterministica. E se non lo fanno, cosa potresti fare comunque?
Galik

5
@AlexanderHuszagh Non ne sono così sicuro. La mia intenzione è di rendere la mia "soluzione portatile" dipendente dal dispositivo perché se il dispositivo supporta generatori non deterministici, dovrebbe farlo std::random_device. Credo che questo sia lo spirito dello standard. Quindi ho cercato e posso solo scoprire MinGWche è rotto in questo senso. Nessuno sembra segnalare questo problema con qualsiasi altra cosa che ho trovato. Quindi, nella mia libreria, ho semplicemente contrassegnato MinGWcome non supportato. Se ci fosse un problema più ampio, lo ripenserei. Solo che non ne vedo le prove in questo momento.
Galik

5
Sono davvero deluso dal fatto che MinGW stia rovinando std::random_deviceper tutti rendendolo disponibile in una forma che non offre le capacità di casualità della piattaforma. Le implementazioni di bassa qualità annullano lo scopo dell'API esistente. Sarebbe meglio IMO se non lo implementassero affatto finché non lo facessero funzionare. (O meglio, se l'API fornisse un modo per richiedere il fallimento se la casualità di alta qualità non fosse disponibile, quindi MinGW potrebbe evitare di causare rischi per la sicurezza fornendo ancora semi diversi per i giochi o altro.)
Peter Cordes

2

Non c'è niente di sbagliato nel seeding usando il tempo, supponendo che non ne hai bisogno per essere sicuro (e non hai detto che era necessario). L'intuizione è che puoi usare l'hashing per correggere la non casualità. Ho trovato che funziona adeguatamente in tutti i casi, inclusi e in particolare per le simulazioni Monte Carlo pesanti.

Una caratteristica interessante di questo approccio è che generalizza all'inizializzazione da altri insiemi di seed non casuali. Ad esempio, se desideri che ogni thread abbia il proprio RNG (per threadsafety), puoi semplicemente inizializzare in base all'ID thread con hash.

Quello che segue è un SSCCE , distillato dalla mia base di codice (per semplicità; alcune strutture di supporto OO elide):

#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
Concordo con il tuo punto di vista che il seminare con il tempo è probabilmente abbastanza buono in pratica, se non ne hai bisogno per essere sicuro. Ma non sono d'accordo con il resto della tua risposta. Seminare con l'hash del tempo non è meglio che seminare con il tempo stesso.
DW

@ DW empiricamente, è molto meglio. Il motivo è che l'hash è discontinuo e copre un intervallo di valori molto più ampio (provalo tu stesso: seme con 1e 2e osserva che la sequenza di float da essi generata impiega un po 'di tempo per divergere davvero).
imallett

Non vedo perché sia ​​importante. Stiamo solo utilizzando un singolo seme alla volta. Lo spazio dei possibili valori per il seme (l'entropia del seme) è lo stesso in entrambi i casi: l'hashing non aumenta l'entropia. Forse potresti modificare la domanda per spiegare perché l'hashing è migliore?
DW

0

Ecco la mia pugnalata alla domanda:

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

L'idea qui è di utilizzare XOR per combinare molte potenziali fonti di entropia (tempo veloce, tempo lento, std::random-deviceposizioni di variabili statiche, posizioni di heap, posizioni di funzioni, posizioni di libreria, valori specifici del programma) per fare un tentativo migliore per inizializzare il mt19937. Finché almeno una volta la fonte è "buona", il risultato sarà almeno "buono".

Questa risposta non è breve come sarebbe preferibile e può contenere uno o più errori di logica. Quindi lo considero un work in progress. Si prega di commentare se si dispone di feedback.


3
Gli indirizzi potrebbero avere pochissima casualità. Hai sempre le stesse allocazioni, quindi su sistemi embedded più piccoli in cui hai accesso all'intera memoria, è probabile che si ottengano gli stessi risultati ogni volta. Direi che probabilmente è abbastanza buono per un grande sistema, ma potrebbe fare una merda su un microcontrollore.
meneldal

1
Immagino che &i ^ &myseeddovrebbe avere un'entropia notevolmente inferiore rispetto a uno solo, poiché entrambi sono oggetti con durata di memorizzazione statica nella stessa unità di traduzione e quindi è probabile che siano piuttosto vicini tra loro. E non sembri effettivamente utilizzare il valore speciale dell'inizializzazione di myseed?
aschepler

7
La conversione di puntatori dislocati in int è un comportamento indefinito; fallo finché esiste ancora. ^è un orribile combinatore di hash; se due valori hanno entrambi molta entropia, ma poca l'uno rispetto all'altro, la rimuove. +di solito è migliore (poiché x + x brucia solo 1 bit di entropia in x, mentre x ^ x li brucia tutti). La funzione non è sicura, sospetto ( rd())
Yakk - Adam Nevraumont

2
Oh, e +intendo su non firmato ( +su firmato è UB-bait). Mentre questi sono casi UB un po 'ridicoli, hai detto portatile. Considera anche di ottenere l'indirizzo di una funzione come valore integrale, se possibile (incerto se lo è?)
Yakk - Adam Nevraumont

1
@meneldal: anche su un PC a piena potenza, sebbene le allocazioni possano avere posizioni fisiche diverse (a seconda dello stato della macchina esterno al processo), i puntatori sono astratti dallo spazio degli indirizzi virtuali del processo e probabilmente altamente ripetibili, in particolare è ASLR non è in vigore.
Ben Voigt

0
  • Usa getentropy () per seminare un generatore di numeri pseudocasuali (PRNG).
  • Usa getrandom () se vuoi valori casuali (invece di, diciamo, /dev/urandomo /dev/random).

Questi sono disponibili sui moderni sistemi simili a UNIX, come Linux, Solaris e OpenBSD.


-2

Una data piattaforma potrebbe avere una fonte di entropia, come /dev/random. Nanosecondi dall'Epoch con std::chrono::high_resolution_clock::now()è probabilmente il miglior seme nella Standard Library.

In precedenza ho usato qualcosa come (uint64_t)( time(NULL)*CLOCKS_PER_SEC + clock() )ottenere più bit di entropia per applicazioni che non sono critiche per la sicurezza.


2
Dovresti davvero usare /dev/urandom, soprattutto in un caso come questo. /dev/randomblocchi, e spesso senza buone ragioni per farlo ([inserire una lunga spiegazione su quanti diversi sistemi operativi stimano la casualità dei byte prodotti da / dev / random]).
Alexander Huszagh

2
@AlexanderHuszagh Vero, anche se ho dovuto scrivere codice su sistemi in cui /dev/urandomnon esistevano e l'alternativa al blocco era il determinismo. Una scatola potrebbe avere /dev/hwrngo /dev/hw_randomanche, che dovrebbe essere ancora migliore.
Davislor

Ok, ho detto, "come /dev/random", e questo sembra aver scatenato una guerra santa /dev/randomcontro /dev/urandomLinux che non intendevo quando ho fatto quell'esempio ..
Davislor
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.