19 #if defined(HAVE_CHACHA)
29 #define CHACHA_STATE_ARRAY_SIZE 16
30 #define CHACHA_BLOCK_SIZE 64
32 #define ROTATE(v, n) (cx_rotl(v, n))
33 #define XOR(v, w) ((v) ^ (w))
34 #define PLUS(v, w) ((uint32_t) (v + w))
36 static const uint8_t constants[16] =
"expand 32-byte k";
39 static void cx_chacha_quarter_round(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
42 *d = ROTATE(XOR(*d, *a), 16);
44 *b = ROTATE(XOR(*b, *c), 12);
46 *d = ROTATE(XOR(*d, *a), 8);
48 *b = ROTATE(XOR(*b, *c), 7);
51 static void cx_chacha_process_block(cx_chacha_context_t *ctx)
54 uint32_t *x = (uint32_t *) ctx->block;
55 for (i = 0; i < CHACHA_STATE_ARRAY_SIZE; i++) {
58 for (i = 0; i < ctx->nrounds; i += 2) {
60 cx_chacha_quarter_round(&x[0], &x[4], &x[8], &x[12]);
61 cx_chacha_quarter_round(&x[1], &x[5], &x[9], &x[13]);
62 cx_chacha_quarter_round(&x[2], &x[6], &x[10], &x[14]);
63 cx_chacha_quarter_round(&x[3], &x[7], &x[11], &x[15]);
66 cx_chacha_quarter_round(&x[0], &x[5], &x[10], &x[15]);
67 cx_chacha_quarter_round(&x[1], &x[6], &x[11], &x[12]);
68 cx_chacha_quarter_round(&x[2], &x[7], &x[8], &x[13]);
69 cx_chacha_quarter_round(&x[3], &x[4], &x[9], &x[14]);
71 for (i = 0; i < CHACHA_STATE_ARRAY_SIZE; i++) {
72 x[i] = PLUS(x[i], ctx->state[i]);
76 void cx_chacha_init(cx_chacha_context_t *ctx, uint32_t nrounds)
78 memset(ctx, 0,
sizeof(cx_chacha_context_t));
79 ctx->nrounds = nrounds;
82 cx_err_t cx_chacha_set_key(cx_chacha_context_t *ctx,
const uint8_t *key,
size_t key_len)
85 return CX_INVALID_PARAMETER_VALUE;
89 ctx->state[4] = U4LE(key, 0);
90 ctx->state[5] = U4LE(key, 4);
91 ctx->state[6] = U4LE(key, 8);
92 ctx->state[7] = U4LE(key, 12);
93 ctx->state[8] = U4LE(key, 16);
94 ctx->state[9] = U4LE(key, 20);
95 ctx->state[10] = U4LE(key, 24);
96 ctx->state[11] = U4LE(key, 28);
98 ctx->state[0] = U4LE(constants, 0);
99 ctx->state[1] = U4LE(constants, 4);
100 ctx->state[2] = U4LE(constants, 8);
101 ctx->state[3] = U4LE(constants, 12);
106 cx_err_t cx_chacha_start(cx_chacha_context_t *ctx,
const uint8_t *iv,
size_t iv_len)
109 return CX_INVALID_PARAMETER_VALUE;
112 ctx->state[12] = U4BE(iv, 0);
114 ctx->state[13] = U4LE(iv, 4);
115 ctx->state[14] = U4LE(iv, 8);
116 ctx->state[15] = U4LE(iv, 12);
122 cx_err_t cx_chacha_update(cx_chacha_context_t *ctx,
131 if ((0 == ctx->pos) || (ctx->pos >= 64)) {
132 cx_chacha_process_block(ctx);
134 if (0 == ctx->state[12]) {
139 n =
MIN(len, CHACHA_BLOCK_SIZE - ctx->pos);
140 key_stream = (
uint8_t *) ctx->block + ctx->pos;
142 for (i = 0; i < n; i++) {
143 output[i] = key_stream[i];
147 for (i = 0; i < n; i++) {
148 output[i] = input[i] ^ key_stream[i];
159 cx_err_t cx_chacha_cipher(uint32_t nrounds,
168 cx_chacha_context_t *ctx = &
G_cx.chacha;
170 cx_chacha_init(ctx, nrounds);
171 CX_CHECK(cx_chacha_set_key(ctx, key, key_len));
172 CX_CHECK(cx_chacha_start(ctx, iv, iv_len));
173 CX_CHECK(cx_chacha_update(ctx, input, output, len));
176 explicit_bzero(ctx,
sizeof(cx_chacha_context_t));
185 static void test_chacha_round(
void **state)
189 uint32_t state_array[16] = {0x61707865,
205 uint32_t expected_array[16] = {0x837778ab,
221 for (
int i = 0; i < 10; i++) {
222 cx_chacha_quarter_round(
223 &state_array[0], &state_array[4], &state_array[8], &state_array[12]);
224 cx_chacha_quarter_round(
225 &state_array[1], &state_array[5], &state_array[9], &state_array[13]);
226 cx_chacha_quarter_round(
227 &state_array[2], &state_array[6], &state_array[10], &state_array[14]);
228 cx_chacha_quarter_round(
229 &state_array[3], &state_array[7], &state_array[11], &state_array[15]);
231 cx_chacha_quarter_round(
232 &state_array[0], &state_array[5], &state_array[10], &state_array[15]);
233 cx_chacha_quarter_round(
234 &state_array[1], &state_array[6], &state_array[11], &state_array[12]);
235 cx_chacha_quarter_round(
236 &state_array[2], &state_array[7], &state_array[8], &state_array[13]);
237 cx_chacha_quarter_round(
238 &state_array[3], &state_array[4], &state_array[9], &state_array[14]);
241 assert_memory_equal(state_array, expected_array,
sizeof(state_array));
246 const struct CMUnitTest tests[] = {cmocka_unit_test(test_chacha_round)};
248 return cmocka_run_group_tests(tests, NULL, NULL);