1use crate::guts::ChaCha;
12use core::convert::Infallible;
13use core::fmt;
14use rand_core::block::{BlockRng, Generator};
15use rand_core::{SeedableRng, TryCryptoRng, TryRng};
16
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Deserializer, Serialize, Serializer};
19
20const BUF_BLOCKS: u8 = 4;
22const BLOCK_WORDS: u8 = 16;
24
25macro_rules! chacha_impl {
26 ($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident,) => {
27 #[doc=$doc]
28 #[derive(Clone, PartialEq, Eq)]
29 pub struct $ChaChaXCore {
30 state: ChaCha,
31 }
32
33 impl fmt::Debug for $ChaChaXCore {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 write!(f, "ChaChaXCore {{}}")
37 }
38 }
39
40 impl Generator for $ChaChaXCore {
41 type Output = [u32; 64];
42
43 #[inline]
44 fn generate(&mut self, output: &mut Self::Output) {
45 self.state.refill4($rounds, output);
46 }
47 }
48
49 impl SeedableRng for $ChaChaXCore {
50 type Seed = [u8; 32];
51
52 #[inline]
53 fn from_seed(seed: Self::Seed) -> Self {
54 $ChaChaXCore {
55 state: ChaCha::new(&seed, &[0u8; 8]),
56 }
57 }
58 }
59
60 #[derive(Clone, Debug)]
99 pub struct $ChaChaXRng {
100 rng: BlockRng<$ChaChaXCore>,
101 }
102
103 impl SeedableRng for $ChaChaXRng {
104 type Seed = [u8; 32];
105
106 #[inline]
107 fn from_seed(seed: Self::Seed) -> Self {
108 let core = $ChaChaXCore::from_seed(seed);
109 Self {
110 rng: BlockRng::new(core),
111 }
112 }
113 }
114
115 impl TryRng for $ChaChaXRng {
116 type Error = Infallible;
117
118 #[inline]
119 fn try_next_u32(&mut self) -> Result<u32, Infallible> {
120 Ok(self.rng.next_word())
121 }
122
123 #[inline]
124 fn try_next_u64(&mut self) -> Result<u64, Infallible> {
125 Ok(self.rng.next_u64_from_u32())
126 }
127
128 #[inline]
129 fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Infallible> {
130 Ok(self.rng.fill_bytes(bytes))
131 }
132 }
133
134 impl $ChaChaXRng {
135 #[inline]
145 pub fn get_word_pos(&self) -> u128 {
146 let mut block_counter = self.rng.core.state.get_block_pos();
147 if self.rng.word_offset() != 0 {
148 block_counter = block_counter.wrapping_sub(BUF_BLOCKS as u64);
149 }
150 let word_pos = u128::from(block_counter) * u128::from(BLOCK_WORDS);
151 word_pos + self.rng.word_offset() as u128
152 }
153
154 #[inline]
160 pub fn set_word_pos(&mut self, word_offset: u128) {
161 let block = (word_offset / u128::from(BLOCK_WORDS)) as u64;
162 self.rng.core.state.set_block_pos(block);
163 self.rng
164 .reset_and_skip((word_offset % u128::from(BLOCK_WORDS)) as usize);
165 }
166
167 #[inline]
179 pub fn set_stream(&mut self, stream: u64) {
180 self.rng.core.state.set_nonce(stream);
181 if self.rng.word_offset() != 0 {
182 let wp = self.get_word_pos();
183 self.set_word_pos(wp);
184 }
185 }
186
187 #[inline]
189 pub fn get_stream(&self) -> u64 {
190 self.rng.core.state.get_nonce()
191 }
192
193 #[inline]
195 pub fn get_seed(&self) -> [u8; 32] {
196 self.rng.core.state.get_seed()
197 }
198 }
199
200 impl TryCryptoRng for $ChaChaXRng {}
201
202 impl From<$ChaChaXCore> for $ChaChaXRng {
203 fn from(core: $ChaChaXCore) -> Self {
204 $ChaChaXRng {
205 rng: BlockRng::new(core),
206 }
207 }
208 }
209
210 impl PartialEq<$ChaChaXRng> for $ChaChaXRng {
211 fn eq(&self, rhs: &$ChaChaXRng) -> bool {
212 let a: $abst::$ChaChaXRng = self.into();
213 let b: $abst::$ChaChaXRng = rhs.into();
214 a == b
215 }
216 }
217 impl Eq for $ChaChaXRng {}
218
219 #[cfg(feature = "serde")]
220 impl Serialize for $ChaChaXRng {
221 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
222 where
223 S: Serializer,
224 {
225 $abst::$ChaChaXRng::from(self).serialize(s)
226 }
227 }
228 #[cfg(feature = "serde")]
229 impl<'de> Deserialize<'de> for $ChaChaXRng {
230 fn deserialize<D>(d: D) -> Result<Self, D::Error>
231 where
232 D: Deserializer<'de>,
233 {
234 $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
235 }
236 }
237
238 mod $abst {
239 #[cfg(feature = "serde")]
240 use serde::{Deserialize, Serialize};
241
242 #[derive(Debug, PartialEq, Eq)]
246 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
247 pub(crate) struct $ChaChaXRng {
248 seed: [u8; 32],
249 stream: u64,
250 word_pos: u128,
251 }
252
253 impl From<&super::$ChaChaXRng> for $ChaChaXRng {
254 fn from(r: &super::$ChaChaXRng) -> Self {
257 Self {
258 seed: r.get_seed(),
259 stream: r.get_stream(),
260 word_pos: r.get_word_pos(),
261 }
262 }
263 }
264
265 impl From<&$ChaChaXRng> for super::$ChaChaXRng {
266 fn from(a: &$ChaChaXRng) -> Self {
268 use rand_core::SeedableRng;
269 let mut r = Self::from_seed(a.seed);
270 r.set_stream(a.stream);
271 r.set_word_pos(a.word_pos);
272 r
273 }
274 }
275 }
276 };
277}
278
279chacha_impl!(
280 ChaCha20Core,
281 ChaCha20Rng,
282 10,
283 "ChaCha with 20 rounds",
284 abstract20,
285);
286chacha_impl!(
287 ChaCha12Core,
288 ChaCha12Rng,
289 6,
290 "ChaCha with 12 rounds",
291 abstract12,
292);
293chacha_impl!(
294 ChaCha8Core,
295 ChaCha8Rng,
296 4,
297 "ChaCha with 8 rounds",
298 abstract8,
299);
300
301#[cfg(test)]
302mod test {
303 #[cfg(feature = "serde")]
304 use super::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
305 use rand_core::{Rng, SeedableRng};
306
307 type ChaChaRng = super::ChaCha20Rng;
308
309 #[cfg(feature = "serde")]
310 #[test]
311 fn test_chacha_serde_roundtrip() {
312 let seed = [
313 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,
314 0, 0, 0, 2, 92,
315 ];
316 let mut rng1 = ChaCha20Rng::from_seed(seed);
317 let mut rng2 = ChaCha12Rng::from_seed(seed);
318 let mut rng3 = ChaCha8Rng::from_seed(seed);
319
320 let encoded1 = serde_json::to_string(&rng1).unwrap();
321 let encoded2 = serde_json::to_string(&rng2).unwrap();
322 let encoded3 = serde_json::to_string(&rng3).unwrap();
323
324 let mut decoded1: ChaCha20Rng = serde_json::from_str(&encoded1).unwrap();
325 let mut decoded2: ChaCha12Rng = serde_json::from_str(&encoded2).unwrap();
326 let mut decoded3: ChaCha8Rng = serde_json::from_str(&encoded3).unwrap();
327
328 assert_eq!(rng1, decoded1);
329 assert_eq!(rng2, decoded2);
330 assert_eq!(rng3, decoded3);
331
332 assert_eq!(rng1.next_u32(), decoded1.next_u32());
333 assert_eq!(rng2.next_u32(), decoded2.next_u32());
334 assert_eq!(rng3.next_u32(), decoded3.next_u32());
335 }
336
337 #[cfg(feature = "serde")]
348 #[test]
349 fn test_chacha_serde_format_stability() {
350 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}"#;
351 let r: ChaChaRng = serde_json::from_str(j).unwrap();
352 let j1 = serde_json::to_string(&r).unwrap();
353 assert_eq!(j, j1);
354 }
355
356 #[test]
357 fn test_chacha_construction() {
358 let seed = [
359 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,
360 0, 0, 0,
361 ];
362 let mut rng1 = ChaChaRng::from_seed(seed);
363 assert_eq!(rng1.next_u32(), 137206642);
364
365 let mut rng2 = ChaChaRng::from_rng(&mut rng1);
366 assert_eq!(rng2.next_u32(), 1325750369);
367 }
368
369 #[test]
370 fn test_chacha_true_values_a() {
371 let seed = [0u8; 32];
374 let mut rng = ChaChaRng::from_seed(seed);
375
376 let mut results = [0u32; 16];
377 for i in results.iter_mut() {
378 *i = rng.next_u32();
379 }
380 let expected = [
381 0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8,
382 0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, 0xf4b8436a, 0x1ca11815,
383 0x69b687c3, 0x8665eeb2,
384 ];
385 assert_eq!(results, expected);
386
387 for i in results.iter_mut() {
388 *i = rng.next_u32();
389 }
390 let expected = [
391 0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612,
392 0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, 0x281fed31, 0x45fb0a51,
393 0x1f0ae1ac, 0x6f4d794b,
394 ];
395 assert_eq!(results, expected);
396 }
397
398 #[test]
399 fn test_chacha_true_values_b() {
400 let seed = [
403 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,
404 0, 0, 1,
405 ];
406 let mut rng = ChaChaRng::from_seed(seed);
407
408 for _ in 0..16 {
410 rng.next_u32();
411 }
412
413 let mut results = [0u32; 16];
414 for i in results.iter_mut() {
415 *i = rng.next_u32();
416 }
417 let expected = [
418 0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, 0xe8252083, 0x60818b01, 0xf38422b8,
419 0x5aaa49c9, 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, 0x4436274e, 0x2561b3c8,
420 0xebdd4aa6, 0xa0136c00,
421 ];
422 assert_eq!(results, expected);
423 }
424
425 #[test]
426 fn test_chacha_true_values_c() {
427 let seed = [
430 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,
431 0, 0, 0, 0,
432 ];
433 let expected = [
434 0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, 0xa78dea8f, 0x5e269039, 0xa1bebbc1,
435 0xcaf09aae, 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, 0x546ca624, 0x1bec45d5,
436 0x87f47473, 0x96f0992e,
437 ];
438 let expected_end = 3 * 16;
439 let mut results = [0u32; 16];
440
441 let mut rng1 = ChaChaRng::from_seed(seed);
443 for _ in 0..32 {
444 rng1.next_u32();
445 }
446 for i in results.iter_mut() {
447 *i = rng1.next_u32();
448 }
449 assert_eq!(results, expected);
450 assert_eq!(rng1.get_word_pos(), expected_end);
451
452 let mut rng2 = ChaChaRng::from_seed(seed);
454 rng2.set_word_pos(2 * 16);
455 for i in results.iter_mut() {
456 *i = rng2.next_u32();
457 }
458 assert_eq!(results, expected);
459 assert_eq!(rng2.get_word_pos(), expected_end);
460
461 let mut buf = [0u8; 32];
463 rng2.fill_bytes(&mut buf[..]);
464 assert_eq!(rng2.get_word_pos(), expected_end + 8);
465 rng2.fill_bytes(&mut buf[0..25]);
466 assert_eq!(rng2.get_word_pos(), expected_end + 15);
467 rng2.next_u64();
468 assert_eq!(rng2.get_word_pos(), expected_end + 17);
469 rng2.next_u32();
470 rng2.next_u64();
471 assert_eq!(rng2.get_word_pos(), expected_end + 20);
472 rng2.fill_bytes(&mut buf[0..1]);
473 assert_eq!(rng2.get_word_pos(), expected_end + 21);
474 }
475
476 #[test]
477 fn test_chacha_multiple_blocks() {
478 let seed = [
479 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,
480 0, 0, 0,
481 ];
482 let mut rng = ChaChaRng::from_seed(seed);
483
484 let mut results = [0u32; 16];
487 for i in results.iter_mut() {
488 *i = rng.next_u32();
489 for _ in 0..16 {
490 rng.next_u32();
491 }
492 }
493 let expected = [
494 0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186,
495 0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc,
496 0x5f1c86d9, 0xc1f8e7f4,
497 ];
498 assert_eq!(results, expected);
499 }
500
501 #[test]
502 fn test_chacha_true_bytes() {
503 let seed = [0u8; 32];
504 let mut rng = ChaChaRng::from_seed(seed);
505 let mut results = [0u8; 32];
506 rng.fill_bytes(&mut results);
507 let expected = [
508 118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
509 25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
510 ];
511 assert_eq!(results, expected);
512 }
513
514 #[test]
515 fn test_chacha_nonce() {
516 let seed = [0u8; 32];
521 let mut rng = ChaChaRng::from_seed(seed);
522 rng.set_stream(2u64 << (24 + 32));
524
525 let mut results = [0u32; 16];
526 for i in results.iter_mut() {
527 *i = rng.next_u32();
528 }
529 let expected = [
530 0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, 0x88228b1a, 0x96a4dfb3, 0x5b76ab72,
531 0xc727ee54, 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, 0x99c28f5f, 0x628314e8,
532 0x398a19fa, 0x6ded1b53,
533 ];
534 assert_eq!(results, expected);
535 }
536
537 #[test]
538 fn test_chacha_clone_streams() {
539 let seed = [
540 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,
541 0, 0, 0,
542 ];
543 let mut rng = ChaChaRng::from_seed(seed);
544 let mut clone = rng.clone();
545 for _ in 0..16 {
546 assert_eq!(rng.next_u64(), clone.next_u64());
547 }
548
549 rng.set_stream(51);
550 for _ in 0..7 {
551 assert!(rng.next_u32() != clone.next_u32());
552 }
553 clone.set_stream(51); for _ in 7..16 {
555 assert_eq!(rng.next_u32(), clone.next_u32());
556 }
557 }
558
559 #[test]
560 fn test_chacha_word_pos_wrap_exact() {
561 use super::{BLOCK_WORDS, BUF_BLOCKS};
562 let mut rng = ChaChaRng::from_seed(Default::default());
563 let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS);
565 rng.set_word_pos(last_block);
566 assert_eq!(rng.get_word_pos(), last_block);
567 }
568
569 #[test]
570 fn test_chacha_word_pos_wrap_excess() {
571 use super::BLOCK_WORDS;
572 let mut rng = ChaChaRng::from_seed(Default::default());
573 let last_block = (1 << 68) - u128::from(BLOCK_WORDS);
575 rng.set_word_pos(last_block);
576 assert_eq!(rng.get_word_pos(), last_block);
577 }
578
579 #[test]
580 fn test_chacha_word_pos_zero() {
581 let mut rng = ChaChaRng::from_seed(Default::default());
582 assert_eq!(rng.get_word_pos(), 0);
583 rng.set_word_pos(0);
584 assert_eq!(rng.get_word_pos(), 0);
585 }
586
587 #[test]
588 fn test_trait_objects() {
589 use rand_core::CryptoRng;
590
591 let mut rng1 = ChaChaRng::from_seed(Default::default());
592 let rng2 = &mut rng1.clone() as &mut dyn CryptoRng;
593 for _ in 0..1000 {
594 assert_eq!(rng1.next_u64(), rng2.next_u64());
595 }
596 }
597}