Quelle est la graine la plus petite et la plus simple pour un générateur de nombres aléatoires?

40

Un petit microcontrôleur (Atmel 8 bits) contrôle un certain nombre de lumières afin de présenter un spectacle lumineux avec de nombreuses séquences lumineuses aléatoires fantaisistes.

Un pseudo-RNG approprié fait bien son travail, mais je cherche une bonne graine pour cela. Une graine sera nécessaire, car si quelqu'un allume plusieurs de ces dispositifs en même temps, il ne semblera pas bon qu'ils génèrent tous les mêmes séquences d'effets jusqu'à ce qu'ils se séparent lentement en raison des différences minimes entre leurs sources d'horloge individuelles.

Une très bonne méthode pour générer un pseudo-RNG, que j'ai souvent utilisée, est possible dans le cas d'un périphérique devant être démarré par une simple pression sur un bouton ou un commutateur. Dès que le µc est mis en marche, une minuterie très rapide peut être démarrée et la valeur de cette minuterie sème le RNG dès que le bouton est pressé pour la première fois.

Le problème est que, dans ce scénario, il n'y a pas de boutons. Le programme doit démarrer dès que l'appareil est allumé.

La place sur le circuit imprimé est extrêmement limitée (seules quelques-unes des plus petites pièces CMS peuvent être utilisées), je recherche donc la solution la plus petite et la plus simple possible. Par conséquent, j'éliminerai les solutions sophistiquées telles que le vrai matériel RNG, les récepteurs radio, etc.

Tout ce que j'ai est un compteur de minuterie 16 bits dans la CPU, et un portpin inutilisé qui a accès à un ADC.

Ma solution actuelle consiste simplement à utiliser une résistance (aussi imprécise que possible) pour fournir environ la moitié de la tension d'alimentation à la broche du convertisseur analogique-numérique, et ensemencer le générateur de base de réseau avec la première valeur de conversion AD. Cependant, de nos jours, la plupart des résistances à 10% ont une imprécision bien inférieure à 1% (il serait amusant d’imaginer le visage d’un fournisseur lorsque je leur dis que nous voulons les résistances CMS les plus médiocres qu’elles puissent trouver). plusieurs unités commençant par la même graine.

Une meilleure solution consisterait à effectuer plusieurs conversions et à créer une valeur à partir des bits les moins significatifs de ces mesures. Cependant, j’avais utilisé un ADC de ce type avant et je sais que c’est très précis. Faire fonctionner le CAN à la vitesse la plus rapide possible pourrait aider ici.

Quelqu'un a-t-il une meilleure suggestion? Il n'est pas nécessaire que la graine soit parfaitement uniformément distribuée, mais plus la distribution est uniforme, mieux c'est. Une graine de 16 bits avec une distribution parfaitement uniforme serait un rêve trop beau pour être vrai, mais je pense qu'une distribution à peu près décente sur 5 ou 6 bits pourrait suffire.

