Contiki 2.5
rng.c
1 // ADC-based strong RNG
2 // Very slow, but who cares---if you need fast random numbers, use a PRNG.
3 
4 #include "rng.h"
5 #include <avr/interrupt.h>
6 #include <avr/io.h>
7 #include <util/delay.h>
8 #include "contiki.h"
9 
10 #ifndef RNG_CONF_USE_ADC
11 #define RNG_CONF_USE_ADC (!RNG_CONF_USE_RADIO_CLOCK && defined(ADMUX) && defined(ADCSRA) && defined(ADCSRB) && defined(ADSC) && defined(ADEN))
12 #endif
13 
14 #ifndef RNG_CONF_USE_RADIO_CLOCK
15 #define RNG_CONF_USE_RADIO_CLOCK ((!RNG_CONF_USE_ADC) && RF230BB)
16 #endif
17 
18 /* delay_us uses floating point which includes (in some avr-gcc's) a 256 byte __clz_tab in the RAM through the .data section. */
19 /* _delay_loop_1 avoids this, it is 3 CPU cycles per loop, 375ns @ 8MHz */
20 //#define TEMPORAL_AGITATION() do { static uint8_t agitator; agitator*=97; agitator+=101; _delay_us(agitator>>1); } while (0);
21 #define TEMPORAL_AGITATION() do { static uint8_t agitator; agitator*=97; agitator+=101; _delay_loop_1(agitator>>1); } while (0);
22 
23 
24 // -------------------------------------------------------------------------
25 #if RNG_CONF_USE_ADC
26 /* The hope is that there is enough noise in the LSB when pointing the
27 ** ADC at the internal band-gap input and using the internal 2.56v
28 ** AREF.
29 **
30 ** TODO: Run some randomness tests on the output of this RNG!
31 */
32 
33 #define BITS_TO_SHIFT 9
34 
35 #define ADC_CHAN_ADC1 ((0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0))
36 #define ADC_CHAN_BAND_GAP ((1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0))
37 #define ADC_REF_AREF ((0<<REFS1)|(0<<REFS0))
38 #define ADC_REF_AVCC ((0<<REFS1)|(1<<REFS0))
39 #define ADC_REF_INT ((1<<REFS1)|(1<<REFS0))
40 #define ADC_TRIG_FREE_RUN ((0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0))
41 #define ADC_PS_128 ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0))
42 #define ADC_PS_2 ((0<<ADPS2)|(0<<ADPS1)|(1<<ADPS0))
43 
44 #ifndef CONTIKI_CONF_RNG_ADC_CHANNEL
45 #define CONTIKI_CONF_RNG_ADC_CHANNEL ADC_CHAN_BAND_GAP
46 #endif
47 
48 #ifndef CONTIKI_CONF_RNG_ADC_REF
49 #define CONTIKI_CONF_RNG_ADC_REF ADC_REF_INT
50 #endif
51 
52 static uint8_t
53 extract_random_bit_() {
54  uint8_t ret = 0;
55 
56  // Store the state so that we can restore it when we are done.
57  uint8_t sreg = SREG;
58  uint8_t adcsra = ADCSRA;
59  uint8_t admux = ADMUX;
60  uint8_t adcsrb = ADCSRB;
61 #ifdef PRR
62  uint8_t prr = PRR;
63 #endif
64 
65  // Disable interrupts
66  cli();
67 
68 #ifdef PRR
69  // Enable ADC module
70  PRR &= ~(1 << PRADC);
71 #endif
72 
73  // Wait for any ADC conversion which
74  // might currently be happening to finish.
75  while(ADCSRA & (1<<ADSC));
76 
77  // Configure the ADC module
78  ADCSRA = (1<<ADEN)|ADC_PS_128;
79  ADMUX = (uint8_t)CONTIKI_CONF_RNG_ADC_REF|(uint8_t)CONTIKI_CONF_RNG_ADC_CHANNEL;
80  ADCSRB = ADC_TRIG_FREE_RUN;
81 
82  // This loop is where we try to come up with our
83  // random bit. Unfortunately, the time it takes
84  // for this to happen is non-deterministic, but
85  // the result should be non-biased random bit.
86  do {
87  // Start conversion for first bit
88  ADCSRA |= (1<<ADSC);
89  // Wait for conversion to complete.
90  while(ADCSRA & (1<<ADSC));
91  ret = (ADC&1);
92  ret <<= 1;
93 
94  // Start conversion for second bit
95  ADCSRA |= (1<<ADSC);
96  // Wait for conversion to complete.
97  while(ADCSRA & (1<<ADSC));
98  ret |= (ADC&1);
99 
100  // Toggling the reference voltage
101  // seems to help introduce noise.
102  ADMUX^=(1<<REFS1);
103 
104  // We only want to exit the loop if the first
105  // and second sampled bits are different.
106  // This is preliminary conditioning.
107  } while((ret==0)||(ret==3));
108 
109  // Toss out the other bit, we only care about one of them.
110  ret &= 1;
111 
112  ADCSRA=0;
113 
114  // Restore the state
115  ADCSRB = adcsrb;
116  ADMUX = admux;
117  ADCSRA = adcsra;
118 #ifdef PRR
119  PRR = prr;
120 #endif
121  SREG = sreg;
122 
123  return ret;
124 }
125 
126 // -------------------------------------------------------------------------
127 #elif RNG_CONF_USE_RADIO_CLOCK
128 /* Here we are hoping to find some noise in the clock skew
129 ** of two different oscilating crystals. On the RZUSBstick,
130 ** there are two such crystals: An 8MHz crystal for the
131 ** microcontroller, and a 16MHz crystal and for the radio.
132 ** The MCLK pin of the RF230 chip is conveniently connected
133 ** to pin 6 of port D. First we need to have the radio
134 ** output the 16MHz signal (it defaults to 1MHz), and then
135 ** we can try to find some noise by sampling pin 6 of port D.
136 **
137 ** The suitability of this method as a real random number
138 ** generator has yet to be determined. It is entirely possible
139 ** that the perceived randomness of the output is due to
140 ** the temporal agitator mechanism that I have employed.
141 ** Use with caution!
142 **
143 ** TODO: Run some randomness tests on the output of this RNG!
144 */
145 
146 #define BITS_TO_SHIFT 8
147 
148 #include "radio/rf230bb/hal.h"
150 
151 #ifndef TRX_CTRL_0
152 #define TRX_CTRL_0 0x03
153 #endif
154 
155 static uint8_t
156 extract_random_bit_() {
157  uint8_t ret;
158  uint8_t trx_ctrl_0 = hal_register_read(TRX_CTRL_0);
159 
160  // Set radio clock output to 8MHz
161  hal_register_write(TRX_CTRL_0,0x8|5);
162 
163  do {
164  TEMPORAL_AGITATION(); // WARNING: This step may hide lack of entropy!
165 
166  ret = !!(PIND&(1<<6));
167  ret <<= 1;
168  ret |= !!(PIND&(1<<6));
169  } while((ret==0)||(ret==3));
170 
171  // Toss out the other bit, we only care about one of them.
172  ret &= 1;
173 
174  // Restore the clkm state
175  hal_register_write(TRX_CTRL_0,trx_ctrl_0);
176 
177  return ret;
178 }
179 
180 #endif
181 
182 // -------------------------------------------------------------------------
183 
184 static uint8_t
185 extract_random_bit() {
186  uint8_t ret;
187 
188  // These next two lines attempt to sync ourselves to
189  // any pattern that might happen to be present in the
190  // raw random source stream. After this, we use the
191  // bias removal mechanism below to filter out the first
192  // sign of noise.
193  while(extract_random_bit_()==1);
194  while(extract_random_bit_()==0);
195 
196  do {
197  ret = extract_random_bit_();
198  ret <<= 1;
199  ret |= extract_random_bit_();
200  } while((ret==0)||(ret==3));
201 
202  // Toss out the other bit, we only care about one of them.
203  ret &= 1;
204 
205  return ret;
206 }
207 
208 uint8_t
209 rng_get_uint8() {
210  uint8_t ret = 0, i;
211  for(i=0;i<BITS_TO_SHIFT;i++) {
212  // Leftshift.
213  ret <<= 1;
214 
215  // Add a random bit.
216  ret |= extract_random_bit();
217  }
218  return ret;
219 }
220