10
10
11
11
//! The ChaCha random number generator.
12
12
13
- use core:: num:: Wrapping as w;
14
13
use core:: fmt;
14
+ use rand_core:: impls;
15
15
use { Rng , CryptoRng , SeedFromRng , SeedableRng , Error } ;
16
16
17
- #[ allow( bad_style) ]
18
- type w32 = w < u32 > ;
19
-
20
17
const KEY_WORDS : usize = 8 ; // 8 words for the 256-bit key
21
18
const STATE_WORDS : usize = 16 ;
22
19
const CHACHA_ROUNDS : u32 = 20 ; // Cryptographically secure from 8 upwards as of this writing
@@ -32,9 +29,9 @@ const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of
32
29
/// Salsa20*](http://cr.yp.to/chacha.html)
33
30
#[ derive( Clone ) ]
34
31
pub struct ChaChaRng {
35
- buffer : [ w32 ; STATE_WORDS ] , // Internal buffer of output
36
- state : [ w32 ; STATE_WORDS ] , // Initial state
37
- index : usize , // Index into state
32
+ buffer : [ u32 ; STATE_WORDS ] , // Internal buffer of output
33
+ state : [ u32 ; STATE_WORDS ] , // Initial state
34
+ index : usize , // Index into state
38
35
}
39
36
40
37
// Custom Debug implementation that does not expose the internal state
@@ -46,10 +43,10 @@ impl fmt::Debug for ChaChaRng {
46
43
47
44
macro_rules! quarter_round{
48
45
( $a: expr, $b: expr, $c: expr, $d: expr) => { {
49
- $a = $a + $b ; $d = $d ^ $ a; $d = w ( $d. 0 . rotate_left( 16 ) ) ;
50
- $c = $c + $d ; $b = $b ^ $ c; $b = w ( $b. 0 . rotate_left( 12 ) ) ;
51
- $a = $a + $b ; $d = $d ^ $ a; $d = w ( $d. 0 . rotate_left( 8 ) ) ;
52
- $c = $c + $d ; $b = $b ^ $ c; $b = w ( $b. 0 . rotate_left( 7 ) ) ;
46
+ $a = $a. wrapping_add ( $b ) ; $d ^ = $a; $d = $d. rotate_left( 16 ) ;
47
+ $c = $c. wrapping_add ( $d ) ; $b ^ = $c; $b = $b. rotate_left( 12 ) ;
48
+ $a = $a. wrapping_add ( $b ) ; $d ^ = $a; $d = $d. rotate_left( 8 ) ;
49
+ $c = $c. wrapping_add ( $d ) ; $b ^ = $c; $b = $b. rotate_left( 7 ) ;
53
50
} }
54
51
}
55
52
@@ -69,15 +66,15 @@ macro_rules! double_round{
69
66
}
70
67
71
68
#[ inline]
72
- fn core ( output : & mut [ w32 ; STATE_WORDS ] , input : & [ w32 ; STATE_WORDS ] ) {
73
- * output = * input;
69
+ fn core ( new : & mut [ u32 ; STATE_WORDS ] , input : & [ u32 ; STATE_WORDS ] ) {
70
+ * new = * input;
74
71
75
72
for _ in 0 ..CHACHA_ROUNDS / 2 {
76
- double_round ! ( output ) ;
73
+ double_round ! ( new ) ;
77
74
}
78
75
79
76
for i in 0 ..STATE_WORDS {
80
- output [ i] = output [ i] + input[ i] ;
77
+ new [ i] = new [ i] . wrapping_add ( input[ i] ) ;
81
78
}
82
79
}
83
80
@@ -104,8 +101,8 @@ impl ChaChaRng {
104
101
/// - 2419978656
105
102
pub fn new_unseeded ( ) -> ChaChaRng {
106
103
let mut rng = ChaChaRng {
107
- buffer : [ w ( 0 ) ; STATE_WORDS ] ,
108
- state : [ w ( 0 ) ; STATE_WORDS ] ,
104
+ buffer : [ 0 ; STATE_WORDS ] ,
105
+ state : [ 0 ; STATE_WORDS ] ,
109
106
index : STATE_WORDS
110
107
} ;
111
108
rng. init ( & [ 0 ; KEY_WORDS ] ) ;
@@ -133,10 +130,10 @@ impl ChaChaRng {
133
130
/// println!("{:?}", ra.next_u32());
134
131
/// ```
135
132
pub fn set_counter ( & mut self , counter_low : u64 , counter_high : u64 ) {
136
- self . state [ 12 ] = w ( ( counter_low >> 0 ) as u32 ) ;
137
- self . state [ 13 ] = w ( ( counter_low >> 32 ) as u32 ) ;
138
- self . state [ 14 ] = w ( ( counter_high >> 0 ) as u32 ) ;
139
- self . state [ 15 ] = w ( ( counter_high >> 32 ) as u32 ) ;
133
+ self . state [ 12 ] = ( counter_low >> 0 ) as u32 ;
134
+ self . state [ 13 ] = ( counter_low >> 32 ) as u32 ;
135
+ self . state [ 14 ] = ( counter_high >> 0 ) as u32 ;
136
+ self . state [ 15 ] = ( counter_high >> 32 ) as u32 ;
140
137
self . index = STATE_WORDS ; // force recomputation
141
138
}
142
139
@@ -159,19 +156,19 @@ impl ChaChaRng {
159
156
/// [1]: Daniel J. Bernstein. [*Extending the Salsa20
160
157
/// nonce.*](http://cr.yp.to/papers.html#xsalsa)
161
158
fn init ( & mut self , key : & [ u32 ; KEY_WORDS ] ) {
162
- self . state [ 0 ] = w ( 0x61707865 ) ;
163
- self . state [ 1 ] = w ( 0x3320646E ) ;
164
- self . state [ 2 ] = w ( 0x79622D32 ) ;
165
- self . state [ 3 ] = w ( 0x6B206574 ) ;
159
+ self . state [ 0 ] = 0x61707865 ;
160
+ self . state [ 1 ] = 0x3320646E ;
161
+ self . state [ 2 ] = 0x79622D32 ;
162
+ self . state [ 3 ] = 0x6B206574 ;
166
163
167
164
for i in 0 ..KEY_WORDS {
168
- self . state [ 4 +i] = w ( key[ i] ) ;
165
+ self . state [ 4 +i] = key[ i] ;
169
166
}
170
167
171
- self . state [ 12 ] = w ( 0 ) ;
172
- self . state [ 13 ] = w ( 0 ) ;
173
- self . state [ 14 ] = w ( 0 ) ;
174
- self . state [ 15 ] = w ( 0 ) ;
168
+ self . state [ 12 ] = 0 ;
169
+ self . state [ 13 ] = 0 ;
170
+ self . state [ 14 ] = 0 ;
171
+ self . state [ 15 ] = 0 ;
175
172
176
173
self . index = STATE_WORDS ;
177
174
}
@@ -181,69 +178,54 @@ impl ChaChaRng {
181
178
core ( & mut self . buffer , & self . state ) ;
182
179
self . index = 0 ;
183
180
// update 128-bit counter
184
- self . state [ 12 ] = self . state [ 12 ] + w ( 1 ) ;
185
- if self . state [ 12 ] != w ( 0 ) { return } ;
186
- self . state [ 13 ] = self . state [ 13 ] + w ( 1 ) ;
187
- if self . state [ 13 ] != w ( 0 ) { return } ;
188
- self . state [ 14 ] = self . state [ 14 ] + w ( 1 ) ;
189
- if self . state [ 14 ] != w ( 0 ) { return } ;
190
- self . state [ 15 ] = self . state [ 15 ] + w ( 1 ) ;
181
+ self . state [ 12 ] = self . state [ 12 ] . wrapping_add ( 1 ) ;
182
+ if self . state [ 12 ] != 0 { return } ;
183
+ self . state [ 13 ] = self . state [ 13 ] . wrapping_add ( 1 ) ;
184
+ if self . state [ 13 ] != 0 { return } ;
185
+ self . state [ 14 ] = self . state [ 14 ] . wrapping_add ( 1 ) ;
186
+ if self . state [ 14 ] != 0 { return } ;
187
+ self . state [ 15 ] = self . state [ 15 ] . wrapping_add ( 1 ) ;
191
188
}
192
189
}
193
190
194
191
impl Rng for ChaChaRng {
195
192
#[ inline]
196
193
fn next_u32 ( & mut self ) -> u32 {
197
- if self . index == STATE_WORDS {
194
+ // Using a local variable for `index`, and checking the size avoids a
195
+ // bounds check later on.
196
+ let mut index = self . index as usize ;
197
+ if index >= STATE_WORDS {
198
198
self . update ( ) ;
199
+ index = 0 ;
199
200
}
200
201
201
- let value = self . buffer [ self . index % STATE_WORDS ] ;
202
+ let value = self . buffer [ index] ;
202
203
self . index += 1 ;
203
- value. 0
204
+ value
204
205
}
205
-
206
+
206
207
fn next_u64 ( & mut self ) -> u64 {
207
- :: rand_core :: impls:: next_u64_via_u32 ( self )
208
+ impls:: next_u64_via_u32 ( self )
208
209
}
210
+
209
211
#[ cfg( feature = "i128_support" ) ]
210
212
fn next_u128 ( & mut self ) -> u128 {
211
- :: rand_core :: impls:: next_u128_via_u64 ( self )
213
+ impls:: next_u128_via_u64 ( self )
212
214
}
213
-
214
- // Custom implementation allowing larger reads from buffer is about 8%
215
- // faster than default implementation in my tests
215
+
216
216
fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
217
- use core:: cmp:: min;
218
- use core:: intrinsics:: { transmute, copy_nonoverlapping} ;
219
-
220
- let mut left = dest;
221
- while left. len ( ) >= 4 {
222
- if self . index == STATE_WORDS {
217
+ let mut read_len = 0 ;
218
+ while read_len < dest. len ( ) {
219
+ if self . index >= self . buffer . len ( ) {
223
220
self . update ( ) ;
224
221
}
225
-
226
- let words = min ( left. len ( ) / 4 , STATE_WORDS - self . index ) ;
227
- let ( l, r) = { left} . split_at_mut ( 4 * words) ;
228
- left = r;
229
-
230
- // convert to LE:
231
- for ref mut x in self . buffer [ self . index ..self . index +words] . iter_mut ( ) {
232
- * * x = w ( ( * x) . 0 . to_le ( ) ) ;
233
- }
234
-
235
- unsafe { copy_nonoverlapping (
236
- & self . buffer [ self . index ] . 0 as * const u32 as * const u8 ,
237
- l. as_mut_ptr ( ) ,
238
- 4 * words) } ;
239
- self . index += words;
240
- }
241
- let n = left. len ( ) ;
242
- if n > 0 {
243
- let chunk: [ u8 ; 4 ] = unsafe {
244
- transmute ( self . next_u32 ( ) . to_le ( ) )
245
- } ;
246
- left. copy_from_slice ( & chunk[ ..n] ) ;
222
+
223
+ let ( consumed_u32, filled_u8) =
224
+ impls:: fill_via_u32_chunks ( & mut self . buffer [ self . index ..] ,
225
+ & mut dest[ read_len..] ) ;
226
+
227
+ self . index += consumed_u32;
228
+ read_len += filled_u8;
247
229
}
248
230
}
249
231
@@ -271,16 +253,16 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
271
253
/// words are used, the remaining are set to zero.
272
254
fn from_seed ( seed : & ' a [ u32 ] ) -> ChaChaRng {
273
255
let mut rng = ChaChaRng {
274
- buffer : [ w ( 0 ) ; STATE_WORDS ] ,
275
- state : [ w ( 0 ) ; STATE_WORDS ] ,
256
+ buffer : [ 0 ; STATE_WORDS ] ,
257
+ state : [ 0 ; STATE_WORDS ] ,
276
258
index : STATE_WORDS
277
259
} ;
278
260
rng. init ( & [ 0u32 ; KEY_WORDS ] ) ;
279
261
// set key in place
280
262
{
281
263
let key = & mut rng. state [ 4 .. 4 +KEY_WORDS ] ;
282
264
for ( k, s) in key. iter_mut ( ) . zip ( seed. iter ( ) ) {
283
- * k = w ( * s ) ;
265
+ * k = * s ;
284
266
}
285
267
}
286
268
rng
0 commit comments