Hello,

When I'm trying to implement ML-KEM (Kyber), I realized that the current
API for SHAKE (sha3_256_shake) is a bit too limited: while ML-KEM uses
SHAKE128 as a source of pseudorandom samples[1], the the current API
requires the total number of bytes are determined prior to the call, and
after the call the hash context is reset.

Here I propose adding a couple of helper functions to support such
streaming use-case: sha3_256_shake_pad to process the final block, and
sha3_256_shake_read to read the digest from the current state without
resetting the context.  With those functions, one could write a
streaming read interface as attached.

What do you think?  The actual code changes can be found at:
https://git.lysator.liu.se/nettle/nettle/-/merge_requests/61

I also have a SHAKE128 implementation with analogous API, which I will
post later.

Regards,

Footnotes:
[1]  
https://bwesterb.github.io/draft-schwabe-cfrg-kyber/draft-cfrg-schwabe-kyber.html#name-uniformly

-- 
Daiki Ueno
#include "sha3.h"
#include <stdio.h>

struct shake_reader
{
  struct sha3_256_ctx ctx;
  uint8_t buf[SHA3_256_BLOCK_SIZE];
  size_t offset;
};

static void
shake_reader_init (struct shake_reader *reader)
{
  sha3_256_init (&reader->ctx);
  reader->offset = sizeof(reader->buf);
}

static void
shake_reader_read (struct shake_reader *reader,
                   size_t length,
                   uint8_t *digest)
{
  while (length > 0)
    {
      while (reader->offset < sizeof(reader->buf))
        {
          *digest++ = reader->buf[reader->offset++];
          length--;

          if (!length)
            return;
        }

      if (reader->offset == sizeof(reader->buf))
        {
          sha3_256_shake_read (&reader->ctx, sizeof(reader->buf), reader->buf);
          sha3_permute (&reader->ctx.state);
          reader->offset = 0;
        }
    }
}

int main (void)
{
  struct shake_reader reader;
  uint8_t buf[3];
  size_t n = 0;

  shake_reader_init (&reader);

  sha3_256_update (&reader.ctx, 0, NULL);
  sha3_256_shake_pad (&reader.ctx);

  while (n < 256)
    {
      shake_reader_read (&reader, sizeof(buf), buf);

      int d1 = buf[0] + 256 * (buf[1] % 16);
      int d2 = (buf[1] >> 4) + 16 * buf[2];

      if (d1 < 3329)
        {
          printf ("%d\n", d1);
          n++;
        }

      if (n == 256)
        break;

      if (d2 < 3329)
        {
          printf ("%d\n", d2);
          n++;
        }
    }

  return 0;
}
_______________________________________________
nettle-bugs mailing list -- nettle-bugs@lists.lysator.liu.se
To unsubscribe send an email to nettle-bugs-le...@lists.lysator.liu.se

Reply via email to