From e57e3c811912660dbd88c9ab42893ae09db9209c Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sun, 3 Sep 2023 01:21:55 -0400 Subject: sha3.c: add bytepad(), test_bytepad(), and MIN() --- sha3.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 14 deletions(-) diff --git a/sha3.c b/sha3.c index cc4a367..3f6c9c6 100644 --- a/sha3.c +++ b/sha3.c @@ -10,6 +10,9 @@ // 64-bit rotate left #define ROL(v, n) (((v) << (n)) | ((v) >> (64-(n)))) +// minimum of two values +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + static inline void theta(uint64_t a[static 25]) { const uint64_t c[5] = { a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20], @@ -498,6 +501,26 @@ static inline bytepad_lens_t bytepad_prefix(uint8_t buf[static 9], const size_t }; } +typedef struct { + uint8_t prefix[9]; // bytepad prefix + size_t prefix_len; // length of bytepad prefix, in bytes + size_t pad_len; // number of padding bytes after prefix and data +} bytepad_t; + +// write bytepad() prefix to buffer, then return structure containing +// the length of the prefix, in bytes, and the total number of +static inline bytepad_t bytepad(const size_t data_len, const size_t width) { + bytepad_t r = { { 0 }, 0, 0 }; + const size_t prefix_len = left_encode(r.prefix, width); + const size_t total_len = prefix_len + data_len; + const size_t padded_len = (total_len / width + ((total_len % width) ? 1 : 0)) * width; + + r.prefix_len = prefix_len; + r.pad_len = padded_len - total_len; + + return r; +} + #define CSHAKE128_XOF_RATE (200 - 2 * 16) #define CSHAKE128_XOF_PAD 0x04 @@ -532,27 +555,29 @@ void cshake128_xof_init(sha3_xof_t * const xof, const cshake_params_t params) { const size_t raw_len = name_len + params.name_len + custom_len + params.custom_len; // build bytepad prefix - uint8_t bytepad_buf[9] = { 0 }; - const bytepad_lens_t lens = bytepad_prefix(bytepad_buf, raw_len, CSHAKE128_XOF_RATE); + const bytepad_t bp = bytepad(raw_len, CSHAKE128_XOF_RATE); // init xof xof_init(xof); - // absorb cshake prefix and padding - (void) cshake128_xof_absorb(xof, bytepad_buf, lens.prefix_len); + // absorb bytepad prefix + (void) cshake128_xof_absorb(xof, bp.prefix, bp.prefix_len); + // absorb name string (void) cshake128_xof_absorb(xof, name_buf, name_len); if (params.name_len > 0) { (void) cshake128_xof_absorb(xof, params.name, params.name_len); } + // absorb custom string (void) cshake128_xof_absorb(xof, custom_buf, custom_len); if (params.custom_len > 0) { (void) cshake128_xof_absorb(xof, params.custom, params.custom_len); } - for (size_t ofs = 0; ofs < lens.pad_len; ofs += sizeof(PAD)) { - const size_t len = (lens.pad_len - ofs) < sizeof(PAD) ? lens.pad_len - ofs : sizeof(PAD); + // absorb padding + for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { + const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake128_xof_absorb(xof, PAD, len); } } @@ -613,27 +638,29 @@ void cshake256_xof_init(sha3_xof_t * const xof, const cshake_params_t params) { const size_t raw_len = name_len + params.name_len + custom_len + params.custom_len; // build bytepad prefix - uint8_t bytepad_buf[9] = { 0 }; - const bytepad_lens_t lens = bytepad_prefix(bytepad_buf, raw_len, CSHAKE256_XOF_RATE); + const bytepad_t bp = bytepad(raw_len, CSHAKE256_XOF_RATE); // init xof xof_init(xof); - // absorb cshake prefix and padding - (void) cshake256_xof_absorb(xof, bytepad_buf, lens.prefix_len); + // absorb bytepad prefix + (void) cshake256_xof_absorb(xof, bp.prefix, bp.prefix_len); + // absorb name string (void) cshake256_xof_absorb(xof, name_buf, name_len); if (params.name_len > 0) { (void) cshake256_xof_absorb(xof, params.name, params.name_len); } + // absorb custom string (void) cshake256_xof_absorb(xof, custom_buf, custom_len); if (params.custom_len > 0) { (void) cshake256_xof_absorb(xof, params.custom, params.custom_len); } - for (size_t ofs = 0; ofs < lens.pad_len; ofs += sizeof(PAD)) { - const size_t len = (lens.pad_len - ofs) < sizeof(PAD) ? lens.pad_len - ofs : sizeof(PAD); + // absorb padding + for (size_t ofs = 0; ofs < bp.pad_len; ofs += sizeof(PAD)) { + const size_t len = MIN(bp.pad_len - ofs, sizeof(PAD)); (void) cshake256_xof_absorb(xof, PAD, len); } } @@ -1661,7 +1688,7 @@ static void test_shake128_xof(void) { // absorb for (size_t ofs = 0; ofs < tests[i].len; ofs += len) { - const size_t absorb_len = (tests[i].len - ofs < len) ? tests[i].len - ofs : len; + const size_t absorb_len = MIN(tests[i].len - ofs, len); if (!shake128_xof_absorb(&xof, tests[i].msg + ofs, absorb_len)) { fprintf(stderr, "test_shake128_xof(\"%s\", %zu) failed: shake128_xof_absorb()\n", tests[i].name, len); return; @@ -1886,7 +1913,7 @@ static void test_shake256_xof(void) { // absorb for (size_t ofs = 0; ofs < tests[i].len; ofs += len) { - const size_t absorb_len = (tests[i].len - ofs < len) ? tests[i].len - ofs : len; + const size_t absorb_len = MIN(tests[i].len - ofs, len); if (!shake256_xof_absorb(&xof, tests[i].msg + ofs, absorb_len)) { fprintf(stderr, "test_shake256_xof(\"%s\", %zu) failed: shake256_xof_absorb()\n", tests[i].name, len); return; @@ -2273,6 +2300,66 @@ static void test_bytepad_prefix(void) { } } +static void test_bytepad(void) { + static const struct { + const char *name; + size_t data_len, width; + uint8_t exp_prefix[9]; + size_t exp_prefix_len, exp_pad_len; + bytepad_lens_t exp_lens; + } tests[] = {{ + .name = "0-10", + .data_len = 0, + .width = 10, + .exp_prefix = { 0x01, 0x0a }, + .exp_prefix_len = 2, + .exp_pad_len = 8, + }, { + .name = "8-10", + .data_len = 8, + .width = 10, + .exp_prefix = { 0x01, 0x0a }, + .exp_prefix_len = 2, + .exp_pad_len = 0, + }, { + .name = "9-10", + .data_len = 9, + .width = 10, + .exp_prefix = { 0x01, 0x0a }, + .exp_prefix_len = 2, + .exp_pad_len = 9, + }, { + .name = "10-10", + .data_len = 10, + .width = 10, + .exp_prefix = { 0x01, 0x0a }, + .exp_prefix_len = 2, + .exp_pad_len = 8, + }, { + .name = "11-10", + .data_len = 11, + .width = 10, + .exp_prefix = { 0x01, 0x0a }, + .exp_prefix_len = 2, + .exp_pad_len = 7, + }}; + + for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + const bytepad_t got = bytepad(tests[i].data_len, tests[i].width); + + // check prefix length and data + if (got.prefix_len != tests[i].exp_prefix_len || got.pad_len != tests[i].exp_pad_len) { + fprintf(stderr, "test_bytepad(\"%s\") length check failed:\n got: { %zu, %zu }\n exp: { %zu, %zu }\n", tests[i].name, got.prefix_len, got.pad_len, tests[i].exp_prefix_len, tests[i].exp_pad_len); + } else if (memcmp(got.prefix, tests[i].exp_prefix, got.prefix_len)) { + fprintf(stderr, "test_bytepad_prefix(\"%s\") failed, got:\n", tests[i].name); + dump_hex(stderr, got.prefix, got.prefix_len); + + fprintf(stderr, "exp:\n"); + dump_hex(stderr, tests[i].exp_prefix, got.prefix_len); + } + } +} + static void test_cshake128(void) { static const struct { const char *test_name; // test name @@ -2452,6 +2539,7 @@ int main(void) { test_right_encode(); test_encode_string_prefix(); test_bytepad_prefix(); + test_bytepad(); test_cshake128(); test_cshake256(); printf("ok\n"); -- cgit v1.2.3