1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #include <hyptypes.h>
6 #include <string.h>
7 
8 #include "chacha20.h"
9 
10 // Subset of ChaCha20 cipher (block generation) for DRBG.
11 // Implementation based on RFC8439
12 
13 static const uint32_t chacha20_const[4] = { 0x61707865U, 0x3320646eU,
14 					    0x79622d32U, 0x6b206574U };
15 
16 static uint32_t
rotl32(uint32_t x,index_t shift)17 rotl32(uint32_t x, index_t shift)
18 {
19 	return (x << shift) | (x >> (32U - shift));
20 }
21 
22 static void
Qround(uint32_t (* state)[16],index_t a,index_t b,index_t c,index_t d)23 Qround(uint32_t (*state)[16], index_t a, index_t b, index_t c, index_t d)
24 {
25 	(*state)[a] += (*state)[b];
26 	(*state)[d] ^= (*state)[a];
27 	(*state)[d] = rotl32((*state)[d], 16U);
28 	(*state)[c] += (*state)[d];
29 	(*state)[b] ^= (*state)[c];
30 	(*state)[b] = rotl32((*state)[b], 12U);
31 	(*state)[a] += (*state)[b];
32 	(*state)[d] ^= (*state)[a];
33 	(*state)[d] = rotl32((*state)[d], 8U);
34 	(*state)[c] += (*state)[d];
35 	(*state)[b] ^= (*state)[c];
36 	(*state)[b] = rotl32((*state)[b], 7U);
37 }
38 
39 static void
chacha20_inner_block(uint32_t (* state)[16])40 chacha20_inner_block(uint32_t (*state)[16])
41 {
42 	Qround(state, 0U, 4U, 8U, 12U);
43 	Qround(state, 1U, 5U, 9U, 13U);
44 	Qround(state, 2U, 6U, 10U, 14U);
45 	Qround(state, 3U, 7U, 11U, 15U);
46 	Qround(state, 0U, 5U, 10U, 15U);
47 	Qround(state, 1U, 6U, 11U, 12U);
48 	Qround(state, 2U, 7U, 8U, 13U);
49 	Qround(state, 3U, 4U, 9U, 14U);
50 }
51 
52 void
chacha20_block(const uint32_t (* key)[8],uint32_t counter,const uint32_t (* nonce)[3],uint32_t (* out)[16])53 chacha20_block(const uint32_t (*key)[8], uint32_t counter,
54 	       const uint32_t (*nonce)[3], uint32_t (*out)[16])
55 {
56 	count_t i;
57 
58 	// Setup output with input
59 	for (i = 0U; i < 4U; i++) {
60 		(*out)[i] = chacha20_const[i];
61 	}
62 	for (i = 0U; i < 8U; i++) {
63 		(*out)[i + 4U] = (*key)[i];
64 	}
65 	(*out)[12] = counter;
66 	for (i = 0U; i < 3U; i++) {
67 		(*out)[i + 13U] = (*nonce)[i];
68 	}
69 
70 	// Run 20 rounds (10 column interleaved with 10 diagonal rounds)
71 	for (i = 0U; i < 10U; i++) {
72 		chacha20_inner_block(out);
73 	}
74 
75 	// Add the original state to the result
76 	for (i = 0U; i < 4U; i++) {
77 		(*out)[i] += chacha20_const[i];
78 	}
79 	for (i = 0U; i < 8U; i++) {
80 		(*out)[4U + i] += (*key)[i];
81 	}
82 	(*out)[12] += counter;
83 	for (i = 0U; i < 3U; i++) {
84 		(*out)[13U + i] += (*nonce)[i];
85 	}
86 }
87