¿Cuál es la semilla más pequeña y más simple para un generador de números aleatorios?

40

Un pequeño microcontrolador (Atmel de 8 bits) controla una serie de luces para presentar un espectáculo de luces con muchas secuencias de luces aleatorias elegantes.

Un pseudo-RNG adecuado hace bien su trabajo, pero estoy buscando una buena semilla para él. Será necesaria una semilla porque si alguien enciende múltiples dispositivos de este tipo al mismo tiempo, no se verá bien si todos generaron las mismas secuencias de efectos hasta que se separen lentamente debido a las pequeñas diferencias en sus fuentes de reloj individuales.

Un método muy bueno para sembrar un pseudo-RNG, que solía usar, es posible en el caso de un dispositivo que debe iniciarse presionando un botón o presionando un interruptor. Tan pronto como se enciende el µc, se puede iniciar un temporizador muy rápido, y el valor de este temporizador genera el RNG tan pronto como se presiona el botón por primera vez.

El problema es que, en este escenario, no hay botones. El programa debe iniciarse tan pronto como se encienda el dispositivo.

El lugar en la PCB es extremadamente limitado (nada más que algunas de las piezas SMD más pequeñas pueden caber), por lo que estoy buscando la solución más pequeña y simple posible. Por lo tanto, descartaré soluciones sofisticadas como hardware RNG verdadero, receptores de radio, etc.

Todo lo que tengo es un contador de temporizador de 16 bits en la CPU y un portpin no utilizado que tiene acceso a un ADC.

Mi solución actual es usar una resistencia (lo más inexacta posible) para proporcionar aproximadamente la mitad del voltaje de alimentación al pin ADC, y sembrar el RNG con el primer valor de conversión AD. Sin embargo, hoy en día la mayoría de las resistencias del 10% tienen una imprecisión muy por debajo del 1% (sería divertido imaginar la cara de un proveedor cuando les digo que queremos las resistencias SMD de peor calidad que puedan encontrar), por lo que hay una gran probabilidad de unidades múltiples que comienzan con la misma semilla.

Una mejor alternativa sería hacer conversiones múltiples y construir un valor a partir de los bits menos significativos de estas mediciones. Sin embargo, usé el ADC de este tipo µc antes y sé que es muy preciso. Ejecutar el ADC a la velocidad más rápida posible podría ayudar aquí.

¿Alguien tiene una mejor sugerencia? No es necesario que la semilla esté distribuida de manera perfectamente uniforme, pero cuanto más uniforme sea la distribución, mejor. Una semilla de 16 bits con una distribución perfectamente uniforme sería un sueño demasiado bueno para ser verdad, pero creo que una distribución media decente de más de 5 o 6 bits podría ser suficiente.

vsz
fuente
12
"Sería divertido imaginar la cara de un proveedor cuando les digo que queremos las resistencias SMD de peor calidad que puedan encontrar". Sería aún más divertido dejar que el valor de esta resistencia no esté definido en el diagrama del circuito, y decirle al personas en producción que esta parte debe soldarse manualmente después de que la PCB salga de la máquina de colocación, de un contenedor donde mezclamos todos los valores de resistencia que tenemos. - Porque no estoy buscando un RNG, sino una semilla . Entonces, si genera el mismo valor casi cada vez que no es tan malo, es más importante ser diferente en todos los dispositivos.
vsz
8
¿Por qué no escribir un valor aleatorio en el almacenamiento EEPROM durante la programación de producción? De esta manera, puede usar el RNG más elegante que desee, ya que solo estará en los programadores de producción y no en los dispositivos finales. (Crédito a @immibis: su 'archivo de software ligeramente diferente' me dio la idea.)
Calrion
2
Entonces, para ser claros al 100%, el problema es que podrían comenzar en la misma secuencia, no que podrían separarse con el tiempo, ¿correcto?
wedstrom
2
La elección de su RNG es importante: algunos necesitan semillas de buena calidad, otros no. Por ejemplo, para Xorshift, cualquier semilla que no sea 0 funcionará y funcionará igual de bien. Incluso una pequeña diferencia en la semilla inicial dará como resultado una posición inicial muy diferente en el ciclo del RNG.
curiousdannii
3
Puede combinar todas las respuestas de ADC con estadísticas y tiempos para obtener aún más aleatoriedad. Por ejemplo, mida cuántos ticks de procesador se necesitan hasta que tome N muestras donde los 3 LSB inferiores son 101, y M muestras donde los 3 LSB inferiores son 110. Expanda este concepto como desee.
wjl

