¿Cómo sembrar de manera sucinta, portátil y completa el mt19937 PRNG?

112

Me parece ver muchas respuestas en las que alguien sugiere usar <random>para generar números aleatorios, generalmente junto con un código como este:

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

Por lo general, esto reemplaza algún tipo de "abominación impía" como:

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

Podríamos criticar la forma antigua argumentando que time(NULL)proporciona una entropía baja, time(NULL)es predecible y el resultado final no es uniforme.

Pero todo eso es cierto en la nueva forma: simplemente tiene un barniz más brillante.

  • rd()devuelve un single unsigned int. Esto tiene al menos 16 bits y probablemente 32. Eso no es suficiente para generar los 19937 bits de estado de MT.

  • Usar std::mt19937 gen(rd());gen()(sembrar con 32 bits y mirar la primera salida) no da una buena distribución de salida. 7 y 13 nunca pueden ser la primera salida. Dos semillas producen 0. Doce semillas producen 1226181350. ( Enlace )

  • std::random_devicepuede implementarse, y a veces se implementa, como un PRNG simple con una semilla fija. Por lo tanto, podría producir la misma secuencia en cada ejecución. ( Enlace ) Esto es incluso peor que time(NULL).

Peor aún, es muy fácil copiar y pegar los fragmentos de código anteriores, a pesar de los problemas que contienen. Algunas soluciones para esto requieren la adquisición de bibliotecas grandes que pueden no ser adecuadas para todos.

A la luz de esto, mi pregunta es ¿Cómo se puede sembrar de manera sucinta, portátil y completa el PRNG mt19937 en C ++?

Dados los problemas anteriores, una buena respuesta:

  • Debe sembrar completamente el mt19937 / mt19937_64.
  • No se puede confiar únicamente en std::random_deviceo time(NULL)como fuente de entropía.
  • No debería confiar en Boost u otras bibliotecas.
  • Debe caber en una pequeña cantidad de líneas para que se vea bien pegado en una respuesta.

Pensamientos

  • Mi pensamiento actual es que las salidas de std::random_devicese pueden combinar (tal vez a través de XOR) con time(NULL)valores derivados de la aleatorización del espacio de direcciones y una constante codificada (que podría establecerse durante la distribución) para obtener un mejor esfuerzo en la entropía.

  • std::random_device::entropy() no da una buena indicación de lo que std::random_devicepodría o no hacer.

Ricardo
fuente
24
@Fabien: ¿Qué tiene eso de portátil? Esta es una pregunta de C ++, no de Linux.
Lightness Races in Orbit
6
Mi pensamiento personal fue que tal vez se podrían extraer valores de std::random_device, time(NULL)y direcciones de funciones, y luego XOR juntos para producir una especie de fuente de entropía de mejor esfuerzo.
Richard
5
Sería bueno si hubiera una función como does_random_device_actually_work () para que uno pudiera al menos degradar con gracia, o producir advertencias o errores para el usuario.
4
La solución adecuada no es corta, la solución corta no será la adecuada. Mi enfoque que utilizo en mi biblioteca seed11 es básicamente implementar std::random_devicecorrectamente en las plataformas en las que planea ejecutar su programa y proporcionar una función auxiliar que crea un generador inicial ( seed11::make_seeded<std::mt19937>())
milleniumbug
5
Aparte: tu segunda viñeta no agrega nada nuevo. No es de extrañar que haya encontrado un valor que aparece 12 veces. Debe esperar que haya poco más de tres valores que aparezcan exactamente 12 veces , asumiendo que tiene 2 ^ 32 muestras independientes y uniformemente aleatorias .

Respuestas:

58

Yo diría que el mayor defecto std::random_devicees que se permite una alternativa determinista si no hay ningún CSPRNG disponible. Esto por sí solo es una buena razón para no sembrar un PRNG usando std::random_device, ya que los bytes producidos pueden ser deterministas. Desafortunadamente, no proporciona una API para averiguar cuándo sucede esto o para solicitar fallas en lugar de números aleatorios de baja calidad.

