Permítanme disculparme de antemano, porque esto es un poco difícil de entender ...
En primer lugar, ya sabes que java.util.Random
no es completamente aleatorio en absoluto. Genera secuencias de una manera perfectamente predecible a partir de la semilla. Tiene toda la razón en que, dado que la semilla tiene solo 64 bits de longitud, solo puede generar 2 ^ 64 secuencias diferentes. Si de alguna manera generara 64 bits aleatorios reales y los usara para seleccionar una semilla, no podría usar esa semilla para elegir aleatoriamente entre todos de los 52! posibles secuencias con igual probabilidad.
Sin embargo, este hecho no tiene ninguna consecuencia , siempre y cuando no vayas a generar más de 2 ^ 64 secuencias, siempre que no haya nada 'especial' o 'notablemente especial' sobre las secuencias 2 ^ 64 que pueda generar .
Digamos que tenía un PRNG mucho mejor que utilizaba semillas de 1000 bits. Imagine que tiene dos formas de inicializarlo: una forma lo inicializaría utilizando toda la semilla, y una forma la reduciría a 64 bits antes de inicializarla.
Si no sabía qué inicializador era cuál, ¿podría escribir algún tipo de prueba para distinguirlos? A menos que haya tenido la (des) suerte de terminar inicializando al malo con el mismo 64 bits dos veces, la respuesta es no. No podría distinguir entre los dos inicializadores sin un conocimiento detallado de alguna debilidad en la implementación específica de PRNG.
Alternativamente, imagine que el Random
clase tenía una matriz de 2 ^ 64 secuencias que se seleccionaron completamente y al azar en algún momento en el pasado distante, y que la semilla era solo un índice en esta matriz.
Entonces, el hecho de que Random
use solo 64 bits para su semilla no es necesariamente un problema estadístico, siempre que no haya una posibilidad significativa de que use la misma semilla dos veces.
Por supuesto, para propósitos criptográficos , una semilla de 64 bits simplemente no es suficiente, porque hacer que un sistema use la misma semilla dos veces es computacionalmente factible.
EDITAR:
Debo agregar que, a pesar de que todo lo anterior es correcto, la implementación real java.util.Random
no es asombrosa. Si está escribiendo un juego de cartas, tal vez use la MessageDigest
API para generar el hash SHA-256 "MyGameName"+System.currentTimeMillis()
y use esos bits para barajar el mazo. Según el argumento anterior, siempre y cuando sus usuarios no estén jugando realmente, no tiene que preocuparse porque eso currentTimeMillis
regrese mucho tiempo. Si los usuarios están realmente el juego, a continuación, utilizar SecureRandom
sin semilla.
Random
nunca son números aleatorios reales . Es un PRNG, donde P significa "pseudo". Para números aleatorios reales , necesita una fuente de aleatoriedad (como random.org).