11
11
//! The ChaCha random number generator.
12
12
13
13
use core:: fmt;
14
- use { RngCore , CryptoRng , SeedableRng } ;
15
- use { impls, le} ;
14
+ use { RngCore , BlockRngCore , CryptoRng , SeedableRng , Error } ;
15
+ use impls:: BlockRng ;
16
+ use le;
16
17
17
18
const SEED_WORDS : usize = 8 ; // 8 words for the 256-bit key
18
19
const STATE_WORDS : usize = 16 ;
@@ -62,45 +63,45 @@ const STATE_WORDS: usize = 16;
62
63
/// http://cr.yp.to/papers.html#xsalsa)
63
64
///
64
65
/// [`set_rounds`]: #method.set_counter
65
- #[ derive( Clone ) ]
66
- pub struct ChaChaRng {
67
- buffer : [ u32 ; STATE_WORDS ] , // Internal buffer of output
68
- state : [ u32 ; STATE_WORDS ] , // Initial state
69
- index : usize , // Index into state
70
- rounds : usize ,
71
- }
66
+ #[ derive( Clone , Debug ) ]
67
+ pub struct ChaChaRng ( BlockRng < ChaChaCore > ) ;
72
68
73
- // Custom Debug implementation that does not expose the internal state
74
- impl fmt :: Debug for ChaChaRng {
75
- fn fmt ( & self , f : & mut fmt :: Formatter ) -> fmt :: Result {
76
- write ! ( f , "ChaChaRng {{}}" )
69
+ impl RngCore for ChaChaRng {
70
+ # [ inline ]
71
+ fn next_u32 ( & mut self ) -> u32 {
72
+ self . 0 . next_u32 ( )
77
73
}
78
- }
79
74
80
- macro_rules! quarter_round{
81
- ( $a: expr, $b: expr, $c: expr, $d: expr) => { {
82
- $a = $a. wrapping_add( $b) ; $d ^= $a; $d = $d. rotate_left( 16 ) ;
83
- $c = $c. wrapping_add( $d) ; $b ^= $c; $b = $b. rotate_left( 12 ) ;
84
- $a = $a. wrapping_add( $b) ; $d ^= $a; $d = $d. rotate_left( 8 ) ;
85
- $c = $c. wrapping_add( $d) ; $b ^= $c; $b = $b. rotate_left( 7 ) ;
86
- } }
75
+ #[ inline]
76
+ fn next_u64 ( & mut self ) -> u64 {
77
+ self . 0 . next_u64 ( )
78
+ }
79
+
80
+ #[ inline]
81
+ fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
82
+ self . 0 . fill_bytes ( dest)
83
+ }
84
+
85
+ #[ inline]
86
+ fn try_fill_bytes ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
87
+ self . 0 . try_fill_bytes ( dest)
88
+ }
87
89
}
88
90
89
- macro_rules! double_round{
90
- ( $x: expr) => { {
91
- // Column round
92
- quarter_round!( $x[ 0 ] , $x[ 4 ] , $x[ 8 ] , $x[ 12 ] ) ;
93
- quarter_round!( $x[ 1 ] , $x[ 5 ] , $x[ 9 ] , $x[ 13 ] ) ;
94
- quarter_round!( $x[ 2 ] , $x[ 6 ] , $x[ 10 ] , $x[ 14 ] ) ;
95
- quarter_round!( $x[ 3 ] , $x[ 7 ] , $x[ 11 ] , $x[ 15 ] ) ;
96
- // Diagonal round
97
- quarter_round!( $x[ 0 ] , $x[ 5 ] , $x[ 10 ] , $x[ 15 ] ) ;
98
- quarter_round!( $x[ 1 ] , $x[ 6 ] , $x[ 11 ] , $x[ 12 ] ) ;
99
- quarter_round!( $x[ 2 ] , $x[ 7 ] , $x[ 8 ] , $x[ 13 ] ) ;
100
- quarter_round!( $x[ 3 ] , $x[ 4 ] , $x[ 9 ] , $x[ 14 ] ) ;
101
- } }
91
+ impl SeedableRng for ChaChaRng {
92
+ type Seed = <ChaChaCore as SeedableRng >:: Seed ;
93
+
94
+ fn from_seed ( seed : Self :: Seed ) -> Self {
95
+ ChaChaRng ( BlockRng :: < ChaChaCore > :: from_seed ( seed) )
96
+ }
97
+
98
+ fn from_rng < R : RngCore > ( rng : & mut R ) -> Result < Self , Error > {
99
+ BlockRng :: < ChaChaCore > :: from_rng ( rng) . map ( |rng| ChaChaRng ( rng) )
100
+ }
102
101
}
103
102
103
+ impl CryptoRng for ChaChaRng { }
104
+
104
105
impl ChaChaRng {
105
106
/// Create an ChaCha random number generator using the default
106
107
/// fixed key of 8 zero words.
@@ -153,11 +154,8 @@ impl ChaChaRng {
153
154
/// assert_eq!(rng1.next_u32(), rng2.next_u32());
154
155
/// ```
155
156
pub fn set_counter ( & mut self , counter_low : u64 , counter_high : u64 ) {
156
- self . state [ 12 ] = counter_low as u32 ;
157
- self . state [ 13 ] = ( counter_low >> 32 ) as u32 ;
158
- self . state [ 14 ] = counter_high as u32 ;
159
- self . state [ 15 ] = ( counter_high >> 32 ) as u32 ;
160
- self . index = STATE_WORDS ; // force recomputation on next use
157
+ self . 0 . core . set_counter ( counter_low, counter_high) ;
158
+ self . 0 . index = STATE_WORDS ; // force recomputation on next use
161
159
}
162
160
163
161
/// Sets the number of rounds to run the ChaCha core algorithm per block to
@@ -180,13 +178,52 @@ impl ChaChaRng {
180
178
/// assert_eq!(rng.next_u32(), 0x2fef003e);
181
179
/// ```
182
180
pub fn set_rounds ( & mut self , rounds : usize ) {
183
- assert ! ( [ 4usize , 8 , 12 , 16 , 20 ] . iter( ) . any( |x| * x == rounds) ) ;
184
- self . rounds = rounds;
185
- self . index = STATE_WORDS ; // force recomputation on next use
181
+ self . 0 . core . set_rounds ( rounds) ;
182
+ self . 0 . index = STATE_WORDS ; // force recomputation on next use
186
183
}
184
+ }
187
185
188
- /// Refill the internal output buffer (`self.buffer`)
189
- fn update ( & mut self ) {
186
+ #[ derive( Clone ) ]
187
+ pub struct ChaChaCore {
188
+ state : [ u32 ; STATE_WORDS ] ,
189
+ rounds : usize ,
190
+ }
191
+
192
+ // Custom Debug implementation that does not expose the internal state
193
+ impl fmt:: Debug for ChaChaCore {
194
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
195
+ write ! ( f, "ChaChaCore {{}}" )
196
+ }
197
+ }
198
+
199
+ macro_rules! quarter_round{
200
+ ( $a: expr, $b: expr, $c: expr, $d: expr) => { {
201
+ $a = $a. wrapping_add( $b) ; $d ^= $a; $d = $d. rotate_left( 16 ) ;
202
+ $c = $c. wrapping_add( $d) ; $b ^= $c; $b = $b. rotate_left( 12 ) ;
203
+ $a = $a. wrapping_add( $b) ; $d ^= $a; $d = $d. rotate_left( 8 ) ;
204
+ $c = $c. wrapping_add( $d) ; $b ^= $c; $b = $b. rotate_left( 7 ) ;
205
+ } }
206
+ }
207
+
208
+ macro_rules! double_round{
209
+ ( $x: expr) => { {
210
+ // Column round
211
+ quarter_round!( $x[ 0 ] , $x[ 4 ] , $x[ 8 ] , $x[ 12 ] ) ;
212
+ quarter_round!( $x[ 1 ] , $x[ 5 ] , $x[ 9 ] , $x[ 13 ] ) ;
213
+ quarter_round!( $x[ 2 ] , $x[ 6 ] , $x[ 10 ] , $x[ 14 ] ) ;
214
+ quarter_round!( $x[ 3 ] , $x[ 7 ] , $x[ 11 ] , $x[ 15 ] ) ;
215
+ // Diagonal round
216
+ quarter_round!( $x[ 0 ] , $x[ 5 ] , $x[ 10 ] , $x[ 15 ] ) ;
217
+ quarter_round!( $x[ 1 ] , $x[ 6 ] , $x[ 11 ] , $x[ 12 ] ) ;
218
+ quarter_round!( $x[ 2 ] , $x[ 7 ] , $x[ 8 ] , $x[ 13 ] ) ;
219
+ quarter_round!( $x[ 3 ] , $x[ 4 ] , $x[ 9 ] , $x[ 14 ] ) ;
220
+ } }
221
+ }
222
+
223
+ impl BlockRngCore < u32 > for ChaChaCore {
224
+ type Results = [ u32 ; STATE_WORDS ] ;
225
+
226
+ fn generate ( & mut self , results : & mut Self :: Results ) -> Result < ( ) , Error > {
190
227
// For some reason extracting this part into a separate function
191
228
// improves performance by 50%.
192
229
fn core ( results : & mut [ u32 ; STATE_WORDS ] ,
@@ -202,71 +239,49 @@ impl ChaChaRng {
202
239
}
203
240
}
204
241
205
- core ( & mut self . buffer , & self . state , self . rounds ) ;
206
- self . index = 0 ;
242
+ core ( results , & self . state , self . rounds ) ;
243
+
207
244
// update 128-bit counter
208
245
self . state [ 12 ] = self . state [ 12 ] . wrapping_add ( 1 ) ;
209
- if self . state [ 12 ] != 0 { return } ;
246
+ if self . state [ 12 ] != 0 { return Ok ( ( ) ) } ;
210
247
self . state [ 13 ] = self . state [ 13 ] . wrapping_add ( 1 ) ;
211
- if self . state [ 13 ] != 0 { return } ;
248
+ if self . state [ 13 ] != 0 { return Ok ( ( ) ) } ;
212
249
self . state [ 14 ] = self . state [ 14 ] . wrapping_add ( 1 ) ;
213
- if self . state [ 14 ] != 0 { return } ;
250
+ if self . state [ 14 ] != 0 { return Ok ( ( ) ) } ;
214
251
self . state [ 15 ] = self . state [ 15 ] . wrapping_add ( 1 ) ;
252
+ Ok ( ( ) )
215
253
}
216
254
}
217
255
218
- impl RngCore for ChaChaRng {
219
- #[ inline]
220
- fn next_u32 ( & mut self ) -> u32 {
221
- // Using a local variable for `index`, and checking the size avoids a
222
- // bounds check later on.
223
- let mut index = self . index as usize ;
224
- if index >= STATE_WORDS {
225
- self . update ( ) ;
226
- index = 0 ;
227
- }
228
-
229
- let value = self . buffer [ index] ;
230
- self . index += 1 ;
231
- value
232
- }
233
-
234
- fn next_u64 ( & mut self ) -> u64 {
235
- impls:: next_u64_via_u32 ( self )
256
+ impl ChaChaCore {
257
+ /// Sets the internal 128-bit ChaCha counter to a user-provided value. This
258
+ /// permits jumping arbitrarily ahead (or backwards) in the pseudorandom
259
+ /// stream.
260
+ pub fn set_counter ( & mut self , counter_low : u64 , counter_high : u64 ) {
261
+ self . state [ 12 ] = counter_low as u32 ;
262
+ self . state [ 13 ] = ( counter_low >> 32 ) as u32 ;
263
+ self . state [ 14 ] = counter_high as u32 ;
264
+ self . state [ 15 ] = ( counter_high >> 32 ) as u32 ;
236
265
}
237
266
238
-
239
- fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
240
- let mut read_len = 0 ;
241
- while read_len < dest. len ( ) {
242
- if self . index >= self . buffer . len ( ) {
243
- self . update ( ) ;
244
- }
245
-
246
- let ( consumed_u32, filled_u8) =
247
- impls:: fill_via_u32_chunks ( & self . buffer [ self . index ..] ,
248
- & mut dest[ read_len..] ) ;
249
-
250
- self . index += consumed_u32;
251
- read_len += filled_u8;
252
- }
267
+ /// Sets the number of rounds to run the ChaCha core algorithm per block to
268
+ /// generate.
269
+ pub fn set_rounds ( & mut self , rounds : usize ) {
270
+ assert ! ( [ 4usize , 8 , 12 , 16 , 20 ] . iter( ) . any( |x| * x == rounds) ) ;
271
+ self . rounds = rounds;
253
272
}
254
273
}
255
274
256
- impl CryptoRng for ChaChaRng { }
257
-
258
- impl SeedableRng for ChaChaRng {
275
+ impl SeedableRng for ChaChaCore {
259
276
type Seed = [ u8 ; SEED_WORDS * 4 ] ;
260
277
fn from_seed ( seed : Self :: Seed ) -> Self {
261
278
let mut seed_le = [ 0u32 ; SEED_WORDS ] ;
262
279
le:: read_u32_into ( & seed, & mut seed_le) ;
263
- ChaChaRng {
264
- buffer : [ 0 ; STATE_WORDS ] ,
280
+ Self {
265
281
state : [ 0x61707865 , 0x3320646E , 0x79622D32 , 0x6B206574 , // constants
266
282
seed_le[ 0 ] , seed_le[ 1 ] , seed_le[ 2 ] , seed_le[ 3 ] , // seed
267
283
seed_le[ 4 ] , seed_le[ 5 ] , seed_le[ 6 ] , seed_le[ 7 ] , // seed
268
284
0 , 0 , 0 , 0 ] , // counter
269
- index : STATE_WORDS , // generate on first use
270
285
rounds : 20 ,
271
286
}
272
287
}
0 commit comments