Respuestas:

24

Coloque una resistencia paralela y un capacitor entre el pin A / D y tierra. Haga que la resistencia sea bastante alta, preferiblemente muy por encima del requisito de impedancia de la señal de entrada para A / D. Haga que el tiempo RC sea constante, tal vez alrededor de 10 µs. Por ejemplo, 100 kΩ y 100 pF suena como una buena combinación.

Para obtener un valor con cierta aleatoriedad, suba el pin por un tiempo, luego ajústelo a alta impedancia y tome una lectura A / D unos µs más tarde. Particularmente si abusa adecuadamente del tiempo de adquisición de A / D, el voltaje que verá dependerá de los valores R y C, la corriente de fuga del pin, otro ruido cercano y la temperatura.

Tome el bit bajo o los dos bits bajos y repita según sea necesario para obtener cualquier cantidad de bits aleatorios.

Para un patrón más aleatorio, realice este procedimiento ocasionalmente e inyecte el bit bajo del resultado A / D en el generador de números aleatorios que ya está utilizando.

Olin Lathrop
fuente
Esto suena bien. Asegúrese de verificar la impedancia de entrada en el ADC: la serie Atmega8 tiene una impedancia de entrada analógica de 100Meg que hace que el valor de la resistencia de Olin sea un poco bajo.
stefandz
3
@stef: la impedancia de entrada y la impedancia de señal requerida para la conversión correcta son dos cosas diferentes. Sí, la impedancia de entrada es muy alta debido a que es CMOS. Sin embargo, hay un límite máximo de impedancia en la señal para permitirle cargar la muestra y mantener la tapa dentro del tiempo especificado, y para superar cualquier fuga que pueda tener el pin.
Olin Lathrop
2
lo siento, por su respuesta, pensé que estaba haciendo referencia a la impedancia de entrada en lugar de la especificación de la impedancia de la fuente. 10k es la impedancia de fuente máxima especificada de Atmega8, por lo que su respuesta es acertada. Como referencia, la tapa S / H en el interior es de 14pF, en caso de que alguien esté interesado.
stefandz
2
@stef: edité la respuesta para aclarar esto.
Olin Lathrop
Te perdiste la fase lunar y los días festivos. También agite a mano una adición útil, especialmente si tiene una C baja y no está bien protegida.
Russell McMahon
23

Algunas opciones posibles:

  1. Preprograme una dirección de serie única para cada dispositivo. Si tiene un algoritmo RNG lo suficientemente bueno, incluso una lista secuencial de direcciones en serie producirá resultados muy diferentes.

  2. Dependiendo de su MCU / configuración, puede tener dos fuentes de reloj diferentes disponibles para el reloj del sistema y la entrada del temporizador de vigilancia / contador de temporizador. Si uno / ambos tienen una variación significativa, puede usar esto para generar una semilla adecuadamente diferente. Aquí hay un ejemplo que escribí que usa un temporizador de vigilancia interno de Arduino y un reloj del sistema XTAL externo .

  3. Use un transistor BJT y construya un amplificador altamente dependiente de beta. Esto se puede leer de un ADC para la semilla.

  4. Los condensadores / inductores generalmente se especifican con una tolerancia mucho peor que las resistencias. Puede construir algún tipo de circuito de filtro (RC, RL, LC) con estos y medir la salida con el ADC.