Es decir, no existe una solución completamente portátil : sin embargo, existe un enfoque mínimo y decente. Puede usar una envoltura mínima alrededor de un CSPRNG (definido a sysrandomcontinuación) para sembrar el PRNG.

Ventanas


Puede confiar en CryptGenRandomun CSPRNG. Por ejemplo, puede utilizar el siguiente código:

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

Tipo Unix


En muchos sistemas similares a Unix, debe usar / dev / urandom cuando sea posible (aunque no se garantiza que exista en sistemas compatibles con 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;
}

Otro


Si no hay CSPRNG disponible, puede optar por confiar en él std::random_device. Sin embargo, evitaría esto si es posible, ya que varios compiladores (en particular, MinGW) lo implementan como un PRNG (de hecho, producen la misma secuencia cada vez para alertar a los humanos de que no es correctamente aleatorio).

Siembra


Ahora que tenemos nuestras piezas con una sobrecarga mínima, podemos generar los bits deseados de entropía aleatoria para sembrar nuestro PRNG. El ejemplo usa 32 bits (obviamente insuficientes) para inicializar el PRNG, y debe aumentar este valor (que depende de su CSPRNG).

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

Comparación con Boost


Podemos ver paralelismos con boost :: random_device (un verdadero CSPRNG) después de un vistazo rápido al código fuente . Boost se usa MS_DEF_PROVen Windows, que es el tipo de proveedor para PROV_RSA_FULL. Lo único que faltaría sería verificar el contexto criptográfico, lo que se puede hacer CRYPT_VERIFYCONTEXT. En * Nix, Boost usa /dev/urandom. Es decir, esta solución es portátil, está bien probada y es fácil de usar.

Especialización Linux


Si está dispuesto a sacrificar la concisión por la seguridad, getrandomes una excelente opción en Linux 3.17 y superior, y en Solaris reciente. getrandomse comporta de manera idéntica a /dev/urandom, excepto que se bloquea si el kernel no ha inicializado su CSPRNG aún después de arrancar. El siguiente fragmento detecta si Linux getrandomestá disponible y, si no, recurre a /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


Hay una advertencia final: el OpenBSD moderno no tiene /dev/urandom. Deberías usar getentropy en su lugar.

#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

otros pensamientos


Si necesita bytes aleatorios criptográficamente seguros, probablemente debería reemplazar el fstream con abrir / leer / cerrar sin búfer de POSIX. Esto se debe a que ambos basic_filebufy FILEcontienen un búfer interno, que se asignará a través de un asignador estándar (y, por lo tanto, no se borrará de la memoria).

Esto se puede hacer fácilmente cambiando sysrandoma:

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

Gracias


Un agradecimiento especial a Ben Voigt por señalar el FILEuso de lecturas almacenadas en búfer y, por lo tanto, no debe usarse.

También me gustaría agradecer a Peter Cordes por mencionar getrandomy la falta de OpenBSD /dev/urandom.

Alexander Huszagh
fuente
11
Esto es lo que he hecho en el pasado, pero la pregunta, o al menos una, es WTF, ¿no pueden los escritores de bibliotecas de estas plataformas hacer esto por nosotros? Espero que el acceso a archivos y los subprocesos (por ejemplo) sean abstraídos por las implementaciones de la biblioteca, entonces, ¿por qué no la generación de números aleatorios?
2
OP aquí: sería bueno si esta respuesta demostrara la siembra un poco mejor. En la medida de lo posible, espero obtener respuestas que generen un código que se pueda copiar y que haga el trabajo mejor que el ejemplo simple que publiqué en mi pregunta sin requerir mucha interpretación técnica o pensamiento por parte del codificador.
Richard
4
Pensé /dev/randomque sería la mejor opción para sembrar un RNG, pero aparentemente /dev/urandomtodavía se considera computacionalmente seguro incluso cuando /dev/randomse bloquearía debido a la baja entropía disponible, por lo que urandomes la opción recomendada para todo, excepto tal vez los pads únicos. Consulte también unix.stackexchange.com/questions/324209/… . Sin urandomembargo, tenga cuidado con las semillas predecibles desde muy temprano después del arranque.
Peter Cordes
2
La getrandom(2)llamada al sistema de Linux es como abrir y leer /dev/urandom, excepto que se bloqueará si las fuentes de aleatoriedad del kernel aún no se han inicializado. Creo que esto te salva del problema de aleatoriedad de baja calidad de arranque temprano sin bloquear en otros casos como lo /dev/randomhace.
Peter Cordes
1
@PeterCordes, seguro, y esa es una gran opción cuando está disponible. Sin embargo, no funciona en BSD u otros * Nixes, que es algo en lo que /dev/urandomgeneralmente funciona. La discusión de la lista de correo de Python sobre esto es algo a lo que generalmente me suscribo: bugs.python.org/issue27266
Alexander Huszagh
22

