1mod real_chacha {
13 use core::cmp;
14 use core::convert::TryInto;
15
16 #[derive(Clone, Copy, PartialEq, Eq)]
17 #[allow(non_camel_case_types)]
18 struct u32x4(pub u32, pub u32, pub u32, pub u32);
19 impl ::core::ops::Add for u32x4 {
20 type Output = u32x4;
21 fn add(self, rhs: u32x4) -> u32x4 {
22 u32x4(
23 self.0.wrapping_add(rhs.0),
24 self.1.wrapping_add(rhs.1),
25 self.2.wrapping_add(rhs.2),
26 self.3.wrapping_add(rhs.3),
27 )
28 }
29 }
30 impl ::core::ops::Sub for u32x4 {
31 type Output = u32x4;
32 fn sub(self, rhs: u32x4) -> u32x4 {
33 u32x4(
34 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 }
41 impl ::core::ops::BitXor for u32x4 {
42 type Output = u32x4;
43 fn bitxor(self, rhs: u32x4) -> u32x4 {
44 u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
45 }
46 }
47 impl ::core::ops::Shr<u32x4> for u32x4 {
48 type Output = u32x4;
49 fn shr(self, rhs: u32x4) -> u32x4 {
50 u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3)
51 }
52 }
53 impl ::core::ops::Shl<u32x4> for u32x4 {
54 type Output = u32x4;
55 fn shl(self, rhs: u32x4) -> u32x4 {
56 u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3)
57 }
58 }
59 impl u32x4 {
60 fn from_bytes(bytes: &[u8]) -> Self {
61 assert_eq!(bytes.len(), 4 * 4);
62 Self(
63 u32::from_le_bytes(bytes[0 * 4..1 * 4].try_into().expect("len is 4")),
64 u32::from_le_bytes(bytes[1 * 4..2 * 4].try_into().expect("len is 4")),
65 u32::from_le_bytes(bytes[2 * 4..3 * 4].try_into().expect("len is 4")),
66 u32::from_le_bytes(bytes[3 * 4..4 * 4].try_into().expect("len is 4")),
67 )
68 }
69 }
70
71 const BLOCK_SIZE: usize = 64;
72
73 #[derive(Clone, Copy)]
74 struct ChaChaState {
75 a: u32x4,
76 b: u32x4,
77 c: u32x4,
78 d: u32x4,
79 }
80
81 #[derive(Copy)]
82 pub struct ChaCha20 {
83 state: ChaChaState,
84 output: [u8; BLOCK_SIZE],
85 offset: usize,
86 }
87
88 impl Clone for ChaCha20 {
89 fn clone(&self) -> ChaCha20 {
90 *self
91 }
92 }
93
94 macro_rules! swizzle {
95 ($b: expr, $c: expr, $d: expr) => {{
96 let u32x4(b10, b11, b12, b13) = $b;
97 $b = u32x4(b11, b12, b13, b10);
98 let u32x4(c10, c11, c12, c13) = $c;
99 $c = u32x4(c12, c13, c10, c11);
100 let u32x4(d10, d11, d12, d13) = $d;
101 $d = u32x4(d13, d10, d11, d12);
102 }};
103 }
104
105 macro_rules! state_to_buffer {
106 ($state: expr, $output: expr) => {{
107 let u32x4(a1, a2, a3, a4) = $state.a;
108 let u32x4(b1, b2, b3, b4) = $state.b;
109 let u32x4(c1, c2, c3, c4) = $state.c;
110 let u32x4(d1, d2, d3, d4) = $state.d;
111 let lens = [a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4];
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 pub fn get_single_block(key: &[u8; 32], nonce: &[u8; 16]) -> [u8; 32] {
156 let mut chacha = ChaCha20 {
157 state: ChaCha20::expand(key, nonce),
158 output: [0u8; BLOCK_SIZE],
159 offset: 64,
160 };
161 let mut chacha_bytes = [0; 32];
162 chacha.process_in_place(&mut chacha_bytes);
163 chacha_bytes
164 }
165
166 fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
167 let constant = match key.len() {
168 16 => b"expand 16-byte k",
169 32 => b"expand 32-byte k",
170 _ => unreachable!(),
171 };
172 ChaChaState {
173 a: u32x4::from_bytes(&constant[0..16]),
174 b: u32x4::from_bytes(&key[0..16]),
175 c: if key.len() == 16 {
176 u32x4::from_bytes(&key[0..16])
177 } else {
178 u32x4::from_bytes(&key[16..32])
179 },
180 d: if nonce.len() == 16 {
181 u32x4::from_bytes(&nonce[0..16])
182 } else if nonce.len() == 12 {
183 let mut nonce4 = [0; 4 * 4];
184 nonce4[4..].copy_from_slice(nonce);
185 u32x4::from_bytes(&nonce4)
186 } else {
187 let mut nonce4 = [0; 4 * 4];
188 nonce4[8..].copy_from_slice(nonce);
189 u32x4::from_bytes(&nonce4)
190 },
191 }
192 }
193
194 fn update(&mut self) {
196 let mut state = self.state;
197
198 for _ in 0..10 {
199 round!(state);
200 swizzle!(state.b, state.c, state.d);
201 round!(state);
202 swizzle!(state.d, state.c, state.b);
203 }
204 state.a = state.a + self.state.a;
205 state.b = state.b + self.state.b;
206 state.c = state.c + self.state.c;
207 state.d = state.d + self.state.d;
208
209 state_to_buffer!(state, self.output);
210
211 self.state.d = self.state.d + u32x4(1, 0, 0, 0);
212 let u32x4(c12, _, _, _) = self.state.d;
213 if c12 == 0 {
214 panic!("counter is exhausted");
218 }
219
220 self.offset = 0;
221 }
222
223 #[inline] pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
225 assert!(input.len() == output.len());
226 let len = input.len();
227 let mut i = 0;
228 while i < len {
229 if self.offset == BLOCK_SIZE {
232 self.update();
233 }
234
235 let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
237 assert!(output.len() >= i + count);
239 assert!(input.len() >= i + count);
240 assert!(self.output.len() >= self.offset + count);
241 for j in 0..count {
242 output[i + j] = input[i + j] ^ self.output[self.offset + j];
243 }
244 i += count;
245 self.offset += count;
246 }
247 }
248
249 pub fn process_in_place(&mut self, input_output: &mut [u8]) {
250 let len = input_output.len();
251 let mut i = 0;
252 while i < len {
253 if self.offset == BLOCK_SIZE {
256 self.update();
257 }
258
259 let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
261 assert!(input_output.len() >= i + count);
263 assert!(self.output.len() >= self.offset + count);
264 for j in 0..count {
265 input_output[i + j] ^= self.output[self.offset + j];
266 }
267 i += count;
268 self.offset += count;
269 }
270 }
271
272 #[cfg(test)]
273 pub fn seek_to_block(&mut self, block_offset: u32) {
274 self.state.d.0 = block_offset;
275 self.update();
276 }
277 }
278}
279pub use self::real_chacha::ChaCha20;
280
281#[cfg(test)]
282mod test {
283 use core::iter::repeat;
284
285 use super::ChaCha20;
286 use std::convert::TryInto;
287
288 #[test]
289 fn test_chacha20_256_tls_vectors() {
290 struct TestVector {
291 key: [u8; 32],
292 nonce: [u8; 8],
293 keystream: Vec<u8>,
294 }
295 let test_vectors = vec![
297 TestVector {
298 key: [
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 ],
303 nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
304 keystream: vec![
305 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53,
306 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36,
307 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48,
308 0x8d, 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4,
309 0x15, 0x18, 0xa1, 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
310 ],
311 },
312 TestVector {
313 key: [
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 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, 0xd7, 0x73, 0x6e, 0x7b, 0x20,
321 0x8e, 0x3c, 0x96, 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60, 0x4f, 0x45,
322 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41, 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66,
323 0xd2, 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c, 0x53, 0xd7, 0x92, 0xb1,
324 0xc4, 0x3f, 0xea, 0x81, 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
325 ],
326 },
327 TestVector {
328 key: [
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 ],
333 nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
334 keystream: vec![
335 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5, 0xe7, 0x86, 0xdc, 0x63, 0x97,
336 0x3f, 0x65, 0x3a, 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13, 0x4f, 0xcb,
337 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31, 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08,
338 0x45, 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b, 0x52, 0x77, 0x06, 0x2e,
339 0xb7, 0xa0, 0x43, 0x3e, 0x44, 0x5f, 0x41, 0xe3,
340 ],
341 },
342 TestVector {
343 key: [
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 ],
348 nonce: [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
349 keystream: vec![
350 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, 0xf5, 0xcf, 0x35, 0xbd, 0x3d,
351 0xd3, 0x3b, 0x80, 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac, 0x33, 0x96,
352 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5,
353 0x3c, 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54, 0x5d, 0xdc, 0x49, 0x7a,
354 0x0b, 0x46, 0x6e, 0x7d, 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
355 ],
356 },
357 TestVector {
358 key: [
359 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
360 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
361 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
362 ],
363 nonce: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
364 keystream: vec![
365 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, 0x64,
366 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, 0xec, 0x01,
367 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46,
368 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, 0x05, 0xd3, 0xbe, 0x59,
369 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a, 0x38,
370 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a,
371 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60,
372 0xe8, 0x46, 0x29, 0xc9, 0xbd, 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
373 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49,
374 0x2b, 0x56, 0x2e, 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9,
375 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f,
376 0xc3, 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76,
377 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, 0x07,
378 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c,
379 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, 0x0e, 0xaf, 0x46,
380 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
381 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, 0x94, 0xdf, 0x76, 0x28, 0xfe,
382 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9,
383 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40,
384 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
385 ],
386 },
387 ];
388
389 for tv in test_vectors.iter() {
390 let mut c = ChaCha20::new(&tv.key, &tv.nonce);
391 let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
392 let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
393 c.process(&input[..], &mut output[..]);
394 assert_eq!(output, tv.keystream);
395 }
396 }
397
398 #[test]
399 fn test_chacha20_256_tls_vectors_96_nonce() {
400 struct TestVector {
401 key: [u8; 32],
402 nonce: [u8; 12],
403 keystream: Vec<u8>,
404 }
405 let test_vectors = vec![
407 TestVector {
408 key: [
409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
412 ],
413 nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
414 keystream: vec![
415 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53,
416 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36,
417 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48,
418 0x8d, 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4,
419 0x15, 0x18, 0xa1, 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
420 ],
421 },
422 TestVector {
423 key: [
424 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
425 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
426 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
427 ],
428 nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
429 keystream: vec![
430 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96, 0xd7, 0x73, 0x6e, 0x7b, 0x20,
431 0x8e, 0x3c, 0x96, 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60, 0x4f, 0x45,
432 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41, 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66,
433 0xd2, 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c, 0x53, 0xd7, 0x92, 0xb1,
434 0xc4, 0x3f, 0xea, 0x81, 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
435 ],
436 },
437 TestVector {
438 key: [
439 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
442 ],
443 nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
444 keystream: vec![
445 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5, 0xe7, 0x86, 0xdc, 0x63, 0x97,
446 0x3f, 0x65, 0x3a, 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13, 0x4f, 0xcb,
447 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31, 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08,
448 0x45, 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b, 0x52, 0x77, 0x06, 0x2e,
449 0xb7, 0xa0, 0x43, 0x3e, 0x44, 0x5f, 0x41, 0xe3,
450 ],
451 },
452 TestVector {
453 key: [
454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457 ],
458 nonce: [0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
459 keystream: vec![
460 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, 0xf5, 0xcf, 0x35, 0xbd, 0x3d,
461 0xd3, 0x3b, 0x80, 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac, 0x33, 0x96,
462 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5,
463 0x3c, 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54, 0x5d, 0xdc, 0x49, 0x7a,
464 0x0b, 0x46, 0x6e, 0x7d, 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
465 ],
466 },
467 TestVector {
468 key: [
469 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
470 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
471 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
472 ],
473 nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
474 keystream: vec![
475 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, 0x64,
476 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, 0xec, 0x01,
477 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46,
478 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, 0x05, 0xd3, 0xbe, 0x59,
479 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a, 0x38,
480 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a,
481 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60,
482 0xe8, 0x46, 0x29, 0xc9, 0xbd, 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
483 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49,
484 0x2b, 0x56, 0x2e, 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9,
485 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f,
486 0xc3, 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76,
487 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, 0x07,
488 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c,
489 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, 0x0e, 0xaf, 0x46,
490 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
491 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, 0x94, 0xdf, 0x76, 0x28, 0xfe,
492 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9,
493 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40,
494 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
495 ],
496 },
497 ];
498
499 for tv in test_vectors.iter() {
500 let mut c = ChaCha20::new(&tv.key, &tv.nonce);
501 let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
502 let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
503 c.process(&input[..], &mut output[..]);
504 assert_eq!(output, tv.keystream);
505 }
506 }
507
508 #[test]
509 fn get_single_block() {
510 let key = [
514 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
515 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
516 0x1c, 0x1d, 0x1e, 0x1f,
517 ];
518 let nonce_16bytes = [
519 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
520 0x0a, 0x0b,
521 ];
522 let counter_pos = &nonce_16bytes[..4];
523 let nonce_12bytes = &nonce_16bytes[4..];
524
525 let mut chacha20 = ChaCha20::new(&key, nonce_12bytes);
527 chacha20.seek_to_block(u32::from_le_bytes(counter_pos.try_into().unwrap()));
529 let mut block_bytes = [0; 32];
530 chacha20.process_in_place(&mut block_bytes);
531
532 assert_eq!(ChaCha20::get_single_block(&key, &nonce_16bytes), block_bytes);
533 }
534}