1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
//! Reproducible, robust and (last but not least) fast pseudorandomness.
//!
//! This crate implements the [ChaCha8Rand][spec] specification, originally designed for Go's
//! `math/rand/v2` package. The language-independent specification and test vector helps with
//! long-term reproducibility and interoperability. Building on the ChaCha8 stream cipher ensures
//! high statistical quality and removes entire classes of "you're holding it wrong"-style problems
//! that lead to sub-par output. It's also carefully designed and implemented (using SIMD
//! instructions when available) to be so fast that it shouldn't ever be a bottleneck. However, it
//! [should not be used for cryptography](#no-crypto).
//!
//! # Quick Start
//!
//! In the interest of simplicity and reproducibility, there's no global or thread-local generator.
//! You'll always have to pick a 32-byte seed yourself, create a [`ChaCha8Rand`] instance from it,
//! and pass it around in your program. Usually, you'll generate an unpredictable seed at startup by
//! default, but store or log it somewhere and support running the program again with the same seed.
//! For the first half, it's usually best to provide a full 256 bits of entropy via the
//! [`getrandom`][getrandom] crate:
//!
//! ```
//! use chacha8rand::ChaCha8Rand;
//!
//! let mut seed = [0; 32];
//! getrandom::fill(&mut seed).unwrap();
//! let mut rng = ChaCha8Rand::new(&seed);
//! // Now we can make random choices
//! let heads_or_tails = if rng.read_u32() & 1 == 0 { "heads" } else { "tails" };
//! println!("The coin came up {heads_or_tails}.");
//! ```
//!
//! The best place and format to store the seed will vary, but 64 hex digits is a good default
//! because it can be copied and pasted as (technically) human-readable text. However, if you want
//! to let humans *pick a seed by hand* for any reason, then asking them for exactly 64 hex digits
//! would be a bit rude. For such cases, it's more convenient to accept an UTF-8 string and feed it
//! into a hash function with 256 bit output, such as SHA-256 or Blake3.
//!
//! In any case, once you've created a [`ChaCha8Rand`] instance with an initial seed, you can
//! consume its output as a sequence of bytes or as stream of 32-bit or 64-bit integers. If you need
//! support for other types, for integers in a certain interval, or other distributions, you might
//! want to enable the [crate feature](#crate-features) to combine [`ChaCha8Rand`] with the `rand`
//! crate. Another thing you can do (even without `rand`) is deriving seeds for multiple sub-RNGs
//! that are used for different purposes, without creating correlation between those different
//! streams of randomness. The ability to do this with confidence is one reason why I decided to
//! implement ChaCha8Rand in the first place, so there's a little helper for it:
//!
//! ```
//! use chacha8rand::ChaCha8Rand;
//!
//! let mut seed_gen = ChaCha8Rand::new(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456");
//! // Create new instances with seeds from `seed_gen`...
//! let mut rng1 = ChaCha8Rand::new(&seed_gen.read_seed());
//! let mut rng2 = ChaCha8Rand::new(&seed_gen.read_seed());
//! assert_ne!(rng1.read_u64(), rng2.read_u64());
//! // ... and/or re-seed an existing instance in-place:
//! rng1.set_seed(&seed_gen.read_seed());
//! ```
//!
//! Note that using the output of a statistical RNG to seed other instances of the same algorithm
//! (or a related one) is often risky or outright broken. Even generators that explicitly support
//! it, like SplitMix, often distinguish "generate a new seed" from ordinary random output.
//! ChaCha8Rand has no such caveats: its state space is so large, and its output is of such high
//! quality, that there's no risk of creating overlapping output sequences or correlations between
//! generators seeded this way. Indeed, every instance regularly replaces its current seed with some
//! of its own output. Using the rest of the output as seeds for other instances works just as well.
//!
//! # <a name="no-crypto"></a> Don't Use This For Cryptography
//!
//! ChaCha8Rand derives its high quality from ChaCha8, which is a secure stream cipher as far as
//! anyone knows today (although in most cases you also want ciphertext authenticity, i.e., an AEAD
//! mode). Thus, ChaCha8Rand can mostly be used as a black-box source of high quality
//! pseudorandomness. If there were any patterns or biases in its output, or if the output sequences
//! for different seeds (with some known relation between them) were not statistically independent,
//! that would most likely imply a major breakthrough in the cryptanalysis of ChaCha. However, that
//! doesn't mean this crate is a replacement for cryptographically secure randomness from the
//! operating system or libraries that wrap it, such as [`getrandom`][getrandom].
//!
//! As Russ Cox and Filippo Valsorda wrote [while introducing the algorithm][go-blog], regarding
//! accidental use of Go's `math/rand` to generate cryptographic keys and other secrets:
//!
//! > Using Go 1.20, that mistake is a serious security problem that merits a detailed investigation
//! > to understand the damage. [...] Using Go 1.22, that mistake is just a mistake. It’s still
//! > better to use crypto/rand, because the operating system kernel can do a better job keeping the
//! > random values secret from various kinds of prying eyes, the kernel is continually adding new
//! > entropy to its generator, and the kernel has had more scrutiny. But accidentally using
//! > math/rand is no longer a security catastrophe.
//!
//! Keep in mind that Go has a global generator which is seeded from OS-provided entropy on startup.
//! If you pick a seed yourself (which you always do when using this crate), the output of the
//! generator is at best as unpredictable as that seed was. There are also other design decisions in
//! this implementations that would be inappropriate for security-sensitive applications. For
//! example, it doesn't handle process forking or VM image cloning, it doesn't even try to scrub
//! generated data from its internal buffer after it's consumed, and it sacrifices so-called *fast
//! key erasure* in favor of needing fewer bytes to serialize the current state.
//!
//! # <a name="crate-features"></a> Crate Features
//!
//! The crate is `no_std` and "no `alloc`" by default. There are currently two crate features you
//! might enable when depending on `chacha8rand`. You can manually add them to Cargo.toml (`features
//! = [...]` key) or use a command like `cargo add chacha8rand -F rand_core_0_9`. The features are:
//!
//! * **`std`**: opts out of `#![no_std]`, enables runtime detection of `target_feature`s for higher
//! performance on some targets. It does not (currently) affect the API surface, so ideally
//! libraries leave this decision to the top-level binary. For forward compatibility, enabling
//! this feature *always* adds a dependency on `std`, even on targets where `std` isn't needed
//! today.
//! * **`rand_core_0_6`**: implement the `RngCore` and `SeedableRng` traits from `rand_core` v0.6,
//! for integration with `rand` v0.8.
//! * **`rand_core_0_9`**: implement the `RngCore` and `SeedableRng` traits from `rand_core` v0.9,
//! for integration with `rand` v0.9.
//!
//! No feature is enabled by default, so you don't need `no-default-features = true` / `cargo add
//! --no-default-features`. In fact, please don't, because then your code might break if a later
//! version moves existing functionality under a new on-by-default feature.
//!
//! There are also some features with an "unstable" prefix in their name. Anything covered by these
//! is for internal use only (e.g., the crate's benchmarks are compiled as a separate crate) and
//! explicitly not covered by SemVer.
//!
//! # Minimum Supported Rust Version (MSRV)
//!
//! There is no MSRV policy at the moment, so features from new stable Rust versions may be adopted
//! as soon as they come out (but in practice I don't expect to make frequent releases). If you need
//! to use this crate with a specific older version, you can open an issue and we can take a look at
//! how easy or difficult it would be to support that version.
//!
//! # Drawbacks
//!
//! The main reasons why you might not want to use this crate are the use of `unsafe` for accessing
//! SIMD intrinsics and the relatively large buffer (4x larger than the Go implementation). The
//! latter means each RNG instance is a little over a thousand bytes large, which may be an issue if
//! you want to have many instances and care about memory consumption and/or only consume a small
//! amount of randomness from most of those instances.
//!
//! [getrandom]: https://crates.io/crates/getrandom
//! [go-blog]: https://go.dev/blog/chacha8rand
//! [spec]: https://c2sp.org/chacha8rand
use ;
// We only need `std` on some platforms for runtime feature detection. But later versions might use
// runtime detection on more platforms, or implement traits that require `std`. It would suck if a
// semver-minor update like that broke something because people (like myself) were using the crate
// with the `std` feature enabled in a `#![no_std]` binary. So we always pull in std here.
extern crate std;
use slice_array;
use Backend;
const BUF_TOTAL_LEN: usize = 1024;
const BUF_OUTPUT_LEN: usize = BUF_TOTAL_LEN - 32;
/// A deterministic stream of pseudorandom bytes from a 32-byte seed.
///
/// See the crate documentation for a higher-level introduction and quick-start examples. Here
/// you'll only find excessive extra details about reproducibility and some notes about
/// (de-)serialization and SIMD backends.
///
/// This type implements traits from the rand crate (`RngCore` and `SeedableRng`), but you need to
/// [opt-in with a feature flag][crate-features] to use those impls.
///
/// # <a name="repro-details"></a> Reproducibility
///
/// The [ChaCha8Rand specification][spec] describes how a seed is expanded into an unbounded stream
/// of pseudorandom bytes. This stream should be uniquely determined: byte order is fixed to little
/// endian, the differences between various ChaCha20 variants (32- or 64-bit counter, nonce size)
/// don't matter in this context, and the test vector included in the spec should remove any
/// remaining doubts.
///
/// Until the 1.0 release of this crate, I reserve the right to make API breaking changes and fix
/// bugs even if they change the output. But the intent is to match the spec precisely and not
/// change anything about the output for a given seed in future releases. If the spec gets an
/// incompatible 2.0 release and I want to implement it, that will be a semver-major release. Note
/// that the spec technically hasn't been tagged as 1.0, but breaking changes seem very unlikely
/// since the same people already shipped an implementation in the Go standard library.
///
/// Besides treating the generator as a byte stream with [`ChaCha8Rand::read_bytes`], you can also
/// use other methods such as [`ChaCha8Rand::read_u64`]. What happens when you interleave calls to
/// these methods, i.e., mix and match different read granularities? There's no clear "best" answer.
/// Different implementation strategies lead to different behavior and it's reasonable to not
/// specify it or reserve the right to change it later. However, for this crate I wanted to commit
/// to a simple and useful mental model. What I ended up with is:
///
/// * The generator is *just* the spec-mandated stream of bytes. Repeatedly calling `read_bytes`
/// gives you these bytes in order without skipping, reordering, or duplicating anything.
/// * The number of calls to `read_bytes` and the size of each read doesn't affect behavior. The
/// number of bytes consumed is never rounded up internally because that would skip some bytes.
/// Zero-sized reads are no-ops.
/// * Methods like `read_u32`, `read_u64`, `read_seed`, and any others that might be added in the
/// future, behave exactly like reading the appropriate number of bytes from the stream and
/// converting those to the result type. When byte order matters, this always uses little endian.
///
/// This is different from what Go's implementation does when you interleave calls to its `Uint64`
/// and `Read` methods. The documentation explicitly says the results are unspecified and may return
/// bytes "out of order". The implementation in Go 1.23 does in fact behave differently from this
/// crate in many cases. (It also doesn't provide a direct way to read a 32-bit integer.)
///
/// # Serialization and Deserialization
///
/// Besides storing the initial seed, you can also snapshot state of the generator at any point in
/// time with [`ChaCha8Rand::clone_state`] and [`ChaCha8Rand::try_restore_state`]. See
/// [`ChaCha8State`] for more details. The important thing with respect to reproducibility is that
/// the serialized state records an exact position in the output byte stream. Thus, if you save the
/// state at any point and later restore it, you'll get the same output as if you had kept working
/// with the original generator, regardless of how how you read from it before and after.
///
/// # SIMD Backends
///
/// This crate has all the same SIMD code paths as Go 1.23 and then some more:
///
/// * SSE2 and AVX2 on x86_64 and 32-bit x86
/// * NEON on AArch64 ([little-endian only for now][aarch64be-neon])
/// * simd128 on Webassembly
///
/// All backends except Webassembly support runtime feature detection with the `std` crate feature.
/// More backends may be added in the future as Rust stabilizes the corresponding `core::arch`
/// intrinsics. Of course, there's also a portable scalar backend for all platforms without SIMD
/// backends.
///
/// [aarch64be-neon]: https://github.com/rust-lang/stdarch/issues/1484
/// [crate-features]: ./index.html#crate-features
/// [spec]: https://c2sp.org/chacha8rand
/// Snapshot of the state of a [`ChaCha8Rand`] instance.
///
/// Created with [`ChaCha8Rand::clone_state`] and used by [`ChaCha8Rand::try_restore_state`]. It
/// simply records the seed of the current iteration of the generator and how many output bytes of
/// that iteration have already been consumed. Restoring from it is effectively the same as calling
/// `rng.set_seed(&seed)` and then throwing away `bytes_consumed` many bytes of output. However,
/// going through [`ChaCha8Rand::try_restore_state`] can catch some possible mistakes because it
/// validates that `bytes_consumed` is in the range it should be.
///
/// Possible use cases include:
///
/// * Saving and restoring the RNG state as part of a game's (auto-)save feature.
/// * Suspending and later resume a long-running computation by saving the RNG (and all other state)
/// to disk.
/// * Forking a randomized algorithm, running it twice with the same randomness but handling
/// different input, to see how they diverge (e.g., "what if" queries).
///
/// There are no `serde` impls. Instead, the fields are public so you can (de-)serialize them in any
/// way you see fit. In this case you should be prepared to handle errors due to out-of-range
/// `bytes_consumed` values gracefully.
///
/// Nothing stops you from constructing a [`ChaCha8State`] out of thin air (rather than cloning from
/// an existing generator), but there's probably no reason to do so. You can supply a new seed
/// directly with [`ChaCha8Rand::new`] or [`ChaCha8Rand::set_seed`].
///
/// Finally, note that [`ChaCha8Rand`] also implements `Clone`. Cloning a generator achieves the
/// same effect as taking a snapshot of its state and restoring from it, but the generator is much
/// larger because it includes a big buffer of output. If you want to duplicate a generator and
/// consume output from both copies, cloning is easier *and* doesn't have to re-compute the output
/// that's already buffered. But if you store several snapshots and *possibly* use some of them at a
/// later time, cloning would waste a lot of memory.
///
/// # Examples
///
/// ```
/// # use chacha8rand::ChaCha8Rand;
/// # let mut rng = ChaCha8Rand::new(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456");
/// let state = rng.clone_state();
/// let first_output = rng.read_u64();
/// rng.try_restore_state(&state).expect("snapshot is valid because it was not modified");
/// assert_eq!(rng.read_u64(), first_output);
/// ```
// None of the backends currently require this alignment for soundness, but SIMD memory accesses
// that cross 32- or 64-byte boundaries are slightly slower on a bunch of CPUs, so higher alignment
// is occasionally useful. Since we don't do 512-bit SIMD, 32-byte alignment is sufficient.
/// Error returned from [`ChaCha8Rand::try_restore_state`] for corrupted snapshots.