En cierto sentido, esto no se puede hacer de forma portátil. Es decir, se puede concebir una plataforma totalmente determinista válida que ejecute C ++ (digamos, un simulador que acelere el reloj de la máquina de forma determinista y con E / S "determinizadas") en la que no hay una fuente de aleatoriedad para sembrar un PRNG.

einpoklum
fuente
1
@kbelder: 1. ¿Quién dice que el usuario es una persona? 2. No todos los programas tienen interacción con el usuario y ciertamente no se puede asumir que siempre hay un usuario alrededor ...
einpoklum
8
Aprecio esta respuesta, pero también siento que un programa debería hacer un intento razonable de mejor esfuerzo.
Richard
3
@Richard De acuerdo, pero el problema es que los escritores estándar de C ++ tienen que (o al menos hacer todo lo posible) adaptarse a este tipo de situaciones extrañas. Es por eso que obtienes este tipo de definiciones estándar imprecisas, donde puedes obtener resultados decentes, pero el compilador aún puede cumplir con los estándares incluso si devuelve algo que no tiene valor funcional. - Por lo tanto, sus restricciones ("breves y no pueden depender de otras bibliotecas") descartan cualquier respuesta, ya que efectivamente necesita una carcasa especial plataforma por plataforma / compilador por compilador. (por ejemplo, lo que Boost hace tan bien)
RM
2
@Richard, lo que explica, sin embargo, es que obtienes lo que obtienes en el estándar porque no hay una forma portátil de hacerlo mejor. Si quieres hacerlo mejor (que es un objetivo noble) tendrás que aceptar una cantidad mayor o menor de abominación :)
hobbs
1
@Richard: A veces solo tienes que aceptar que es posible hacer una implementación de C ++ compatible con los estándares que no es útil. Dado que las implementaciones que la gente usa para cualquier cosa que importa están diseñadas para ser útiles, a veces tienes que vivir con argumentos como "cualquier implementación sensata hará algo razonable". Hubiera esperado que std::random_deviceestuviera en esa categoría, pero aparentemente no lo es si algunas implementaciones reales usan un PRNG de semilla fija. Eso va mucho más allá del argumento de einpoklum.
Peter Cordes
14

Puede usar un std::seed_seqy llenarlo al menos hasta el tamaño de estado requerido para el generador usando el método de Alexander Huszagh para obtener la entropía:

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

Si hubiera una forma adecuada de completar o crear una SeedSequence a partir de un UniformRandomBitGenerator en la biblioteca estándar, usar std::random_devicepara sembrar correctamente sería mucho más simple.

monstruo del trinquete
fuente
1
Sin embargo, seed_seq tiene problemas, pcg-random.org/posts/developing-a-seed_seq-alternative.html
etarion
No hay nada en el estándar C ++ ni en ningún otro que garantice que el generador de números aleatorios utilizará toda la matriz cuando se siembra desde seed_seq. Este método conducirá al fracaso si está utilizando el rng para una simulación científica y, obviamente, también para criptografía. El único caso de uso para esto será aleatorizar un videojuego, pero sería una exageración.
Kostas
5

La implementación en la que estoy trabajando aprovecha la state_sizepropiedad del mt19937PRNG para decidir cuántas semillas proporcionar en la inicialización:

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

Creo que hay margen de mejora porque std::random_device::result_typepodría diferir std::mt19937::result_typeen tamaño y rango, por lo que realmente debería tenerse en cuenta.

Una nota sobre std :: random_device .

