1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! The ChaCha random number generator.
13 use {Rng, SeedableRng, Rand};
15 const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
16 const STATE_WORDS : usize = 16;
17 const CHACHA_ROUNDS: usize = 20; // Cryptographically secure from 8 upwards as of this writing
19 /// A random number generator that uses the ChaCha20 algorithm [1].
21 /// The ChaCha algorithm is widely accepted as suitable for
22 /// cryptographic purposes, but this implementation has not been
23 /// verified as such. Prefer a generator like `OsRng` that defers to
24 /// the operating system for cases that need high security.
26 /// [1]: D. J. Bernstein, [*ChaCha, a variant of
27 /// Salsa20*](http://cr.yp.to/chacha.html)
28 #[derive(Copy, Clone)]
29 pub struct ChaChaRng {
30 buffer: [u32; STATE_WORDS], // Internal buffer of output
31 state: [u32; STATE_WORDS], // Initial state
32 index: usize, // Index into state
35 static EMPTY: ChaChaRng = ChaChaRng {
36 buffer: [0; STATE_WORDS],
37 state: [0; STATE_WORDS],
42 macro_rules! quarter_round{
43 ($a: expr, $b: expr, $c: expr, $d: expr) => {{
44 $a = $a.wrapping_add($b); $d = $d ^ $a; $d = $d.rotate_left(16);
45 $c = $c.wrapping_add($d); $b = $b ^ $c; $b = $b.rotate_left(12);
46 $a = $a.wrapping_add($b); $d = $d ^ $a; $d = $d.rotate_left( 8);
47 $c = $c.wrapping_add($d); $b = $b ^ $c; $b = $b.rotate_left( 7);
51 macro_rules! double_round{
54 quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
55 quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
56 quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
57 quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
59 quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
60 quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
61 quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
62 quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
67 fn core(output: &mut [u32; STATE_WORDS], input: &[u32; STATE_WORDS]) {
70 for _ in 0..CHACHA_ROUNDS / 2 {
71 double_round!(output);
74 for i in 0..STATE_WORDS {
75 output[i] = output[i].wrapping_add(input[i]);
81 /// Create an ChaCha random number generator using the default
82 /// fixed key of 8 zero words.
83 pub fn new_unseeded() -> ChaChaRng {
85 rng.init(&[0; KEY_WORDS]);
89 /// Sets the internal 128-bit ChaCha counter to
90 /// a user-provided value. This permits jumping
91 /// arbitrarily ahead (or backwards) in the pseudorandom stream.
93 /// Since the nonce words are used to extend the counter to 128 bits,
94 /// users wishing to obtain the conventional ChaCha pseudorandom stream
95 /// associated with a particular nonce can call this function with
96 /// arguments `0, desired_nonce`.
97 pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
98 self.state[12] = (counter_low >> 0) as u32;
99 self.state[13] = (counter_low >> 32) as u32;
100 self.state[14] = (counter_high >> 0) as u32;
101 self.state[15] = (counter_high >> 32) as u32;
102 self.index = STATE_WORDS; // force recomputation
105 /// Initializes `self.state` with the appropriate key and constants
107 /// We deviate slightly from the ChaCha specification regarding
108 /// the nonce, which is used to extend the counter to 128 bits.
109 /// This is provably as strong as the original cipher, though,
110 /// since any distinguishing attack on our variant also works
111 /// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
112 /// security proof for a more involved example of this.
114 /// The modified word layout is:
116 /// constant constant constant constant
119 /// counter counter counter counter
121 /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
122 /// nonce.*](http://cr.yp.to/papers.html#xsalsa)
123 fn init(&mut self, key: &[u32; KEY_WORDS]) {
124 self.state[0] = 0x61707865;
125 self.state[1] = 0x3320646E;
126 self.state[2] = 0x79622D32;
127 self.state[3] = 0x6B206574;
129 for i in 0..KEY_WORDS {
130 self.state[4 + i] = key[i];
138 self.index = STATE_WORDS;
141 /// Refill the internal output buffer (`self.buffer`)
142 fn update(&mut self) {
143 core(&mut self.buffer, &self.state);
145 // update 128-bit counter
147 if self.state[12] != 0 {
151 if self.state[13] != 0 {
155 if self.state[14] != 0 {
162 impl Rng for ChaChaRng {
164 fn next_u32(&mut self) -> u32 {
165 if self.index == STATE_WORDS {
169 let value = self.buffer[self.index % STATE_WORDS];
175 impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
177 fn reseed(&mut self, seed: &'a [u32]) {
179 self.init(&[0; KEY_WORDS]);
181 let key = &mut self.state[4..4 + KEY_WORDS];
182 for (k, s) in key.iter_mut().zip(seed) {
187 /// Create a ChaCha generator from a seed,
188 /// obtained from a variable-length u32 array.
189 /// Only up to 8 words are used; if less than 8
190 /// words are used, the remaining are set to zero.
191 fn from_seed(seed: &'a [u32]) -> ChaChaRng {
198 impl Rand for ChaChaRng {
199 fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
200 let mut key: [u32; KEY_WORDS] = [0; KEY_WORDS];
201 for word in &mut key {
204 SeedableRng::from_seed(&key[..])
211 use std::prelude::v1::*;
213 use core::iter::order;
214 use {Rng, SeedableRng};
215 use super::ChaChaRng;
218 fn test_rng_rand_seeded() {
219 let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
220 let mut ra: ChaChaRng = SeedableRng::from_seed(&*s);
221 let mut rb: ChaChaRng = SeedableRng::from_seed(&*s);
222 assert!(order::equals(ra.gen_ascii_chars().take(100),
223 rb.gen_ascii_chars().take(100)));
227 fn test_rng_seeded() {
228 let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
229 let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
230 let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
231 assert!(order::equals(ra.gen_ascii_chars().take(100),
232 rb.gen_ascii_chars().take(100)));
236 fn test_rng_reseed() {
237 let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
238 let mut r: ChaChaRng = SeedableRng::from_seed(&*s);
239 let string1: String = r.gen_ascii_chars().take(100).collect();
243 let string2: String = r.gen_ascii_chars().take(100).collect();
244 assert_eq!(string1, string2);
248 fn test_rng_true_values() {
249 // Test vectors 1 and 2 from
250 // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
251 let seed: &[_] = &[0; 8];
252 let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
254 let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
273 let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
293 let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
294 let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
296 // Store the 17*i-th 32-bit word,
297 // i.e., the i-th word of the i-th 16-word block
298 let mut v: Vec<u32> = Vec::new();
300 v.push(ra.next_u32());
326 fn test_rng_clone() {
327 let seed: &[_] = &[0; 8];
328 let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
329 let mut clone = rng.clone();
331 assert_eq!(rng.next_u64(), clone.next_u64());