Contiki 2.6
|
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