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.
4 //
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.
10 
11 //! The ChaCha random number generator.
12 
13 use core::num::Wrapping as w;
14 use {Rng, SeedableRng, Rand};
15 
16 #[allow(bad_style)]
17 type w32 = w<u32>;
18 
19 const KEY_WORDS    : usize =  8; // 8 words for the 256-bit key
20 const STATE_WORDS  : usize = 16;
21 const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of this writing
22 
23 /// A random number generator that uses the ChaCha20 algorithm [1].
24 ///
25 /// The ChaCha algorithm is widely accepted as suitable for
26 /// cryptographic purposes, but this implementation has not been
27 /// verified as such. Prefer a generator like `OsRng` that defers to
28 /// the operating system for cases that need high security.
29 ///
30 /// [1]: D. J. Bernstein, [*ChaCha, a variant of
31 /// Salsa20*](http://cr.yp.to/chacha.html)
32 #[derive(Copy, Clone, Debug)]
33 pub struct ChaChaRng {
34     buffer:  [w32; STATE_WORDS], // Internal buffer of output
35     state:   [w32; STATE_WORDS], // Initial state
36     index:   usize,                 // Index into state
37 }
38 
39 static EMPTY: ChaChaRng = ChaChaRng {
40     buffer:  [w(0); STATE_WORDS],
41     state:   [w(0); STATE_WORDS],
42     index:   STATE_WORDS
43 };
44 
45 
46 macro_rules! quarter_round{
47     ($a: expr, $b: expr, $c: expr, $d: expr) => {{
48         $a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left(16));
49         $c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left(12));
50         $a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left( 8));
51         $c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left( 7));
52     }}
53 }
54 
55 macro_rules! double_round{
56     ($x: expr) => {{
57         // Column round
58         quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
59         quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
60         quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
61         quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
62         // Diagonal round
63         quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
64         quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
65         quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
66         quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
67     }}
68 }
69 
70 #[inline]
core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS])71 fn core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS]) {
72     *output = *input;
73 
74     for _ in 0..CHACHA_ROUNDS / 2 {
75         double_round!(output);
76     }
77 
78     for i in 0..STATE_WORDS {
79         output[i] = output[i] + input[i];
80     }
81 }
82 
83 impl ChaChaRng {
84 
85     /// Create an ChaCha random number generator using the default
86     /// fixed key of 8 zero words.
87     ///
88     /// # Examples
89     ///
90     /// ```rust
91     /// use rand::{Rng, ChaChaRng};
92     ///
93     /// let mut ra = ChaChaRng::new_unseeded();
94     /// println!("{:?}", ra.next_u32());
95     /// println!("{:?}", ra.next_u32());
96     /// ```
97     ///
98     /// Since this equivalent to a RNG with a fixed seed, repeated executions
99     /// of an unseeded RNG will produce the same result. This code sample will
100     /// consistently produce:
101     ///
102     /// - 2917185654
103     /// - 2419978656
new_unseeded() -> ChaChaRng104     pub fn new_unseeded() -> ChaChaRng {
105         let mut rng = EMPTY;
106         rng.init(&[0; KEY_WORDS]);
107         rng
108     }
109 
110     /// Sets the internal 128-bit ChaCha counter to
111     /// a user-provided value. This permits jumping
112     /// arbitrarily ahead (or backwards) in the pseudorandom stream.
113     ///
114     /// Since the nonce words are used to extend the counter to 128 bits,
115     /// users wishing to obtain the conventional ChaCha pseudorandom stream
116     /// associated with a particular nonce can call this function with
117     /// arguments `0, desired_nonce`.
118     ///
119     /// # Examples
120     ///
121     /// ```rust
122     /// use rand::{Rng, ChaChaRng};
123     ///
124     /// let mut ra = ChaChaRng::new_unseeded();
125     /// ra.set_counter(0u64, 1234567890u64);
126     /// println!("{:?}", ra.next_u32());
127     /// println!("{:?}", ra.next_u32());
128     /// ```
set_counter(&mut self, counter_low: u64, counter_high: u64)129     pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
130         self.state[12] = w((counter_low >>  0) as u32);
131         self.state[13] = w((counter_low >> 32) as u32);
132         self.state[14] = w((counter_high >>  0) as u32);
133         self.state[15] = w((counter_high >> 32) as u32);
134         self.index = STATE_WORDS; // force recomputation
135     }
136 
137     /// Initializes `self.state` with the appropriate key and constants
138     ///
139     /// We deviate slightly from the ChaCha specification regarding
140     /// the nonce, which is used to extend the counter to 128 bits.
141     /// This is provably as strong as the original cipher, though,
142     /// since any distinguishing attack on our variant also works
143     /// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
144     /// security proof for a more involved example of this.
145     ///
146     /// The modified word layout is:
147     /// ```text
148     /// constant constant constant constant
149     /// key      key      key      key
150     /// key      key      key      key
151     /// counter  counter  counter  counter
152     /// ```
153     /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
154     /// nonce.*](http://cr.yp.to/papers.html#xsalsa)
init(&mut self, key: &[u32; KEY_WORDS])155     fn init(&mut self, key: &[u32; KEY_WORDS]) {
156         self.state[0] = w(0x61707865);
157         self.state[1] = w(0x3320646E);
158         self.state[2] = w(0x79622D32);
159         self.state[3] = w(0x6B206574);
160 
161         for i in 0..KEY_WORDS {
162             self.state[4+i] = w(key[i]);
163         }
164 
165         self.state[12] = w(0);
166         self.state[13] = w(0);
167         self.state[14] = w(0);
168         self.state[15] = w(0);
169 
170         self.index = STATE_WORDS;
171     }
172 
173     /// Refill the internal output buffer (`self.buffer`)
update(&mut self)174     fn update(&mut self) {
175         core(&mut self.buffer, &self.state);
176         self.index = 0;
177         // update 128-bit counter
178         self.state[12] = self.state[12] + w(1);
179         if self.state[12] != w(0) { return };
180         self.state[13] = self.state[13] + w(1);
181         if self.state[13] != w(0) { return };
182         self.state[14] = self.state[14] + w(1);
183         if self.state[14] != w(0) { return };
184         self.state[15] = self.state[15] + w(1);
185     }
186 }
187 
188 impl Rng for ChaChaRng {
189     #[inline]
next_u32(&mut self) -> u32190     fn next_u32(&mut self) -> u32 {
191         if self.index == STATE_WORDS {
192             self.update();
193         }
194 
195         let value = self.buffer[self.index % STATE_WORDS];
196         self.index += 1;
197         value.0
198     }
199 }
200 
201 impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
202 
reseed(&mut self, seed: &'a [u32])203     fn reseed(&mut self, seed: &'a [u32]) {
204         // reset state
205         self.init(&[0u32; KEY_WORDS]);
206         // set key in place
207         let key = &mut self.state[4 .. 4+KEY_WORDS];
208         for (k, s) in key.iter_mut().zip(seed.iter()) {
209             *k = w(*s);
210         }
211     }
212 
213     /// Create a ChaCha generator from a seed,
214     /// obtained from a variable-length u32 array.
215     /// Only up to 8 words are used; if less than 8
216     /// words are used, the remaining are set to zero.
from_seed(seed: &'a [u32]) -> ChaChaRng217     fn from_seed(seed: &'a [u32]) -> ChaChaRng {
218         let mut rng = EMPTY;
219         rng.reseed(seed);
220         rng
221     }
222 }
223 
224 impl Rand for ChaChaRng {
rand<R: Rng>(other: &mut R) -> ChaChaRng225     fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
226         let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
227         for word in key.iter_mut() {
228             *word = other.gen();
229         }
230         SeedableRng::from_seed(&key[..])
231     }
232 }
233 
234 
235 #[cfg(test)]
236 mod test {
237     use {Rng, SeedableRng};
238     use super::ChaChaRng;
239 
240     #[test]
test_rng_rand_seeded()241     fn test_rng_rand_seeded() {
242         let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
243         let mut ra: ChaChaRng = SeedableRng::from_seed(&s[..]);
244         let mut rb: ChaChaRng = SeedableRng::from_seed(&s[..]);
245         assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
246                                 rb.gen_ascii_chars().take(100)));
247     }
248 
249     #[test]
test_rng_seeded()250     fn test_rng_seeded() {
251         let seed : &[_] = &[0,1,2,3,4,5,6,7];
252         let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
253         let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
254         assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
255                                 rb.gen_ascii_chars().take(100)));
256     }
257 
258     #[test]
test_rng_reseed()259     fn test_rng_reseed() {
260         let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
261         let mut r: ChaChaRng = SeedableRng::from_seed(&s[..]);
262         let string1: String = r.gen_ascii_chars().take(100).collect();
263 
264         r.reseed(&s);
265 
266         let string2: String = r.gen_ascii_chars().take(100).collect();
267         assert_eq!(string1, string2);
268     }
269 
270     #[test]
test_rng_true_values()271     fn test_rng_true_values() {
272         // Test vectors 1 and 2 from
273         // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
274         let seed : &[_] = &[0u32; 8];
275         let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
276 
277         let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
278         assert_eq!(v,
279                    vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
280                         0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
281                         0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
282                         0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2));
283 
284         let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
285         assert_eq!(v,
286                    vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
287                         0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
288                         0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
289                         0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));
290 
291 
292         let seed : &[_] = &[0,1,2,3,4,5,6,7];
293         let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
294 
295         // Store the 17*i-th 32-bit word,
296         // i.e., the i-th word of the i-th 16-word block
297         let mut v : Vec<u32> = Vec::new();
298         for _ in 0..16 {
299             v.push(ra.next_u32());
300             for _ in 0..16 {
301                 ra.next_u32();
302             }
303         }
304 
305         assert_eq!(v,
306                    vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
307                         0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
308                         0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
309                         0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
310     }
311 
312     #[test]
test_rng_clone()313     fn test_rng_clone() {
314         let seed : &[_] = &[0u32; 8];
315         let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
316         let mut clone = rng.clone();
317         for _ in 0..16 {
318             assert_eq!(rng.next_u64(), clone.next_u64());
319         }
320     }
321 }
322