rgb_lightning/util/
chacha20.rs

1// This file was stolen from rust-crypto.
2// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
3// file at the top-level directory of this distribution and at
4// http://rust-lang.org/COPYRIGHT.
5//
6// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9// You may not use this file except in accordance with one or both of these
10// licenses.
11
12use crate::io;
13
14#[cfg(not(fuzzing))]
15mod real_chacha {
16	use core::cmp;
17	use core::convert::TryInto;
18
19	#[derive(Clone, Copy, PartialEq, Eq)]
20	#[allow(non_camel_case_types)]
21	struct u32x4(pub u32, pub u32, pub u32, pub u32);
22	impl ::core::ops::Add for u32x4 {
23		type Output = u32x4;
24		fn add(self, rhs: u32x4) -> u32x4 {
25			u32x4(self.0.wrapping_add(rhs.0),
26			      self.1.wrapping_add(rhs.1),
27			      self.2.wrapping_add(rhs.2),
28			      self.3.wrapping_add(rhs.3))
29		}
30	}
31	impl ::core::ops::Sub for u32x4 {
32		type Output = u32x4;
33		fn sub(self, rhs: u32x4) -> u32x4 {
34			u32x4(self.0.wrapping_sub(rhs.0),
35			      self.1.wrapping_sub(rhs.1),
36			      self.2.wrapping_sub(rhs.2),
37			      self.3.wrapping_sub(rhs.3))
38		}
39	}
40	impl ::core::ops::BitXor for u32x4 {
41		type Output = u32x4;
42		fn bitxor(self, rhs: u32x4) -> u32x4 {
43			u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
44		}
45	}
46	impl ::core::ops::Shr<u32x4> for u32x4 {
47		type Output = u32x4;
48		fn shr(self, rhs: u32x4) -> u32x4 {
49			u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3)
50		}
51	}
52	impl ::core::ops::Shl<u32x4> for u32x4 {
53		type Output = u32x4;
54		fn shl(self, rhs: u32x4) -> u32x4 {
55			u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3)
56		}
57	}
58	impl u32x4 {
59		fn from_bytes(bytes: &[u8]) -> Self {
60			assert_eq!(bytes.len(), 4*4);
61			Self (
62				u32::from_le_bytes(bytes[0*4..1*4].try_into().expect("len is 4")),
63				u32::from_le_bytes(bytes[1*4..2*4].try_into().expect("len is 4")),
64				u32::from_le_bytes(bytes[2*4..3*4].try_into().expect("len is 4")),
65				u32::from_le_bytes(bytes[3*4..4*4].try_into().expect("len is 4")),
66			)
67		}
68	}
69
70	const BLOCK_SIZE: usize = 64;
71
72	#[derive(Clone,Copy)]
73	struct ChaChaState {
74		a: u32x4,
75		b: u32x4,
76		c: u32x4,
77		d: u32x4
78	}
79
80	#[derive(Copy)]
81	pub struct ChaCha20 {
82		state  : ChaChaState,
83		output : [u8; BLOCK_SIZE],
84		offset : usize,
85	}
86
87	impl Clone for ChaCha20 { fn clone(&self) -> ChaCha20 { *self } }
88
89	macro_rules! swizzle {
90		($b: expr, $c: expr, $d: expr) => {{
91			let u32x4(b10, b11, b12, b13) = $b;
92			$b = u32x4(b11, b12, b13, b10);
93			let u32x4(c10, c11, c12, c13) = $c;
94			$c = u32x4(c12, c13,c10, c11);
95			let u32x4(d10, d11, d12, d13) = $d;
96			$d = u32x4(d13, d10, d11, d12);
97		}}
98	}
99
100	macro_rules! state_to_buffer {
101		($state: expr, $output: expr) => {{
102			let u32x4(a1, a2, a3, a4) = $state.a;
103			let u32x4(b1, b2, b3, b4) = $state.b;
104			let u32x4(c1, c2, c3, c4) = $state.c;
105			let u32x4(d1, d2, d3, d4) = $state.d;
106			let lens = [
107				a1,a2,a3,a4,
108				b1,b2,b3,b4,
109				c1,c2,c3,c4,
110				d1,d2,d3,d4
111			];
112			for i in 0..lens.len() {
113				$output[i*4..(i+1)*4].copy_from_slice(&lens[i].to_le_bytes());
114			}
115		}}
116	}
117
118	macro_rules! round{
119		($state: expr) => {{
120			$state.a = $state.a + $state.b;
121			rotate!($state.d, $state.a, S16);
122			$state.c = $state.c + $state.d;
123			rotate!($state.b, $state.c, S12);
124			$state.a = $state.a + $state.b;
125			rotate!($state.d, $state.a, S8);
126			$state.c = $state.c + $state.d;
127			rotate!($state.b, $state.c, S7);
128		}}
129	}
130
131	macro_rules! rotate {
132		($a: expr, $b: expr, $c:expr) => {{
133			let v = $a ^ $b;
134			let r = S32 - $c;
135			let right = v >> r;
136			$a = (v << $c) ^ right
137		}}
138	}
139
140	const S32:u32x4 = u32x4(32, 32, 32, 32);
141	const S16:u32x4 = u32x4(16, 16, 16, 16);
142	const S12:u32x4 = u32x4(12, 12, 12, 12);
143	const S8:u32x4 = u32x4(8, 8, 8, 8);
144	const S7:u32x4 = u32x4(7, 7, 7, 7);
145
146	impl ChaCha20 {
147		pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
148			assert!(key.len() == 16 || key.len() == 32);
149			assert!(nonce.len() == 8 || nonce.len() == 12);
150
151			ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 }
152		}
153
154		/// Get one block from a ChaCha stream.
155		pub fn get_single_block(key: &[u8; 32], nonce: &[u8; 16]) -> [u8; 32] {
156			let mut chacha = ChaCha20 { state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 };
157			let mut chacha_bytes = [0; 32];
158			chacha.process_in_place(&mut chacha_bytes);
159			chacha_bytes
160		}
161
162		fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
163			let constant = match key.len() {
164				16 => b"expand 16-byte k",
165				32 => b"expand 32-byte k",
166				_  => unreachable!(),
167			};
168			ChaChaState {
169				a: u32x4::from_bytes(&constant[0..16]),
170				b: u32x4::from_bytes(&key[0..16]),
171				c: if key.len() == 16 {
172					u32x4::from_bytes(&key[0..16])
173				} else {
174					u32x4::from_bytes(&key[16..32])
175				},
176				d: if nonce.len() == 16 {
177					u32x4::from_bytes(&nonce[0..16])
178				} else if nonce.len() == 12 {
179					let mut nonce4 = [0; 4*4];
180					nonce4[4..].copy_from_slice(nonce);
181					u32x4::from_bytes(&nonce4)
182				} else {
183					let mut nonce4 = [0; 4*4];
184					nonce4[8..].copy_from_slice(nonce);
185					u32x4::from_bytes(&nonce4)
186				}
187			}
188		}
189
190		// put the the next BLOCK_SIZE keystream bytes into self.output
191		fn update(&mut self) {
192			let mut state = self.state;
193
194			for _ in 0..10 {
195				round!(state);
196				swizzle!(state.b, state.c, state.d);
197				round!(state);
198				swizzle!(state.d, state.c, state.b);
199			}
200			state.a = state.a + self.state.a;
201			state.b = state.b + self.state.b;
202			state.c = state.c + self.state.c;
203			state.d = state.d + self.state.d;
204
205			state_to_buffer!(state, self.output);
206
207			self.state.d = self.state.d + u32x4(1, 0, 0, 0);
208			let u32x4(c12, _, _, _) = self.state.d;
209			if c12 == 0 {
210				// we could increment the other counter word with an 8 byte nonce
211				// but other implementations like boringssl have this same
212				// limitation
213				panic!("counter is exhausted");
214			}
215
216			self.offset = 0;
217		}
218
219		#[inline] // Useful cause input may be 0s on stack that should be optimized out
220		pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
221			assert!(input.len() == output.len());
222			let len = input.len();
223			let mut i = 0;
224			while i < len {
225				// If there is no keystream available in the output buffer,
226				// generate the next block.
227				if self.offset == BLOCK_SIZE {
228					self.update();
229				}
230
231				// Process the min(available keystream, remaining input length).
232				let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
233				// explicitly assert lengths to avoid bounds checks:
234				assert!(output.len() >= i + count);
235				assert!(input.len() >= i + count);
236				assert!(self.output.len() >= self.offset + count);
237				for j in 0..count {
238					output[i + j] = input[i + j] ^ self.output[self.offset + j];
239				}
240				i += count;
241				self.offset += count;
242			}
243		}
244
245		pub fn process_in_place(&mut self, input_output: &mut [u8]) {
246			let len = input_output.len();
247			let mut i = 0;
248			while i < len {
249				// If there is no keystream available in the output buffer,
250				// generate the next block.
251				if self.offset == BLOCK_SIZE {
252					self.update();
253				}
254
255				// Process the min(available keystream, remaining input length).
256				let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
257				// explicitly assert lengths to avoid bounds checks:
258				assert!(input_output.len() >= i + count);
259				assert!(self.output.len() >= self.offset + count);
260				for j in 0..count {
261					input_output[i + j] ^= self.output[self.offset + j];
262				}
263				i += count;
264				self.offset += count;
265			}
266		}
267
268		#[cfg(test)]
269		pub fn seek_to_block(&mut self, block_offset: u32) {
270			self.state.d.0 = block_offset;
271			self.update();
272		}
273	}
274}
275#[cfg(not(fuzzing))]
276pub use self::real_chacha::ChaCha20;
277
278#[cfg(fuzzing)]
279mod fuzzy_chacha {
280	pub struct ChaCha20 {}
281
282	impl ChaCha20 {
283		pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
284			assert!(key.len() == 16 || key.len() == 32);
285			assert!(nonce.len() == 8 || nonce.len() == 12);
286			Self {}
287		}
288
289		pub fn get_single_block(_key: &[u8; 32], _nonce: &[u8; 16]) -> [u8; 32] {
290			[0; 32]
291		}
292
293		pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
294			output.copy_from_slice(input);
295		}
296
297		pub fn process_in_place(&mut self, _input_output: &mut [u8]) {}
298	}
299}
300#[cfg(fuzzing)]
301pub use self::fuzzy_chacha::ChaCha20;
302
303pub(crate) struct ChaChaReader<'a, R: io::Read> {
304	pub chacha: &'a mut ChaCha20,
305	pub read: R,
306}
307impl<'a, R: io::Read> io::Read for ChaChaReader<'a, R> {
308	fn read(&mut self, dest: &mut [u8]) -> Result<usize, io::Error> {
309		let res = self.read.read(dest)?;
310		if res > 0 {
311			self.chacha.process_in_place(&mut dest[0..res]);
312		}
313		Ok(res)
314	}
315}
316
317#[cfg(test)]
318mod test {
319	use crate::prelude::*;
320	use core::iter::repeat;
321
322	use super::ChaCha20;
323	use std::convert::TryInto;
324
325	#[test]
326	fn test_chacha20_256_tls_vectors() {
327		struct TestVector {
328			key:   [u8; 32],
329			nonce: [u8; 8],
330			keystream: Vec<u8>,
331		}
332		// taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
333		let test_vectors = vec!(
334			TestVector{
335				key: [
336					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340				],
341				nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
342				keystream: vec!(
343					0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
344					0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
345					0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
346					0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
347					0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
348					0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
349					0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
350					0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
351				),
352			}, TestVector{
353				key: [
354					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
358				],
359				nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
360				keystream: vec!(
361					0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
362					0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
363					0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
364					0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
365					0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
366					0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
367					0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
368					0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
369				),
370			}, TestVector{
371				key: [
372					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
373					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
374					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376				],
377				nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
378				keystream: vec!(
379					0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
380					0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
381					0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
382					0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
383					0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
384					0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
385					0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
386					0x44, 0x5f, 0x41, 0xe3,
387				),
388			}, TestVector{
389				key: [
390					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394				],
395				nonce: [ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
396				keystream: vec!(
397					0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
398					0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
399					0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
400					0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
401					0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
402					0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
403					0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
404					0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
405				),
406			}, TestVector{
407				key: [
408					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
409					0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
410					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
411					0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
412				],
413				nonce: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
414				keystream: vec!(
415					0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
416					0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
417					0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
418					0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
419					0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
420					0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
421					0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
422					0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
423					0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
424					0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
425					0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
426					0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
427					0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
428					0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
429					0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
430					0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
431					0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
432					0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
433					0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
434					0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
435					0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
436					0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
437					0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
438					0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
439					0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
440					0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
441					0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
442					0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
443					0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
444					0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
445					0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
446					0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
447				),
448			},
449		);
450
451		for tv in test_vectors.iter() {
452			let mut c = ChaCha20::new(&tv.key, &tv.nonce);
453			let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
454			let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
455			c.process(&input[..], &mut output[..]);
456			assert_eq!(output, tv.keystream);
457		}
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	#[test]
596	fn get_single_block() {
597		// Test that `get_single_block` (which takes a 16-byte nonce) is equivalent to getting a block
598		// using a 12-byte nonce, with the block starting at the counter offset given by the remaining 4
599		// bytes.
600		let key = [
601			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
602			0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
603			0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
604			0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
605		];
606		let nonce_16bytes = [
607			0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
608		];
609		let counter_pos = &nonce_16bytes[..4];
610		let nonce_12bytes = &nonce_16bytes[4..];
611
612		// Initialize a ChaCha20 instance with its counter starting at 0.
613		let mut chacha20 = ChaCha20::new(&key, nonce_12bytes);
614		// Seek its counter to the block at counter_pos.
615		chacha20.seek_to_block(u32::from_le_bytes(counter_pos.try_into().unwrap()));
616		let mut block_bytes = [0; 32];
617		chacha20.process_in_place(&mut block_bytes);
618
619		assert_eq!(ChaCha20::get_single_block(&key, &nonce_16bytes), block_bytes);
620	}
621}