@@ -129,35 +129,92 @@ impl ChaChaRng {
129
129
ChaChaRng :: from_seed ( [ 0 ; SEED_WORDS * 4 ] )
130
130
}
131
131
132
- /// Sets the internal 128-bit ChaCha counter to a user-provided value. This
133
- /// permits jumping arbitrarily ahead (or backwards) in the pseudorandom
134
- /// stream.
135
- ///
136
- /// The 128 bits used for the counter overlap with the nonce and smaller
137
- /// counter of ChaCha when used as a stream cipher. It is in theory possible
138
- /// to use `set_counter` to obtain the conventional ChaCha pseudorandom
139
- /// stream associated with a particular nonce. This is not a supported use
140
- /// of the RNG, because a nonce set that way is not treated as a constant
141
- /// value but still as part of the counter, besides endian issues.
142
- ///
143
- /// # Examples
144
- ///
145
- /// ```rust
146
- /// use rand::{ChaChaRng, RngCore, SeedableRng};
147
- ///
148
- /// // Note: Use `NewRng` or `ChaChaRng::from_rng()` outside of testing.
149
- /// let mut rng1 = ChaChaRng::from_seed([0; 32]);
150
- /// let mut rng2 = rng1.clone();
151
- ///
152
- /// // Skip to round 20. Because every round generates 16 `u32` values, this
153
- /// // actually means skipping 320 values.
154
- /// for _ in 0..(20*16) { rng1.next_u32(); }
155
- /// rng2.set_counter(20, 0);
156
- /// assert_eq!(rng1.next_u32(), rng2.next_u32());
157
- /// ```
158
- pub fn set_counter ( & mut self , counter_low : u64 , counter_high : u64 ) {
159
- self . 0 . inner_mut ( ) . set_counter ( counter_low, counter_high) ;
160
- self . 0 . reset ( ) ; // force recomputation on next use
132
+ /// Get the low 64-bits of the counter.
133
+ ///
134
+ /// Note that the low 32-bits of the counter are sufficient to produce
135
+ /// 256 GiB of data and 64-bits are enough to produce 1 ZiB of data
136
+ /// (2<sup>70</sup> bytes), thus 64-bits are sufficient unless one also
137
+ /// wants to read a nonce.
138
+ ///
139
+ /// If only the low 32-bits of the counter are wanted, simply cast:
140
+ /// `get_counter() as u32`.
141
+ pub fn get_counter ( & self ) -> u64 {
142
+ let core = self . 0 . inner ( ) ;
143
+ core. state [ 12 ] as u64 + ( ( core. state [ 13 ] as u64 ) << 32 )
144
+ }
145
+
146
+ /// Get the full 128-bit counter.
147
+ ///
148
+ /// The upper half of this counter is likely to be zero unless a nonce has
149
+ /// been set, therefore `get_counter()` will usually suffice.
150
+ #[ cfg( feature="i128_support" ) ]
151
+ pub fn get_counter_128 ( & self ) -> u128 {
152
+ let core = self . 0 . inner ( ) ;
153
+ let low = core. state [ 12 ] as u64
154
+ + ( ( core. state [ 13 ] as u64 ) << 32 ) ;
155
+ let high = core. state [ 14 ] as u64
156
+ + ( ( core. state [ 15 ] as u64 ) << 32 ) ;
157
+ low as u128 + ( ( high as u128 ) << 64 )
158
+ }
159
+
160
+ /// Set the counter.
161
+ ///
162
+ /// Note that this sets the full 128-bit counter by setting the upper
163
+ /// 64-bits to zero. If setting a nonce, do so *after* setting the counter.
164
+ pub fn set_counter ( & mut self , counter : u64 ) {
165
+ let core = self . 0 . inner_mut ( ) ;
166
+ core. state [ 12 ] = counter as u32 ;
167
+ core. state [ 13 ] = ( counter >> 32 ) as u32 ;
168
+ core. state [ 14 ] = 0 ;
169
+ core. state [ 15 ] = 0 ;
170
+ }
171
+
172
+ /// Set the full counter.
173
+ #[ cfg( feature="i128_support" ) ]
174
+ pub fn set_counter_128 ( & mut self , counter : u128 ) {
175
+ let core = self . 0 . inner_mut ( ) ;
176
+ core. state [ 12 ] = counter as u32 ;
177
+ core. state [ 13 ] = ( counter >> 32 ) as u32 ;
178
+ core. state [ 14 ] = ( counter >> 64 ) as u32 ;
179
+ core. state [ 15 ] = ( counter >> 96 ) as u32 ;
180
+ }
181
+
182
+ /// Set a 64-bit nonce.
183
+ ///
184
+ /// The original ChaCha cipher takes a 64-bit counter and 64-bit nonce.
185
+ /// Output can be replicated by setting the counter (if non-zero) then
186
+ /// calling this function with the nonce.
187
+ ///
188
+ /// It is possible to achieve the same result with a single call to
189
+ /// `set_counter_128`, but in that case be careful of Endianness when
190
+ /// converting the nonce.
191
+ pub fn set_nonce_64 ( & mut self , nonce : [ u8 ; 8 ] ) {
192
+ let mut nonce_le = [ 0u32 ; 2 ] ;
193
+ le:: read_u32_into ( & nonce, & mut nonce_le) ;
194
+ let core = self . 0 . inner_mut ( ) ;
195
+ core. state [ 14 ] = nonce_le[ 0 ] ;
196
+ core. state [ 15 ] = nonce_le[ 1 ] ;
197
+ }
198
+
199
+ /// Set a 96-bit nonce.
200
+ ///
201
+ /// The IETF ChaCha cipher standard takes a 32-bit counter and 96-bit nonce.
202
+ /// Output can be replicated by setting the counter (if non-zero) then
203
+ /// calling this function with the nonce, though note that after 256 GiB of
204
+ /// output the low 32-bits of the nonce will be incremented and this RNG
205
+ /// will continue to produce output, instead of terminating as the IETF
206
+ /// cipher would.
207
+ ///
208
+ /// It is possible to achieve the same result with a single call to
209
+ /// `set_counter_128`, but in that case be careful of Endianness when
210
+ /// converting the nonce.
211
+ pub fn set_nonce_96 ( & mut self , nonce : [ u8 ; 12 ] ) {
212
+ let mut nonce_le = [ 0u32 ; 3 ] ;
213
+ le:: read_u32_into ( & nonce, & mut nonce_le) ;
214
+ let core = self . 0 . inner_mut ( ) ;
215
+ core. state [ 13 ] = nonce_le[ 0 ] ;
216
+ core. state [ 14 ] = nonce_le[ 1 ] ;
217
+ core. state [ 15 ] = nonce_le[ 2 ] ;
161
218
}
162
219
163
220
/// Sets the number of rounds to run the ChaCha core algorithm per block to
@@ -256,16 +313,6 @@ impl BlockRngCore for ChaChaCore {
256
313
}
257
314
258
315
impl ChaChaCore {
259
- /// Sets the internal 128-bit ChaCha counter to a user-provided value. This
260
- /// permits jumping arbitrarily ahead (or backwards) in the pseudorandom
261
- /// stream.
262
- pub fn set_counter ( & mut self , counter_low : u64 , counter_high : u64 ) {
263
- self . state [ 12 ] = counter_low as u32 ;
264
- self . state [ 13 ] = ( counter_low >> 32 ) as u32 ;
265
- self . state [ 14 ] = counter_high as u32 ;
266
- self . state [ 15 ] = ( counter_high >> 32 ) as u32 ;
267
- }
268
-
269
316
/// Sets the number of rounds to run the ChaCha core algorithm per block to
270
317
/// generate.
271
318
pub fn set_rounds ( & mut self , rounds : usize ) {
@@ -377,7 +424,7 @@ mod test {
377
424
378
425
// Test block 2 by using `set_counter`
379
426
let mut rng2 = ChaChaRng :: from_seed ( seed) ;
380
- rng2. set_counter ( 2 , 0 ) ;
427
+ rng2. set_counter ( 2 ) ;
381
428
for i in results. iter_mut ( ) { * i = rng2. next_u32 ( ) ; }
382
429
assert_eq ! ( results, expected) ;
383
430
}
@@ -417,14 +464,12 @@ mod test {
417
464
}
418
465
419
466
#[ test]
420
- fn test_chacha_set_counter ( ) {
467
+ fn test_chacha_nonce ( ) {
421
468
// Test vector 5 from
422
469
// https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
423
- // Although we do not support setting a nonce, we try it here anyway so
424
- // we can use this test vector.
425
470
let seed = [ 0u8 ; 32 ] ;
426
471
let mut rng = ChaChaRng :: from_seed ( seed) ;
427
- rng. set_counter ( 0 , 2u64 << 56 ) ;
472
+ rng. set_nonce_96 ( [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 ] ) ;
428
473
429
474
let mut results = [ 0u32 ; 16 ] ;
430
475
for i in results. iter_mut ( ) { * i = rng. next_u32 ( ) ; }
0 commit comments