Jakie jest najmniejsze i najprostsze ziarno generatora liczb losowych?

40

Mały mikrokontroler (8-bitowy Atmel) steruje wieloma światłami, aby zaprezentować pokaz świetlny z wieloma fantazyjnymi losowymi sekwencjami światła.

Odpowiedni pseudo-RNG dobrze sobie radzi, ale szukam dla niego dobrego ziarna. Ziarno będzie konieczne, ponieważ jeśli ktoś włączy jednocześnie wiele takich urządzeń, nie będzie dobrze wyglądać, jeśli wszystkie wygenerują te same sekwencje efektów, dopóki nie zaczną się powoli rozsuwać z powodu niewielkich różnic w poszczególnych źródłach zegara.

Bardzo dobra metoda wysiewu pseudo-RNG, której często używałem, jest możliwa w przypadku urządzenia, które należy uruchomić przez naciśnięcie przycisku lub naciśnięcie przełącznika. Zaraz po włączeniu µc można uruchomić bardzo szybki timer, a wartość tego timera uruchamia RNG, gdy tylko przycisk zostanie naciśnięty po raz pierwszy.

Problem polega na tym, że w tym scenariuszu nie ma przycisków. Program musi zostać uruchomiony natychmiast po włączeniu urządzenia.

Miejsce na płytce drukowanej jest bardzo ograniczone (może się zmieścić tylko kilka bardzo małych części SMD), więc szukam możliwie najmniejszego i najprostszego rozwiązania. Dlatego wykluczę wymyślne rozwiązania, takie jak prawdziwy sprzęt RNG, odbiorniki radiowe itp.

Wszystko, co mam, to 16-bitowy licznik timera w procesorze i nieużywany portpin, który ma dostęp do ADC.

Moje obecne rozwiązanie polega na użyciu rezystora (tak niedokładnego, jak to możliwe), aby dostarczyć około połowy napięcia zasilania na pin ADC i zaszczepić RNG pierwszą wartością konwersji AD. Jednak obecnie większość 10% rezystorów ma niedokładność znacznie poniżej 1% (fajnie byłoby wyobrazić sobie twarz dostawcy, gdy mówię im, że chcemy najgorszej jakości rezystorów SMD, jakie mogą znaleźć), więc istnieje bardzo duża szansa na wiele jednostek zaczynających się od tego samego ziarna.

Lepszą alternatywą byłoby wykonanie wielu konwersji i zbudowanie wartości z najmniej znaczących bitów tych pomiarów. Jednak wcześniej użyłem ADC tego typu µc i wiem, że jest bardzo dokładny. Pomocne może być uruchomienie ADC z najszybszą możliwą prędkością.

Czy ktoś ma lepszą sugestię? Nasiona nie muszą być idealnie równomiernie rozmieszczone, ale im bardziej równomierny jest rozkład, tym lepiej. 16-bitowe ziarno z idealnie jednolitym rozkładem byłoby snem zbyt pięknym, aby mogło być prawdziwe, ale myślę, że wystarczający może być w połowie przyzwoity rozkład na 5 lub 6 bitów.

vsz
źródło
12
„fajnie byłoby wyobrazić sobie twarz dostawcy, gdy mówię im, że chcemy rezystory SMD o najgorszej jakości, jakie mogą znaleźć” - jeszcze śmieszniej byłoby pozwolić, aby wartość tego rezystora nie była zdefiniowana na schemacie, i powiedzieć ludzie w produkcji, że ta jedna część musi być przylutowana ręcznie po wyjściu płytki drukowanej z maszyny do układania, z pojemnika, w którym zmieszaliśmy razem każdą wartość rezystora. - Ponieważ nie szukam RNG, ale nasienie . Więc jeśli generuje tę samą wartość prawie za każdym razem, gdy nie jest tak źle, ważniejsze jest, aby być różnym na różnych urządzeniach.
vsz
8
Dlaczego nie zapisać losowej wartości do pamięci EEPROM podczas programowania produkcyjnego? W ten sposób możesz użyć najbardziej wymyślnego RNG, który ci się podoba, ponieważ będzie on tylko w programistach programistycznych, a nie w urządzeniach końcowych. (Podziękowania dla @immibis: twój „nieco inny plik oprogramowania” dał mi pomysł.)
Calrion
2
Tak więc, żeby być czystym na 100%, problem polega na tym, że mogą zacząć od tej samej sekwencji, a nie, że z czasem mogą się rozchodzić, prawda?
wedstrom
2
Wybór twojego RNG ma znaczenie: niektóre potrzebują nasion dobrej jakości, inne nie. Na przykład w przypadku Xorshift każde ziarno inne niż 0 będzie działać i będzie działać równie dobrze. Nawet niewielka różnica w początkowym nasionku spowoduje zupełnie inną pozycję początkową w cyklu RNG.
curiousdannii
3
Możesz połączyć wszystkie odpowiedzi ADC ze statystykami i czasem, aby uzyskać jeszcze więcej losowości. Na przykład zmierz, ile zajmie procesora, dopóki nie pobierzesz N próbek, w których 3 niższe LSB mają wartość 101, i M próbek, w których 3 niższe LSB mają wartość 110. Rozwiń tę koncepcję zgodnie z potrzebami.
wjl