helloworld922
fuente
55
Voto por la opción 1, es una solución de recuento cero que dará como resultado que las secuencias nunca tengan que coincidir. El número de serie y el generador RND pueden decir 16 bits, lo que hace que cualquier dispositivo tenga una posibilidad insignificante de imitar el patrón de otro.
KalleMP
1
También me gusta la solución. Si usa un algoritmo de hash simple, debería estar bien incluso si tiene números de serie secuenciales.
magu_
66
Lo bueno de la opción 1 es que algunos dispositivos vienen con números de serie integrados (generalmente micros relacionados con la red / RF), por lo que ni siquiera necesita un paso separado para grabar los números de serie
slebetman
3
Incluso un generador de números aleatorios de basura como un LCG será "tremendamente producir resultados diferentes para una lista secuencial de direcciones de serie" . Yo voto por 1 también.
BlueRaja - Danny Pflughoeft
3
Si tiene una fuente de tiempo, usar eso como base para su cambio en la semilla ayudaría a compensar las cosas entre las ejecuciones. Combine esto con una dirección / número de serie o la dirección MAC si su dispositivo tiene uno y también arreglará la coincidencia entre dispositivos. He visto algún software que almacena de manera persistente algunos o todos los números aleatorios generados para su uso como semilla, incluso después de un reinicio. Si sus dispositivos tienen diferentes tiempos de funcionamiento, deberían separarse.
TafT
8

Memoria no inicializada

Puede intentar usar la memoria no inicializada en el microcontrolador. El truco es encontrar los bits que tienen los flip-flops más 'balanceados', y que en realidad son aleatorios. El procedimiento consiste en leer toda la memoria, restablecer y repetir varias veces para medir qué bits son verdaderamente aleatorios. ¡Luego usa este mapa para leer suficientes bits aleatorios para sembrar tu PRNG o LFSR!

Este método le debe dar semillas aleatorias, incluso con hardware idéntico, más detalles (y enlaces) están disponibles en este Hack-a-día artículo

Me gusta este método porque no requiere ningún circuito adicional o pines; su AVR ya tiene ram, solo necesita encontrar los bits inestables (aleatorios). También el procedimiento de mapeo podría ser automatizado; ¡puede aplicar el mismo código y procedimiento a cada dispositivo y obtener resultados verdaderamente aleatorios!

esoterik
fuente
1
Realmente no necesitas descubrir qué bits son aleatorios. Hacer XOR de todos los bytes le dará un resultado aleatorio incluso si solo 8 bits son aleatorios. Y como muestra la imagen, los valores reales pueden no ser aleatorios en un sentido temporal, son lo suficientemente únicos, que es exactamente lo que necesitamos aquí.
MSalters
1
Si puede encontrar un PRNG que le permita "mezclar" la entropía, entonces eso podría ser incluso mejor que la opción XOR-then-seed. Itere a través de la memoria no inicializada y mezcle los bytes con el PRNG. Por ejemplo, vea mi biblioteca C aleatoria simple: función de mezcla .
Craig McQueen
Esto no le dará aleatoriedad de calidad criptográfica.
@CamilStaps, por supuesto, no lo hará.
Navin
1
Esto no funcionará. La memoria no inicializada es un comportamiento indefinido si tengo un sistema operativo y no tengo ningún control sobre qué parte de la memoria se asignará a mi programa y qué estaba allí antes. En un microcontrolador sin sistema operativo, este no es el caso. Especialmente con AVR, porque allí toda la RAM será cero si ha pasado suficiente tiempo para que los condensadores se vacíen por el consumo de corriente en la caída de tensión.
vsz
7

Lo que hice para un reproductor de MP3 con capacidad aleatoria es usar una semilla secuencial diferente en cada encendido. Comencé en 1 y almacené esto en la EEPROM para que en el siguiente ciclo de energía utilizara 2, etc. Esto estaba en un ATMEGA168. Como señaló helloworld922, incluso una semilla secuencial simple generará secuencias pseudoaleatorias completamente diferentes.

