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.
16 use {Rng, SeedableRng, Rand};
18 const KEY_WORDS : uint = 8; // 8 words for the 256-bit key
19 const STATE_WORDS : uint = 16;
20 const CHACHA_ROUNDS: uint = 20; // Cryptographically secure from 8 upwards as of this writing
22 /// A random number generator that uses the ChaCha20 algorithm [1].
24 /// The ChaCha algorithm is widely accepted as suitable for
25 /// cryptographic purposes, but this implementation has not been
26 /// verified as such. Prefer a generator like `OsRng` that defers to
27 /// the operating system for cases that need high security.
29 /// [1]: D. J. Bernstein, [*ChaCha, a variant of
30 /// Salsa20*](http://cr.yp.to/chacha.html)
33 pub struct ChaChaRng {
34 buffer: [u32; STATE_WORDS], // Internal buffer of output
35 state: [u32; STATE_WORDS], // Initial state
36 index: uint, // Index into state
39 static EMPTY: ChaChaRng = ChaChaRng {
40 buffer: [0; STATE_WORDS],
41 state: [0; STATE_WORDS],
46 macro_rules! quarter_round{
47 ($a: expr, $b: expr, $c: expr, $d: expr) => {{
48 $a += $b; $d ^= $a; $d = $d.rotate_left(16);
49 $c += $d; $b ^= $c; $b = $b.rotate_left(12);
50 $a += $b; $d ^= $a; $d = $d.rotate_left( 8);
51 $c += $d; $b ^= $c; $b = $b.rotate_left( 7);
55 macro_rules! double_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]);
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]);
71 fn core(output: &mut [u32; STATE_WORDS], input: &[u32; STATE_WORDS]) {
74 for _ in range(0, CHACHA_ROUNDS / 2) {
75 double_round!(output);
78 for i in range(0, STATE_WORDS) {
79 output[i] += input[i];
85 /// Create an ChaCha random number generator using the default
86 /// fixed key of 8 zero words.
87 pub fn new_unseeded() -> ChaChaRng {
89 rng.init(&[0; KEY_WORDS]);
93 /// Sets the internal 128-bit ChaCha counter to
94 /// a user-provided value. This permits jumping
95 /// arbitrarily ahead (or backwards) in the pseudorandom stream.
97 /// Since the nonce words are used to extend the counter to 128 bits,
98 /// users wishing to obtain the conventional ChaCha pseudorandom stream
99 /// associated with a particular nonce can call this function with
100 /// arguments `0, desired_nonce`.
101 pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
102 self.state[12] = (counter_low >> 0) as u32;
103 self.state[13] = (counter_low >> 32) as u32;
104 self.state[14] = (counter_high >> 0) as u32;
105 self.state[15] = (counter_high >> 32) as u32;
106 self.index = STATE_WORDS; // force recomputation
109 /// Initializes `self.state` with the appropriate key and constants
111 /// We deviate slightly from the ChaCha specification regarding
112 /// the nonce, which is used to extend the counter to 128 bits.
113 /// This is provably as strong as the original cipher, though,
114 /// since any distinguishing attack on our variant also works
115 /// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
116 /// security proof for a more involved example of this.
118 /// The modified word layout is:
120 /// constant constant constant constant
123 /// counter counter counter counter
125 /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
126 /// nonce.*](http://cr.yp.to/papers.html#xsalsa)
127 fn init(&mut self, key: &[u32; KEY_WORDS]) {
128 self.state[0] = 0x61707865;
129 self.state[1] = 0x3320646E;
130 self.state[2] = 0x79622D32;
131 self.state[3] = 0x6B206574;
133 for i in range(0, KEY_WORDS) {
134 self.state[4+i] = key[i];
142 self.index = STATE_WORDS;
145 /// Refill the internal output buffer (`self.buffer`)
146 fn update(&mut self) {
147 core(&mut self.buffer, &self.state);
149 // update 128-bit counter
151 if self.state[12] != 0 { return };
153 if self.state[13] != 0 { return };
155 if self.state[14] != 0 { return };
160 impl Rng for ChaChaRng {
162 fn next_u32(&mut self) -> u32 {
163 if self.index == STATE_WORDS {
167 let value = self.buffer[self.index % STATE_WORDS];
173 impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
175 fn reseed(&mut self, seed: &'a [u32]) {
177 self.init(&[0u32; KEY_WORDS]);
179 let key = self.state.slice_mut(4, 4+KEY_WORDS);
180 for (k, s) in key.iter_mut().zip(seed.iter()) {
185 /// Create a ChaCha generator from a seed,
186 /// obtained from a variable-length u32 array.
187 /// Only up to 8 words are used; if less than 8
188 /// words are used, the remaining are set to zero.
189 fn from_seed(seed: &'a [u32]) -> ChaChaRng {
196 impl Rand for ChaChaRng {
197 fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
198 let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
199 for word in key.iter_mut() {
202 SeedableRng::from_seed(key.as_slice())
209 use std::prelude::v1::*;
211 use core::iter::order;
212 use {Rng, SeedableRng};
213 use super::ChaChaRng;
216 fn test_rng_rand_seeded() {
217 let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
218 let mut ra: ChaChaRng = SeedableRng::from_seed(s.as_slice());
219 let mut rb: ChaChaRng = SeedableRng::from_seed(s.as_slice());
220 assert!(order::equals(ra.gen_ascii_chars().take(100),
221 rb.gen_ascii_chars().take(100)));
225 fn test_rng_seeded() {
226 let seed : &[_] = &[0,1,2,3,4,5,6,7];
227 let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
228 let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
229 assert!(order::equals(ra.gen_ascii_chars().take(100),
230 rb.gen_ascii_chars().take(100)));
234 fn test_rng_reseed() {
235 let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
236 let mut r: ChaChaRng = SeedableRng::from_seed(s.as_slice());
237 let string1: String = r.gen_ascii_chars().take(100).collect();
239 r.reseed(s.as_slice());
241 let string2: String = r.gen_ascii_chars().take(100).collect();
242 assert_eq!(string1, string2);
246 fn test_rng_true_values() {
247 // Test vectors 1 and 2 from
248 // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
249 let seed : &[_] = &[0u32; 8];
250 let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
252 let v = range(0, 16).map(|_| ra.next_u32()).collect::<Vec<_>>();
254 vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
255 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
256 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
257 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2));
259 let v = range(0, 16).map(|_| ra.next_u32()).collect::<Vec<_>>();
261 vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
262 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
263 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
264 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));
267 let seed : &[_] = &[0,1,2,3,4,5,6,7];
268 let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
270 // Store the 17*i-th 32-bit word,
271 // i.e., the i-th word of the i-th 16-word block
272 let mut v : Vec<u32> = Vec::new();
273 for _ in range(0u, 16) {
274 v.push(ra.next_u32());
275 for _ in range(0u, 16) {
281 vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
282 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
283 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
284 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));