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