Usé uno de los generadores de secuencia aleatoria congruentes lineales, esto da una distribución uniforme.

int i;
seed = seed * 2053 + 13849;
i = (seed % max) + 1;  // max is the maximum value I want out of the function

Por supuesto, si desea que varias unidades tengan secuencias diferentes a pesar de que hayan tenido el mismo número de ciclos de potencia, entonces necesita algo para comenzar al azar.

Esto podría hacerse por cualquiera de los métodos propuestos por los otros carteles: un método que se me ocurra podría utilizar el cruce de cero de CA que entra en el procesador si lo tiene (para el control de fase de la lámpara, por ejemplo). Esto podría usarse para muestrear el temporizador en el primer cruce después del encendido y luego usarlo como semilla.

¿Hay botones en la unidad para seleccionar el modo, etc.? Si es así, puede probar el contador la primera vez que se presiona el botón después de que se programa la MCU, puede generar una semilla aleatoria inicialmente y almacenarla en EEPROM. Cada Power-up después de este punto usaría la semilla almacenada.

Kevin White
fuente
5

Un ADC es una muy buena fuente de aleatoriedad.

No necesita confiar en las tolerancias de resistencia. Cualquier resistencia generará ruido térmico , y el mismo efecto físico introducirá ruido en el ADC al realizar todos los pasos de muestreo y conversión. (La hoja de datos le informará sobre la cantidad de ruido y qué ajustes de configuración son peores / mejores).

No debe dejar el pin ADC flotando; Esto puede dejar que el voltaje flote demasiado y se corre el riesgo de saturar la entrada.
(Muchas MCU le permiten usar algo como la mitad del voltaje de alimentación como entrada de ADC, para la calibración. Esto ahorra la resistencia externa y aún le produce ruido. Nuevamente, consulte la hoja de datos para ver la peor / mejor configuración).

No necesita confiar en una sola medición de ADC; Puede combinar varias mediciones con una simple función hash o de suma de verificación (CRC sería suficiente). Si necesita comenzar a usar el RNG de inmediato, más tarde puede combinar el resultado de ADC con la semilla de RNG actual.

CL.
fuente
2
No estoy seguro de que el ruido Johnson sea adecuado en esta aplicación; En STP, una resistencia de 10 Meg sobre un ancho 40uVde banda de 10 kHz tiene ruido Johnson. Necesitaría un ADC> 14 bit o un circuito amplificador para medir esto razonablemente.
helloworld922
STP no es realmente relevante. La temperatura especialmente podría elevarse intencionalmente, pero 60 grados adicionales sobre STP es solo un 10% de ruido adicional.
MSalters
1
Un enfoque similar sería utilizar el ruido de disparo en un diodo. en.wikipedia.org/wiki/Noise_generator#Shot_noise_generators
teambob
2

¿Se puede guardar la semilla de una sesión a otra? Si es así, ¿es factible encender cada unidad durante un período de tiempo aleatorio después de la creación? De esa forma, todas las unidades se enviarán con semillas preestablecidas que probablemente no sean las mismas.

Otro pensamiento: ¿Cómo se unen varias unidades para que se enciendan simultáneamente? Si están en serie, agregue algún tipo de condensador para que el (n + 1) dispositivo inicie algunos ciclos de reloj después del dispositivo n. Idealmente, los condensadores se descargarían muy rápidamente en el apagado del dispositivo, por lo que cada inicio / reinicio hay una brecha más grande entre las secuencias.

Si están en paralelo, aún puede aleatorizar un poco el tiempo de inicio. Supongo que hay algún tipo de filtración de energía usando condensadores. Si es así, la fabricación de dispositivos con circuitos de filtración ligeramente diferentes provocaría que cada dispositivo se inicie en un momento ligeramente diferente, lo que provocaría divergencias después de varios reinicios.

Una variación de esto es agregar variación a sus señales de reloj si es posible. Una diferencia del 0.1% en la velocidad del reloj podría tener poco impacto en el espectáculo de luces, mientras cambia la velocidad con la que recorre la tabla PRNG con bastante rapidez.