Odpowiedzi:

24

Umieść rezystor równoległy i kondensator między stykiem A / D a masą. Ustaw rezystor na dość wysokim poziomie, najlepiej znacznie powyżej wymaganej impedancji sygnału wejściowego dla A / D. Ustaw czas RC na stały, może około 10 µs. Na przykład 100 kΩ i 100 pF brzmi jak dobra kombinacja.

Aby uzyskać wartość z pewną przypadkowością, podnieś pin przez chwilę, a następnie ustaw na wysoką impedancję i zrób odczyt A / D kilka µs później. W szczególności, jeśli właściwie wykorzystasz czas akwizycji A / D, napięcie, które zobaczy, będzie zależeć od wartości R i C, prądu upływu pinów, innych pobliskich szumów i temperatury.

Chwyć niski bit lub dwa niskie bity i powtórz w razie potrzeby, aby uzyskać dowolną liczbę losowych bitów.

Aby uzyskać bardziej losowy wzorzec, należy od czasu do czasu wykonać tę procedurę i wstrzyknąć niski bit wyniku A / D do generatora liczb losowych, którego już używasz.

Olin Lathrop
źródło
To brzmi dobrze. Koniecznie sprawdź impedancję wejściową w ADC - seria Atmega8 ma analogową impedancję wejściową 100 Meg, co sprawia, że ​​wartość rezystora Olin jest nieco niska.
Stefan
3
@stef: Impedancja wejściowa i impedancja sygnału wymagana do poprawnej konwersji to dwie różne rzeczy. Tak, impedancja wejściowa jest bardzo wysoka, ponieważ jest to CMOS. Jednak istnieje maksymalny limit impedancji dla sygnału, aby umożliwić mu naładowanie próbki i przytrzymanie trzonka w określonym czasie oraz aby przezwyciężyć wszelkie wycieki, jakie może mieć pin.
Olin Lathrop,
2
przepraszam, z twojej odpowiedzi myślałem, że odnosisz się do impedancji wejściowej w przeciwieństwie do specyfikacji impedancji źródłowej. 10k to maksymalna impedancja źródła w Atmega8, więc twoja odpowiedź jest natychmiastowa. Dla porównania, czapka S / H w środku to 14pF, na wypadek gdyby ktoś był zainteresowany.
Stefan
2
@stef: Zredagowałem odpowiedź, aby to wyjaśnić.
Olin Lathrop,
Przegapiłeś fazę księżycową i święta. Również machanie ręką przydatnym dodatkiem, szczególnie jeśli ma niską temperaturę C i nie jest dobrze osłonięty.
Russell McMahon,
23

Niektóre możliwe opcje:

  1. Zaprogramuj unikalny adres seryjny dla każdego urządzenia. Jeśli masz wystarczająco dobry algorytm RNG, to nawet sekwencyjna lista adresów szeregowych da zupełnie odmienne wyniki.

  2. W zależności od MCU / konfiguracji mogą być dostępne dwa różne źródła zegara dla zegara systemowego i wejścia watchdog licznik / licznik timera. Jeśli jedno / oba mają znaczną wariancję, możesz użyć tego do wygenerowania odpowiednio innego ziarna. Oto przykład, który napisałem, który wykorzystuje wewnętrzny zegar kontrolny Arduino i zewnętrzny zegar systemowy XTAL .

  3. Użyj tranzystora BJT i ​​zbuduj wzmacniacz wysoce zależny od wersji beta. Można to odczytać z ADC dla nasion.

  4. Kondensatory / cewki indukcyjne mają zwykle znacznie gorszą tolerancję niż rezystory. Za ich pomocą można zbudować jakiś obwód filtra (RC, RL, LC) i zmierzyć moc wyjściową za pomocą ADC.

