1 // Copyright 2018 Developers of the Rand project.
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
9 //! The ChaCha random number generator.
11 #[cfg(not(feature = "std"))] use core;
12 #[cfg(feature = "std")] use std as core;
15 use crate::guts
::ChaCha
;
16 use rand_core
::block
::{BlockRng, BlockRngCore}
;
17 use rand_core
::{CryptoRng, Error, RngCore, SeedableRng}
;
19 const STREAM_PARAM_NONCE
: u32 = 1;
20 const STREAM_PARAM_BLOCK
: u32 = 0;
22 pub struct Array64
<T
>([T
; 64]);
23 impl<T
> Default
for Array64
<T
>
27 fn default() -> Self {
29 T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(),
30 T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(),
31 T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(),
32 T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(), T
::default(),
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(),
40 impl<T
> AsRef
<[T
]> for Array64
<T
> {
41 fn as_ref(&self) -> &[T
] {
45 impl<T
> AsMut
<[T
]> for Array64
<T
> {
46 fn as_mut(&mut self) -> &mut [T
] {
50 impl<T
> Clone
for Array64
<T
>
51 where T
: Copy
+ Default
53 fn clone(&self) -> Self {
54 let mut new
= Self::default();
55 new
.0.copy_from_slice(&self.0);
59 impl<T
> fmt
::Debug
for Array64
<T
> {
60 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
61 write
!(f
, "Array64 {{}}")
65 macro_rules
! chacha_impl
{
66 ($ChaChaXCore
:ident
, $ChaChaXRng
:ident
, $rounds
:expr
, $doc
:expr
) => {
69 pub struct $ChaChaXCore
{
73 // Custom Debug implementation that does not expose the internal state
74 impl fmt
::Debug
for $ChaChaXCore
{
75 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
76 write
!(f
, "ChaChaXCore {{}}")
80 impl BlockRngCore
for $ChaChaXCore
{
82 type Results
= Array64
<u32>;
84 fn generate(&mut self, r
: &mut Self::Results
) {
85 // Fill slice of words by writing to equivalent slice of bytes, then fixing endianness.
86 self.state
.refill4($rounds
, unsafe {
87 &mut *(&mut *r
as *mut Array64
<u32> as *mut [u8; 256])
95 impl SeedableRng
for $ChaChaXCore
{
98 fn from_seed(seed
: Self::Seed
) -> Self {
99 $ChaChaXCore { state: ChaCha::new(&seed, &[0u8; 8]) }
103 impl CryptoRng
for $ChaChaXCore {}
105 /// A cryptographically secure random number generator that uses the ChaCha algorithm.
107 /// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use as an RNG. It is
108 /// an improved variant of the Salsa20 cipher family, which was selected as one of the "stream
109 /// ciphers suitable for widespread adoption" by eSTREAM[^2].
111 /// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe against timing
112 /// attacks, although that is mostly a concern for ciphers and not for RNGs. We provide a SIMD
113 /// implementation to support high throughput on a variety of common hardware platforms.
115 /// With the ChaCha algorithm it is possible to choose the number of rounds the core algorithm
116 /// should run. The number of rounds is a tradeoff between performance and security, where 8
117 /// rounds is the minimum potentially secure configuration, and 20 rounds is widely used as a
118 /// conservative choice.
120 /// We use a 64-bit counter and 64-bit stream identifier as in Bernstein's implementation[^1]
121 /// except that we use a stream identifier in place of a nonce. A 64-bit counter over 64-byte
122 /// (16 word) blocks allows 1 ZiB of output before cycling, and the stream identifier allows
123 /// 2<sup>64</sup> unique streams of output per seed. Both counter and stream are initialized
124 /// to zero but may be set via the `set_word_pos` and `set_stream` methods.
126 /// The word layout is:
129 /// constant constant constant constant
130 /// seed seed seed seed
131 /// seed seed seed seed
132 /// counter counter stream_id stream_id
135 /// This implementation uses an output buffer of sixteen `u32` words, and uses
136 /// [`BlockRng`] to implement the [`RngCore`] methods.
138 /// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
139 /// https://cr.yp.to/chacha.html)
141 /// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
142 /// http://www.ecrypt.eu.org/stream/)
143 #[derive(Clone, Debug)]
144 pub struct $ChaChaXRng
{
145 rng
: BlockRng
<$ChaChaXCore
>,
148 impl SeedableRng
for $ChaChaXRng
{
149 type Seed
= [u8; 32];
151 fn from_seed(seed
: Self::Seed
) -> Self {
152 let core
= $ChaChaXCore
::from_seed(seed
);
154 rng
: BlockRng
::new(core
),
159 impl RngCore
for $ChaChaXRng
{
161 fn next_u32(&mut self) -> u32 {
165 fn next_u64(&mut self) -> u64 {
169 fn fill_bytes(&mut self, bytes
: &mut [u8]) {
170 self.rng
.fill_bytes(bytes
)
173 fn try_fill_bytes(&mut self, bytes
: &mut [u8]) -> Result
<(), Error
> {
174 self.rng
.try_fill_bytes(bytes
)
179 // The buffer is a 4-block window, i.e. it is always at a block-aligned position in the
180 // stream but if the stream has been seeked it may not be self-aligned.
182 /// Get the offset from the start of the stream, in 32-bit words.
184 /// Since the generated blocks are 16 words (2<sup>4</sup>) long and the
185 /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are
186 /// not supported, hence the result can simply be multiplied by 4 to get a
189 pub fn get_word_pos(&self) -> u128
{
190 let mut block
= u128
::from(self.rng
.core
.state
.get_stream_param(STREAM_PARAM_BLOCK
));
191 // counter is incremented *after* filling buffer
193 (block
<< 4) + self.rng
.index() as u128
196 /// Set the offset from the start of the stream, in 32-bit words.
198 /// As with `get_word_pos`, we use a 68-bit number. Since the generator
199 /// simply cycles at the end of its period (1 ZiB), we ignore the upper
202 pub fn set_word_pos(&mut self, word_offset
: u128
) {
203 let block
= (word_offset
>> 4) as u64;
207 .set_stream_param(STREAM_PARAM_BLOCK
, block
);
208 self.rng
.generate_and_set((word_offset
& 15) as usize);
211 /// Set the stream number.
213 /// This is initialized to zero; 2<sup>64</sup> unique streams of output
214 /// are available per seed/key.
216 /// Note that in order to reproduce ChaCha output with a specific 64-bit
217 /// nonce, one can convert that nonce to a `u64` in little-endian fashion
218 /// and pass to this function. In theory a 96-bit nonce can be used by
219 /// passing the last 64-bits to this function and using the first 32-bits as
220 /// the most significant half of the 64-bit counter (which may be set
221 /// indirectly via `set_word_pos`), but this is not directly supported.
223 pub fn set_stream(&mut self, stream
: u64) {
227 .set_stream_param(STREAM_PARAM_NONCE
, stream
);
228 if self.rng
.index() != 64 {
229 let wp
= self.get_word_pos();
230 self.set_word_pos(wp
);
235 impl CryptoRng
for $ChaChaXRng {}
237 impl From
<$ChaChaXCore
> for $ChaChaXRng
{
238 fn from(core
: $ChaChaXCore
) -> Self {
240 rng
: BlockRng
::new(core
),
247 chacha_impl
!(ChaCha20Core
, ChaCha20Rng
, 10, "ChaCha with 20 rounds");
248 chacha_impl
!(ChaCha12Core
, ChaCha12Rng
, 6, "ChaCha with 12 rounds");
249 chacha_impl
!(ChaCha8Core
, ChaCha8Rng
, 4, "ChaCha with 8 rounds");
253 use rand_core
::{RngCore, SeedableRng}
;
255 type ChaChaRng
= super::ChaCha20Rng
;
258 fn test_chacha_construction() {
260 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,
263 let mut rng1
= ChaChaRng
::from_seed(seed
);
264 assert_eq
!(rng1
.next_u32(), 137206642);
266 let mut rng2
= ChaChaRng
::from_rng(rng1
).unwrap();
267 assert_eq
!(rng2
.next_u32(), 1325750369);
271 fn test_chacha_true_values_a() {
272 // Test vectors 1 and 2 from
273 // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
274 let seed
= [0u8; 32];
275 let mut rng
= ChaChaRng
::from_seed(seed
);
277 let mut results
= [0u32; 16];
278 for i
in results
.iter_mut() {
282 0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8,
283 0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, 0xf4b8436a, 0x1ca11815,
284 0x69b687c3, 0x8665eeb2,
286 assert_eq
!(results
, expected
);
288 for i
in results
.iter_mut() {
292 0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612,
293 0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, 0x281fed31, 0x45fb0a51,
294 0x1f0ae1ac, 0x6f4d794b,
296 assert_eq
!(results
, expected
);
300 fn test_chacha_true_values_b() {
301 // Test vector 3 from
302 // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
304 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,
307 let mut rng
= ChaChaRng
::from_seed(seed
);
314 let mut results
= [0u32; 16];
315 for i
in results
.iter_mut() {
319 0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, 0xe8252083, 0x60818b01, 0xf38422b8,
320 0x5aaa49c9, 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, 0x4436274e, 0x2561b3c8,
321 0xebdd4aa6, 0xa0136c00,
323 assert_eq
!(results
, expected
);
327 fn test_chacha_true_values_c() {
328 // Test vector 4 from
329 // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
331 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,
335 0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, 0xa78dea8f, 0x5e269039, 0xa1bebbc1,
336 0xcaf09aae, 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, 0x546ca624, 0x1bec45d5,
337 0x87f47473, 0x96f0992e,
339 let expected_end
= 3 * 16;
340 let mut results
= [0u32; 16];
342 // Test block 2 by skipping block 0 and 1
343 let mut rng1
= ChaChaRng
::from_seed(seed
);
347 for i
in results
.iter_mut() {
348 *i
= rng1
.next_u32();
350 assert_eq
!(results
, expected
);
351 assert_eq
!(rng1
.get_word_pos(), expected_end
);
353 // Test block 2 by using `set_word_pos`
354 let mut rng2
= ChaChaRng
::from_seed(seed
);
355 rng2
.set_word_pos(2 * 16);
356 for i
in results
.iter_mut() {
357 *i
= rng2
.next_u32();
359 assert_eq
!(results
, expected
);
360 assert_eq
!(rng2
.get_word_pos(), expected_end
);
362 // Test skipping behaviour with other types
363 let mut buf
= [0u8; 32];
364 rng2
.fill_bytes(&mut buf
[..]);
365 assert_eq
!(rng2
.get_word_pos(), expected_end
+ 8);
366 rng2
.fill_bytes(&mut buf
[0..25]);
367 assert_eq
!(rng2
.get_word_pos(), expected_end
+ 15);
369 assert_eq
!(rng2
.get_word_pos(), expected_end
+ 17);
372 assert_eq
!(rng2
.get_word_pos(), expected_end
+ 20);
373 rng2
.fill_bytes(&mut buf
[0..1]);
374 assert_eq
!(rng2
.get_word_pos(), expected_end
+ 21);
378 fn test_chacha_multiple_blocks() {
380 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,
383 let mut rng
= ChaChaRng
::from_seed(seed
);
385 // Store the 17*i-th 32-bit word,
386 // i.e., the i-th word of the i-th 16-word block
387 let mut results
= [0u32; 16];
388 for i
in results
.iter_mut() {
395 0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186,
396 0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc,
397 0x5f1c86d9, 0xc1f8e7f4,
399 assert_eq
!(results
, expected
);
403 fn test_chacha_true_bytes() {
404 let seed
= [0u8; 32];
405 let mut rng
= ChaChaRng
::from_seed(seed
);
406 let mut results
= [0u8; 32];
407 rng
.fill_bytes(&mut results
);
409 118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
410 25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
412 assert_eq
!(results
, expected
);
416 fn test_chacha_nonce() {
417 // Test vector 5 from
418 // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
419 // Although we do not support setting a nonce, we try it here anyway so
420 // we can use this test vector.
421 let seed
= [0u8; 32];
422 let mut rng
= ChaChaRng
::from_seed(seed
);
423 // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2
424 rng
.set_stream(2u64 << (24 + 32));
426 let mut results
= [0u32; 16];
427 for i
in results
.iter_mut() {
431 0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, 0x88228b1a, 0x96a4dfb3, 0x5b76ab72,
432 0xc727ee54, 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, 0x99c28f5f, 0x628314e8,
433 0x398a19fa, 0x6ded1b53,
435 assert_eq
!(results
, expected
);
439 fn test_chacha_clone_streams() {
441 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,
444 let mut rng
= ChaChaRng
::from_seed(seed
);
445 let mut clone
= rng
.clone();
447 assert_eq
!(rng
.next_u64(), clone
.next_u64());
452 assert
!(rng
.next_u32() != clone
.next_u32());
454 clone
.set_stream(51); // switch part way through block
456 assert_eq
!(rng
.next_u32(), clone
.next_u32());