Niels Möller <[email protected]> writes: > Daiki Ueno <[email protected]> writes: > >> Yes, this makes the code a lot simpler. I'm attaching an updated patch. > > Thanks, looks good to me. Some details I'm thinking about that might be > improvements: > > * One could perhaps use index == 0 instead of index == block_size for > the case that there is no buffered data. But the current convention > does make your "if (length <= left)" nice and simple.
I agree that the current convention is a bit awkward, so in the attached patch I changed to use index == 0 as the indicator where buffering is needed. That actually makes the code simpler as we can defer buffering until when the data is read. One drawback though is that it causes additional memcpy in a corner case where the _shake_output is used to retrieve data smaller than the block size. > * It looks a bit backwards to me that each iteration *first* copies data > to the digest, and *then* calls sha3_permute. In case no more data is > to be output, that sha3_permute call is wasted. It would be more > natural to me to not call sha3_permute until we know the output is > needed. But to fix that and still keep things nice for the first > output block, I think one would need to reorganize _nettle_sha3_pad to > not imply a call to sha3_permute (via sha3_absorb). So that's better > done in a separate change. Right, I can do that after the current patch is settled. > * I'm still tempted to use ctx->index = ~index rather than ctx->index = > index | INDEX_HIGH_BIT. But maybe that would just be too obfuscated. I'm actually not sure how this works. For example, if unsigned int is 32-bit and index is 3, wouldn't ~index turn to 0xfffffffc, while index | INDEX_HIGH_BIT is 0x80000003? > In next step, to also support shake128, we should generalize your code > using an internal function _sha3_shake_output taking block and block > size as arguments. Yes. > I'm also not sure about proper naming for shake128. If I read the > Instances table at https://en.wikipedia.org/wiki/SHA-3 right, there's no > standard regular hash function corresponding to shake128. We could still > name it sha3_128_shake, but that might be confusing (there's no > corresponding sha3_128_digest, would there be any use for that?). The > alternative could be to use names sha3_shakeN_init, sha3_shakeN_update, > sha3_shakeN_digest, sha3_shakeN_output (with some of the shake256 > functions, as well as the context struct, being aliases to corresponding > sha3_256 names). But aliases also have a cost in potential confusion. I agree; we probably shouldn't expose sha3_128_digest et. al., from the API. >> + if (length > 0) >> + { >> + /* Fill in the buffer for next call. */ >> + _nettle_write_le64 (sizeof (ctx->block), ctx->block, ctx->state.a); >> + sha3_permute (&ctx->state); >> + memcpy (digest, ctx->block, length); >> + ctx->index = length | INDEX_HIGH_BIT; >> + } >> + else >> + ctx->index = sizeof (ctx->block) | INDEX_HIGH_BIT; >> +} > > If I read your code right, we actually always have length > 0 at this > place. So either delete the if conditional, or change the condition of > the loop above from (length > sizeof (ctx->block)) to (length >= sizeof > (ctx->block)). The latter option would avoid a memcpy in the case that > the requested digest ends with a full block. Indeed, fixed. Regards, -- Daiki Ueno
>From 42c6b5686d361f5572fc6e2daf5d7e355d5b90c0 Mon Sep 17 00:00:00 2001 From: Daiki Ueno <[email protected]> Date: Sun, 10 Mar 2024 09:43:04 +0900 Subject: [PATCH] sha3: Extend SHAKE256 API with incremental output This adds an alternative function sha3_256_shake_output in the SHAKE256 support, which enables to read output multiple times in an incremental manner. Signed-off-by: Daiki Ueno <[email protected]> --- sha3.h | 8 +++++ shake256.c | 65 +++++++++++++++++++++++++++++++++++++++ testsuite/shake256-test.c | 65 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/sha3.h b/sha3.h index 9220829d..4b7e186c 100644 --- a/sha3.h +++ b/sha3.h @@ -49,6 +49,7 @@ extern "C" { #define sha3_256_update nettle_sha3_256_update #define sha3_256_digest nettle_sha3_256_digest #define sha3_256_shake nettle_sha3_256_shake +#define sha3_256_shake_output nettle_sha3_256_shake_output #define sha3_384_init nettle_sha3_384_init #define sha3_384_update nettle_sha3_384_update #define sha3_384_digest nettle_sha3_384_digest @@ -143,6 +144,13 @@ sha3_256_shake(struct sha3_256_ctx *ctx, size_t length, uint8_t *digest); +/* Unlike sha3_256_shake, this function can be called multiple times + to retrieve output from shake256 in an incremental manner */ +void +sha3_256_shake_output(struct sha3_256_ctx *ctx, + size_t length, + uint8_t *digest); + struct sha3_384_ctx { struct sha3_state state; diff --git a/shake256.c b/shake256.c index f5c77a43..cba22af4 100644 --- a/shake256.c +++ b/shake256.c @@ -36,6 +36,8 @@ # include "config.h" #endif +#include <assert.h> +#include <limits.h> #include <stddef.h> #include <string.h> @@ -44,6 +46,8 @@ #include "nettle-write.h" +#define INDEX_HIGH_BIT (~((UINT_MAX) >> 1)) + void sha3_256_shake (struct sha3_256_ctx *ctx, size_t length, @@ -61,3 +65,64 @@ sha3_256_shake (struct sha3_256_ctx *ctx, sha3_256_init (ctx); } + +void +sha3_256_shake_output (struct sha3_256_ctx *ctx, + size_t length, + uint8_t *digest) +{ + unsigned index, left; + + /* We use the leftmost bit as a flag to indicate SHAKE is initialized. */ + if (ctx->index & INDEX_HIGH_BIT) + index = ctx->index & ~INDEX_HIGH_BIT; + else + { + /* This is the first call of _shake_output. */ + _sha3_pad_shake (&ctx->state, sizeof (ctx->block), ctx->block, ctx->index); + /* Point at the end of block to trigger fill in of the buffer. */ + index = 0; + } + + assert (index < sizeof (ctx->block)); + + if (index == 0) + { + /* Fill in the buffer. */ + _nettle_write_le64 (sizeof (ctx->block), ctx->block, ctx->state.a); + sha3_permute (&ctx->state); + } + + /* Write remaining data from the buffer. */ + left = sizeof (ctx->block) - index; + if (length <= left) + { + memcpy (digest, ctx->block + index, length); + ctx->index = ((index + length) % sizeof (ctx->block)) | INDEX_HIGH_BIT; + return; + } + else + { + memcpy (digest, ctx->block + index, left); + length -= left; + digest += left; + } + + /* Write full blocks. */ + while (length >= sizeof (ctx->block)) + { + _nettle_write_le64 (sizeof (ctx->block), digest, ctx->state.a); + sha3_permute (&ctx->state); + length -= sizeof (ctx->block); + digest += sizeof (ctx->block); + } + + if (length > 0) + { + /* Fill in the buffer. */ + _nettle_write_le64 (sizeof (ctx->block), ctx->block, ctx->state.a); + sha3_permute (&ctx->state); + memcpy (digest, ctx->block, length); + } + ctx->index = length | INDEX_HIGH_BIT; +} diff --git a/testsuite/shake256-test.c b/testsuite/shake256-test.c index b91417cb..8a2f8589 100644 --- a/testsuite/shake256-test.c +++ b/testsuite/shake256-test.c @@ -34,6 +34,8 @@ #include "sha3.h" +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + const struct nettle_hash nettle_shake256 = { "shake256", @@ -45,9 +47,37 @@ const struct nettle_hash nettle_shake256 = (nettle_hash_digest_func *) sha3_256_shake, }; +static void +test_incremental (const struct tstring *msg, + const struct tstring *digest, + size_t interval) +{ + struct sha3_256_ctx ctx; + size_t offset = 0; + uint8_t *buffer = xalloc (digest->length); + + sha3_256_init (&ctx); + sha3_256_update (&ctx, msg->length, msg->data); + + while (offset < digest->length) + { + size_t to_read = MIN(digest->length - offset, interval); + + sha3_256_shake_output (&ctx, to_read, buffer + offset); + + offset += to_read; + } + + ASSERT (MEMEQ (digest->length, digest->data, buffer)); + free (buffer); +} + void test_main(void) { + const struct tstring *msg; + struct tstring *digest; + /* Extracted from ShortMsgKAT_SHAKE256.txt. */ test_hash (&nettle_shake256, /* 0 octets */ SHEX(""), @@ -5937,4 +5967,39 @@ test_main(void) "805C7B7E2CFD54E0FAD62F0D8CA67A775DC4546AF9096F2EDB2" "21DB42843D65327861282DC946A0BA01A11863AB2D1DFD16E39" "73D4")); + + /* Test incremental API */ + msg = SHEX("3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1"); + digest = SHEX("8A5199B4A7E133E264A86202720655894D48CFF344A928CF834" + "7F48379CEF347DFC5BCFFAB99B27B1F89AA2735E23D30088FFA" + "03B9EDB02B9635470AB9F1038985D55F9CA774572DD006470EA" + "65145469609F9FA0831BF1FFD842DC24ACADE27BD9816E3B5BF" + "2876CB112232A0EB4475F1DFF9F5C713D9FFD4CCB89AE5607FE" + "35731DF06317949EEF646E9591CF3BE53ADD6B7DD2B6096E2B3" + "FB06E662EC8B2D77422DAAD9463CD155204ACDBD38E319613F3" + "9F99B6DFB35CA9365160066DB19835888C2241FF9A731A4ACBB" + "5663727AAC34A401247FBAA7499E7D5EE5B69D31025E63D04C3" + "5C798BCA1262D5673A9CF0930B5AD89BD485599DC184528DA47" + "90F088EBD170B635D9581632D2FF90DB79665CED430089AF13C" + "9F21F6D443A818064F17AEC9E9C5457001FA8DC6AFBADBE3138" + "F388D89D0E6F22F66671255B210754ED63D81DCE75CE8F189B5" + "34E6D6B3539AA51E837C42DF9DF59C71E6171CD4902FE1BDC73" + "FB1775B5C754A1ED4EA7F3105FC543EE0418DAD256F3F6118EA" + "77114A16C15355B42877A1DB2A7DF0E155AE1D8670ABCEC3450" + "F4E2EEC9838F895423EF63D261138BAAF5D9F104CB5A957AEA0" + "6C0B9B8C78B0D441796DC0350DDEABB78A33B6F1F9E68EDE3D1" + "805C7B7E2CFD54E0FAD62F0D8CA67A775DC4546AF9096F2EDB2" + "21DB42843D65327861282DC946A0BA01A11863AB2D1DFD16E39" + "73D4"); + + test_incremental (msg, digest, 16); + test_incremental (msg, digest, SHA3_256_BLOCK_SIZE - 1); + test_incremental (msg, digest, SHA3_256_BLOCK_SIZE); + test_incremental (msg, digest, SHA3_256_BLOCK_SIZE + 1); + + /* Exercise the case where the requested bytes are multiple of + blocks. */ + ASSERT (SHA3_256_BLOCK_SIZE * 3 <= digest->length); + digest->length = SHA3_256_BLOCK_SIZE * 3; + test_incremental (msg, digest, SHA3_256_BLOCK_SIZE); } -- 2.43.2
_______________________________________________ nettle-bugs mailing list -- [email protected] To unsubscribe send an email to [email protected]
