1#[cfg(not(feature = "std"))] use core;
12#[cfg(feature = "std")] use std as core;
13
14use self::core::fmt;
15use crate::guts::ChaCha;
16use rand_core::block::{BlockRng, BlockRngCore};
17use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
18
19#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize, Serializer, Deserializer};
20
21const BUF_BLOCKS: u8 = 4;
23const BLOCK_WORDS: u8 = 16;
25
26#[repr(transparent)]
27pub struct Array64<T>([T; 64]);
28impl<T> Default for Array64<T>
29where T: Default
30{
31 #[rustfmt::skip]
32 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}
45impl<T> AsRef<[T]> for Array64<T> {
46 fn as_ref(&self) -> &[T] {
47 &self.0
48 }
49}
50impl<T> AsMut<[T]> for Array64<T> {
51 fn as_mut(&mut self) -> &mut [T] {
52 &mut self.0
53 }
54}
55impl<T> Clone for Array64<T>
56where 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 #[inline]
89 fn generate(&mut self, r: &mut Self::Results) {
90 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 #[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 #[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 #[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 #[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 #[inline]
250 pub fn get_stream(&self) -> u64 {
251 self.rng
252 .core
253 .state
254 .get_nonce()
255 }
256
257 #[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 #[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 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 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
343chacha_impl!(ChaCha20Core, ChaCha20Rng, 10, "ChaCha with 20 rounds", abstract20);
344chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds", abstract12);
345chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds", abstract8);
346
347#[cfg(test)]
348mod 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]
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 #[cfg(feature = "serde1")]
394 #[test]
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]
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]
416 fn test_chacha_true_values_a() {
417 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]
445 fn test_chacha_true_values_b() {
446 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 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]
472 fn test_chacha_true_values_c() {
473 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 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 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 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]
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 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]
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]
561 fn test_chacha_nonce() {
562 let seed = [0u8; 32];
567 let mut rng = ChaChaRng::from_seed(seed);
568 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]
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); for _ in 7..16 {
601 assert_eq!(rng.next_u32(), clone.next_u32());
602 }
603 }
604
605 #[test]
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 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]
616 fn test_chacha_word_pos_wrap_excess() {
617 use super::BLOCK_WORDS;
618 let mut rng = ChaChaRng::from_seed(Default::default());
619 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]
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}