1use crate::guts::ChaCha;
12use core::fmt;
13use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
14use rand_core::{CryptoRng, RngCore, SeedableRng};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Deserializer, Serialize, Serializer};
18
19const BUF_BLOCKS: u8 = 4;
21const BLOCK_WORDS: u8 = 16;
23
24#[repr(transparent)]
25pub struct Array64<T>([T; 64]);
26impl<T> Default for Array64<T>
27where
28 T: Default,
29{
30 #[rustfmt::skip]
31 fn default() -> Self {
32 Self([
33 T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
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 ])
42 }
43}
44impl<T> AsRef<[T]> for Array64<T> {
45 fn as_ref(&self) -> &[T] {
46 &self.0
47 }
48}
49impl<T> AsMut<[T]> for Array64<T> {
50 fn as_mut(&mut self) -> &mut [T] {
51 &mut self.0
52 }
53}
54impl<T> Clone for Array64<T>
55where
56 T: Copy + Default,
57{
58 fn clone(&self) -> Self {
59 let mut new = Self::default();
60 new.0.copy_from_slice(&self.0);
61 new
62 }
63}
64impl<T> fmt::Debug for Array64<T> {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 write!(f, "Array64 {{}}")
67 }
68}
69
70macro_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 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
89 #[inline]
90 fn generate(&mut self, r: &mut Self::Results) {
91 self.state.refill4($rounds, &mut r.0);
92 }
93 }
94
95 impl SeedableRng for $ChaChaXCore {
96 type Seed = [u8; 32];
97
98 #[inline]
99 fn from_seed(seed: Self::Seed) -> Self {
100 $ChaChaXCore {
101 state: ChaCha::new(&seed, &[0u8; 8]),
102 }
103 }
104 }
105
106 impl CryptoBlockRng for $ChaChaXCore {}
107
108 #[derive(Clone, Debug)]
147 pub struct $ChaChaXRng {
148 rng: BlockRng<$ChaChaXCore>,
149 }
150
151 impl SeedableRng for $ChaChaXRng {
152 type Seed = [u8; 32];
153
154 #[inline]
155 fn from_seed(seed: Self::Seed) -> Self {
156 let core = $ChaChaXCore::from_seed(seed);
157 Self {
158 rng: BlockRng::new(core),
159 }
160 }
161 }
162
163 impl RngCore for $ChaChaXRng {
164 #[inline]
165 fn next_u32(&mut self) -> u32 {
166 self.rng.next_u32()
167 }
168
169 #[inline]
170 fn next_u64(&mut self) -> u64 {
171 self.rng.next_u64()
172 }
173
174 #[inline]
175 fn fill_bytes(&mut self, bytes: &mut [u8]) {
176 self.rng.fill_bytes(bytes)
177 }
178 }
179
180 impl $ChaChaXRng {
181 #[inline]
191 pub fn get_word_pos(&self) -> u128 {
192 let buf_start_block = {
193 let buf_end_block = self.rng.core.state.get_block_pos();
194 u64::wrapping_sub(buf_end_block, BUF_BLOCKS.into())
195 };
196 let (buf_offset_blocks, block_offset_words) = {
197 let buf_offset_words = self.rng.index() as u64;
198 let blocks_part = buf_offset_words / u64::from(BLOCK_WORDS);
199 let words_part = buf_offset_words % u64::from(BLOCK_WORDS);
200 (blocks_part, words_part)
201 };
202 let pos_block = u64::wrapping_add(buf_start_block, buf_offset_blocks);
203 let pos_block_words = u128::from(pos_block) * u128::from(BLOCK_WORDS);
204 pos_block_words + u128::from(block_offset_words)
205 }
206
207 #[inline]
213 pub fn set_word_pos(&mut self, word_offset: u128) {
214 let block = (word_offset / u128::from(BLOCK_WORDS)) as u64;
215 self.rng.core.state.set_block_pos(block);
216 self.rng
217 .generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
218 }
219
220 #[inline]
232 pub fn set_stream(&mut self, stream: u64) {
233 self.rng.core.state.set_nonce(stream);
234 if self.rng.index() != 64 {
235 let wp = self.get_word_pos();
236 self.set_word_pos(wp);
237 }
238 }
239
240 #[inline]
242 pub fn get_stream(&self) -> u64 {
243 self.rng.core.state.get_nonce()
244 }
245
246 #[inline]
248 pub fn get_seed(&self) -> [u8; 32] {
249 self.rng.core.state.get_seed()
250 }
251 }
252
253 impl CryptoRng for $ChaChaXRng {}
254
255 impl From<$ChaChaXCore> for $ChaChaXRng {
256 fn from(core: $ChaChaXCore) -> Self {
257 $ChaChaXRng {
258 rng: BlockRng::new(core),
259 }
260 }
261 }
262
263 impl PartialEq<$ChaChaXRng> for $ChaChaXRng {
264 fn eq(&self, rhs: &$ChaChaXRng) -> bool {
265 let a: $abst::$ChaChaXRng = self.into();
266 let b: $abst::$ChaChaXRng = rhs.into();
267 a == b
268 }
269 }
270 impl Eq for $ChaChaXRng {}
271
272 #[cfg(feature = "serde")]
273 impl Serialize for $ChaChaXRng {
274 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
275 where
276 S: Serializer,
277 {
278 $abst::$ChaChaXRng::from(self).serialize(s)
279 }
280 }
281 #[cfg(feature = "serde")]
282 impl<'de> Deserialize<'de> for $ChaChaXRng {
283 fn deserialize<D>(d: D) -> Result<Self, D::Error>
284 where
285 D: Deserializer<'de>,
286 {
287 $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
288 }
289 }
290
291 mod $abst {
292 #[cfg(feature = "serde")]
293 use serde::{Deserialize, Serialize};
294
295 #[derive(Debug, PartialEq, Eq)]
299 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
300 pub(crate) struct $ChaChaXRng {
301 seed: [u8; 32],
302 stream: u64,
303 word_pos: u128,
304 }
305
306 impl From<&super::$ChaChaXRng> for $ChaChaXRng {
307 fn from(r: &super::$ChaChaXRng) -> Self {
310 Self {
311 seed: r.get_seed(),
312 stream: r.get_stream(),
313 word_pos: r.get_word_pos(),
314 }
315 }
316 }
317
318 impl From<&$ChaChaXRng> for super::$ChaChaXRng {
319 fn from(a: &$ChaChaXRng) -> Self {
321 use rand_core::SeedableRng;
322 let mut r = Self::from_seed(a.seed);
323 r.set_stream(a.stream);
324 r.set_word_pos(a.word_pos);
325 r
326 }
327 }
328 }
329 };
330}
331
332chacha_impl!(
333 ChaCha20Core,
334 ChaCha20Rng,
335 10,
336 "ChaCha with 20 rounds",
337 abstract20,
338);
339chacha_impl!(
340 ChaCha12Core,
341 ChaCha12Rng,
342 6,
343 "ChaCha with 12 rounds",
344 abstract12,
345);
346chacha_impl!(
347 ChaCha8Core,
348 ChaCha8Rng,
349 4,
350 "ChaCha with 8 rounds",
351 abstract8,
352);
353
354#[cfg(test)]
355mod test {
356 use rand_core::{RngCore, SeedableRng};
357
358 #[cfg(feature = "serde")]
359 use super::{ChaCha12Rng, ChaCha20Rng, ChaCha8Rng};
360
361 type ChaChaRng = super::ChaCha20Rng;
362
363 #[cfg(feature = "serde")]
364 #[test]
365 fn test_chacha_serde_roundtrip() {
366 let seed = [
367 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,
368 0, 0, 0, 2, 92,
369 ];
370 let mut rng1 = ChaCha20Rng::from_seed(seed);
371 let mut rng2 = ChaCha12Rng::from_seed(seed);
372 let mut rng3 = ChaCha8Rng::from_seed(seed);
373
374 let encoded1 = serde_json::to_string(&rng1).unwrap();
375 let encoded2 = serde_json::to_string(&rng2).unwrap();
376 let encoded3 = serde_json::to_string(&rng3).unwrap();
377
378 let mut decoded1: ChaCha20Rng = serde_json::from_str(&encoded1).unwrap();
379 let mut decoded2: ChaCha12Rng = serde_json::from_str(&encoded2).unwrap();
380 let mut decoded3: ChaCha8Rng = serde_json::from_str(&encoded3).unwrap();
381
382 assert_eq!(rng1, decoded1);
383 assert_eq!(rng2, decoded2);
384 assert_eq!(rng3, decoded3);
385
386 assert_eq!(rng1.next_u32(), decoded1.next_u32());
387 assert_eq!(rng2.next_u32(), decoded2.next_u32());
388 assert_eq!(rng3.next_u32(), decoded3.next_u32());
389 }
390
391 #[cfg(feature = "serde")]
402 #[test]
403 fn test_chacha_serde_format_stability() {
404 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}"#;
405 let r: ChaChaRng = serde_json::from_str(j).unwrap();
406 let j1 = serde_json::to_string(&r).unwrap();
407 assert_eq!(j, j1);
408 }
409
410 #[test]
411 fn test_chacha_construction() {
412 let seed = [
413 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,
414 0, 0, 0,
415 ];
416 let mut rng1 = ChaChaRng::from_seed(seed);
417 assert_eq!(rng1.next_u32(), 137206642);
418
419 let mut rng2 = ChaChaRng::from_rng(&mut rng1);
420 assert_eq!(rng2.next_u32(), 1325750369);
421 }
422
423 #[test]
424 fn test_chacha_true_values_a() {
425 let seed = [0u8; 32];
428 let mut rng = ChaChaRng::from_seed(seed);
429
430 let mut results = [0u32; 16];
431 for i in results.iter_mut() {
432 *i = rng.next_u32();
433 }
434 let expected = [
435 0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8,
436 0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, 0xf4b8436a, 0x1ca11815,
437 0x69b687c3, 0x8665eeb2,
438 ];
439 assert_eq!(results, expected);
440
441 for i in results.iter_mut() {
442 *i = rng.next_u32();
443 }
444 let expected = [
445 0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612,
446 0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, 0x281fed31, 0x45fb0a51,
447 0x1f0ae1ac, 0x6f4d794b,
448 ];
449 assert_eq!(results, expected);
450 }
451
452 #[test]
453 fn test_chacha_true_values_b() {
454 let seed = [
457 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,
458 0, 0, 1,
459 ];
460 let mut rng = ChaChaRng::from_seed(seed);
461
462 for _ in 0..16 {
464 rng.next_u32();
465 }
466
467 let mut results = [0u32; 16];
468 for i in results.iter_mut() {
469 *i = rng.next_u32();
470 }
471 let expected = [
472 0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, 0xe8252083, 0x60818b01, 0xf38422b8,
473 0x5aaa49c9, 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, 0x4436274e, 0x2561b3c8,
474 0xebdd4aa6, 0xa0136c00,
475 ];
476 assert_eq!(results, expected);
477 }
478
479 #[test]
480 fn test_chacha_true_values_c() {
481 let seed = [
484 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,
485 0, 0, 0, 0,
486 ];
487 let expected = [
488 0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, 0xa78dea8f, 0x5e269039, 0xa1bebbc1,
489 0xcaf09aae, 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, 0x546ca624, 0x1bec45d5,
490 0x87f47473, 0x96f0992e,
491 ];
492 let expected_end = 3 * 16;
493 let mut results = [0u32; 16];
494
495 let mut rng1 = ChaChaRng::from_seed(seed);
497 for _ in 0..32 {
498 rng1.next_u32();
499 }
500 for i in results.iter_mut() {
501 *i = rng1.next_u32();
502 }
503 assert_eq!(results, expected);
504 assert_eq!(rng1.get_word_pos(), expected_end);
505
506 let mut rng2 = ChaChaRng::from_seed(seed);
508 rng2.set_word_pos(2 * 16);
509 for i in results.iter_mut() {
510 *i = rng2.next_u32();
511 }
512 assert_eq!(results, expected);
513 assert_eq!(rng2.get_word_pos(), expected_end);
514
515 let mut buf = [0u8; 32];
517 rng2.fill_bytes(&mut buf[..]);
518 assert_eq!(rng2.get_word_pos(), expected_end + 8);
519 rng2.fill_bytes(&mut buf[0..25]);
520 assert_eq!(rng2.get_word_pos(), expected_end + 15);
521 rng2.next_u64();
522 assert_eq!(rng2.get_word_pos(), expected_end + 17);
523 rng2.next_u32();
524 rng2.next_u64();
525 assert_eq!(rng2.get_word_pos(), expected_end + 20);
526 rng2.fill_bytes(&mut buf[0..1]);
527 assert_eq!(rng2.get_word_pos(), expected_end + 21);
528 }
529
530 #[test]
531 fn test_chacha_multiple_blocks() {
532 let seed = [
533 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,
534 0, 0, 0,
535 ];
536 let mut rng = ChaChaRng::from_seed(seed);
537
538 let mut results = [0u32; 16];
541 for i in results.iter_mut() {
542 *i = rng.next_u32();
543 for _ in 0..16 {
544 rng.next_u32();
545 }
546 }
547 let expected = [
548 0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186,
549 0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc,
550 0x5f1c86d9, 0xc1f8e7f4,
551 ];
552 assert_eq!(results, expected);
553 }
554
555 #[test]
556 fn test_chacha_true_bytes() {
557 let seed = [0u8; 32];
558 let mut rng = ChaChaRng::from_seed(seed);
559 let mut results = [0u8; 32];
560 rng.fill_bytes(&mut results);
561 let expected = [
562 118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
563 25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
564 ];
565 assert_eq!(results, expected);
566 }
567
568 #[test]
569 fn test_chacha_nonce() {
570 let seed = [0u8; 32];
575 let mut rng = ChaChaRng::from_seed(seed);
576 rng.set_stream(2u64 << (24 + 32));
578
579 let mut results = [0u32; 16];
580 for i in results.iter_mut() {
581 *i = rng.next_u32();
582 }
583 let expected = [
584 0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, 0x88228b1a, 0x96a4dfb3, 0x5b76ab72,
585 0xc727ee54, 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, 0x99c28f5f, 0x628314e8,
586 0x398a19fa, 0x6ded1b53,
587 ];
588 assert_eq!(results, expected);
589 }
590
591 #[test]
592 fn test_chacha_clone_streams() {
593 let seed = [
594 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,
595 0, 0, 0,
596 ];
597 let mut rng = ChaChaRng::from_seed(seed);
598 let mut clone = rng.clone();
599 for _ in 0..16 {
600 assert_eq!(rng.next_u64(), clone.next_u64());
601 }
602
603 rng.set_stream(51);
604 for _ in 0..7 {
605 assert!(rng.next_u32() != clone.next_u32());
606 }
607 clone.set_stream(51); for _ in 7..16 {
609 assert_eq!(rng.next_u32(), clone.next_u32());
610 }
611 }
612
613 #[test]
614 fn test_chacha_word_pos_wrap_exact() {
615 use super::{BLOCK_WORDS, BUF_BLOCKS};
616 let mut rng = ChaChaRng::from_seed(Default::default());
617 let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS);
619 rng.set_word_pos(last_block);
620 assert_eq!(rng.get_word_pos(), last_block);
621 }
622
623 #[test]
624 fn test_chacha_word_pos_wrap_excess() {
625 use super::BLOCK_WORDS;
626 let mut rng = ChaChaRng::from_seed(Default::default());
627 let last_block = (1 << 68) - u128::from(BLOCK_WORDS);
629 rng.set_word_pos(last_block);
630 assert_eq!(rng.get_word_pos(), last_block);
631 }
632
633 #[test]
634 fn test_chacha_word_pos_zero() {
635 let mut rng = ChaChaRng::from_seed(Default::default());
636 assert_eq!(rng.get_word_pos(), 0);
637 rng.set_word_pos(0);
638 assert_eq!(rng.get_word_pos(), 0);
639 }
640
641 #[test]
642 fn test_trait_objects() {
643 use rand_core::CryptoRng;
644
645 let mut rng1 = ChaChaRng::from_seed(Default::default());
646 let rng2 = &mut rng1.clone() as &mut dyn CryptoRng;
647 for _ in 0..1000 {
648 assert_eq!(rng1.next_u64(), rng2.next_u64());
649 }
650 }
651}