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}