MichaelS
fuente
1
quizás conecte un vertido grande al análogo en el pin y tome algunas lecturas de "zumbido de red" para sembrar el RNG.
Jasen
1
@Jasen, todas las unidades conectadas al mismo cable de extensión verán el mismo zumbido de red.
Ian Ringrose
2

Si se ejecuta en una fuente de reloj interna "calibrada". ¿No podría guardar una semilla después de un tiempo, preferiblemente en la EEPROM? El reloj se desplazará y diferirá de una unidad a otra. Para guardar un nuevo valor después de algún tiempo nuevamente (tal vez cada 10 minutos más o menos, o después de un tiempo que sea lo suficientemente corto como para que ocurra dentro del tiempo de funcionamiento normal del dispositivo. Cuanto más tiempo esté encendido el dispositivo, es más probable que ahorre un valor "diferente" en la EEPROM.

También dé un salto de vez en cuando (no con demasiada frecuencia) y reinicialice mientras el dispositivo está encendido (guarde este nuevo valor en EEPROM).

Colchonetas
fuente
2

¿Qué pasa con extender su idea original de conversión AD basada en una resistencia variable agregando un LDR o termistor? (El primero debería ser capaz de "mirar" afuera, no sé si eso es factible; pero la variación en la luz puede ser mayor que la variación en la temperatura entre los dispositivos iniciados aproximadamente al mismo tiempo en el mismo lugar. ..)

Hagen von Eitzen
fuente
1
Los termistores vienen con otra propiedad útil. Varias series de la mayoría de los fabricantes tienen una tremenda variación e imprecisión. Esto "mejorará" aún más el resultado.
Ariser
1

2 soluciones potenciales, ambas suponiendo que necesita una semilla única por unidad.

  1. Si actualiza sus unidades una por una en la fábrica, el archivo hexadecimal puede modificarse mediante programación mediante algún script intermedio en el programador. Si está controlado por PC, puede sobrescribir una inicialización variable con la fecha y la hora. ¡Garantizado para ser único para cada unidad!

  2. Los dispositivos de cable Dallas 1 usan solo un pin y cada uno viene con un número de serie único de 64 bits. Puedes usar esto como la semilla.

Loganf
fuente
1
Me gusta 2, pero desafortunadamente las partes de DS son bastante caras.
Ariser
No use la marca de tiempo de producción para aleatoriedad de calidad criptográfica, es predecible.
2
@CamilStaps Para la aplicación del OP, no se requiere calidad de cifrado
Hagen von Eitzen
1
@HagenvonEitzen es cierto, pero otros pueden llegar a esta pregunta en busca de aleatoriedad de crypto-Q, por lo que vale la pena mencionar.
44
@CamilStaps Sigh , parece que has renunciado a la humanidad :) ¿Es realmente demasiado exigente esperar de alguien que quiere usar una respuesta de electronicsSE con fines criptográficos que sean al menos lo suficientemente cuidadosos como para leer la pregunta que se supone que debe responder? ? Las semillas "16bit" o "5 o5 6 bit" no son crypto-Q, incluso si son generadas por un grupo de gatos Schrödinger :)
Hagen von Eitzen
1

Puede dejar un pin ADC flotante para alimentar el generador de números aleatorios (RNG) con el ruido capturado. Debería ser suficiente para generar una semilla o incluso usarla como generador de RNG.

No olvides usar el mínimo tiempo de conversión posible.

La otra solución podría ser un generador de ruido aplicado en el pin ADC.

jnk0le
fuente
2
Haré algunas mediciones, pero si no recuerdo mal, un pin ADC flotante lee 0o cerca 0. Lo revisaré nuevamente para ver si ese es el caso.
vsz
1
Estoy interesado, ¿se lee 0cuando flota?
Bence Kaulics
2
El problema es que esto podría funcionar en una placa de desarrollo y fallar en el producto final.
vsz