helloworld922
źródło
5
Głosuję na opcję 1, jest to rozwiązanie z zerową liczbą części, które spowoduje, że sekwencje nigdy nie będą pasować. Numer seryjny i generator RND mogą powiedzieć 16 bitów, dzięki czemu każde urządzenie ma znikomą szansę naśladowania wzoru innej osoby.
KalleMP
1
Podoba mi się również rozwiązanie. Jeśli używasz prostego algorytmu mieszającego, wszystko powinno być w porządku, nawet jeśli masz kolejne numery seryjne.
magu_
6
Zaletą opcji 1 jest to, że niektóre urządzenia są wyposażone we wbudowane numery seryjne (zwykle
mikra
3
Nawet śmieciowe RNG, takie jak LCG , „generują zupełnie odmienne wyniki dla sekwencyjnej listy adresów szeregowych” . Głosuję również na 1.
BlueRaja - Danny Pflughoeft
3
Jeśli masz źródło czasu, użycie go jako podstawy dla przełącznika na ziarnie pomogłoby zrównoważyć rzeczy między uruchomieniami. Połącz to z adresem / numerem seryjnym lub adresem MAC, jeśli Twoje urządzenie je posiada, a także naprawisz dopasowanie między urządzeniami. Widziałem pewne oprogramowanie, które stale przechowuje część lub każdą liczbę losową wygenerowaną do użycia jako ziarno, nawet po ponownym uruchomieniu. Jeśli twoje urządzenia mają różne czasy działania, powinny się rozchodzić.
TafT
8

Niezainicjowana pamięć

Możesz spróbować użyć niezainicjowanej pamięci w mikrokontrolerze. Sztuką jest znalezienie bitów, które mają najbardziej „zbalansowane” przerzutniki i są w rzeczywistości losowe. Procedura polega na odczytaniu całej pamięci, zresetowaniu i powtórzeniu kilka razy, aby zmierzyć, które bity są naprawdę losowe. Następnie używasz tej mapy, aby odczytać wystarczającą liczbę losowych bitów, aby zasiać PRNG lub LFSR!

Ta metoda powinna dać ci losowe nasiona, nawet z identycznym sprzętem, więcej szczegółów (i linki) są dostępne w tym artykule o hack-dziennie

Podoba mi się ta metoda, ponieważ nie wymaga żadnych dodatkowych obwodów ani styków; twój AVR ma już ram, po prostu musisz znaleźć niestabilne (losowe) bity. Można również zautomatyzować procedurę mapowania; możesz zastosować ten sam kod i procedurę do każdego urządzenia i uzyskać naprawdę losowe wyniki!

ezoterik
źródło
1
Naprawdę nie musisz wiedzieć, które bity są losowe. XOR-ing wszystkich bajtów da losowy wynik, nawet jeśli tylko 8 bitów jest losowych. Jak pokazuje zdjęcie, rzeczywiste wartości mogą nie być losowe w sensie czasowym, są wystarczająco wyjątkowe - właśnie tego potrzebujemy tutaj.
MSalters
1
Jeśli możesz znaleźć PRNG, który pozwala ci „wmieszać” entropię, to może być jeszcze lepsza niż opcja XOR-then-seed. Iteruj przez niezainicjowaną pamięć i wklej bajty do PRNG. Np. Zobacz moją prostszą bibliotekę C - funkcję miksowania .
Craig McQueen,
Nie zapewni to losowości o jakości kryptograficznej.
@CamilStaps oczywiście, że nie.
Navin
1
To nie zadziała. Niezainicjowana pamięć jest niezdefiniowanym zachowaniem, jeśli mam system operacyjny i nie mam żadnej kontroli nad tym, która część pamięci zostanie przypisana do mojego programu i co tam było wcześniej. W przypadku mikrokontrolera bez systemu operacyjnego tak nie jest. Zwłaszcza w przypadku AVR, ponieważ cała pamięć RAM wyniesie zero, jeśli minie wystarczająco dużo czasu, aby kondensatory mogły zostać opróżnione przez zużycie prądu podczas zaniku zasilania.
vsz
7

To, co zrobiłem dla odtwarzacza MP3 z funkcją losowego, to po prostu użycie innego sekwencyjnego materiału siewnego przy każdym włączeniu zasilania. Zacząłem od 1 i zapisałem to w EEPROM, więc przy następnym cyklu zasilania użyłem 2 itd. To było na ATMEGA168. Jak zauważył helloworld922, nawet proste sekwencyjne ziarno wygeneruje zupełnie inne pseudolosowe sekwencje.

Użyłem jednego z liniowych przystających generatorów losowych sekwencji, co daje równomierny rozkład.

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

Oczywiście, jeśli chcesz, aby wiele jednostek miało różne sekwencje, mimo że mogły mieć taką samą liczbę cykli zasilania, potrzebujesz czegoś, aby zacząć losowo.

Można tego dokonać dowolną z metod zaproponowanych przez inne plakaty - Jedna z metod, o której myślę, mogłaby użyć przejścia przez zero prądu przemiennego do procesora, jeśli go masz (na przykład do kontroli fazy lampy)? Można to wykorzystać do próbkowania licznika czasu na pierwszym przejeździe po włączeniu zasilania, a następnie wykorzystać jako ziarno.

Czy na urządzeniu są jakieś przyciski do wyboru trybu itp.? Jeśli tak, możesz próbkować licznik przy pierwszym naciśnięciu przycisku po zaprogramowaniu MCU, możesz początkowo wygenerować losowe ziarno i zapisać je w EEPROM. Każde wzmocnienie po tym punkcie użyłoby przechowywanego ziarna.

Kevin White
źródło
5

ADC jest bardzo dobrym źródłem losowości.

Nie musisz polegać na tolerancjach rezystorów. Każdy rezystor generuje szum termiczny , a ten sam efekt fizyczny wprowadzi szum do ADC podczas wykonywania wszystkich kroków próbkowania i konwersji. (Arkusz danych powie ci o ilości hałasu i jakie ustawienia konfiguracji są najgorsze / najlepsze.)

Nie należy pozostawiać pływającego styku ADC; może to pozwolić, aby napięcie unosiło się zbyt daleko i grozi nasyceniem wejścia.
(Wiele MCU pozwala na użycie czegoś takiego jak połowa napięcia zasilania jako wejścia ADC, do kalibracji. To oszczędza zewnętrzny rezystor i wciąż powoduje hałas. Ponownie, patrz arkusz danych dla najgorszej / najlepszej konfiguracji.)

Nie musisz polegać na pojedynczym pomiarze ADC; możesz łączyć wiele pomiarów za pomocą prostej funkcji skrótu lub sumy kontrolnej (wystarczy CRC). Jeśli musisz natychmiast zacząć korzystać z RNG, możesz później połączyć wynik ADC z bieżącym ziarnem RNG.

CL.
źródło
2
Nie jestem pewien, czy hałas Johnsona jest odpowiedni w tej aplikacji; W STP rezystor 10 Meg w paśmie 10kHz ma 40uVszum Johnsona. Potrzebny byłby> 14-bitowy przetwornik ADC lub obwód wzmacniacza, aby rozsądnie to zmierzyć.
helloworld922,
STP nie jest tak naprawdę istotny. W szczególności można celowo podnieść temperaturę, ale dodatkowe 60 stopni w stosunku do STP to zaledwie 10% dodatkowego hałasu.
MSalters
1
Podobne podejście polegałoby na wykorzystaniu szumu wystrzeliwanego w diodzie. en.wikipedia.org/wiki/Noise_generator#Shot_noise_generators
teambob
2

Czy możesz zapisać ziarno między sesjami? Jeśli tak, to czy możliwe jest włączenie każdej jednostki na jakiś losowy okres czasu po utworzeniu? W ten sposób wszystkie jednostki zostaną wysłane ze wstępnie ustawionymi nasionami, które prawdopodobnie nie będą takie same.

Kolejna myśl: jak połączyć ze sobą wiele jednostek, aby włączały się jednocześnie? Jeśli są połączone szeregowo, dodaj jakiś kondensator, aby (n + 1) urządzenie zaczęło kilka cykli zegara po n-tym urządzeniu. Idealnie kondensatory rozładowałyby się bardzo szybko przy wyłączaniu urządzenia, więc przy każdym uruchomieniu / ponownym uruchomieniu występuje większa przerwa między sekwencjami.

Jeśli są one równoległe, nadal możesz trochę losowo ustalić czas uruchamiania. Zakładam, że jest jakaś filtracja mocy za pomocą kondensatorów. Jeśli tak, wytworzenie urządzeń z nieco innymi obwodami filtracyjnymi spowodowałoby, że każde urządzenie uruchomiłoby się w nieco innym czasie, powodując rozbieżność po kilku ponownych uruchomieniach.

Odmianą tego jest dodanie wariancji do sygnałów zegara, jeśli to możliwe. Różnica prędkości zegara o 0,1% może mieć niewielki wpływ na pokaz świetlny, a jednocześnie dość szybko zmieniasz tempo przechodzenia przez tabelę PRNG.

MichaelS
źródło
1
być może podłącz dużą wylewkę do analogu w pinie i zrób kilka odczytów „szumu sieci”, aby zaszczepić RNG.
Jasen
1
@Jasen, wszystkie urządzenia podłączone do tego samego przedłużacza będą widzieć ten sam szum sieci.
Ian Ringrose,
2

Jeśli korzystasz z wewnętrznego „skalibrowanego” źródła zegara. Czy po pewnym czasie nie możesz zapisać ziarna, najlepiej w pamięci EEPROM? Zegar będzie dryfował i będzie się różnił w zależności od jednostki. Aby zapisać nową wartość po jakimś czasie (może co 10 minut lub po czasie, który jest wystarczająco krótki, aby nastąpił w normalnym czasie włączenia urządzenia. Im dłużej urządzenie jest włączone, tym bardziej prawdopodobne jest, że zapisze „inna” wartość w EEPROM.

Od czasu do czasu również wykonuj skok (nie za często) i resetuj, gdy urządzenie jest włączone (zapisz tę nową wartość w EEPROM).

Maty
źródło
2

Co powiesz na rozszerzenie oryginalnego pomysłu konwersji AD w oparciu o zmienny rezystor poprzez dodanie LDR lub termistora? (Pierwszy musiałby być w stanie „spojrzeć” na zewnątrz, nie wiem, czy to wykonalne; ale zmiana światła może być wyższa niż zmiana temperatury między urządzeniami uruchomiona mniej więcej w tym samym czasie i w tym samym miejscu. ..)

Hagen von Eitzen
źródło
1
Termistory mają inną przydatną właściwość. Kilka serii od większości producentów ma ogromną wariancję i niedokładność. To jeszcze bardziej „poprawi” wynik.
Ariser,
1

2 potencjalne rozwiązania, przy założeniu, że potrzebujesz unikalnego materiału siewnego na jednostkę.

  1. Jeśli flashujesz swoje jednostki jeden po drugim w fabryce, plik hex może być programowo modyfikowany przez jakiś skrypt pośredni w programerze. Jeśli jest sterowany komputerowo, możesz nadpisać inicjalizację zmiennej datą i godziną. Gwarantujemy, że będzie unikalny dla każdej jednostki!

  2. Urządzenia drutowe Dallas 1 wykorzystują tylko jeden pin, a każdy z nich ma unikalny 64-bitowy numer seryjny. Możesz użyć tego jako ziarna.

Loganf
źródło
1
Lubię 2, ale niestety wszystkie części DS są dość drogie.
Ariser
Nie używaj znacznika czasu produkcji dla losowości jakości kryptograficznej, jest to przewidywalne.
2
@CamilStaps W przypadku aplikacji PO jakość kryptograficzna nie jest wymagana
Hagen von Eitzen
1
@HagenvonEitzen to prawda, ale inni mogą przyjść na to pytanie, szukając losowości crypto-Q, więc warto o tym wspomnieć.
4
@CamilStaps Westchnienie , wygląda na to, że porzuciłeś ludzkość :) Czy to naprawdę zbyt wymagające, aby oczekiwać od kogoś, kto chce użyć odpowiedzi z electronicSE do celów kryptograficznych, aby byli przynajmniej wystarczająco ostrożni, aby przeczytać pytanie, na które ma odpowiedzieć ? „16-bitowe” lub „5 o5 6-bitowe” nasiona nie są krypto-Q, nawet jeśli są generowane przez grupę kotów Schrödinger :)
Hagen von Eitzen
1

Możesz zostawić pływający pin ADC, aby zasilić generator liczb losowych (RNG) przechwyconym hałasem. Wystarczy wygenerować ziarno, a nawet użyć go jako generatora RNG.

Nie zapomnij użyć minimalnego możliwego czasu konwersji.

Innym rozwiązaniem może być generator szumów zastosowany w pinie ADC.

jnk0le
źródło
2
Zrobię kilka pomiarów, ale jeśli dobrze pamiętam, pływający pin ADC czyta 0lub zbliża się 0. Sprawdzę to jeszcze raz, aby zobaczyć, czy tak jest.
vsz
1
Jestem zainteresowany, czy to czyta 0podczas pływania?
Bence Kaulics,
2
Problem polega na tym, że może to działać na płycie programistycznej i zawieść w produkcie końcowym.
vsz