// ADC-based strong RNG // Very slow, but who cares---if you need fast random numbers, use a PRNG. #include "rng.h" #include <avr/interrupt.h> #include <avr/io.h> #include <util/delay.h> #include "contiki.h" #ifndef RNG_CONF_USE_ADC #define RNG_CONF_USE_ADC (!RNG_CONF_USE_RADIO_CLOCK && defined(ADMUX) && defined(ADCSRA) && defined(ADCSRB) && defined(ADSC) && defined(ADEN)) #endif #ifndef RNG_CONF_USE_RADIO_CLOCK #define RNG_CONF_USE_RADIO_CLOCK ((!RNG_CONF_USE_ADC) && RF230BB) #endif /* delay_us uses floating point which includes (in some avr-gcc's) a 256 byte __clz_tab in the RAM through the .data section. */ /* _delay_loop_1 avoids this, it is 3 CPU cycles per loop, 375ns @ 8MHz */ //#define TEMPORAL_AGITATION() do { static uint8_t agitator; agitator*=97; agitator+=101; _delay_us(agitator>>1); } while (0); #define TEMPORAL_AGITATION() do { static uint8_t agitator; agitator*=97; agitator+=101; _delay_loop_1(agitator>>1); } while (0); // ------------------------------------------------------------------------- #if RNG_CONF_USE_ADC /* The hope is that there is enough noise in the LSB when pointing the ** ADC at the internal band-gap input and using the internal 2.56v ** AREF. ** ** TODO: Run some randomness tests on the output of this RNG! */ #define BITS_TO_SHIFT 9 #define ADC_CHAN_ADC1 ((0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0)) #define ADC_CHAN_BAND_GAP ((1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0)) #define ADC_REF_AREF ((0<<REFS1)|(0<<REFS0)) #define ADC_REF_AVCC ((0<<REFS1)|(1<<REFS0)) #define ADC_REF_INT ((1<<REFS1)|(1<<REFS0)) #define ADC_TRIG_FREE_RUN ((0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0)) #define ADC_PS_128 ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)) #define ADC_PS_2 ((0<<ADPS2)|(0<<ADPS1)|(1<<ADPS0)) #ifndef CONTIKI_CONF_RNG_ADC_CHANNEL #define CONTIKI_CONF_RNG_ADC_CHANNEL ADC_CHAN_BAND_GAP #endif #ifndef CONTIKI_CONF_RNG_ADC_REF #define CONTIKI_CONF_RNG_ADC_REF ADC_REF_INT #endif static uint8_t extract_random_bit_() { uint8_t ret = 0; // Store the state so that we can restore it when we are done. uint8_t sreg = SREG; uint8_t adcsra = ADCSRA; uint8_t admux = ADMUX; uint8_t adcsrb = ADCSRB; #ifdef PRR uint8_t prr = PRR; #endif // Disable interrupts cli(); #ifdef PRR // Enable ADC module PRR &= ~(1 << PRADC); #endif // Wait for any ADC conversion which // might currently be happening to finish. while(ADCSRA & (1<<ADSC)); // Configure the ADC module ADCSRA = (1<<ADEN)|ADC_PS_128; ADMUX = (uint8_t)CONTIKI_CONF_RNG_ADC_REF|(uint8_t)CONTIKI_CONF_RNG_ADC_CHANNEL; ADCSRB = ADC_TRIG_FREE_RUN; // This loop is where we try to come up with our // random bit. Unfortunately, the time it takes // for this to happen is non-deterministic, but // the result should be non-biased random bit. do { // Start conversion for first bit ADCSRA |= (1<<ADSC); // Wait for conversion to complete. while(ADCSRA & (1<<ADSC)); ret = (ADC&1); ret <<= 1; // Start conversion for second bit ADCSRA |= (1<<ADSC); // Wait for conversion to complete. while(ADCSRA & (1<<ADSC)); ret |= (ADC&1); // Toggling the reference voltage // seems to help introduce noise. ADMUX^=(1<<REFS1); // We only want to exit the loop if the first // and second sampled bits are different. // This is preliminary conditioning. } while((ret==0)||(ret==3)); // Toss out the other bit, we only care about one of them. ret &= 1; ADCSRA=0; // Restore the state ADCSRB = adcsrb; ADMUX = admux; ADCSRA = adcsra; #ifdef PRR PRR = prr; #endif SREG = sreg; return ret; } // ------------------------------------------------------------------------- #elif RNG_CONF_USE_RADIO_CLOCK /* Here we are hoping to find some noise in the clock skew ** of two different oscilating crystals. On the RZUSBstick, ** there are two such crystals: An 8MHz crystal for the ** microcontroller, and a 16MHz crystal and for the radio. ** The MCLK pin of the RF230 chip is conveniently connected ** to pin 6 of port D. First we need to have the radio ** output the 16MHz signal (it defaults to 1MHz), and then ** we can try to find some noise by sampling pin 6 of port D. ** ** The suitability of this method as a real random number ** generator has yet to be determined. It is entirely possible ** that the perceived randomness of the output is due to ** the temporal agitator mechanism that I have employed. ** Use with caution! ** ** TODO: Run some randomness tests on the output of this RNG! */ #define BITS_TO_SHIFT 8 #include "radio/rf230bb/hal.h" #include "radio/rf230bb/at86rf230_registermap.h" #ifndef TRX_CTRL_0 #define TRX_CTRL_0 0x03 #endif static uint8_t extract_random_bit_() { uint8_t ret; uint8_t trx_ctrl_0 = hal_register_read(TRX_CTRL_0); // Set radio clock output to 8MHz hal_register_write(TRX_CTRL_0,0x8|5); do { TEMPORAL_AGITATION(); // WARNING: This step may hide lack of entropy! ret = !!(PIND&(1<<6)); ret <<= 1; ret |= !!(PIND&(1<<6)); } while((ret==0)||(ret==3)); // Toss out the other bit, we only care about one of them. ret &= 1; // Restore the clkm state hal_register_write(TRX_CTRL_0,trx_ctrl_0); return ret; } #endif // ------------------------------------------------------------------------- static uint8_t extract_random_bit() { uint8_t ret; // These next two lines attempt to sync ourselves to // any pattern that might happen to be present in the // raw random source stream. After this, we use the // bias removal mechanism below to filter out the first // sign of noise. while(extract_random_bit_()==1); while(extract_random_bit_()==0); do { ret = extract_random_bit_(); ret <<= 1; ret |= extract_random_bit_(); } while((ret==0)||(ret==3)); // Toss out the other bit, we only care about one of them. ret &= 1; return ret; } uint8_t rng_get_uint8() { uint8_t ret = 0, i; for(i=0;i<BITS_TO_SHIFT;i++) { // Leftshift. ret <<= 1; // Add a random bit. ret |= extract_random_bit(); } return ret; }