vsz
la source
12
"il serait amusant d'imaginer le visage d'un fournisseur lorsque je leur dirais que nous voulons trouver les résistances CMS les plus médiocres qu'ils puissent trouver" - il serait encore plus drôle de laisser la valeur de cette résistance indéfinie dans le schéma de circuit les personnes en production que cette une partie doit être soudée manuellement après que la carte soit sortie de la machine de placement, dans une corbeille où nous avons mélangé toutes les valeurs de résistance que nous avons. - Parce que ce n'est pas un GNA que je cherche, mais une graine . Donc, si elle génère la même valeur presque à chaque fois, ce n'est pas si grave, il est plus important d'être différent d'un périphérique à l'autre.
vsz
8
Pourquoi ne pas écrire une valeur aléatoire dans la mémoire EEPROM pendant la programmation de production? De cette façon, vous pouvez utiliser le RNG le plus fantaisiste que vous aimez, car ce sera uniquement dans le (s) programmeur (s) de production, et non dans les périphériques finaux. (Merci à @immibis: c'est votre "fichier logiciel légèrement différent" qui m'a donné l'idée.)
Calrion le
2
Donc, pour être clair à 100%, le problème est qu’ils pourraient commencer par la même séquence, non pas qu’ils pourraient s’écarter au fil du temps, n’est-ce pas?
mercredi
2
Le choix de votre RNG est important: certains ont besoin de semences de bonne qualité, d’autres pas. Par exemple, pour Xorshift, toute graine autre que 0 fonctionnera et fonctionnera tout aussi bien. Même une toute petite différence dans la graine initiale entraînera une position de départ très différente dans le cycle du GNA.
strangedannii
3
Vous pouvez combiner toutes les réponses de l'ADC avec des statistiques et une synchronisation pour encore plus de caractère aléatoire. Par exemple, mesurez le nombre de ticks de processeur nécessaires jusqu'à ce que vous preniez N échantillons où les 3 LSB inférieurs sont 101 et M échantillons où les 3 LSB inférieurs ont 110. Développez ce concept comme vous le souhaitez.
WJL

Réponses:

24

Placez une résistance parallèle et un condensateur entre la broche A / D et la terre. Rendez la résistance assez haute, de préférence bien au-dessus de l'impédance du signal d'entrée requise pour le convertisseur analogique-numérique. Faites la constante de temps RC peut-être autour de 10 µs. Par exemple, 100 kΩ et 100 pF semblent constituer une bonne combinaison.

Pour obtenir une valeur quelque peu aléatoire, enfoncez la broche pendant un moment, puis réglez-la sur une impédance élevée et effectuez une lecture A / N quelques µs plus tard. En particulier si vous abusez correctement du temps d’acquisition A / N, la tension qu’elle verra dépendra des valeurs de R et C, du courant de fuite de la broche, des autres bruits à proximité et de la température.

Saisissez le bit bas ou les deux bits bas et répétez-le si nécessaire pour obtenir un nombre quelconque de bits aléatoires.

Pour un motif plus aléatoire, effectuez de temps en temps cette procédure et injectez le bit le plus faible du résultat A / D dans le générateur de nombre aléatoire que vous utilisez déjà.

Olin Lathrop
la source
Ça semble bon. Assurez-vous de vérifier l'impédance d'entrée sur le CAN - la série Atmega8 a une impédance d'entrée analogique de 100Meg, ce qui rend la valeur de la résistance d'Olin un peu basse.
Stefan
3
@stef: l'impédance d'entrée et l'impédance du signal requises pour une conversion correcte sont deux choses différentes. Oui, l'impédance d'entrée est très élevée car elle est CMOS. Cependant, il existe une limite d'impédance maximale sur le signal pour lui permettre de charger l'échantillon et de le maintenir dans le délai spécifié, et de surmonter les fuites éventuelles de la broche.
Olin Lathrop
2
désolé, d'après votre réponse, je pensais que vous faisiez référence à l'impédance d'entrée par opposition à la spécification d'impédance source. 10k est l'impédance de source maximale spécifiée de l'Atmega8, votre réponse est donc parfaite. Pour référence, le plafond S / H à l'intérieur est de 14pF, au cas où quelqu'un serait intéressé.
stefandz
2
@stef: J'ai édité la réponse pour que cela soit plus clair.
Olin Lathrop
Vous avez manqué la phase lunaire et les jours fériés. Aussi, agitant à la main un ajout utile, surtout si faible C et pas bien protégé.
Russell McMahon
23

Quelques options possibles:

  1. Pré-programmez une adresse série unique pour chaque périphérique. Si vous avez un assez bon algorithme RNG, alors même une liste séquentielle d'adresses série produira des résultats très différents.

  2. En fonction de votre MCU / configuration, vous pouvez avoir deux sources d'horloge différentes disponibles pour l'horloge système et l'entrée de chien de garde / compteur. Si l'une / les deux ont une variance significative, vous pouvez l'utiliser pour générer une graine convenablement différente. Voici un exemple que j'ai écrit et qui utilise un minuteur de surveillance interne Arduino et une horloge système XTAL externe .

  3. Utilisez un transistor BJT et construisez un amplificateur fortement dépendant de la bêta. Cela peut être lu à partir d'un ADC pour la graine.

  4. Les condensateurs / inducteurs sont généralement spécifiés avec une tolérance bien plus mauvaise que les résistances. Vous pouvez construire une sorte de circuit de filtrage (RC, RL, LC) avec ceux-ci et mesurer la sortie avec le CAN.

helloworld922
la source
5
Je vote pour l’option 1, c’est une solution de comptage partiel qui permettra aux séquences de ne jamais correspondre. Le numéro de série et le générateur RND peuvent indiquer 16 bits, ce qui permet à tout périphérique d’avoir une chance négligeable d’imiter le modèle d’un autre.
KalleMP le
1
J'aime aussi la solution. Si vous utilisez un algorithme de hachage simple, tout va bien, même si vous avez des numéros de série séquentiels.
magu_
6
Une option intéressante de l'option 1 est que certains périphériques sont livrés avec des numéros de série intégrés (généralement des micros réseau / RF), de sorte que vous n'avez même pas besoin d'une étape distincte pour graver les numéros de série
slebetman le
3
Même un GNA ordures comme un GLC produira "des résultats extrêmement différents pour une liste séquentielle d'adresses série" . Je vote pour 1 aussi.
BlueRaja - Danny Pflughoeft
3
Si vous avez une source de temps, l’utiliser comme base pour votre commutateur sur les semences aiderait à compenser les choses entre les séries. Combinez cela avec une adresse / numéro de série ou l'adresse MAC si votre appareil en a un et vous corrigerez également la correspondance entre appareils. J'ai vu certains logiciels qui stockent de manière persistante tout ou partie des nombres aléatoires générés pour les utiliser en tant que graine, même après un redémarrage. Si vos appareils ont des durées de fonctionnement différentes, ils doivent être séparés les uns des autres.
TafT
8

Mémoire non initialisée

Vous pouvez essayer d'utiliser la mémoire non initialisée dans le microcontrôleur. L'astuce consiste à trouver les bits qui ont les bascules les plus «équilibrées» et qui sont réellement aléatoires. La procédure consiste à lire toute la mémoire, à réinitialiser et à répéter plusieurs fois pour déterminer quels bits sont réellement aléatoires. Ensuite, vous utilisez cette carte pour lire suffisamment de bits aléatoires pour ensemencer votre PRNG ou votre LFSR!

Cette méthode devrait vous donner des graines au hasard, même avec un matériel identique, plus de détails (et liens) sont disponibles dans ce hack-a-jour l' article

J'aime cette méthode car elle ne nécessite pas de circuit supplémentaire ni de broches; votre AVR a déjà de la RAM, il vous suffit de trouver les bits instables (aléatoires). La procédure de mappage pourrait également être automatisée; vous pouvez appliquer le même code et la même procédure à chaque appareil et obtenir des résultats vraiment aléatoires!

esoterik
la source
1
Vous n'avez pas vraiment besoin de savoir quels bits sont aléatoires. XOR-ing tous les octets vous donnera un résultat aléatoire même si seulement 8 bits sont aléatoires. Et comme le montre la photo, les valeurs réelles peuvent ne pas être aléatoires au sens temporel, mais elles sont assez uniques - c’est exactement ce dont nous avons besoin ici.
MSalters
1
Si vous pouvez trouver un PRNG qui vous permet de "mélanger" l'entropie, cela pourrait être encore meilleur que l'option XOR-then-seed. Parcourez la mémoire non initialisée et mélangez les octets au PRNG. Voir, par exemple, ma bibliothèque plus simple C: fonction de mixage .
Craig McQueen
Cela ne vous donnera pas une qualité de chiffrement aléatoire.
@ CamilStaps bien sûr que non.
Navin
1
Cela ne fonctionnera pas. La mémoire non initialisée est un comportement indéfini si j'ai un système d'exploitation et que je n'ai aucun contrôle sur la partie de la mémoire qui sera affectée à mon programme ni sur ce qui était auparavant. Sur un microcontrôleur sans système d'exploitation, ce n'est pas le cas. Surtout avec AVR, car toute la mémoire vive sera nulle si le temps nécessaire pour vider les condensateurs est atteint en raison de la consommation de courant en baisse de tension.
vsz
7

Ce que j'ai fait pour un lecteur MP3 avec une capacité aléatoire, c'est simplement d'utiliser une graine séquentielle différente à chaque mise sous tension. J'ai commencé à 1 et l'ai stocké dans l'EEPROM afin qu'au prochain cycle d'alimentation, j'en ai utilisé 2, etc. C'était sur un ATMEGA168. Comme helloworld922 l'a noté, même une simple graine séquentielle générera des séquences pseudo aléatoires complètement différentes.

J'ai utilisé l'un des générateurs de séquence aléatoire congruente linéaire, ce qui donne une distribution uniforme.

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

Bien sûr, si vous voulez que plusieurs unités aient différentes séquences même si elles ont eu le même nombre de cycles d'alimentation, vous avez besoin de quelque chose pour commencer de manière aléatoire.

Cela pourrait être fait par l’une des méthodes proposées par les autres affiches - une méthode à laquelle je peux penser pourrait utiliser le passage à zéro alternatif entrant dans le processeur si vous l’avez (pour le contrôle de la phase de la lampe, par exemple)? Cela pourrait être utilisé pour échantillonner la minuterie lors du premier passage suivant la mise sous tension, puis utilisé comme germe.

Y a-t-il des boutons sur l'appareil pour sélectionner le mode, etc.? Si vous pouvez ainsi échantillonner le compteur la toute première fois que vous appuyez sur le bouton après la programmation de la MCU, vous pouvez générer une graine aléatoire au départ et la stocker dans une EEPROM. Chaque mise sous tension après ce point utiliserait la graine stockée.

Kevin White
la source
5

Un ADC est une très bonne source d’aléatoire.

Vous n'avez pas besoin de vous fier aux tolérances de la résistance. Toute résistance générera du bruit thermique et le même effet physique introduira du bruit dans le CAN lors de toutes les étapes d'échantillonnage et de conversion. (La fiche technique vous indiquera la quantité de bruit et les paramètres de configuration les plus défavorables.)

Vous ne devriez pas laisser la broche ADC flottante; cela pourrait laisser la tension flotter trop loin et risquer de saturer l'entrée.
(De nombreux microcontrôleurs vous permettent d'utiliser environ la moitié de la tension d'alimentation comme entrée ADC, pour l'étalonnage. Cela permet d'économiser la résistance externe tout en générant du bruit. Consultez à nouveau la fiche technique pour connaître la configuration la plus mauvaise / meilleure.)

Vous n'avez pas besoin de compter sur une seule mesure ADC; vous pouvez combiner plusieurs mesures avec une simple fonction de hachage ou de somme de contrôle (un contrôle CRC suffirait). Si vous devez commencer à utiliser le RNG immédiatement, vous pouvez ultérieurement combiner le résultat de l'ADC avec le germe RNG actuel.

CL.
la source
2
Je ne suis pas sûr que le bruit de Johnson convient à cette application; Au STP, une résistance de 10Meg sur une largeur de bande de 10 kHz a un 40uVbruit de Johnson. Vous aurez besoin d’un CAN> 14 bits ou d’un circuit amplificateur pour pouvoir mesurer ce phénomène.
helloworld922
STP n'est pas vraiment pertinent. La température, en particulier, pourrait être intentionnellement élevée, mais une augmentation de 60 degrés par rapport au STP ne représente que 10% de bruit supplémentaire.
MSalters
1
Une approche similaire consisterait à utiliser le bruit de tir dans une diode. en.wikipedia.org/wiki/Noise_generator#Shot_noise_generators
teambob
2

Pouvez-vous sauvegarder la graine d'une session à l'autre? Dans l’affirmative, est-il possible d’allumer chaque unité pendant un certain temps après sa création? Ainsi, toutes les unités seront expédiées avec des semences prédéfinies qui ne seront probablement pas les mêmes.

Une autre pensée: comment relier plusieurs unités afin qu’elles s’allument simultanément? S'ils sont en série, ajoutez une sorte de condensateur pour que le (n + 1) ème appareil commence quelques cycles d'horloge après le nième appareil. Dans l’idéal, les condensateurs se déchargent très rapidement à l’arrêt de l’appareil. Ainsi, chaque démarrage / redémarrage crée un intervalle plus grand entre les séquences.

S'ils sont en parallèle, vous pouvez toujours randomiser un peu le temps de démarrage. Je suppose qu'il existe une sorte de filtrage de puissance utilisant des condensateurs. Dans ce cas, la fabrication des appareils avec des circuits de filtration légèrement différents provoquerait le démarrage de chaque appareil à une heure légèrement différente, ce qui causerait une divergence après plusieurs redémarrages.

Une variante consiste à ajouter de la variance à vos signaux d'horloge, si possible. Une différence de 0,1% de la vitesse d'horloge peut avoir peu d'impact sur le jeu de lumière, tout en modifiant assez rapidement le taux de traversée du tableau PRNG.

MichaelS
la source
1
peut-être connecter une grande quantité à l'analogue en pin et faire quelques lectures de "bourdonnement principal" pour ensemencer le GNA.
Jasen
1
@Jasen, toutes les unités connectées à la même rallonge verront le même bourdonnement principal.
Ian Ringrose
2

Si vous utilisez une source d'horloge interne "calibrée". Ne pourriez-vous pas conserver une graine après un certain temps, de préférence dans l’EEPROM. L'horloge va dériver et différer d'une unité à l'autre. Pour enregistrer une nouvelle valeur après un certain temps (toutes les 10 minutes environ, ou après un temps suffisamment court pour se produire dans les délais impartis pour le périphérique. Plus le périphérique est allumé longtemps, plus il économisera une valeur "différente" dans la mémoire EEPROM.

Faites également un saut de temps en temps (pas trop souvent) et réamorcez lorsque le périphérique est allumé (enregistrez cette nouvelle valeur dans EEPROM).

Tapis
la source
2

Que diriez-vous d'étendre votre idée originale de conversion AD basée sur une résistance variable en ajoutant un LDR ou une thermistance? (Le premier devrait pouvoir "regarder" dehors, je ne sais pas si c'est faisable, mais la variation de la lumière peut être supérieure à la variation de la température entre les dispositifs démarrés à peu près au même moment à peu près au même endroit. ..)

Hagen von Eitzen
la source
1
Les thermistances entrent avec une autre propriété utile. Plusieurs séries de la plupart des fabricants ont une variance et une imprécision énormes. Cela "améliorera" davantage le résultat.
Ariser
1

Deux solutions potentielles, les deux supposant que vous avez besoin d'une graine unique par unité.

  1. Si vous flashez vos unités une à une dans l'usine, le fichier hexadécimal peut être modifié par programme par un script intermédiaire du programmeur. S'il est contrôlé par l'ordinateur, vous pouvez écraser une initialisation de variable avec la date et l'heure. Garanti d'être unique pour chaque unité!

  2. Les appareils Dallas 1 wire utilisent une seule broche et sont dotés d’un numéro de série 64 bits unique. Vous pouvez l'utiliser comme la graine.

Loganf
la source
1
J'aime 2, mais malheureusement les pièces DS sont toutes assez chères.
Ariser
N'utilisez pas l'horodatage de production pour un caractère aléatoire de qualité cryptée, c'est prévisible.
2
@CamilStaps Pour l'application de l'OP, la crypto-qualité n'est pas requise
Hagen von Eitzen
1
@HagenvonEitzen c'est vrai, mais d'autres peuvent venir à cette question en recherchant le caractère aléatoire crypto-Q, alors il vaut la peine de le mentionner.
4
@CamilStaps Sigh , il semble que vous ayez renoncé à l'humanité :) Est-ce vraiment trop exigeant de s'attendre de la part d'une personne qui souhaite utiliser une réponse de electronicsSE à des fins cryptographiques qu'elle soit au moins assez attentive pour lire la question à laquelle elle est censée répondre ? Les graines "16bit" ou "5 o5 6 bit" ne sont pas crypto-Q, même si elles sont générées par un groupe de chats Schrödinger :)
Hagen von Eitzen
1

Vous pouvez laisser une broche ADC flottante pour alimenter le générateur de nombres aléatoires (RNG) avec le bruit capturé. Cela devrait suffire à générer une graine ou même à l'utiliser comme générateur de GNA.

N'oubliez pas d'utiliser le temps de conversion minimum possible.

L'autre solution pourrait être un générateur de bruit appliqué à la broche ADC.

jnk0le
la source
2
Je vais faire quelques mesures, mais si je me souviens bien, une broche ADC flottante lit 0ou près de 0. Je vais vérifier à nouveau pour voir si c'est le cas.
vsz le
1
Je suis intéressé, est-ce que ça se lit 0quand on flotte?
Bence Kaulics
2
Le problème est que cela pourrait fonctionner sur une carte de développement et échouer dans le produit final.
vsz