У Брюса Шнайера в прикладной криптографии этот вопрос рассмотрен. Далее последует мой плохой пересказ. Нужен какой-то источник случайных данных. Это может быть, например, АЦП. Сам по себе этот источник может быть исключительно плохим ГСЧ, это не слишком важно, важно лишь, чтоб в получаемых от него данных действительно была случайная составлающая. Далее нужен какой-то хеш, сойдёт для примера MD5. Кстати не плохой вариант для 8-битных контроллеров, вопреки повсеместно написанному (MD5 позволяет развернуть циклы и получить достаточно быстрый код, а MD2 несмотря на всё считается в итоге гораздо дольше). И далее, каждый раз, когда нужно получить случайное число (64 бита, например) -- берётся предыдущее число, к нему добавляются плохие случайные данные, считается очередное значение хеша и выдаётся как случайное число. Всё просто. Но есть ньюансы которые лучше почерпнуть в упомянутой литературе.
Есть и другие методы. Например, на основе LFSR. Есть неплохой application note у maxim: http://www.maxim-i …otes/index.mvp/id/4400 Конкретная реализация, опять же сожалею об отсутствии src.caxapa.ru, выглядит примерно так:
#define PMASK32 0xB4BCD35C
#define PMASK31 0x7A5BC2E3
#ifndef PERSISTENT
#define PERSISTENT(v) v
#endif
PERSISTENT(static uint_fast32_t lfsr32);
PERSISTENT(static uint_fast32_t lfsr31);
static unsigned shift(uint_fast32_t *lfsr, uint_fast32_t mask, uint_fast8_t xor)
{
uint_fast8_t fb = (*lfsr ^ xor)&1;
*lfsr>>=1;
if (fb) *lfsr^=mask;
return *lfsr;
}
static unsigned rand_16(void)
{
shift(&lfsr32, PMASK32, 0);
return (shift(&lfsr32, PMASK32, 0) ^ shift(&lfsr31, PMASK31, 0)) & 0xffff;
}
unsigned long random_get(void)
{
return rand_16()<<16 | rand_16();
}
void random_feed(unsigned r)
{
do {
r=r*31153;
shift(&lfsr32, PMASK32, r>>8);
shift(&lfsr31, PMASK31, r>>9);
} while (lfsr31==0 || lfsr32==0); /* avoid zeroizing LFSR */
}
void random_init(void)
{
if (lfsr32==0) lfsr32=0xABCDE;
if (lfsr31==0) lfsr31=0x23456789;
}
#ifdef RANDOM_TEST
#include <stdio.h>
int main()
{
unsigned long n;
random_init();
n=65536; do {
random_feed(n);
printf("%lu\n", random_get()&0xffff);
printf("%lu\n", random_get()>>16);
} while (--n);
return 0;
}
#endif
/* пример из жизни: в качестве источника "плохих случайных данных"
* используется датчик температуры: младшие биты там шумят хорошо. */
void randfeed_fsm(void)
{
if (clock() - T < 10*CLOCKS_PER_SEC) return;
T=clock();
adc_once(TEMP_ADC);
while(! adc_ready(TEMP_ADC));
random_feed(adc_val[TEMP_ADC]);
}
PS: да, можно использовать значение таймера аппаратного и т.п. тоже, но если есть уверенность, что какие-либо события относительно времени действительно имеют случайную составляющую. Время нажатия кнопок пользователем, например. Работа же алгоритма (программы) в целом ни разу не случайная и можно получить очень неслучайные результаты... Нельзя, например, считать случайным момент вызова какой-либо функции (той же rand()).
[ZX]