Contiki 2.6

rng.c

00001 //      ADC-based strong RNG
00002 //      Very slow, but who cares---if you need fast random numbers, use a PRNG.
00003 
00004 #include "rng.h"
00005 #include <avr/interrupt.h>
00006 #include <avr/io.h>
00007 #include <util/delay.h>
00008 #include "contiki.h"
00009 
00010 #ifndef RNG_CONF_USE_ADC
00011 #define RNG_CONF_USE_ADC                        (!RNG_CONF_USE_RADIO_CLOCK && defined(ADMUX) && defined(ADCSRA) && defined(ADCSRB) && defined(ADSC) && defined(ADEN))
00012 #endif
00013 
00014 #ifndef RNG_CONF_USE_RADIO_CLOCK
00015 #define RNG_CONF_USE_RADIO_CLOCK        ((!RNG_CONF_USE_ADC) && RF230BB)
00016 #endif
00017 
00018 /* delay_us uses floating point which includes (in some avr-gcc's) a 256 byte __clz_tab in the RAM through the .data section. */
00019 /* _delay_loop_1 avoids this, it is 3 CPU cycles per loop, 375ns @ 8MHz */
00020 //#define TEMPORAL_AGITATION()          do { static uint8_t agitator; agitator*=97; agitator+=101; _delay_us(agitator>>1); } while (0);
00021 #define TEMPORAL_AGITATION()            do { static uint8_t agitator; agitator*=97; agitator+=101; _delay_loop_1(agitator>>1); } while (0);
00022 
00023 
00024 // -------------------------------------------------------------------------
00025 #if RNG_CONF_USE_ADC
00026 /*      The hope is that there is enough noise in the LSB when pointing the
00027 **      ADC at the internal band-gap input and using the internal 2.56v
00028 **      AREF.
00029 **
00030 **      TODO: Run some randomness tests on the output of this RNG!
00031 */
00032 
00033 #define BITS_TO_SHIFT           9
00034 
00035 #define ADC_CHAN_ADC1 ((0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0))
00036 #define ADC_CHAN_BAND_GAP ((1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0))
00037 #define ADC_REF_AREF  ((0<<REFS1)|(0<<REFS0))
00038 #define ADC_REF_AVCC  ((0<<REFS1)|(1<<REFS0))
00039 #define ADC_REF_INT   ((1<<REFS1)|(1<<REFS0))
00040 #define ADC_TRIG_FREE_RUN  ((0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0))
00041 #define ADC_PS_128  ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0))
00042 #define ADC_PS_2  ((0<<ADPS2)|(0<<ADPS1)|(1<<ADPS0))
00043 
00044 #ifndef CONTIKI_CONF_RNG_ADC_CHANNEL
00045 #define CONTIKI_CONF_RNG_ADC_CHANNEL    ADC_CHAN_BAND_GAP
00046 #endif
00047 
00048 #ifndef CONTIKI_CONF_RNG_ADC_REF
00049 #define CONTIKI_CONF_RNG_ADC_REF        ADC_REF_INT
00050 #endif
00051 
00052 static uint8_t
00053 extract_random_bit_() {
00054         uint8_t ret = 0;
00055 
00056         // Store the state so that we can restore it when we are done.
00057         uint8_t sreg = SREG;
00058         uint8_t adcsra = ADCSRA;
00059         uint8_t admux = ADMUX;
00060         uint8_t adcsrb = ADCSRB;
00061 #ifdef PRR
00062         uint8_t prr = PRR;
00063 #endif
00064 
00065         // Disable interrupts
00066         cli();
00067 
00068 #ifdef PRR
00069         // Enable ADC module 
00070         PRR &= ~(1 << PRADC);
00071 #endif
00072 
00073         // Wait for any ADC conversion which
00074         // might currently be happening to finish.
00075         while(ADCSRA & (1<<ADSC));
00076 
00077         // Configure the ADC module
00078         ADCSRA = (1<<ADEN)|ADC_PS_128;
00079         ADMUX = (uint8_t)CONTIKI_CONF_RNG_ADC_REF|(uint8_t)CONTIKI_CONF_RNG_ADC_CHANNEL;
00080         ADCSRB = ADC_TRIG_FREE_RUN;
00081 
00082         // This loop is where we try to come up with our
00083         // random bit. Unfortunately, the time it takes
00084         // for this to happen is non-deterministic, but
00085         // the result should be non-biased random bit.
00086         do {
00087                 // Start conversion for first bit
00088                 ADCSRA |= (1<<ADSC);
00089                 // Wait for conversion to complete.
00090                 while(ADCSRA & (1<<ADSC));
00091                 ret = (ADC&1);
00092                 ret <<= 1;
00093 
00094                 // Start conversion for second bit
00095                 ADCSRA |= (1<<ADSC);
00096                 // Wait for conversion to complete.
00097                 while(ADCSRA & (1<<ADSC));
00098                 ret |= (ADC&1);
00099 
00100                 // Toggling the reference voltage
00101                 // seems to help introduce noise.
00102                 ADMUX^=(1<<REFS1);
00103                                 
00104                 // We only want to exit the loop if the first
00105                 // and second sampled bits are different.
00106                 // This is preliminary conditioning.
00107         } while((ret==0)||(ret==3));
00108 
00109         // Toss out the other bit, we only care about one of them.
00110         ret &= 1;
00111 
00112         ADCSRA=0;
00113 
00114         // Restore the state
00115         ADCSRB = adcsrb;
00116         ADMUX = admux;
00117         ADCSRA = adcsra;
00118 #ifdef PRR
00119         PRR = prr;
00120 #endif
00121         SREG = sreg;
00122 
00123         return ret;
00124 }
00125 
00126 // -------------------------------------------------------------------------
00127 #elif RNG_CONF_USE_RADIO_CLOCK
00128 /*      Here we are hoping to find some noise in the clock skew
00129 **      of two different oscilating crystals. On the RZUSBstick,
00130 **      there are two such crystals: An 8MHz crystal for the
00131 **      microcontroller, and a 16MHz crystal and for the radio.
00132 **      The MCLK pin of the RF230 chip is conveniently connected
00133 **      to pin 6 of port D. First we need to have the radio
00134 **      output the 16MHz signal (it defaults to 1MHz), and then
00135 **      we can try to find some noise by sampling pin 6 of port D.
00136 **
00137 **      The suitability of this method as a real random number
00138 **      generator has yet to be determined. It is entirely possible
00139 **      that the perceived randomness of the output is due to
00140 **      the temporal agitator mechanism that I have employed.
00141 **      Use with caution!
00142 **
00143 **      TODO: Run some randomness tests on the output of this RNG!
00144 */
00145 
00146 #define BITS_TO_SHIFT           8
00147 
00148 #include "radio/rf230bb/hal.h"
00149 #include "radio/rf230bb/at86rf230_registermap.h"
00150 
00151 #ifndef TRX_CTRL_0
00152 #define TRX_CTRL_0 0x03
00153 #endif
00154 
00155 static uint8_t
00156 extract_random_bit_() {
00157         uint8_t ret;
00158         uint8_t trx_ctrl_0 = hal_register_read(TRX_CTRL_0);
00159         
00160         // Set radio clock output to 8MHz
00161         hal_register_write(TRX_CTRL_0,0x8|5);
00162 
00163         do {
00164                 TEMPORAL_AGITATION(); // WARNING: This step may hide lack of entropy!
00165 
00166                 ret = !!(PIND&(1<<6));
00167                 ret <<= 1;
00168                 ret |= !!(PIND&(1<<6));
00169         } while((ret==0)||(ret==3));
00170 
00171         // Toss out the other bit, we only care about one of them.
00172         ret &= 1;
00173         
00174         // Restore the clkm state
00175         hal_register_write(TRX_CTRL_0,trx_ctrl_0);
00176         
00177         return ret;
00178 }
00179 
00180 #endif
00181 
00182 // -------------------------------------------------------------------------
00183 
00184 static uint8_t
00185 extract_random_bit() {
00186         uint8_t ret;
00187 
00188         // These next two lines attempt to sync ourselves to
00189         // any pattern that might happen to be present in the
00190         // raw random source stream. After this, we use the
00191         // bias removal mechanism below to filter out the first
00192         // sign of noise.
00193         while(extract_random_bit_()==1);
00194         while(extract_random_bit_()==0);
00195 
00196         do {
00197                 ret = extract_random_bit_();
00198                 ret <<= 1;
00199                 ret |= extract_random_bit_();
00200         } while((ret==0)||(ret==3));
00201 
00202         // Toss out the other bit, we only care about one of them.
00203         ret &= 1;
00204 
00205         return ret;
00206 }
00207 
00208 uint8_t
00209 rng_get_uint8() {
00210         uint8_t ret = 0, i;
00211         for(i=0;i<BITS_TO_SHIFT;i++) {
00212                 // Leftshift.
00213                 ret <<= 1;
00214 
00215                 // Add a random bit.
00216                 ret |= extract_random_bit();
00217         }
00218         return ret;
00219 }
00220