crypto/
chacha20.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6use std::cmp;
7
8use buffer::{BufferResult, RefReadBuffer, RefWriteBuffer};
9use symmetriccipher::{Encryptor, Decryptor, SynchronousStreamCipher, SymmetricCipherError};
10use cryptoutil::{read_u32_le, symm_enc_or_dec, write_u32_le, xor_keystream};
11use simd::u32x4;
12
13#[derive(Clone,Copy)]
14struct ChaChaState {
15  a: u32x4,
16  b: u32x4,
17  c: u32x4,
18  d: u32x4
19}
20
21#[derive(Copy)]
22pub struct ChaCha20 {
23    state  : ChaChaState,
24    output : [u8; 64],
25    offset : usize,
26}
27
28impl Clone for ChaCha20 { fn clone(&self) -> ChaCha20 { *self } }
29
30macro_rules! swizzle{
31    ($b: expr, $c: expr, $d: expr) => {{
32        let u32x4(b10, b11, b12, b13) = $b;
33        $b = u32x4(b11, b12, b13, b10);
34        let u32x4(c10, c11, c12, c13) = $c;
35        $c = u32x4(c12, c13,c10, c11);
36        let u32x4(d10, d11, d12, d13) = $d;
37        $d = u32x4(d13, d10, d11, d12);
38    }}
39}
40
41macro_rules! state_to_buffer {
42    ($state: expr, $output: expr) => {{
43        let u32x4(a1, a2, a3, a4) = $state.a;
44        let u32x4(b1, b2, b3, b4) = $state.b;
45        let u32x4(c1, c2, c3, c4) = $state.c;
46        let u32x4(d1, d2, d3, d4) = $state.d;
47        let lens = [
48            a1,a2,a3,a4,
49            b1,b2,b3,b4,
50            c1,c2,c3,c4,
51            d1,d2,d3,d4
52        ];
53        for i in 0..lens.len() {
54            write_u32_le(&mut $output[i*4..(i+1)*4], lens[i]);
55        }
56    }}
57}
58
59macro_rules! round{
60    ($state: expr) => {{
61      $state.a = $state.a + $state.b;
62      rotate!($state.d, $state.a, S16);
63      $state.c = $state.c + $state.d;
64      rotate!($state.b, $state.c, S12);
65      $state.a = $state.a + $state.b;
66      rotate!($state.d, $state.a, S8);
67      $state.c = $state.c + $state.d;
68      rotate!($state.b, $state.c, S7);
69    }}
70}
71
72macro_rules! rotate {
73    ($a: expr, $b: expr, $c:expr) => {{
74      let v = $a ^ $b;
75      let r = S32 - $c;
76      let right = v >> r;
77      $a = (v << $c) ^ right
78    }}
79}
80
81static S32:u32x4 = u32x4(32, 32, 32, 32);
82static S16:u32x4 = u32x4(16, 16, 16, 16);
83static S12:u32x4 = u32x4(12, 12, 12, 12);
84static S8:u32x4 = u32x4(8, 8, 8, 8);
85static S7:u32x4 = u32x4(7, 7, 7, 7);
86
87impl ChaCha20 {
88    pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
89        assert!(key.len() == 16 || key.len() == 32);
90        assert!(nonce.len() == 8 || nonce.len() == 12);
91
92        ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; 64], offset: 64 }
93    }
94
95    pub fn new_xchacha20(key: &[u8], nonce: &[u8]) -> ChaCha20 {
96        assert!(key.len() == 32);
97        assert!(nonce.len() == 24);
98
99        // HChaCha20 produces a 256-bit output block starting from a 512 bit
100        // input block where (x0,x1,...,x15) where
101        //
102        //  * (x0, x1, x2, x3) is the ChaCha20 constant.
103        //  * (x4, x5, ... x11) is a 256 bit key.
104        //  * (x12, x13, x14, x15) is a 128 bit nonce.
105        let mut xchacha20 = ChaCha20{ state: ChaCha20::expand(key, &nonce[0..16]), output: [0u8; 64], offset: 64 };
106
107        // Use HChaCha to derive the subkey, and initialize a ChaCha20 instance
108        // with the subkey and the remaining 8 bytes of the nonce.
109        let mut new_key = [0; 32];
110        xchacha20.hchacha20(&mut new_key);
111        xchacha20.state = ChaCha20::expand(&new_key, &nonce[16..24]);
112
113        xchacha20
114    }
115
116    fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
117
118        let constant = match key.len() {
119            16 => b"expand 16-byte k",
120            32 => b"expand 32-byte k",
121            _  => unreachable!(),
122        };
123        ChaChaState {
124            a: u32x4(
125                read_u32_le(&constant[0..4]),
126                read_u32_le(&constant[4..8]),
127                read_u32_le(&constant[8..12]),
128                read_u32_le(&constant[12..16])
129            ),
130            b: u32x4(
131                read_u32_le(&key[0..4]),
132                read_u32_le(&key[4..8]),
133                read_u32_le(&key[8..12]),
134                read_u32_le(&key[12..16])
135            ),
136            c: if key.len() == 16 {
137                    u32x4(
138                        read_u32_le(&key[0..4]),
139                        read_u32_le(&key[4..8]),
140                        read_u32_le(&key[8..12]),
141                        read_u32_le(&key[12..16])
142                    )
143                } else {
144                    u32x4(
145                        read_u32_le(&key[16..20]),
146                        read_u32_le(&key[20..24]),
147                        read_u32_le(&key[24..28]),
148                        read_u32_le(&key[28..32])
149                    )
150                },
151            d: if nonce.len() == 16 {
152                   u32x4(
153                        read_u32_le(&nonce[0..4]),
154                        read_u32_le(&nonce[4..8]),
155                        read_u32_le(&nonce[8..12]),
156                        read_u32_le(&nonce[12..16])
157                    )
158               } else if nonce.len() == 12 {
159                   u32x4(
160                        0,
161                        read_u32_le(&nonce[0..4]),
162                        read_u32_le(&nonce[4..8]),
163                        read_u32_le(&nonce[8..12])
164                    )
165               } else {
166                   u32x4(
167                        0,
168                        0,
169                        read_u32_le(&nonce[0..4]),
170                        read_u32_le(&nonce[4..8])
171                    )
172               }
173        }
174    }
175
176    fn hchacha20(&mut self, out: &mut [u8]) -> () {
177        let mut state = self.state;
178
179        // Apply r/2 iterations of the same "double-round" function,
180        // obtaining (z0, z1, ... z15) = doubleround r/2 (x0, x1, ... x15).
181        for _ in 0..10 {
182            round!(state);
183            let u32x4(b10, b11, b12, b13) = state.b;
184            state.b = u32x4(b11, b12, b13, b10);
185            let u32x4(c10, c11, c12, c13) = state.c;
186            state.c = u32x4(c12, c13,c10, c11);
187            let u32x4(d10, d11, d12, d13) = state.d;
188            state.d = u32x4(d13, d10, d11, d12);
189            round!(state);
190            let u32x4(b20, b21, b22, b23) = state.b;
191            state.b = u32x4(b23, b20, b21, b22);
192            let u32x4(c20, c21, c22, c23) = state.c;
193            state.c = u32x4(c22, c23, c20, c21);
194            let u32x4(d20, d21, d22, d23) = state.d;
195            state.d = u32x4(d21, d22, d23, d20);
196        }
197
198        // HChaCha20 then outputs the 256-bit block (z0, z1, z2, z3, z12, z13,
199        // z14, z15).  These correspond to the constant and input positions in
200        // the ChaCha matrix.
201        let u32x4(a1, a2, a3, a4) = state.a;
202        let u32x4(d1, d2, d3, d4) = state.d;
203        let lens = [
204            a1,a2,a3,a4,
205            d1,d2,d3,d4
206        ];
207        for i in 0..lens.len() {
208            write_u32_le(&mut out[i*4..(i+1)*4], lens[i]);
209        }
210    }
211
212    // put the the next 64 keystream bytes into self.output
213    fn update(&mut self) {
214        let mut state = self.state;
215
216        for _ in 0..10 {
217            round!(state);
218            swizzle!(state.b, state.c, state.d);
219            round!(state);
220            swizzle!(state.d, state.c, state.b);
221        }
222        state.a = state.a + self.state.a;
223        state.b = state.b + self.state.b;
224        state.c = state.c + self.state.c;
225        state.d = state.d + self.state.d;
226
227        state_to_buffer!(state, self.output);
228
229        self.state.d = self.state.d + u32x4(1, 0, 0, 0);
230        let u32x4(c12, _, _, _) = self.state.d;
231        if c12 == 0 {
232            // we could increment the other counter word with an 8 byte nonce
233            // but other implementations like boringssl have this same
234            // limitation
235            panic!("counter is exhausted");
236        }
237
238        self.offset = 0;
239    }
240}
241
242impl SynchronousStreamCipher for ChaCha20 {
243    fn process(&mut self, input: &[u8], output: &mut [u8]) {
244        assert!(input.len() == output.len());
245        let len = input.len();
246        let mut i = 0;
247        while i < len {
248            // If there is no keystream available in the output buffer,
249            // generate the next block.
250            if self.offset == 64 {
251                self.update();
252            }
253
254            // Process the min(available keystream, remaining input length).
255            let count = cmp::min(64 - self.offset, len - i);
256            xor_keystream(&mut output[i..i+count], &input[i..i+count], &self.output[self.offset..]);
257            i += count;
258            self.offset += count;
259        }
260    }
261}
262
263impl Encryptor for ChaCha20 {
264    fn encrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
265            -> Result<BufferResult, SymmetricCipherError> {
266        symm_enc_or_dec(self, input, output)
267    }
268}
269
270impl Decryptor for ChaCha20 {
271    fn decrypt(&mut self, input: &mut RefReadBuffer, output: &mut RefWriteBuffer, _: bool)
272            -> Result<BufferResult, SymmetricCipherError> {
273        symm_enc_or_dec(self, input, output)
274    }
275}
276
277#[cfg(test)]
278mod test {
279    use std::iter::repeat;
280
281    use chacha20::ChaCha20;
282    use symmetriccipher::SynchronousStreamCipher;
283
284    #[test]
285    fn test_chacha20_256_tls_vectors() {
286        struct TestVector {
287            key:   [u8; 32],
288            nonce: [u8; 8],
289            keystream: Vec<u8>,
290        };
291        // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
292        let test_vectors = vec!(
293            TestVector{
294                key: [
295                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299                ],
300                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
301                keystream: vec!(
302                    0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
303                    0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
304                    0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
305                    0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
306                    0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
307                    0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
308                    0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
309                    0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
310                ),
311            }, TestVector{
312                key: [
313                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
317                ],
318                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
319                keystream: vec!(
320                    0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
321                    0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
322                    0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
323                    0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
324                    0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
325                    0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
326                    0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
327                    0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
328                ),
329            }, TestVector{
330                key: [
331                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335                ],
336                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
337                keystream: vec!(
338                    0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
339                    0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
340                    0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
341                    0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
342                    0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
343                    0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
344                    0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
345                    0x44, 0x5f, 0x41, 0xe3,
346                ),
347            }, TestVector{
348                key: [
349                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353                ],
354                nonce: [ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
355                keystream: vec!(
356                    0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
357                    0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
358                    0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
359                    0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
360                    0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
361                    0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
362                    0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
363                    0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
364                ),
365            }, TestVector{
366                key: [
367                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
368                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
369                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
370                    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
371                ],
372                nonce: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
373                keystream: vec!(
374                    0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
375                    0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
376                    0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
377                    0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
378                    0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
379                    0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
380                    0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
381                    0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
382                    0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
383                    0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
384                    0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
385                    0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
386                    0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
387                    0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
388                    0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
389                    0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
390                    0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
391                    0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
392                    0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
393                    0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
394                    0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
395                    0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
396                    0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
397                    0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
398                    0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
399                    0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
400                    0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
401                    0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
402                    0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
403                    0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
404                    0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
405                    0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
406                ),
407            },
408        );
409
410        for tv in test_vectors.iter() {
411            let mut c = ChaCha20::new(&tv.key, &tv.nonce);
412            let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
413            let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
414            c.process(&input[..], &mut output[..]);
415            assert_eq!(output, tv.keystream);
416        }
417    }
418
419    #[test]
420    fn test_xchacha20_basic() {
421        // There aren't any convenient test vectors for XChaCha/20,
422        // so, a simple test case was generated using Andrew Moon's
423        // chacha-opt library, with the key/nonce from test_salsa20_cryptopp().
424        let key =
425            [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4,
426             0x62, 0xcd, 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7,
427             0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
428             0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89];
429        let nonce =
430            [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73,
431             0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6,
432             0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37];
433        let input = [0u8; 139];
434        let mut stream = [0u8; 139];
435        let result =
436            [0x4f, 0xeb, 0xf2, 0xfe, 0x4b, 0x35, 0x9c, 0x50,
437             0x8d, 0xc5, 0xe8, 0xb5, 0x98, 0x0c, 0x88, 0xe3,
438             0x89, 0x46, 0xd8, 0xf1, 0x8f, 0x31, 0x34, 0x65,
439             0xc8, 0x62, 0xa0, 0x87, 0x82, 0x64, 0x82, 0x48,
440             0x01, 0x8d, 0xac, 0xdc, 0xb9, 0x04, 0x17, 0x88,
441             0x53, 0xa4, 0x6d, 0xca, 0x3a, 0x0e, 0xaa, 0xee,
442             0x74, 0x7c, 0xba, 0x97, 0x43, 0x4e, 0xaf, 0xfa,
443             0xd5, 0x8f, 0xea, 0x82, 0x22, 0x04, 0x7e, 0x0d,
444             0xe6, 0xc3, 0xa6, 0x77, 0x51, 0x06, 0xe0, 0x33,
445             0x1a, 0xd7, 0x14, 0xd2, 0xf2, 0x7a, 0x55, 0x64,
446             0x13, 0x40, 0xa1, 0xf1, 0xdd, 0x9f, 0x94, 0x53,
447             0x2e, 0x68, 0xcb, 0x24, 0x1c, 0xbd, 0xd1, 0x50,
448             0x97, 0x0d, 0x14, 0xe0, 0x5c, 0x5b, 0x17, 0x31,
449             0x93, 0xfb, 0x14, 0xf5, 0x1c, 0x41, 0xf3, 0x93,
450             0x83, 0x5b, 0xf7, 0xf4, 0x16, 0xa7, 0xe0, 0xbb,
451             0xa8, 0x1f, 0xfb, 0x8b, 0x13, 0xaf, 0x0e, 0x21,
452             0x69, 0x1d, 0x7e, 0xce, 0xc9, 0x3b, 0x75, 0xe6,
453             0xe4, 0x18, 0x3a];
454
455        let mut xchacha20 = ChaCha20::new_xchacha20(&key, &nonce);
456        xchacha20.process(&input, &mut stream);
457        assert!(stream[..] == result[..]);
458    }
459
460    #[test]
461    fn test_chacha20_256_tls_vectors_96_nonce() {
462        struct TestVector {
463            key:   [u8; 32],
464            nonce: [u8; 12],
465            keystream: Vec<u8>,
466        };
467        // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
468        let test_vectors = vec!(
469            TestVector{
470                key: [
471                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475                ],
476                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
477                keystream: vec!(
478                    0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
479                    0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
480                    0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
481                    0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
482                    0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
483                    0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
484                    0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
485                    0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
486                ),
487            }, TestVector{
488                key: [
489                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
493                ],
494                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
495                keystream: vec!(
496                    0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
497                    0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
498                    0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
499                    0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
500                    0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
501                    0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
502                    0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
503                    0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
504                ),
505            }, TestVector{
506                key: [
507                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511                ],
512                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
513                keystream: vec!(
514                    0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
515                    0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
516                    0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
517                    0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
518                    0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
519                    0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
520                    0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
521                    0x44, 0x5f, 0x41, 0xe3,
522                ),
523            }, TestVector{
524                key: [
525                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
527                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
528                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
529                ],
530                nonce: [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
531                keystream: vec!(
532                    0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
533                    0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
534                    0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
535                    0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
536                    0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
537                    0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
538                    0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
539                    0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
540                ),
541            }, TestVector{
542                key: [
543                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
544                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
545                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
546                    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
547                ],
548                nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
549                keystream: vec!(
550                    0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
551                    0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
552                    0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
553                    0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
554                    0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
555                    0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
556                    0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
557                    0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
558                    0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
559                    0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
560                    0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
561                    0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
562                    0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
563                    0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
564                    0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
565                    0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
566                    0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
567                    0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
568                    0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
569                    0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
570                    0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
571                    0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
572                    0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
573                    0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
574                    0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
575                    0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
576                    0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
577                    0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
578                    0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
579                    0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
580                    0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
581                    0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
582                ),
583            },
584        );
585
586        for tv in test_vectors.iter() {
587            let mut c = ChaCha20::new(&tv.key, &tv.nonce);
588            let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
589            let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
590            c.process(&input[..], &mut output[..]);
591            assert_eq!(output, tv.keystream);
592        }
593    }
594}
595
596#[cfg(all(test, feature = "with-bench"))]
597mod bench {
598    use test::Bencher;
599    use symmetriccipher::SynchronousStreamCipher;
600    use chacha20::ChaCha20;
601
602    #[bench]
603    pub fn chacha20_10(bh: & mut Bencher) {
604        let mut chacha20 = ChaCha20::new(&[0; 32], &[0; 8]);
605        let input = [1u8; 10];
606        let mut output = [0u8; 10];
607        bh.iter( || {
608            chacha20.process(&input, &mut output);
609        });
610        bh.bytes = input.len() as u64;
611    }
612
613    #[bench]
614    pub fn chacha20_1k(bh: & mut Bencher) {
615        let mut chacha20 = ChaCha20::new(&[0; 32], &[0; 8]);
616        let input = [1u8; 1024];
617        let mut output = [0u8; 1024];
618        bh.iter( || {
619            chacha20.process(&input, &mut output);
620        });
621        bh.bytes = input.len() as u64;
622    }
623
624    #[bench]
625    pub fn chacha20_64k(bh: & mut Bencher) {
626        let mut chacha20 = ChaCha20::new(&[0; 32], &[0; 8]);
627        let input = [1u8; 65536];
628        let mut output = [0u8; 65536];
629        bh.iter( || {
630            chacha20.process(&input, &mut output);
631        });
632        bh.bytes = input.len() as u64;
633    }
634}