Cómo generar un número realmente aleatorio (y qué tipo necesitas de verdad)
Actualizado: 2026-09-29
Quieres un número que nadie haya podido predecir. Las respuestas habituales a esta búsqueda fallan en dos cosas: que un navegador pueda medir aleatoriedad física, y que Math.random() sirva hasta que necesitas seguridad. Ninguna de las dos es cierta. Esta guía separa los tres mecanismos a los que llamamos “aleatorios”, resuelve el sesgo modular con aritmética que puedes comprobar en papel, nombra la función correcta en Python, C++, JavaScript y MATLAB, y dice qué hace el generador enlazado — y dónde se detiene.
La respuesta corta
Elige el generador según lo que te cuesta que alguien adivine tu número. Si adivinarle cuesta algo —una cuenta, una clave, un sorteo justo—, usa el generador criptográficamente seguro de tu plataforma: crypto.getRandomValues en el navegador, el módulo secrets de Python, o la fuente de entropía del sistema operativo en la que los dos se apoyan. Si adivinar no cuesta nada —tirar un dado en un juego, una ejecución de Monte Carlo—, un generador pseudaleatorio ordinario con semilla es más rápido y reproducible, que es lo que quieres ahí.
Dos reglas cazan la mayoría de los errores reales. Nunca uses Math.random() ni el rand() de C para producir un secreto. Y nunca reduzas un valor aleatorio más ancho a tu rango con el operador resto y lo des por terminado, porque eso introduce sesgo modular — la razón por la que la herramienta enlazada vuelve a sortear valores en lugar de fiarse de un único resto.
- Secreto, token, clave, o un sorteo que alguien pueda impugnar: el CSPRNG de la plataforma, siempre.
- Simulación, muestreo, o cualquier cosa que quieras ejecutar dos veces con el mismo resultado: un generador con semilla.
- Aleatoriedad física real: hardware o un servicio de entropía, algo inalcanzable desde una página web.
- La herramienta enlazada es el caso del navegador: enteros uniformes sobre un rango inclusivo, desde el CSPRNG del sistema operativo, con muestreo por rechazo, hasta 500 por ejecución.
Tres cosas distintas a las que llamamos aleatorias
Una sola palabra cubre tres mecanismos con tres garantías distintas. Léelos como una escalera de imprevisibilidad.
La aleatoriedad real viene de la física
Un generador de números verdaderamente aleatorios muestrea un proceso físico cuyo resultado no queda resuelto por nada que puedas medir: ruido térmico en una resistencia, el instante de una desintegración radiactiva, ruido atmosférico captado por un receptor de radio, jitter de un oscilador. Existe hardware para esto, los fabricantes de chips lo exponen como una instrucción o un periférico, y servicios públicos emiten ruido atmosférico muestreado a quien lo pida. El resultado es imprevisible en principio: ninguna cantidad de computación lo recupera. Pero las fuentes brutas no son uniformes: su electrónica deja ligeramente más de un símbolo que del otro, así que los generadores de hardware acondicionan las muestras mediante un extractor de aleatoriedad antes de que alguien llame aleatoria a la salida.
Pseudoaleatoriedad criptográficamente segura
Un CSPRNG es un algoritmo determinista que mantiene un estado interno secreto, sembrado una vez con entropía real y luego avanzado por computación. El sistema operativo obtiene esa semilla de fuentes que puede observar —temporización de interrupciones, intervalos de llegada del teclado y del ratón, ruido de hardware cuando un controlador lo expone— en un pool protegido por el kernel. Cada llamada a crypto.getRandomValues extrae de ese pool, o de un generador que el sistema operativo siembra desde él.
La garantía es práctica y no filosófica: un atacante que observe un tramo largo de salida sigue sin poder deducir el estado, así que no puede predecir el siguiente valor ni reconstruir los anteriores. Esa es la propiedad que necesitan las claves y los tokens, y es la razón por la que este nivel, y no el de la física, es el que alcanza el software cotidiano.
Pseudoaleatoriedad ordinaria
Un generador común es la misma construcción con el requisito de seguridad eliminado: una recurrencia determinista sobre un estado fijo, elegida por velocidad y calidad estadística. El módulo random de Python implementa el Mersenne Twister, que distribuye de maravilla y es totalmente predecible en cuanto un observador recoge suficientes salidas consecutivas como para resolver su estado.
Estas son las herramientas correctas para simular: rápidas, comprobables contra baterías estadísticas y configurables —misma semilla, misma corriente—. Eso es una ventaja en un experimento de Monte Carlo y un desastre en un token de sesión, y es la distinción que la gente más a menudo tiene al revés.
Lo que un navegador te puede dar honradamente
Primero, sin rodeos: una página web no puede cosechar entropía física. JavaScript no puede muestrear una fuente de ruido, no tiene ninguna instrucción para leer aleatoriedad de hardware y no puede medir la temporización de los electrones. Todo lo que un navegador te entrega vino de un algoritmo cuyo estado sembró el sistema operativo.
Lo que un navegador sí puede darte es el CSPRNG del sistema operativo, envuelto como crypto.getRandomValues, que rellena una matriz tipada con bytes o palabras de 32 bits desde el pool del kernel. Web Crypto expone exactamente una primitiva y es la criptográfica, así que no hay una llamada más débil en la que tropezar, y la página de la herramienta enlazada la describe como la misma primitiva que se usa para contraseñas y claves de cifrado.
Para todos los propósitos de quien lee esta página, la respuesta respaldada por un CSPRNG es la respuesta correcta. Un sorteo, un identificador de sesión, una contraseña acuñada en tu portátil: ninguno necesita desintegración radiactiva, y todos los sirve un generador que un atacante no puede predecir. Las páginas que anuncian “aleatoriedad real” desde una pestaña son descuidadas o deshonestas; la afirmación exacta es “imprevisible para quien no haya comprometido ya tu sistema operativo”, y eso es suficiente.
Por qué Math.random() no es para secretos
La objeción es mecánica. Math.random() es una función determinista de un estado interno: el motor mantiene un bloque de números, aplica una recurrencia fija para avanzarlos, devuelve un resultado formateado y no consulta nada externo entre medias. La secuencia queda implícita en el estado, así que la única pregunta es si un observador puede encontrarlo.
Durante mucho tiempo la respuesta fue cómodamente que sí. Los generadores que usaban los navegadores eran diseños estadísticos de estado pequeño cuya salida filtra estructura: un puñado de valores consecutivos basta para plantear ecuaciones cuya solución es el estado. Con el estado avanzas la recurrencia hacia delante para predecir cada extracción posterior y hacia atrás para recuperar cada anterior —el modo de fallo documentado que hizo que los navegadores abandonaran esos diseños—.
Hay una segunda capa. Nunca ves el estado, así que no puedes comprobar que ese estado haya sido jamás imprevisible, y un generador sembrado con pereza desde un reloj grueso tiene un espacio de búsqueda que un atacante enumera.
crypto.getRandomValues está construido al revés: observar la salida no ayuda a reconstruir el estado, así que adivinar tu número cuesta un trabajo proporcional al rango y no a unas pocas muestras.
El sesgo modular, con números que puedes comprobar
La parte que muchos artículos equivocan u omiten es aritmética que puedes comprobar a mano. Supón que tu fuente emite un byte uniforme —uno de 256 valores, 0 hasta 255, cada uno con probabilidad 1 entre 256— y quieres un dígito uniforme de 0 a 9. La línea tentadora es el resto al dividir entre 10.
Cuenta cuántos valores de byte caen en cada dígito. 256 entre 10 es 25 con resto 6; exactamente, 256 = 25 × 10 + 6. Cada dígito recibe 25 valores y sobran 6 en la parte alta del rango, y esos caen sobre los dígitos más bajos: los resultados 0 hasta 5 obtienen 26 valores de soporte cada uno, los resultados 6 hasta 9 obtienen 25. El total cuadra, ya que 6 × 26 es 156, 4 × 25 es 100 y 156 + 100 = 256.
Un dígito favorecido tiene probabilidad 26/256, que es 0.1015625; un dígito desfavorecido 25/256, que es 0.09765625; un sorteo justo sería 0.1 para cada uno. Los dígitos favorecidos son 26/25 veces más probables que los demás, y 26/25 es exactamente 1.04: un cuatro por ciento más probable.
Cuándo el sesgo deja de ser académico
Un cuatro por ciento es suave. El sesgo se vuelve serio cuando tu rango es una fracción grande de la fuente, porque entonces hay pocas pasadas completas y el bloque sobrante es proporcionalmente enorme. El generador enlazado extrae palabras de 32 bits, así que su fuente tiene 2^32 valores, que son 4,294,967,296.
Caso amable: un dado de seis caras, mínimo 1 y máximo 6, tamaño de rango 6. División: 4,294,967,296 = 6 × 715,827,882 + 4. Un resto a secas favorece cuatro caras —las caras 1 hasta 4 salen de 715,827,883 entradas cada una, las caras 5 y 6 de 715,827,882—. Una parte por mil millones aproximadamente, que es la razón por la que ningún juego de mesa se ha amañado así.
Caso adversario: un índice de lotería de 0 a 2,147,483,646, un rango de 2^31 − 1 valores. El doble de ese rango es 4,294,967,294, que es 2 menos que 4,294,967,296, así que un resto da a los dos primeros boletos 3 probabilidades cada uno y a todos los demás 2: una ventaja del 50 %, ya que 3/2 es exactamente 1.5.
Muestreo por rechazo: la solución
Descarta la cola incómoda en vez de plegarla. En el caso del byte, 250 = 25 × 10 divide exactamente, así que quédate solo con las entradas 0 hasta 249 y vuelve a sortear siempre que saques 250 o más. Cada entrada aceptada mapea entonces a un dígito mediante exactamente 25 valores, y 25/250 es exactamente 0.1. El coste es una probabilidad de nuevo sorteo de 6/256 por intento, que es insignificante y termina con certeza.
El generador enlazado hace lo mismo a 32 bits. Calcula limit = Math.floor(4294967296 / range) * range —el múltiplo más grande de tu rango que cabe en la fuente—, extrae una palabra, vuelve a sortear mientras el valor sea mayor o igual que ese límite, y devuelve min + (x % range). Para el dado, limit es 6 × 715,827,882, que es 4,294,967,292, así que se rechazan exactamente las cuatro entradas más altas, y la probabilidad de nuevo sorteo es 4 entre 4,294,967,296, o 1 entre 1,073,741,824. Acondicionado a la aceptación, cada cara tiene 715,827,882 entradas de soporte y 6 × 715,827,882 = 4,294,967,292, así que cada cara es exactamente un sexto. El propio texto de la herramienta lo afirma sin el álgebra: un valor extraído fuera del mayor múltiplo de tu rango que cabe en 32 bits se descarta y se vuelve a sortear, y eso elimina el sesgo modular.
Uniforme, con semilla, reproducible: tres ideas separadas
“Número aleatorio” también esconde una pregunta de forma: la distribución, la semilla y si una ejecución puede repetirse.
La uniformidad es una propiedad de la distribución
Una extracción uniforme significa que cada valor de tu rango tuvo la misma probabilidad: el dado, el sorteo, el índice aleatorio. Una extracción no uniforme modela las probabilidades a propósito: ruido de medición normal, huecos exponenciales entre llegadas, muestreo ponderado donde el elemento A es tres veces más probable que el elemento B. La simulación gasta la mayor parte de su esfuerzo en el caso no uniforme, y la técnica estándar es partir de una corriente uniforme y transformarla.
La herramienta enlazada es solo uniforme sobre un rango de enteros: una campana de Gauss, una elección ponderada o un decimal son otro trabajo.
Qué es realmente una semilla
La semilla es el estado inicial de un generador determinista. Mismo generador, misma semilla, misma secuencia de salidas, para siempre. Fijar una semilla no añade aleatoriedad; fija el punto de partida de una computación para que la ejecución pueda repetirse.
Por eso los generadores con semilla son queridos en simulación: un colega repite tu experimento y obtiene tus números, un artículo publica su semilla para que se revise. La predictabilidad es el objetivo, y un CSPRNG sin semilla estorba porque no puedes mostrar la secuencia detrás de tu conclusión.
Por qué la reproducibilidad es el objetivo equivocado para secretos
Gira esa propiedad y es la vulnerabilidad: un generador de secretos reproducible es un generador adivinable. Quien conozca o adivine la semilla regenera cada valor que emitiste, en orden, y un secreto que cualquiera puede regenerar no es un secreto.
Así que las herramientas que acuñan claves y tokens se niegan a exponer semillas. El generador enlazado no tiene entrada de semilla ni forma de repetir una ejecución; cada extracción sale fresca del pool del sistema operativo, y el estado vive en el kernel y no en la página.
En Python, C++, JavaScript y MATLAB
Cada variante lingüística de esta búsqueda tiene la misma respuesta bajo la sintaxis: usa el generador criptográficamente seguro de la plataforma, no el de juguete. En dos de estos lenguajes la biblioteca estándar no proporciona uno completo.
Python reparte el trabajo a propósito. random es el módulo pseudaleatorio —basado en Mersenne Twister, correcto para juegos y simulación, documentado como inadecuado para seguridad—. Para secretos usa el módulo secrets: secrets.randbelow(n) devuelve un valor uniforme entre 0 y n−1 desde la fuente de entropía del sistema operativo, y secrets.token_urlsafe cubre los tokens. Para una simulación reproducible, siembra con random.seed(1234) y quédate en random.
C++ no tiene CSPRNG en su biblioteca estándar, que es la respuesta honesta al autocompletado. std::random_device es la manija prevista sobre entropía no determinista y lo correcto con que sembrar un motor, pero su comportamiento depende de la implementación: en algunas cadenas de herramientas pasa directamente a la fuente del sistema operativo, en otras cae a un motor pseudaleatorio con semilla, puede bloquearse mientras el pool del kernel se llena al principio del arranque, y no se garantiza la uniformidad de los resultados individuales. std::mt19937 es explícitamente un generador estadístico, y el rand() heredado de C no es uniforme bajo un resto ni imprevisible. Cuando de verdad importe, llama a la API de entropía de la propia plataforma o a una biblioteca criptográfica auditada.
JavaScript en el navegador es una sola llamada: crypto.getRandomValues sobre una matriz tipada, que es lo que usa la herramienta enlazada, y ese mismo global existe en Node y Deno. Para un entero sin sesgo, acompáñalo de muestreo por rechazo en lugar de multiplicar un flotante.
MATLAB merece una línea porque quienes lo buscan piden “un número real aleatorio” y “números realmente aleatorios”. Sus funciones de propósito general —rand, randi, randn, con rng controlando la semilla— son pseudaleatorias por diseño: deterministas, sembrables, estadísticamente excelentes, pensadas para trabajo numérico reproducible. Una fuente de entropía real es otra cosa, y conseguirla significa acudir a una prestación del sistema operativo o a un servicio externo.
La regla que cubre los cuatro: el CSPRNG de la plataforma cuando que te predigan te perjudica, el generador estadístico con semilla cuando que te predigan te ayuda. No hay término medio.
Para qué necesitas aleatoriedad, y qué se rompe cuando es débil
Claves, contraseñas y cualquier cosa derivada de ellas. Aquí la debilidad es aritmética: un atacante enumera el espacio plausible, y cada extracción uniforme independiente de m valores añade log2(m) bits —un byte añade 8 bits porque 2^8 = 256, mientras que diez valores añaden un poco más de 3, ya que log2(10) es alrededor de 3.32—. Cuatro dígitos son menos de 14 bits, que son diez mil conjeturas que enumerar; treinta y dos bytes son 256 bits, que nadie enumera. Un generador con estado reconstruible, o una semilla tomada de un reloj, colapsan esa cifra al tamaño de la semilla.
Tokens: identificadores de sesión, enlaces de restablecimiento, claves de API. Dos formas de perder. La predictabilidad permite a un atacante falsificar el siguiente token en vez de encontrar el tuyo. La colisión es más sutil: los tokens salen de un pool finito, así que emitir muchos cortos acaba dando a dos usuarios la misma cadena, y la sesión autenticada de uno se convierte en la de otro. Dimensiona el token para el volumen que emites y extráelo de un CSPRNG.
Sorteos y loterías —rifas, selección de alumnos, muestreo de auditoría—. El requisito es la defensabilidad y no el secreto: después alguien pregunta si el proceso pudo favorecer a un participante, y necesitas una respuesta. El sesgo modular es la forma clásica en que un sorteo bienintencionado se vuelve injusto, y la predictabilidad es la forma en que se amaña de antemano. Usa el generador criptográfico con muestreo por rechazo, conserva la lista de participantes y la salida, y no dejes que el ganador haya escrito el guion.
Muestreo y simulación —integración de Monte Carlo, bootstrap, tráfico de pruebas de carga—. Aquí quieres calidad estadística y reproducibilidad, y un CSPRNG falla en las dos direcciones: más lento e incapaz de repetir una ejecución. Usa un generador estadístico con semilla y registra la semilla. Para aleatoriedad puramente cosmética, no se rompe nada.
Modos de fallo habituales
Cuatro patrones explican la mayor parte de la aleatoriedad rota en código real, y los cuatro parecen perfectos en una prueba rápida.
Inventar tu propio barajado. La versión tentadora —para cada posición, intercambiar con un elemento elegido de cualquier parte del array— tiene sesgo y hace que algunos órdenes sean más probables que otros. El recorrido Fisher–Yates correcto intercambia cada elemento con una posición extraída uniformemente en ella o después, y si el orden protege algo, esas extracciones necesitan el CSPRNG. La versión chapucera no se puede afinar hasta la corrección: elegir un índice para cada una de n posiciones produce n^n caminos igualmente probables, que se reparten exactamente entre los n! órdenes solo si n! divide a n^n, y para una baraja de 52 cartas no lo hace —52^52 tiene solo 2 y 13 como factores primos, mientras que 52! incluye 3—.
rand() % n, o cualquier resto sobre una fuente que no divide. Los resultados bajos acumulan las sobras, el sesgo es invisible en el uso casual y es decisivo cuando el rango es una fracción grande de la fuente. El muestreo por rechazo es la solución, no una fuente más ancha: 10 tampoco divide a 65,536.
Sembrar desde el reloj. Una semilla de marca de tiempo deja un espacio de búsqueda que puedes enumerar: un atacante que sabe que tu token apareció durante un minuto dado prueba las cerca de 60 semillas de ese minuto y adelanta cada generador. Sembrar desde el reloj también colisiona: dos procesos iniciados juntos reciben la misma semilla y emiten corrientes idénticas.
Reutilizar una semilla, o una sola corriente para dos propósitos. Misma semilla, misma secuencia, así que dos componentes sembrados igual producen valores que coinciden, y recuperar uno recupera el otro. Extrae de forma independiente, por propósito, desde el CSPRNG, y si tu diseño necesita que dos valores difieran, comprueba que difieran en vez de esperar que las extracciones independientes no se encuentren.
El generador enlazado: qué hace y dónde se detiene
La herramienta detrás de este botón es el caso del navegador, construida como argumentan las secciones de arriba. Fijas un mínimo y un máximo inclusivos y un número de enteros; extrae cada valor con crypto.getRandomValues en un Uint32Array y aplica muestreo por rechazo —limit = Math.floor(4294967296 / range) * range, se vuelve a sortear mientras la palabra sea mayor o igual que ese límite—, y luego devuelve min + (x % range). En la salida, ningún valor es más probable por la posición que ocupa dentro de tu rango.
Los controles son deliberadamente pequeños. Los extremos son inclusivos, así que 1 a 6 es un dado, y máximo igual a mínimo está permitido. Los negativos valen, y las entradas de los extremos son texto sin límite. Los resultados se imprimen uno por línea o separados por comas, y un botón Copiar los deja en el portapapeles. Un modo opcional sin duplicados mantiene cada valor en un conjunto y vuelve a sortear hasta llenarlo, y da error cuando pides más valores de los que el rango contiene. Lo que no hará es la parte honesta.
- Solo enteros: nada de decimales ni flotantes; un real uniforme en un intervalo es otra herramienta.
- Solo uniforme: sin extracciones ponderadas, normales ni exponenciales.
- Hasta 500 números por ejecución; el propio consejo de la herramienta para necesitar más es ejecutarla varias veces y combinar las salidas.
- Sin control de semilla y sin ejecuciones reproducibles, a propósito: una ejecución que tú puedes repetir es una ejecución que otro también puede repetir.
- Sin listas de exclusión; no puedes extraer de 1 a 100 saltando los múltiplos de 5.
- No se admiten rangos que abarquen más de 2^32 valores, ya que el límite de rechazo asume una fuente de 32 bits.
- Nada se guarda, exporta ni descarga: cierra la pestaña y los números desaparecen.
- La lógica de generación en sí no hace ninguna petición: solo criptografía, DOM y APIs de portapapeles; pero el sitio carga scripts de terceros, así que la página no está libre de red y no presume de estarlo.
Preguntas frecuentes
¿Se puede generar de verdad un número verdaderamente aleatorio en un sitio web?
En el sentido físico, no, y ninguna página puede honradamente: una pestaña del navegador no puede muestrear ruido térmico, desintegración radiactiva ni ruido atmosférico. Lo que sí puede es llamar al generador criptográficamente seguro del sistema operativo mediante crypto.getRandomValues, que devuelve bytes de un pool que el kernel sembró con entropía real. Eso es imprevisible frente a cualquier atacante que no pueda leer el estado de tu kernel, y para claves, tokens, sorteos y muestreos es la respuesta correcta.
¿Por qué Math.random() no basta para una contraseña o un token?
Porque es determinista: avanza un estado interno con una recurrencia fija y no consulta nada externo, así que toda la corriente queda implícita en ese estado, y los generadores de esta clase han sido reconstruidos a partir de un puñado de salidas observadas. Las implementaciones de los navegadores se han endurecido desde entonces, pero la especificación sigue sin exigir imprevisibilidad, así que estarías apoyando un secreto en una promesa que nadie hizo. Usa crypto.getRandomValues.
¿Qué es el sesgo modular, en breve?
Reducir un valor aleatorio más ancho a tu rango con el operador resto favorece los resultados bajos siempre que el tamaño de la fuente no sea múltiplo de tu rango, porque las entradas sobrantes caen sobre ellos. Reducir un byte uniforme a 0 hasta 9 deja seis dígitos con 26 entradas de soporte cada uno y cuatro dígitos con 25 cada uno, así que esos seis son 26/25 tan probables como los demás: un 4 % más probables. El muestreo por rechazo lo arregla: descarta las entradas mayores o iguales que el mayor múltiplo de tu rango que cabe en la fuente y vuelve a extraer.
¿crypto.getRandomValues es un generador de números aleatorios de hardware?
No. Un generador de hardware transduce un proceso físico en bits y necesita acondicionamiento para volverse uniforme; crypto.getRandomValues devuelve bytes del pool de entropía del sistema operativo, que el kernel mezcla con fuentes que la máquina expone —ruido de hardware cuando un controlador lo aporta, eventos de temporización entre otros— y sirve a través de una construcción criptográfica. Ambos son imprevisibles para un atacante externo, y la interfaz del sistema operativo es la que tu software puede alcanzar.
¿Cómo obtengo un número aleatorio en Python?
Dos módulos, elegidos por amenaza. Para cualquier secreto, importa secrets y usa secrets.randbelow(n) para un valor uniforme por debajo de n, o secrets.token_urlsafe para un token; lee la fuente de entropía del sistema operativo. Para un juego o una simulación, usa el módulo random, un Mersenne Twister: estadísticamente excelente, sembrable con random.seed para que la ejecución se repita exactamente, y explícitamente no apto para seguridad.
¿Cómo obtengo un número verdaderamente aleatorio en C++?
C++ no tiene CSPRNG en su biblioteca estándar. std::random_device es la manija estándar sobre entropía no determinista, pero su comportamiento depende de la implementación: puede bloquearse, puede ser un paso directo a la fuente del sistema operativo o un motor pseudaleatorio de reserva según la cadena de herramientas, y no se garantiza que los resultados individuales sean uniformes. Siembra std::mt19937 desde él para trabajo estadístico; para material de seguridad usa la API de entropía de la plataforma o una biblioteca criptográfica auditada.
¿Y un número realmente aleatorio en MATLAB?
Las funciones de propósito general de allí —rand, randi, randn, con rng para sembrar— son pseudaleatorias por diseño: deterministas y reproducibles, que es lo que el trabajo numérico quiere. No son fuentes de entropía. La entropía real significa sacarla de una prestación del sistema operativo o de un servicio externo e incorporarla.
¿El generador enlazado puede darme decimales o números que saltarse?
No. Solo enteros, de forma uniforme, en un rango inclusivo, sin listas de exclusión y sin ponderaciones. Un número real aleatorio en un intervalo, una elección ponderada o una distribución normal son otra herramienta.
¿Puedo sembrar el generador enlazado para obtener los mismos números otra vez?
No, y a propósito. No hay entrada de semilla, así que una ejecución no se puede repetir: cada valor sale fresco del CSPRNG del sistema operativo. La reproducibilidad es lo que quieres en una simulación y lo que no debes tener en un secreto, porque quien puede regenerar una secuencia puede reproducirla. Usa un generador estadístico con semilla cuando necesites secuencias repetibles.
¿Por qué se detiene en 500 números y si mis números quedan guardados?
500 es el límite por ejecución para una tanda; la sugerencia de la propia herramienta para necesitar más es ejecutarla varias veces y combinar las salidas. No se guarda nada: sin historial, sin exportación, sin descarga de archivos, sin copia en el servidor —la página dice que cierras la pestaña y los números desaparecen—. La lógica de generación no hace ninguna petición propia, aunque el sitio carga scripts de terceros, así que considera que la propiedad de funcionar sin red pertenece a la generación y no a toda la página.