KangarooTwelve128 works for arbitrary input
Juniper Beatitudes [email protected]
Tue, 30 Dec 2025 19:48:08 -0600
6 files changed,
187 insertions(+),
58 deletions(-)
M
tinycrypt/chacha20-poly1305.c
→
tinycrypt/chacha20-poly1305.c
@@ -1,6 +1,7 @@
-#include "tinycript/chacha20-poly1305.h" #include <stdbool.h> #include <stdint.h> + +#include "tinycrypt/chacha20-poly1305.h" static uint32_t rotl_32 (uint32_t x, int c)
M
tinycrypt/chacha20-poly1305.h
→
tinycrypt/chacha20-poly1305.h
@@ -3,8 +3,9 @@ #define TNT_CC20_P1305_H
#include <stdint.h> -/// Implements the AEAD-ChaCha20-Poly1305 algorithm defined in RFC 8439 -void tnt_aead_chacha20_poly1305 (const uint8_t *aad, const uint64_t aad_len, +/// Implements the AEAD-ChaCha20-Poly1305 encryption and MAC algorithm defined +/// in RFC 8439 +void tct_aead_chacha20_poly1305 (const uint8_t *aad, const uint64_t aad_len, const uint8_t *key, const uint8_t *nonce, const uint8_t *plaintext, const uint64_t plaintext_len,
M
tinycrypt/kangarootwelve128.c
→
tinycrypt/kangarootwelve128.c
@@ -1,7 +1,7 @@
#include <stdbool.h> #include <stdint.h> -#include <stdio.h> +#include "tinycrypt/kangarootwelve128.h" static uint64_t rotl64 (uint64_t x, int c)@@ -128,38 +128,23 @@ }
static void turboshake128_absorb (uint8_t *state, const uint8_t *data, - const uint64_t data_len, const uint8_t separation_byte, - const bool is_last) + const uint64_t data_len, const uint8_t separation_byte) { - for (uint64_t i = 0; i <= data_len; i += 168) + for (unsigned int i = 0; i < data_len; ++i) { - uint8_t buf[200]; - for (unsigned int j = 0; j < ((data_len - i < 168) ? data_len - i : 168); - ++j) - { - buf[j] = data[i + j]; - } - for (unsigned int j = ((data_len - i < 168) ? data_len - i : 168); - j < 200; ++j) - { - buf[j] = 0x0; - } - if (data_len - i < 168 && is_last) - { - buf[data_len - i] = separation_byte; - buf[167] = 0x80; - } - for (unsigned int j = 0; j < 200; ++j) - { - state[j] ^= buf[j]; - } - kp (state); + state[i] ^= data[i]; + } + if (data_len < 168) + { + state[data_len] ^= separation_byte; + state[167] ^= 0x80; } + kp (state); } static void -turboshake128_squeeze (uint8_t *state, uint8_t *output, - const uint64_t output_len) +turboshake128_squeeze_destructive (uint8_t *state, uint8_t *output, + const uint64_t output_len) { for (uint64_t i = 0; i < output_len; i += 168) {@@ -180,14 +165,14 @@ for (uint64_t i = n; i > 0; i /= 256)
{ (*out_len)++; } - for (uint64_t i = n; i > 0; i /= 256) + for (uint64_t i = 0; i < (*out_len) - 1; ++i) { - out[(*out_len) - 1 - (i / 256)] = i & 0xFF; + out[(*out_len) - 2 - i] = (n >> (8 * i)) & 0xFF; } out[(*out_len) - 1] = ((*out_len) - 1) & 0xFF; } -static void +void tct_kangarootwelve128 (const uint8_t *input, const uint64_t input_len, const uint8_t *custom_str, const uint64_t cs_len, uint8_t *output, const uint64_t output_len)@@ -195,16 +180,16 @@ {
uint8_t buf[168]; uint8_t state[200]; turboshake128_init (state); - if (input_len + cs_len + sizeof (uint64_t) <= 8192) + uint8_t encoded[8]; + uint64_t encoded_len; + length_encode (cs_len, encoded, &encoded_len); + const uint64_t s_size = input_len + cs_len + encoded_len; + if (s_size <= 8192) { - uint8_t encoded[8]; - uint64_t encoded_len; - length_encode (cs_len, encoded, &encoded_len); - const uint64_t s_size = input_len + cs_len + encoded_len; for (uint64_t i = 0; i < s_size; i += 168) { - for (uint64_t j = 0; j < ((s_size - i < 168) ? s_size - i : 168); - ++j) + uint64_t buf_len = (s_size - i < 168) ? s_size - i : 168; + for (uint64_t j = 0; j < buf_len; ++j) { if (i + j < input_len) {@@ -219,27 +204,149 @@ {
buf[j] = encoded[i + j - input_len - cs_len]; } } - turboshake128_absorb (state, buf, - ((s_size - i < 168) ? s_size - i : 168), 0x07, - s_size - i < 168); + turboshake128_absorb (state, buf, buf_len, 0x07); } - turboshake128_squeeze (state, output, output_len); + turboshake128_squeeze_destructive (state, output, output_len); return; } -} + uint64_t buf_len; + for (unsigned int i = 0; i < 8200; i += 168) + { + buf_len = (8200 - i < 168) ? 8200 - i : 168; + for (unsigned int j = 0; j < buf_len; ++j) + { + if (i + j < 8192) + { + if (i + j < input_len) + { + buf[j] = input[i + j]; + } + else if (i + j < input_len + cs_len) + { + buf[j] = custom_str[i + j - input_len]; + } + else + { + buf[j] = encoded[i + j - input_len - cs_len]; + } + } + else if (i + j < 8193) + { + buf[j] = 0x03; + } + else + { + buf[j] = 0x0; + } + } + if (buf_len == 168) + { + turboshake128_absorb (state, buf, 168, 0x06); + } + } + uint64_t offset = 8192; + uint64_t num_block = 0; + while (offset < s_size) + { + uint64_t block_size = (8192 < s_size - offset) ? 8192 : s_size - offset; + uint8_t cv[32]; + uint8_t cv_buf[168]; + uint8_t cv_state[200]; + turboshake128_init (cv_state); + for (uint64_t i = offset; i < offset + block_size; i += 168) + { + uint64_t cv_block_size = (168 < offset + block_size - i) + ? 168 + : offset + block_size - i; + for (uint64_t j = 0; j < cv_block_size; ++j) + { + if (i + j < input_len) + { + cv_buf[j] = input[i + j]; + } + else if (i + j < input_len + cs_len) + { + cv_buf[j] = custom_str[i + j - input_len]; + } + else + { + cv_buf[j] = encoded[i + j - input_len - cs_len]; + } + } + turboshake128_absorb (cv_state, cv_buf, cv_block_size, 0x0B); + } + turboshake128_squeeze_destructive (cv_state, cv, 32); + if (buf_len + 32 >= 168) + { + for (unsigned int i = buf_len; i < 168; ++i) + { + buf[i] = cv[i - buf_len]; + } + turboshake128_absorb (state, buf, 168, 0x06); + for (unsigned int i = (buf_len + 32) - 168; i < 32; ++i) + { + buf[i] = cv[i]; + } + } + else + { + for (unsigned int i = buf_len; i < buf_len + 32; ++i) + { + buf[i] = cv[i - buf_len]; + } + } + buf_len += 32; + buf_len %= 168; + num_block++; + offset += block_size; + } + uint8_t nb_encoded[8]; + uint64_t nb_encoded_size; + length_encode (num_block, nb_encoded, &nb_encoded_size); + if (buf_len + nb_encoded_size + 2 >= 168) + { + for (unsigned int i = buf_len; i < 168; ++i) + { + if (i - buf_len < nb_encoded_size) + { + buf[i] = nb_encoded[i - buf_len]; + } + else + { + buf[i] = 0xFF; + } + } + turboshake128_absorb (state, buf, 168, 0x06); -int -main (int argc, char **argv) -{ - uint8_t output[64]; - tct_kangarootwelve128 (NULL, 0, NULL, 0, output, 64); - for (unsigned int i = 0; i < 64; ++i) + for (unsigned int i = (buf_len + nb_encoded_size + 2) - 168; + i < nb_encoded_size + 2; ++i) + { + if (i < nb_encoded_size) + { + buf[i] = nb_encoded[i]; + } + else + { + buf[i] = 0xFF; + } + } + buf_len = (buf_len + nb_encoded_size + 2) - 168; + } + else { - printf ("%02x ", output[i]); - if (i % 16 == 15) + for (unsigned int i = buf_len; i < buf_len + nb_encoded_size + 2; ++i) { - printf ("\n"); + if (i - buf_len < nb_encoded_size) + { + buf[i] = nb_encoded[i - buf_len]; + } + else + { + buf[i] = 0xFF; + } } + buf_len += nb_encoded_size + 2; } - return 0; + turboshake128_absorb (state, buf, buf_len, 0x06); + turboshake128_squeeze_destructive (state, output, output_len); }
A
tinycrypt/kangarootwelve128.h
@@ -0,0 +1,11 @@
+#ifndef TCT_KT128_H +#define TCT_KT128_H + +#include <stdint.h> + +/// Implements the KangarooTwelve128 hashing algorithm as defined in RFC 8961 +void tct_kangarootwelve128 (const uint8_t *input, const uint64_t input_len, + const uint8_t *custom_str, const uint64_t cs_len, + uint8_t *output, const uint64_t output_len); + +#endif
M
tinycrypt/x25519.c
→
tinycrypt/x25519.c
@@ -313,8 +313,8 @@ b[i] = b[i] ^ dummy;
} } -static void -x25519 (const uint8_t *key, const uint8_t *u, uint8_t *out) +void +tct_x25519 (const uint8_t *key, const uint8_t *u, uint8_t *out) { uint8_t k_int[32], u_int_big[64], u_int_small[32]; for (unsigned int i = 0; i < 32; ++i)@@ -411,7 +411,7 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
}; print256 (u); uint8_t out[32]; - x25519 (k, u, out); + tct_x25519 (k, u, out); print256 (out); return 0; }
A
tinycrypt/x25519.h
@@ -0,0 +1,9 @@
+#ifndef TCT_X25519_H +#define TCT_X25519_H + +#include <stdint.h> + +/// Implements the X25519 ECDH key derivation function as described in RFC 7748 +void tct_x25519 (const uint8_t *key, const uint8_t *u, uint8_t *out); + +#endif