From 890cd6d0f0c46887e085bf4f661c6d442b1ca8a2 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Wed, 6 Sep 2023 18:17:45 -0400 Subject: sha3.[hc]: refactor k12 api --- sha3.c | 176 ++++++++++++++++++++++++++++++++++------------------------------- sha3.h | 43 ++++++++++++++-- 2 files changed, 130 insertions(+), 89 deletions(-) diff --git a/sha3.c b/sha3.c index e3ec77e..3c3108a 100644 --- a/sha3.c +++ b/sha3.c @@ -870,9 +870,9 @@ static inline size_t right_encode(uint8_t buf[static 9], const uint64_t n) { } } -// kangarootwelve utility function +// kangarootwelve length encoding. // (similar to right_encode(), but slightly different) -static inline size_t kangarootwelve_length_encode(uint8_t buf[static 9], const uint64_t n) { +static inline size_t k12_length_encode(uint8_t buf[static 9], const uint64_t n) { if (n > 0x00ffffffffffffffULL) { buf[0] = (n >> 56) & 0xff; buf[1] = (n >> 40) & 0xff; @@ -1834,175 +1834,183 @@ void turboshake256_custom(const uint8_t pad, const uint8_t * const src, const si } // kangarootwelve block size, in bytes -#define KT_BLOCK_LEN 8192 +#define K12_BLOCK_LEN 8192 // pad byte for single kangarootwelve chunk (<= 8192 bytes) -#define KT_PAD_SINGLE 0x07 +#define K12_PAD_SINGLE 0x07 // pad byte for root kangarootwelve turboshake instance (> 8192 bytes) -#define KT_PAD_ROOT 0x06 +#define K12_PAD_ROOT 0x06 // pad byte for child kangarootwelve turboshake instances (> 8192 bytes) -#define KT_PAD_CHILD 0x0B +#define K12_PAD_CHILD 0x0B -// private kangarootwelve context +// private kangarootwelve big context typedef struct { - turboshake_t root, // root turboshake context + turboshake_t *root, // root turboshake context curr; // current child turboshake context size_t num_bytes, // num bytes in current block num_blocks; // total number of blocks -} kangarootwelve_t; +} k12_big_t; -// init kangarootwelve context -static void kangarootwelve_init(kangarootwelve_t * const kt) { - turboshake128_init_custom(&(kt->root), KT_PAD_ROOT); - kt->num_bytes = 0; - kt->num_blocks = 0; +// init kangarootwelve big context +static void k12_big_init(k12_big_t * const big, turboshake_t * const root) { + // init root context + turboshake128_init_custom(root, K12_PAD_ROOT); + + big->root = root; + big->num_bytes = 0; + big->num_blocks = 0; } // absorb data in child context -static void kangarootwelve_child_absorb(kangarootwelve_t * const kt, const uint8_t *src, size_t src_len) { +static void k12_big_child_absorb(k12_big_t * const big, const uint8_t *src, size_t src_len) { while (src_len > 0) { - const size_t len = MIN(KT_BLOCK_LEN - kt->num_bytes, src_len); + const size_t len = MIN(K12_BLOCK_LEN - big->num_bytes, src_len); // absorb into child context - turboshake128_absorb(&(kt->curr), src, len); + turboshake128_absorb(&(big->curr), src, len); src += len; src_len -= len; - kt->num_bytes += len; + big->num_bytes += len; - if (kt->num_bytes == KT_BLOCK_LEN) { + if (big->num_bytes == K12_BLOCK_LEN) { // hash child uint8_t buf[32] = { 0 }; - turboshake128_squeeze(&(kt->curr), buf, sizeof(buf)); + turboshake128_squeeze(&(big->curr), buf, sizeof(buf)); // absorb hash into root - turboshake128_absorb(&(kt->root), buf, sizeof(buf)); + turboshake128_absorb(big->root, buf, sizeof(buf)); // reset child - turboshake128_init_custom(&(kt->curr), KT_PAD_CHILD); + turboshake128_init_custom(&(big->curr), K12_PAD_CHILD); // clear byte count, increment block count - kt->num_bytes = 0; - kt->num_blocks++; + big->num_bytes = 0; + big->num_blocks++; } } } // absorb data in root context // (passes excess data to child context) -static void kangarootwelve_root_absorb(kangarootwelve_t * const kt, const uint8_t *src, size_t src_len) { +static void k12_big_root_absorb(k12_big_t * const big, const uint8_t *src, size_t src_len) { while (src_len > 0) { - const size_t len = MIN(KT_BLOCK_LEN - kt->num_bytes, src_len); + const size_t len = MIN(K12_BLOCK_LEN - big->num_bytes, src_len); // absorb into root context - turboshake128_absorb(&(kt->root), src, len); + turboshake128_absorb(big->root, src, len); src += len; src_len -= len; - kt->num_bytes += len; + big->num_bytes += len; - if (kt->num_bytes == KT_BLOCK_LEN) { + if (big->num_bytes == K12_BLOCK_LEN) { // absorb trailer for first block uint8_t buf[8] = { 3, 0, 0, 0, 0, 0, 0, 0 }; - turboshake128_absorb(&(kt->root), buf, sizeof(buf)); + turboshake128_absorb(big->root, buf, sizeof(buf)); // init child - turboshake128_init_custom(&(kt->curr), KT_PAD_CHILD); + turboshake128_init_custom(&(big->curr), K12_PAD_CHILD); // clear byte count, increment block count - kt->num_bytes = 0; - kt->num_blocks++; + big->num_bytes = 0; + big->num_blocks++; // absorb rest of source in child - kangarootwelve_child_absorb(kt, src, src_len); + k12_big_child_absorb(big, src, src_len); return; } } } // absorb data -static void kangarootwelve_absorb(kangarootwelve_t * const kt, const uint8_t *src, size_t src_len) { - if (kt->num_blocks) { +static void k12_big_absorb(k12_big_t * const big, const uint8_t *src, size_t src_len) { + if (big->num_blocks) { // absorb successive blocks in child context - kangarootwelve_child_absorb(kt, src, src_len); + k12_big_child_absorb(big, src, src_len); } else { // absorb first block in root context - kangarootwelve_root_absorb(kt, src, src_len); + k12_big_root_absorb(big, src, src_len); } } -// finalize kangarootwelve context and squeeze data into destination -static void kangarootwelve_squeeze(kangarootwelve_t * const kt, uint8_t *dst, const size_t dst_len) { - if (kt->num_bytes > 0) { +// finalize "big" kangarootwelve context +static void k12_big_absorb_done(k12_big_t * const big) { + if (big->num_bytes > 0) { // hash child, absorb into root uint8_t buf[32] = { 0 }; - turboshake128_squeeze(&(kt->curr), buf, sizeof(buf)); - turboshake128_absorb(&(kt->root), buf, sizeof(buf)); + turboshake128_squeeze(&(big->curr), buf, sizeof(buf)); + turboshake128_absorb(big->root, buf, sizeof(buf)); } // absorb block count uint8_t buf[9]; - const size_t buf_len = kangarootwelve_length_encode(buf, kt->num_blocks); - turboshake128_absorb(&(kt->root), buf, buf_len); + const size_t buf_len = k12_length_encode(buf, big->num_blocks); + turboshake128_absorb(big->root, buf, buf_len); // absorb tail static const uint8_t tail[2] = { 0xff, 0xff }; - turboshake128_absorb(&(kt->root), tail, sizeof(tail)); + turboshake128_absorb(big->root, tail, sizeof(tail)); +} - // squeeze - turboshake128_squeeze(&(kt->root), dst, dst_len); +// squeeze into destination +void k12_squeeze(k12_t *k12, uint8_t *dst, const size_t dst_len) { + turboshake128_squeeze(&(k12->ts), dst, dst_len); } -// one-shot kangarootwelve with custom string -void kangarootwelve_custom(const uint8_t *custom, const size_t custom_len, const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len) { +void k12_init(k12_t *k12, const uint8_t *src, const size_t src_len, const uint8_t *custom, const size_t custom_len) { uint8_t cl_buf[9] = { 0 }; - const size_t cl_buf_len = kangarootwelve_length_encode(cl_buf, custom_len); + const size_t cl_buf_len = k12_length_encode(cl_buf, custom_len); // get total size, in bytes const size_t total_len = src_len + custom_len + cl_buf_len; - if (total_len <= KT_BLOCK_LEN) { + if (total_len <= K12_BLOCK_LEN) { // total size is less than a single block, so create a single // turboshake128 instance, absorb the source data and the custom - // string, then squeeze into the destination buffer + // string. - // init - turboshake_t ts; - turboshake128_init_custom(&ts, KT_PAD_SINGLE); + // init turboshake context with single node padding + turboshake128_init_custom(&(k12->ts), K12_PAD_SINGLE); // absorb source, custom string, and custom string length - turboshake128_absorb(&ts, src, src_len); - turboshake128_absorb(&ts, custom, custom_len); - turboshake128_absorb(&ts, cl_buf, cl_buf_len); - - // squeeze into destination - turboshake128_squeeze(&ts, dst, dst_len); + turboshake128_absorb(&(k12->ts), src, src_len); + turboshake128_absorb(&(k12->ts), custom, custom_len); + turboshake128_absorb(&(k12->ts), cl_buf, cl_buf_len); } else { // total size greater than a single block, so create an internal - // kangarootwelve context, absorb the source data and the custom - // string into the context, then squeeze into the destination buffer + // "big" kangarootwelve context, absorb the source data and the custom + // string into the context. // // (the internal kangarootwelve context takes care of multiplexing // the block data between the root and child contexts) - // init - kangarootwelve_t kt; - kangarootwelve_init(&kt); + // init turboshake context with root node padding + turboshake128_init_custom(&(k12->ts), K12_PAD_ROOT); - // absorb source, custom string, and custom string length - kangarootwelve_absorb(&kt, src, src_len); - kangarootwelve_absorb(&kt, custom, custom_len); - kangarootwelve_absorb(&kt, cl_buf, cl_buf_len); + // init big context + k12_big_t big; + k12_big_init(&big, &(k12->ts)); - // squeeze into destination - kangarootwelve_squeeze(&kt, dst, dst_len); + // absorb source, custom string, and custom string length + k12_big_absorb(&big, src, src_len); + k12_big_absorb(&big, custom, custom_len); + k12_big_absorb(&big, cl_buf, cl_buf_len); + k12_big_absorb_done(&big); } } +// one-shot k12 with custom string +void k12_custom_once(const uint8_t *src, const size_t src_len, const uint8_t *custom, const size_t custom_len, uint8_t *dst, const size_t dst_len) { + k12_t k12; + k12_init(&k12, src, src_len, custom, custom_len); + k12_squeeze(&k12, dst, dst_len); +} + // one-shot kangarootwelve w/o custom string -void kangarootwelve(const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len) { - kangarootwelve_custom(NULL, 0, src, src_len, dst, dst_len); +void k12_once(const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len) { + k12_custom_once(src, src_len, NULL, 0, dst, dst_len); } #ifdef SHA3_TEST @@ -6481,7 +6489,7 @@ static void test_turboshake256(void) { } } -static void test_kangarootwelve_length_encode(void) { +static void test_k12_length_encode(void) { static const struct { const char *name; uint64_t val; @@ -6541,13 +6549,13 @@ static void test_kangarootwelve_length_encode(void) { for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint8_t got[9]; - const size_t got_len = kangarootwelve_length_encode(got, tests[i].val); + const size_t got_len = k12_length_encode(got, tests[i].val); // check length and data if (got_len != tests[i].exp_len) { - fprintf(stderr, "test_kangarootwelve_length_encode(\"%s\") length check failed: got %zu, exp %zu:\n", tests[i].name, got_len, tests[i].exp_len); + fprintf(stderr, "test_k12_length_encode(\"%s\") length check failed: got %zu, exp %zu:\n", tests[i].name, got_len, tests[i].exp_len); } else if (memcmp(got, tests[i].exp, got_len)) { - fprintf(stderr, "test_kangarootwelve_length_encode(\"%s\") failed, got:\n", tests[i].name); + fprintf(stderr, "test_k12_length_encode(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, got_len); fprintf(stderr, "exp:\n"); @@ -6556,7 +6564,7 @@ static void test_kangarootwelve_length_encode(void) { } } -static void test_kangarootwelve(void) { +static void test_k12(void) { // test pattern // src: https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-10.html#name-test-vectors static const uint8_t PATTERN[] = { @@ -6719,11 +6727,11 @@ static void test_kangarootwelve(void) { // run uint8_t got[32] = { 0 }; - kangarootwelve_custom(custom, tests[i].custom_len, src, tests[i].len, got, sizeof(got)); + k12_custom_once(src, tests[i].len, custom, tests[i].custom_len, got, sizeof(got)); // check if (memcmp(got, tests[i].exp, sizeof(got))) { - fprintf(stderr, "test_kangarootwelve(\"%s\") failed, got:\n", tests[i].name); + fprintf(stderr, "test_k12(\"%s\") failed, got:\n", tests[i].name); dump_hex(stderr, got, sizeof(got)); fprintf(stderr, "exp:\n"); @@ -6787,8 +6795,8 @@ int main(void) { test_hmac_sha3_512_ctx(); test_turboshake128(); test_turboshake256(); - test_kangarootwelve_length_encode(); - test_kangarootwelve(); + test_k12_length_encode(); + test_k12(); printf("ok\n"); } diff --git a/sha3.h b/sha3.h index 0f7db1e..7ee1c11 100644 --- a/sha3.h +++ b/sha3.h @@ -1292,19 +1292,22 @@ _Bool turboshake256_absorb(turboshake_t *ts, const uint8_t *src, const size_t le */ void turboshake256_squeeze(turboshake_t *ts, uint8_t *dst, const size_t len); +// KangarooTwelve context +typedef struct { + turboshake_t ts; +} k12_t; + /** * Initialize internal KangarooTwelve context, absorb `src_len` bytes of * input from source buffer `src`, then squeeze `dst_len` bytes of * output into destination buffer `dst`. * - * @param[in] custom Custom string buffer. - * @param[in] custom_len Custom string length, in bytes. * @param[in] src Source buffer. * @param[in] src_len Source buffer length, in bytes. * @param[out] dst Destination buffer. * @param[in] dst_len Destination buffer length, in bytes. */ -void kangarootwelve(const uint8_t *custom, const size_t custom_len, const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len); +void k12_once(const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len); /** * Initialize internal KangarooTwelve context with custom string @@ -1312,14 +1315,44 @@ void kangarootwelve(const uint8_t *custom, const size_t custom_len, const uint8_ * source buffer `src`, then squeeze `dst_len` bytes of output into * destination buffer `dst`. * + * @param[in] src Source buffer. + * @param[in] src_len Source buffer length, in bytes. * @param[in] custom Custom string buffer. * @param[in] custom_len Custom string length, in bytes. + * @param[out] dst Destination buffer. + * @param[in] dst_len Destination buffer length, in bytes. + */ +void k12_custom_once(const uint8_t *src, const size_t src_len, const uint8_t *custom, const size_t custom_len, uint8_t *dst, const size_t dst_len); + +/** + * Initialize KangarooTwelve context with message `src` of length + * `src_len` bytes and custom string `custom` of length `custom_len` + * bytes. + * + * Note: This implementation of KangarooTwelve is sequential, not + * parallel. + * + * @param[out] k12 KangarooTwelve context. * @param[in] src Source buffer. * @param[in] src_len Source buffer length, in bytes. + * @param[in] custom Custom string buffer. + * @param[in] custom_len Custom string length, in bytes. + */ +void k12_init(k12_t *k12, const uint8_t *src, const size_t src_len, const uint8_t *custom, const size_t custom_len); + +/** + * Squeeze `dst_len` bytes of output into destination buffer `dst` from + * KangarooTwelve context `k12`. Can be called iteratively to squeeze + * output data in chunks. + * + * Note: This implementation of KangarooTwelve is sequential, not + * parallel. + * + * @param[in/out] k12 KangarooTwelve context. * @param[out] dst Destination buffer. - * @param[in] dst_len Destination buffer length, in bytes. + * @param[in] len Destination buffer length, in bytes. */ -void kangarootwelve_custom(const uint8_t *custom, const size_t custom_len, const uint8_t *src, const size_t src_len, uint8_t *dst, const size_t dst_len); +void k12_squeeze(k12_t *k12, uint8_t *dst, const size_t dst_len); #ifdef __cplusplus } -- cgit v1.2.3