1 // Copyright 2018 Developers of the Rand project.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 //! The ChaCha random number generator.
10 
11 #[cfg(not(feature = "std"))] use core;
12 #[cfg(feature = "std")] use std as core;
13 
14 use self::core::fmt;
15 use crate::guts::ChaCha;
16 use rand_core::block::{BlockRng, BlockRngCore};
17 use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
18 
19 #[cfg(feature = "serde1")] use serde::{Serialize, Deserialize, Serializer, Deserializer};
20 
21 // NB. this must remain consistent with some currently hard-coded numbers in this module
22 const BUF_BLOCKS: u8 = 4;
23 // number of 32-bit words per ChaCha block (fixed by algorithm definition)
24 const BLOCK_WORDS: u8 = 16;
25 
26 #[repr(transparent)]
27 pub struct Array64<T>([T; 64]);
28 impl<T> Default for Array64<T>
29 where T: Default
30 {
31     #[rustfmt::skip]
default() -> Self32     fn default() -> Self {
33         Self([
34             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
35             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
36             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
37             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
38             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
39             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
40             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
41             T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
42         ])
43     }
44 }
45 impl<T> AsRef<[T]> for Array64<T> {
as_ref(&self) -> &[T]46     fn as_ref(&self) -> &[T] {
47         &self.0
48     }
49 }
50 impl<T> AsMut<[T]> for Array64<T> {
as_mut(&mut self) -> &mut [T]51     fn as_mut(&mut self) -> &mut [T] {
52         &mut self.0
53     }
54 }
55 impl<T> Clone for Array64<T>
56 where T: Copy + Default
57 {
clone(&self) -> Self58     fn clone(&self) -> Self {
59         let mut new = Self::default();
60         new.0.copy_from_slice(&self.0);
61         new
62     }
63 }
64 impl<T> fmt::Debug for Array64<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result65     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66         write!(f, "Array64 {{}}")
67     }
68 }
69 
70 macro_rules! chacha_impl {
71     ($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident) => {
72         #[doc=$doc]
73         #[derive(Clone, PartialEq, Eq)]
74         pub struct $ChaChaXCore {
75             state: ChaCha,
76         }
77 
78         // Custom Debug implementation that does not expose the internal state
79         impl fmt::Debug for $ChaChaXCore {
80             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81                 write!(f, "ChaChaXCore {{}}")
82             }
83         }
84 
85         impl BlockRngCore for $ChaChaXCore {
86             type Item = u32;
87             type Results = Array64<u32>;
88             #[inline]
89             fn generate(&mut self, r: &mut Self::Results) {
90                 // Fill slice of words by writing to equivalent slice of bytes, then fixing endianness.
91                 self.state.refill4($rounds, unsafe {
92                     &mut *(&mut *r as *mut Array64<u32> as *mut [u8; 256])
93                 });
94                 for x in r.as_mut() {
95                     *x = x.to_le();
96                 }
97             }
98         }
99 
100         impl SeedableRng for $ChaChaXCore {
101             type Seed = [u8; 32];
102             #[inline]
103             fn from_seed(seed: Self::Seed) -> Self {
104                 $ChaChaXCore { state: ChaCha::new(&seed, &[0u8; 8]) }
105             }
106         }
107 
108         impl CryptoRng for $ChaChaXCore {}
109 
110         /// A cryptographically secure random number generator that uses the ChaCha algorithm.
111         ///
112         /// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use as an RNG. It is
113         /// an improved variant of the Salsa20 cipher family, which was selected as one of the "stream
114         /// ciphers suitable for widespread adoption" by eSTREAM[^2].
115         ///
116         /// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe against timing
117         /// attacks, although that is mostly a concern for ciphers and not for RNGs. We provide a SIMD
118         /// implementation to support high throughput on a variety of common hardware platforms.
119         ///
120         /// With the ChaCha algorithm it is possible to choose the number of rounds the core algorithm
121         /// should run. The number of rounds is a tradeoff between performance and security, where 8
122         /// rounds is the minimum potentially secure configuration, and 20 rounds is widely used as a
123         /// conservative choice.
124         ///
125         /// We use a 64-bit counter and 64-bit stream identifier as in Bernstein's implementation[^1]
126         /// except that we use a stream identifier in place of a nonce. A 64-bit counter over 64-byte
127         /// (16 word) blocks allows 1 ZiB of output before cycling, and the stream identifier allows
128         /// 2<sup>64</sup> unique streams of output per seed. Both counter and stream are initialized
129         /// to zero but may be set via the `set_word_pos` and `set_stream` methods.
130         ///
131         /// The word layout is:
132         ///
133         /// ```text
134         /// constant  constant  constant  constant
135         /// seed      seed      seed      seed
136         /// seed      seed      seed      seed
137         /// counter   counter   stream_id stream_id
138         /// ```
139         ///
140         /// This implementation uses an output buffer of sixteen `u32` words, and uses
141         /// [`BlockRng`] to implement the [`RngCore`] methods.
142         ///
143         /// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
144         ///       https://cr.yp.to/chacha.html)
145         ///
146         /// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
147         ///       http://www.ecrypt.eu.org/stream/)
148         #[derive(Clone, Debug)]
149         pub struct $ChaChaXRng {
150             rng: BlockRng<$ChaChaXCore>,
151         }
152 
153         impl SeedableRng for $ChaChaXRng {
154             type Seed = [u8; 32];
155             #[inline]
156             fn from_seed(seed: Self::Seed) -> Self {
157                 let core = $ChaChaXCore::from_seed(seed);
158                 Self {
159                     rng: BlockRng::new(core),
160                 }
161             }
162         }
163 
164         impl RngCore for $ChaChaXRng {
165             #[inline]
166             fn next_u32(&mut self) -> u32 {
167                 self.rng.next_u32()
168             }
169             #[inline]
170             fn next_u64(&mut self) -> u64 {
171                 self.rng.next_u64()
172             }
173             #[inline]
174             fn fill_bytes(&mut self, bytes: &mut [u8]) {
175                 self.rng.fill_bytes(bytes)
176             }
177             #[inline]
178             fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> {
179                 self.rng.try_fill_bytes(bytes)
180             }
181         }
182 
183         impl $ChaChaXRng {
184             // The buffer is a 4-block window, i.e. it is always at a block-aligned position in the
185             // stream but if the stream has been seeked it may not be self-aligned.
186 
187             /// Get the offset from the start of the stream, in 32-bit words.
188             ///
189             /// Since the generated blocks are 16 words (2<sup>4</sup>) long and the
190             /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are
191             /// not supported, hence the result can simply be multiplied by 4 to get a
192             /// byte-offset.
193             #[inline]
194             pub fn get_word_pos(&self) -> u128 {
195                 let buf_start_block = {
196                     let buf_end_block = self.rng.core.state.get_block_pos();
197                     u64::wrapping_sub(buf_end_block, BUF_BLOCKS.into())
198                 };
199                 let (buf_offset_blocks, block_offset_words) = {
200                     let buf_offset_words = self.rng.index() as u64;
201                     let blocks_part = buf_offset_words / u64::from(BLOCK_WORDS);
202                     let words_part = buf_offset_words % u64::from(BLOCK_WORDS);
203                     (blocks_part, words_part)
204                 };
205                 let pos_block = u64::wrapping_add(buf_start_block, buf_offset_blocks);
206                 let pos_block_words = u128::from(pos_block) * u128::from(BLOCK_WORDS);
207                 pos_block_words + u128::from(block_offset_words)
208             }
209 
210             /// Set the offset from the start of the stream, in 32-bit words.
211             ///
212             /// As with `get_word_pos`, we use a 68-bit number. Since the generator
213             /// simply cycles at the end of its period (1 ZiB), we ignore the upper
214             /// 60 bits.
215             #[inline]
216             pub fn set_word_pos(&mut self, word_offset: u128) {
217                 let block = (word_offset / u128::from(BLOCK_WORDS)) as u64;
218                 self.rng
219                     .core
220                     .state
221                     .set_block_pos(block);
222                 self.rng.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
223             }
224 
225             /// Set the stream number.
226             ///
227             /// This is initialized to zero; 2<sup>64</sup> unique streams of output
228             /// are available per seed/key.
229             ///
230             /// Note that in order to reproduce ChaCha output with a specific 64-bit
231             /// nonce, one can convert that nonce to a `u64` in little-endian fashion
232             /// and pass to this function. In theory a 96-bit nonce can be used by
233             /// passing the last 64-bits to this function and using the first 32-bits as
234             /// the most significant half of the 64-bit counter (which may be set
235             /// indirectly via `set_word_pos`), but this is not directly supported.
236             #[inline]
237             pub fn set_stream(&mut self, stream: u64) {
238                 self.rng
239                     .core
240                     .state
241                     .set_nonce(stream);
242                 if self.rng.index() != 64 {
243                     let wp = self.get_word_pos();
244                     self.set_word_pos(wp);
245                 }
246             }
247 
248             /// Get the stream number.
249             #[inline]
250             pub fn get_stream(&self) -> u64 {
251                 self.rng
252                     .core
253                     .state
254                     .get_nonce()
255             }
256 
257             /// Get the seed.
258             #[inline]
259             pub fn get_seed(&self) -> [u8; 32] {
260                 self.rng
261                     .core
262                     .state
263                     .get_seed()
264             }
265         }
266 
267         impl CryptoRng for $ChaChaXRng {}
268 
269         impl From<$ChaChaXCore> for $ChaChaXRng {
270             fn from(core: $ChaChaXCore) -> Self {
271                 $ChaChaXRng {
272                     rng: BlockRng::new(core),
273                 }
274             }
275         }
276 
277         impl PartialEq<$ChaChaXRng> for $ChaChaXRng {
278             fn eq(&self, rhs: &$ChaChaXRng) -> bool {
279                 let a: $abst::$ChaChaXRng = self.into();
280                 let b: $abst::$ChaChaXRng = rhs.into();
281                 a == b
282             }
283         }
284         impl Eq for $ChaChaXRng {}
285 
286         #[cfg(feature = "serde1")]
287         impl Serialize for $ChaChaXRng {
288             fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
289             where S: Serializer {
290                 $abst::$ChaChaXRng::from(self).serialize(s)
291             }
292         }
293         #[cfg(feature = "serde1")]
294         impl<'de> Deserialize<'de> for $ChaChaXRng {
295             fn deserialize<D>(d: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
296                 $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
297             }
298         }
299 
300         mod $abst {
301             #[cfg(feature = "serde1")] use serde::{Serialize, Deserialize};
302 
303             // The abstract state of a ChaCha stream, independent of implementation choices. The
304             // comparison and serialization of this object is considered a semver-covered part of
305             // the API.
306             #[derive(Debug, PartialEq, Eq)]
307             #[cfg_attr(
308                 feature = "serde1",
309                 derive(Serialize, Deserialize),
310             )]
311             pub(crate) struct $ChaChaXRng {
312                 seed: [u8; 32],
313                 stream: u64,
314                 word_pos: u128,
315             }
316 
317             impl From<&super::$ChaChaXRng> for $ChaChaXRng {
318                 // Forget all information about the input except what is necessary to determine the
319                 // outputs of any sequence of pub API calls.
320                 fn from(r: &super::$ChaChaXRng) -> Self {
321                     Self {
322                         seed: r.get_seed(),
323                         stream: r.get_stream(),
324                         word_pos: r.get_word_pos(),
325                     }
326                 }
327             }
328 
329             impl From<&$ChaChaXRng> for super::$ChaChaXRng {
330                 // Construct one of the possible concrete RNGs realizing an abstract state.
331                 fn from(a: &$ChaChaXRng) -> Self {
332                     use rand_core::SeedableRng;
333                     let mut r = Self::from_seed(a.seed);
334                     r.set_stream(a.stream);
335                     r.set_word_pos(a.word_pos);
336                     r
337                 }
338             }
339         }
340     }
341 }
342 
343 chacha_impl!(ChaCha20Core, ChaCha20Rng, 10, "ChaCha with 20 rounds", abstract20);
344 chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds", abstract12);
345 chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds", abstract8);
346 
347 #[cfg(test)]
348 mod test {
349     use rand_core::{RngCore, SeedableRng};
350 
351     #[cfg(feature = "serde1")] use super::{ChaCha20Rng, ChaCha12Rng, ChaCha8Rng};
352 
353     type ChaChaRng = super::ChaCha20Rng;
354 
355     #[cfg(feature = "serde1")]
356     #[test]
test_chacha_serde_roundtrip()357     fn test_chacha_serde_roundtrip() {
358         let seed = [
359             1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0, 0, 0,
360             0, 2, 92,
361         ];
362         let mut rng1 = ChaCha20Rng::from_seed(seed);
363         let mut rng2 = ChaCha12Rng::from_seed(seed);
364         let mut rng3 = ChaCha8Rng::from_seed(seed);
365 
366         let encoded1 = serde_json::to_string(&rng1).unwrap();
367         let encoded2 = serde_json::to_string(&rng2).unwrap();
368         let encoded3 = serde_json::to_string(&rng3).unwrap();
369 
370         let mut decoded1: ChaCha20Rng = serde_json::from_str(&encoded1).unwrap();
371         let mut decoded2: ChaCha12Rng = serde_json::from_str(&encoded2).unwrap();
372         let mut decoded3: ChaCha8Rng = serde_json::from_str(&encoded3).unwrap();
373 
374         assert_eq!(rng1, decoded1);
375         assert_eq!(rng2, decoded2);
376         assert_eq!(rng3, decoded3);
377 
378         assert_eq!(rng1.next_u32(), decoded1.next_u32());
379         assert_eq!(rng2.next_u32(), decoded2.next_u32());
380         assert_eq!(rng3.next_u32(), decoded3.next_u32());
381     }
382 
383     // This test validates that:
384     // 1. a hard-coded serialization demonstrating the format at time of initial release can still
385     //    be deserialized to a ChaChaRng
386     // 2. re-serializing the resultant object produces exactly the original string
387     //
388     // Condition 2 is stronger than necessary: an equivalent serialization (e.g. with field order
389     // permuted, or whitespace differences) would also be admissible, but would fail this test.
390     // However testing for equivalence of serialized data is difficult, and there shouldn't be any
391     // reason we need to violate the stronger-than-needed condition, e.g. by changing the field
392     // definition order.
393     #[cfg(feature = "serde1")]
394     #[test]
test_chacha_serde_format_stability()395     fn test_chacha_serde_format_stability() {
396         let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#;
397         let r: ChaChaRng = serde_json::from_str(&j).unwrap();
398         let j1 = serde_json::to_string(&r).unwrap();
399         assert_eq!(j, j1);
400     }
401 
402     #[test]
test_chacha_construction()403     fn test_chacha_construction() {
404         let seed = [
405             0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
406             0, 0, 0,
407         ];
408         let mut rng1 = ChaChaRng::from_seed(seed);
409         assert_eq!(rng1.next_u32(), 137206642);
410 
411         let mut rng2 = ChaChaRng::from_rng(rng1).unwrap();
412         assert_eq!(rng2.next_u32(), 1325750369);
413     }
414 
415     #[test]
test_chacha_true_values_a()416     fn test_chacha_true_values_a() {
417         // Test vectors 1 and 2 from
418         // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
419         let seed = [0u8; 32];
420         let mut rng = ChaChaRng::from_seed(seed);
421 
422         let mut results = [0u32; 16];
423         for i in results.iter_mut() {
424             *i = rng.next_u32();
425         }
426         let expected = [
427             0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8,
428             0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, 0xf4b8436a, 0x1ca11815,
429             0x69b687c3, 0x8665eeb2,
430         ];
431         assert_eq!(results, expected);
432 
433         for i in results.iter_mut() {
434             *i = rng.next_u32();
435         }
436         let expected = [
437             0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612,
438             0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, 0x281fed31, 0x45fb0a51,
439             0x1f0ae1ac, 0x6f4d794b,
440         ];
441         assert_eq!(results, expected);
442     }
443 
444     #[test]
test_chacha_true_values_b()445     fn test_chacha_true_values_b() {
446         // Test vector 3 from
447         // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
448         let seed = [
449             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
450             0, 0, 1,
451         ];
452         let mut rng = ChaChaRng::from_seed(seed);
453 
454         // Skip block 0
455         for _ in 0..16 {
456             rng.next_u32();
457         }
458 
459         let mut results = [0u32; 16];
460         for i in results.iter_mut() {
461             *i = rng.next_u32();
462         }
463         let expected = [
464             0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, 0xe8252083, 0x60818b01, 0xf38422b8,
465             0x5aaa49c9, 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, 0x4436274e, 0x2561b3c8,
466             0xebdd4aa6, 0xa0136c00,
467         ];
468         assert_eq!(results, expected);
469     }
470 
471     #[test]
test_chacha_true_values_c()472     fn test_chacha_true_values_c() {
473         // Test vector 4 from
474         // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
475         let seed = [
476             0, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
477             0, 0, 0, 0,
478         ];
479         let expected = [
480             0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, 0xa78dea8f, 0x5e269039, 0xa1bebbc1,
481             0xcaf09aae, 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, 0x546ca624, 0x1bec45d5,
482             0x87f47473, 0x96f0992e,
483         ];
484         let expected_end = 3 * 16;
485         let mut results = [0u32; 16];
486 
487         // Test block 2 by skipping block 0 and 1
488         let mut rng1 = ChaChaRng::from_seed(seed);
489         for _ in 0..32 {
490             rng1.next_u32();
491         }
492         for i in results.iter_mut() {
493             *i = rng1.next_u32();
494         }
495         assert_eq!(results, expected);
496         assert_eq!(rng1.get_word_pos(), expected_end);
497 
498         // Test block 2 by using `set_word_pos`
499         let mut rng2 = ChaChaRng::from_seed(seed);
500         rng2.set_word_pos(2 * 16);
501         for i in results.iter_mut() {
502             *i = rng2.next_u32();
503         }
504         assert_eq!(results, expected);
505         assert_eq!(rng2.get_word_pos(), expected_end);
506 
507         // Test skipping behaviour with other types
508         let mut buf = [0u8; 32];
509         rng2.fill_bytes(&mut buf[..]);
510         assert_eq!(rng2.get_word_pos(), expected_end + 8);
511         rng2.fill_bytes(&mut buf[0..25]);
512         assert_eq!(rng2.get_word_pos(), expected_end + 15);
513         rng2.next_u64();
514         assert_eq!(rng2.get_word_pos(), expected_end + 17);
515         rng2.next_u32();
516         rng2.next_u64();
517         assert_eq!(rng2.get_word_pos(), expected_end + 20);
518         rng2.fill_bytes(&mut buf[0..1]);
519         assert_eq!(rng2.get_word_pos(), expected_end + 21);
520     }
521 
522     #[test]
test_chacha_multiple_blocks()523     fn test_chacha_multiple_blocks() {
524         let seed = [
525             0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7,
526             0, 0, 0,
527         ];
528         let mut rng = ChaChaRng::from_seed(seed);
529 
530         // Store the 17*i-th 32-bit word,
531         // i.e., the i-th word of the i-th 16-word block
532         let mut results = [0u32; 16];
533         for i in results.iter_mut() {
534             *i = rng.next_u32();
535             for _ in 0..16 {
536                 rng.next_u32();
537             }
538         }
539         let expected = [
540             0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186,
541             0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc,
542             0x5f1c86d9, 0xc1f8e7f4,
543         ];
544         assert_eq!(results, expected);
545     }
546 
547     #[test]
test_chacha_true_bytes()548     fn test_chacha_true_bytes() {
549         let seed = [0u8; 32];
550         let mut rng = ChaChaRng::from_seed(seed);
551         let mut results = [0u8; 32];
552         rng.fill_bytes(&mut results);
553         let expected = [
554             118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
555             25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
556         ];
557         assert_eq!(results, expected);
558     }
559 
560     #[test]
test_chacha_nonce()561     fn test_chacha_nonce() {
562         // Test vector 5 from
563         // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
564         // Although we do not support setting a nonce, we try it here anyway so
565         // we can use this test vector.
566         let seed = [0u8; 32];
567         let mut rng = ChaChaRng::from_seed(seed);
568         // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2
569         rng.set_stream(2u64 << (24 + 32));
570 
571         let mut results = [0u32; 16];
572         for i in results.iter_mut() {
573             *i = rng.next_u32();
574         }
575         let expected = [
576             0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, 0x88228b1a, 0x96a4dfb3, 0x5b76ab72,
577             0xc727ee54, 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, 0x99c28f5f, 0x628314e8,
578             0x398a19fa, 0x6ded1b53,
579         ];
580         assert_eq!(results, expected);
581     }
582 
583     #[test]
test_chacha_clone_streams()584     fn test_chacha_clone_streams() {
585         let seed = [
586             0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7,
587             0, 0, 0,
588         ];
589         let mut rng = ChaChaRng::from_seed(seed);
590         let mut clone = rng.clone();
591         for _ in 0..16 {
592             assert_eq!(rng.next_u64(), clone.next_u64());
593         }
594 
595         rng.set_stream(51);
596         for _ in 0..7 {
597             assert!(rng.next_u32() != clone.next_u32());
598         }
599         clone.set_stream(51); // switch part way through block
600         for _ in 7..16 {
601             assert_eq!(rng.next_u32(), clone.next_u32());
602         }
603     }
604 
605     #[test]
test_chacha_word_pos_wrap_exact()606     fn test_chacha_word_pos_wrap_exact() {
607         use super::{BUF_BLOCKS, BLOCK_WORDS};
608         let mut rng = ChaChaRng::from_seed(Default::default());
609         // refilling the buffer in set_word_pos will wrap the block counter to 0
610         let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS);
611         rng.set_word_pos(last_block);
612         assert_eq!(rng.get_word_pos(), last_block);
613     }
614 
615     #[test]
test_chacha_word_pos_wrap_excess()616     fn test_chacha_word_pos_wrap_excess() {
617         use super::BLOCK_WORDS;
618         let mut rng = ChaChaRng::from_seed(Default::default());
619         // refilling the buffer in set_word_pos will wrap the block counter past 0
620         let last_block = (1 << 68) - u128::from(BLOCK_WORDS);
621         rng.set_word_pos(last_block);
622         assert_eq!(rng.get_word_pos(), last_block);
623     }
624 
625     #[test]
test_chacha_word_pos_zero()626     fn test_chacha_word_pos_zero() {
627         let mut rng = ChaChaRng::from_seed(Default::default());
628         assert_eq!(rng.get_word_pos(), 0);
629         rng.set_word_pos(0);
630         assert_eq!(rng.get_word_pos(), 0);
631     }
632 }
633