Primero, no existe un solo número aleatorio; por ejemplo, ¿es 4 un número aleatorio? Solo podemos decir que una secuencia de números es aleatoria si tiene ciertas propiedades matemáticas. Puede obtener verdaderos números aleatorios lanzando una moneda o tirando un par de dados repetidamente. Los generadores de números pseudoaleatorios (PRNG) son algoritmos deterministas que producen secuencias de números que parecen aleatorios.
La propiedad más importante de los PRNG es que los números producidos se distribuyen uniformemente en un rango dado , de modo que los valores en el rango ocurren con probabilidades iguales. Por ejemplo, un lanzamiento de moneda puede tener dos resultados posibles, cara o cruz, cada uno con probabilidad [matemática] p = \ frac {1} {2} [/ matemática]; tirar un dado justo puede producir cualquier número del 1 al 6 con probabilidad [matemática] p = \ frac {1} {6} [/ matemática]. El núcleo de la mayoría de las bibliotecas de generación de números aleatorios es una función, como rand()
de la biblioteca estándar C, que genera números enteros distribuidos uniformemente entre 0 y un valor RAND_MAX
. Se pueden obtener otros rangos y distribuciones transformando los números generados de esta manera (por ejemplo, para obtener números de una distribución exponencial con media [matemática] \ mu [/ matemática] puede usar la fórmula [matemática] E_i = – \ mu \ En U_i [/ matemáticas]). Los generadores de números aleatorios deben inicializarse llamando a una función para proporcionar una semilla, un número a partir del cual se generan todos los números posteriores. En la biblioteca estándar de C, esta función se llama srand()
. Una práctica común es sembrar PRNG con la hora actual. Debido a que los generadores de números aleatorios son programas de computadora deterministas, dos secuencias generadas usando el mismo algoritmo y comenzando desde la misma semilla serán idénticas (un error de programación común es sembrar el generador con un valor constante antes de generar cada número aleatorio; esto dará como resultado generando el mismo número repetidamente).
Para ilustrar cómo funciona esto, explicaré uno de los primeros algoritmos para la generación de números aleatorios, el método lineal congruencial (LC) . El método LC se rige por tres parámetros:
- [matemáticas] M [/ matemáticas], el módulo; [matemáticas] 0
- [matemáticas] A [/ matemáticas], el multiplicador; [matemáticas] 0 \ leq A
- [matemáticas] B [/ matemáticas], el incremento; [matemáticas] 0 \ leq B
Este método genera una secuencia de números sin signo [matemática] X_0 [/ matemática], [matemática] X_1 [/ matemática],…. La función de inicialización inicializa [math] X_0 [/ math]. Cada invocación del generador de números aleatorios producirá un nuevo número [matemática] X_ {i + 1} [/ matemática] al transformar el último número en la secuencia [matemática] X_i [/ matemática] con la siguiente fórmula:
[matemáticas] X_ {i + 1} = (A X_i + B) \ bmod M [/ matemáticas]
Por ejemplo, cuando [matemática] M = 10 [/ matemática] y [matemática] X_0 = A = B = 7 [/ matemática] la secuencia resultante es 7, 6, 9, 0, 7, 6, 9, 0 ...
.. (este ejemplo es de Knuth vol. 2; BTW, ese libro tiene más de lo que siempre quisiste saber sobre la generación de números aleatorios). Porque la secuencia [math] X_i [/ math] se calcula módulo [math] M [/ math] , los números se generan en el rango entre [matemática] 0 [/ matemática] y [matemática] M-1 [/ matemática]. Si [math] M = 2 ^ {32} [/ math] y está utilizando variables unsigned
para estas operaciones, la operación de módulo generalmente puede omitirse (en las CPU x86 de 32 y 64 bits, los números unsigned
se representan en 32 bits y unsigned
operaciones unsigned
se realizan módulo [matemática] 2 ^ {32} [/ matemática]).
Todos los generadores LC entran en una órbita periódica, un ciclo de números que se repiten, como se ve en el ejemplo anterior. Un PRNG debe tener un período lo más largo posible; Algunas aplicaciones requieren millones de números aleatorios que no se repiten. El período más largo posible es el módulo [matemática] M [/ matemática], en cuyo caso la órbita es una permutación completa: cada número en el rango se genera exactamente una vez. Aquí hay una lista de parámetros que proporcionan esta propiedad.
Para asegurarse de que la secuencia generada sea aleatoria, puede verificar que tenga las propiedades matemáticas deseadas aplicando varias pruebas de aleatoriedad . Por ejemplo, puede usar la prueba de chi-cuadrado para determinar si las frecuencias de aparición de los números generados son consistentes con la distribución uniforme. Esta prueba implica dividir el rango de números generados en múltiples contenedores, contando cuántos números caen en cada bin y cuántos se esperaría que caigan en cada bin, dada la distribución uniforme, y calculando una estadística de prueba a partir de las diferencias entre estos conteos. Si el estadístico de prueba es demasiado alto, entonces es poco probable que la secuencia provenga de una distribución uniforme; de lo contrario, decimos que la secuencia es consistente con la distribución uniforme porque no tenemos evidencia de lo contrario. Todas las pruebas de aleatoriedad funcionan así: pueden determinar si las secuencias generadas son consistentes con ciertas propiedades matemáticas, pero ninguna prueba puede probar que los números son aleatorios . Como resultado, la falla es que los algoritmos PRNG a menudo son difíciles de encontrar, como en el caso del algoritmo Dual_EC_DRBG que supuestamente incluía una puerta trasera insertada por la NSA.
La capacidad de predecir el próximo valor generado por un PRNG tiene muchas aplicaciones en seguridad, tanto para fines de ataque como de defensa. Por ejemplo, puede descifrar conexiones TLS, reconstruir claves privadas, inferir el árbol de quién infectado de quién de un gusano de Internet o secuestrar una botnet que se basa en algoritmos de generación de dominio. Debido a que los PRNG son algoritmos deterministas, puede predecir la secuencia generada si conoce la semilla o el estado interno del generador. Para evitar esto, los PRNG criptográficamente seguros tienen requisitos estrictos para evitar tales filtraciones de información. Esto a menudo se logra mediante la recopilación de múltiples fuentes de entropía, como movimientos del mouse, golpes de teclado, entradas de cámara o micrófono, para la semilla y el uso de la salida de un cifrado de bloque, como AES, como el número generado.
Para responder a sus últimas preguntas, sí, existen generadores de números aleatorios en la naturaleza. Por ejemplo, en una sustancia radiactiva que emite una partícula alfa cada [math] \ mu [/ math] segundos en promedio, el tiempo entre emisiones sucesivas sigue una distribución exponencial con media [math] \ mu [/ math]. Esta aleatoriedad es fundamental para la física cuántica, hasta un punto que incomoda a algunos científicos; Por ejemplo, Einstein dijo que “Dios no juega a los dados con el universo” (estaba equivocado).
Como otros han señalado, estos efectos físicos se han utilizado para implementar generadores de números aleatorios en el hardware. Quizás la más utilizada hoy en día es la instrucción RDRAND
de Intel, disponible en todas las CPU modernas x86. La implementación de RDRAND
ha sido analizada ampliamente y generalmente se considera una buena fuente de aleatoriedad. Es particularmente útil cuando necesita una buena semilla y no está dispuesto a esperar /dev/random
, que bloquea hasta que reúne suficiente entropía. Sin embargo, como con cualquier RNG, la ausencia de fallas y puertas traseras realmente no se puede probar. Por lo tanto, algunas personas argumentan que es más seguro confiar en implementaciones de software de código abierto que han sido analizadas en busca de errores (que tal vez sean más fáciles de encontrar que los troyanos de hardware) y en diversas fuentes de entropía.