Según la C++11(/14/17)(s) norma (s):

26.5.6 Clase random_device [ rand.device ]

2 Si las limitaciones de implementación impiden generar números aleatorios no deterministas, la implementación puede emplear un motor de números aleatorios.

Esto significa que la implementación solo puede generar valores deterministas si alguna limitación le impide generar valores no deterministas .

El MinGWcompilador en Windowsfamoso no proporciona valores no deterministas de su std::random_device, a pesar de que están fácilmente disponibles en el sistema operativo. Así que considero que esto es un error y no es probable que ocurra con frecuencia en todas las implementaciones y plataformas.

Galik
fuente
1
Esto puede llenar el estado de MT, pero aún depende únicamente std::random_devicey, por lo tanto, es vulnerable a los problemas que surgen de él.
Richard
1
Creo que los expuse con bastante claridad en la pregunta. Sin embargo, feliz de aclarar / discutir.
Richard
2
@Richard ¿Hay algún sistema real que no implemente un sistema razonable std::random_device? Sé que el estándar permite un PRNGretroceso, pero creo que es solo para cubrirse, ya que es difícil exigir que cada dispositivo que lo use C++tenga una fuente aleatoria no determinista. Y si no es así, ¿qué podrías hacer al respecto de todos modos?
Galik
5
@AlexanderHuszagh No estoy tan seguro. Mi intención es hacer que mi "solución portátil" dependa del dispositivo porque si el dispositivo admite generadores no deterministas, entonces también debería hacerlo std::random_device. Creo que ese es el espíritu del estándar. Por eso he buscado y solo puedo encontrar MinGWque está roto en este sentido. Nadie parece informar de este problema con cualquier otra cosa que haya encontrado. Entonces, en mi biblioteca, simplemente lo he marcado MinGWcomo no admitido. Si hubiera un problema más amplio, lo volvería a pensar. Simplemente no veo la evidencia de eso en este momento.
Galik
5
Estoy realmente decepcionado de que MinGW esté arruinando std::random_devicea todos al ponerlo a disposición en una forma que no ofrece las capacidades de aleatoriedad de la plataforma. Las implementaciones de baja calidad frustran el propósito de la API existente. En mi opinión, sería mejor si simplemente no lo implementaran hasta que lo tengan funcionando. (O mejor, si la API proporciona una forma de solicitar fallas si la aleatoriedad de alta calidad no está disponible, por lo que MinGW podría evitar causar riesgos de seguridad al mismo tiempo que ofrece diferentes semillas para juegos o lo que sea)
Peter Cordes
2

No hay nada de malo en sembrar usando el tiempo, asumiendo que no lo necesita para estar seguro (y no dijo que esto fuera necesario). La idea es que puede usar hash para corregir la no aleatoriedad. Encontré que esto funciona adecuadamente en todos los casos, incluidas y en particular para las simulaciones de Monte Carlo pesadas.

Una característica interesante de este enfoque es que se generaliza a la inicialización de otros conjuntos de semillas no realmente aleatorios. Por ejemplo, si desea que cada subproceso tenga su propio RNG (para la seguridad de subprocesos), puede inicializar en función del ID de subproceso con hash.

El siguiente es un SSCCE , destilado de mi base de código (por simplicidad; algunas estructuras de soporte OO elididas):

#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
fuente
1
Estoy de acuerdo con su punto de que sembrar con el tiempo probablemente sea lo suficientemente bueno en la práctica, si no lo necesita para estar seguro. Pero no puedo estar de acuerdo con el resto de tu respuesta. Sembrar con el hash del tiempo no es mejor que sembrar con el tiempo mismo.
DW
@DW Empíricamente, es mucho mejor. La razón es que el hash es discontinuo y abarca un rango mucho más amplio de valores (intente esto usted mismo: siembre con 1y 2y observe que la secuencia de flotadores generados por ellos tarda un tiempo en divergir realmente).
imallett
No veo por qué eso importa. Solo estamos funcionando con una sola semilla a la vez. El espacio de valores posibles para la semilla (la entropía de la semilla) es el mismo de cualquier manera: el hash no aumenta la entropía. ¿Quizás podría editar la pregunta para explicar por qué es mejor el hash?
DW
0

Aquí está mi propia puñalada a la pregunta:

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

La idea aquí es usar XOR para combinar muchas fuentes potenciales de entropía (tiempo rápido, tiempo lento, std::random-deviceubicaciones de variables estáticas, ubicaciones de montones, ubicaciones de funciones, ubicaciones de bibliotecas, valores específicos del programa) para hacer el mejor esfuerzo para inicializar el mt19937. Siempre que al menos una vez la fuente sea "buena", el resultado será al menos así de "bueno".

Esta respuesta no es tan corta como sería preferible y puede contener uno o más errores de lógica. Así que lo considero un trabajo en progreso. Por favor comente si tiene comentarios.

Ricardo
fuente
3
Las direcciones pueden tener muy poca aleatoriedad. Siempre tiene las mismas asignaciones, por lo que en sistemas integrados más pequeños en los que tiene acceso a toda la memoria, es probable que obtenga los mismos resultados cada vez. Yo diría que es lo suficientemente bueno para un sistema grande, pero podría hacer una mierda en un microcontrolador.
meneldal
1
Supongo que &i ^ &myseeddebería tener considerablemente menos entropía que cualquiera de los dos, ya que ambos son objetos con una duración de almacenamiento estático en la misma unidad de traducción y, por lo tanto, es probable que estén bastante juntos. ¿Y no parece que realmente uses el valor especial de la inicialización de myseed?
aschepler
7
La conversión de punteros desasociados en ints es un comportamiento indefinido; hazlo mientras aún exista. ^es un combinador de hash horrible; si dos valores tienen mucha entropía, pero poca comparados entre sí, los elimina. +suele ser mejor (ya que x + x solo quema 1 bit de entropía en x, mientras que x ^ x los quema todos). La función no es segura, sospecho ( rd())
Yakk - Adam Nevraumont
2
Ah, y +me refiero a sin firmar ( +en firmado es UB-bait). Si bien estos son casos UB algo ridículos, dijiste portátiles. También considere obtener la dirección de una función como un valor integral si es posible (¿no se sabe si lo es?)
Yakk - Adam Nevraumont
1
@meneldal: incluso en una PC de alta potencia, aunque las asignaciones pueden obtener diferentes ubicaciones físicas (según el estado de la máquina externa al proceso), los punteros son abstraídos por el espacio de direcciones virtuales del proceso y probablemente sean altamente repetibles, particularmente si ASLR no está en vigor.
Ben Voigt
0
  • Utilice getentropy () para sembrar un generador de números pseudoaleatorios (PRNG).
  • Utilice getrandom () si desea valores aleatorios (en lugar de, digamos, /dev/urandomo /dev/random).

Están disponibles en sistemas modernos similares a UNIX, como Linux, Solaris y OpenBSD.

Dan Anderson
fuente
-2

Una plataforma determinada puede tener una fuente de entropía, como /dev/random. Nanosegundos desde la Época con std::chrono::high_resolution_clock::now()es probablemente la mejor semilla en la Biblioteca Estándar.

Anteriormente he usado algo como (uint64_t)( time(NULL)*CLOCKS_PER_SEC + clock() )para obtener más bits de entropía para aplicaciones que no son críticas para la seguridad.

Davislor
fuente
2
Realmente debería usar /dev/urandom, especialmente en un caso como este. /dev/randombloques, y a menudo sin buenas razones para hacerlo ([inserte una explicación larga sobre cuántos sistemas operativos diferentes estiman la aleatoriedad de los bytes producidos por / dev / random]).
Alexander Huszagh
2
@AlexanderHuszagh Cierto, aunque tuve que codificar en sistemas donde /dev/urandomno existía, y la alternativa al bloqueo fue el determinismo. Una caja podría tener /dev/hwrngo /dev/hw_randomtambién, que debería ser incluso mejor.
Davislor
De acuerdo, dije, "como /dev/random", y eso parece haber provocado una guerra santa sobre /dev/randomversus /dev/urandomen Linux que no tenía la intención cuando di ese ejemplo ..
Davislor