/*
 * Copyright (c) 2003-2016
 * Distributed Systems Software.  All rights reserved.
 * See the file BN-LICENSE for redistribution information.
 *
 * $Id: sha3.c 2885 2016-05-16 23:48:04Z brachman $
 */

/*
 * SHA-3 (based on FIPS PUB 202 of August, 2015)
 * http://csrc.nist.gov/groups/ST/hash/sha-3/fips202_standard_2015.html
 * http://keccak.noekeon.org/
 *
 * These functions are approved for use with HMAC:
 * Hash Function:    SHA3-224 SHA3-256 SHA3-384 SHA3-512
 * Input Block Size
 *            (bytes)     144      136      104       72
 *
 * "The SHA-3 functions are defined on messages of any bit length, including the
 * empty string. A conforming implementation of a SHA-3 function may restrict
 * the set of supported bit lengths for messages."
 *
 * Adapted from Aleksey Kravchenko's implementation for RHash
 * Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
 * https://github.com/rhash/RHash
 * http://cpansearch.perl.org/src/RHASH/Crypt-RHash-0.91/librhash/
 * See NOTICES. 
 */

#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>

#include "sha3.h"

/* Implementation identifiers. */
#define DIGEST_NONE         0x00
#define DIGEST_DACS         0x01        /* Implemented by DACS. */
#define DIGEST_OPENSSL      0x02        /* Implemented by OpenSSL. */
#define DIGEST_SYSTEM       0x03        /* Provided by O/S. */

#define log_msg(X)

#define DIGEST_USE_HMAC         0x020       /* With HMAC. */

static Digest_tab digest_tab[] = {
  { "sha3-224",    DIGEST_SHA3_224,        144, 28, DIGEST_USE_HMAC },
  { "sha3-256",    DIGEST_SHA3_256,        136, 32, DIGEST_USE_HMAC },
  { "sha3-384",    DIGEST_SHA3_384,        104, 48, DIGEST_USE_HMAC },
  { "sha3-512",    DIGEST_SHA3_512,         72, 64, DIGEST_USE_HMAC },
  { NULL,          DIGEST_INVALID,           0, 0, DIGEST_NONE }
};

/*
 * Validated against test vectors found in the following and elsewhere:
 * http://csrc.nist.gov/groups/ST/toolkit/examples.html
 * http://www.di-mgt.com.au/sha_testvectors.html
 * https://github.com/coruus/nist-testvectors/tree/master/fips202
 */

#define LE_DEC64(X)			lendian_dec64(&X)
#define ROTL64(QWORD, N)	((QWORD) << (N) ^ ((QWORD) >> (64 - (N))))
#define IS_ALIGNED_64(P)	(0 == (7 & ((const char *) (P) - (const char *) 0)))

#define SHA3_MUST_FINALIZE	0x40000000
#define SHA3_FINALIZED		0x80000000

/* Constants for 24 rounds */
static uint64_t keccak_round_constants[SHA3_NUMBER_OF_ROUNDS] = {
  INT64_C(0x0000000000000001), INT64_C(0x0000000000008082),
  INT64_C(0x800000000000808A), INT64_C(0x8000000080008000),
  INT64_C(0x000000000000808B), INT64_C(0x0000000080000001),
  INT64_C(0x8000000080008081), INT64_C(0x8000000000008009),
  INT64_C(0x000000000000008A), INT64_C(0x0000000000000088),
  INT64_C(0x0000000080008009), INT64_C(0x000000008000000A),
  INT64_C(0x000000008000808B), INT64_C(0x800000000000008B),
  INT64_C(0x8000000000008089), INT64_C(0x8000000000008003),
  INT64_C(0x8000000000008002), INT64_C(0x8000000000000080),
  INT64_C(0x000000000000800A), INT64_C(0x800000008000000A),
  INT64_C(0x8000000080008081), INT64_C(0x8000000000008080),
  INT64_C(0x0000000080000001), INT64_C(0x8000000080008008)
};

static inline MAYBE_UNUSED int
streq(const char *p, const char *q)
{

  return(strcmp(p, q) == 0);
}

static inline MAYBE_UNUSED int
strcaseeq(const char *p, const char *q)
{

  return(strcasecmp(p, q) == 0);
}

/*
 * Little-endian 32-bit encode X into byte vector PP.
 */
static inline void
lendian_enc32(void *pp, uint32_t x)
{
  uint8_t *p = (uint8_t *) pp;

  p[0] = (x >>  0) & 0xff;
  p[1] = (x >>  8) & 0xff;
  p[2] = (x >> 16) & 0xff;
  p[3] = (x >> 24) & 0xff;
}

/*
 * Return the little-endian 64-bit decoding of byte vector PP.
 */
static inline uint64_t
lendian_dec64(const void *pp)
{
  const uint8_t *p = (uint8_t const *) pp;

  return ((uint64_t) (p[0]) + ((uint64_t) (p[1]) << 8)
          + ((uint64_t) (p[2]) << 16) + ((uint64_t) (p[3]) << 24)
          + ((uint64_t) (p[4]) << 32) + ((uint64_t) (p[5]) << 40)
          + ((uint64_t) (p[6]) << 48) + ((uint64_t) (p[7]) << 56));
}

/*
 * Little-endian 64-bit encode X into byte vector PP.
 */
static inline void
lendian_enc64(void *pp, uint64_t x)
{
  uint8_t *p = (uint8_t *) pp;

  p[0] = (x >>  0) & 0xff;
  p[1] = (x >>  8) & 0xff;
  p[2] = (x >> 16) & 0xff;
  p[3] = (x >> 24) & 0xff;
  p[4] = (x >> 32) & 0xff;
  p[5] = (x >> 40) & 0xff;
  p[6] = (x >> 48) & 0xff;
  p[7] = (x >> 56) & 0xff;
}

static void inline
lendian_enc64_buf(unsigned char *to, uint64_t *from, size_t length)
{
  uint64_t *from_ptr;
  unsigned char *to_ptr;
  size_t nleft;

  to_ptr = to;
  from_ptr = from;
  nleft = length;

  while (nleft) {
    if (nleft >= sizeof(uint64_t)) {
      lendian_enc64(to_ptr, *from_ptr);
      to_ptr += sizeof(uint64_t);
      from_ptr++;
      nleft -= sizeof(uint64_t);
    }
    else if (nleft >= sizeof(uint32_t)) {
      uint32_t *from_ptr32 = (uint32_t *) from_ptr;

      lendian_enc32(to_ptr, *from_ptr32);
      to_ptr += sizeof(uint32_t);
      from_ptr32++;
      nleft -= sizeof(uint32_t);
    }
    else {
      fprintf(stderr, "Bug: unexpected copy remainder\n");
      abort();
    }
  }
}

static inline int
is_name_match_sep(int ch)
{

  return(strchr("-_/", ch) != NULL);
}

/*
 * The DIGEST_NAME is case-insensitive and may use an underscore or slash
 * instead of a hyphen as a separator character.  When matching DIGEST_NAME
 * against a canonical name, hyphens are ignored, except that more than one
 * consecutive separator is disallowed and a hyphen may not be elided if doing
 * so would conflate two digits.  A leading or trailing separator is disallowed.
 * (e.g., "Sha224" matches "sha-224", "sha512t" matches "sha-512-t",
 * and "SHA_512_224" matches "sha-512-224", but "sha3224" is invalid for
 * "sha3-224", as is "sha3--224".
 *
 * Return 1 if DD matches DIGEST_NAME, 0 otherwise.
 */
static int
digest_name_match(Digest_tab *dt, const char *digest_name)
{
  int desc_dn_prev, dn_prev;
  const char *dn, *desc_dn;

  if (strcaseeq(digest_name, dt->name))
	return(1);

  desc_dn = dt->name;
  desc_dn_prev = 0;

  dn = digest_name;
  dn_prev = 0;

  while (1) {
	if ((*dn == *desc_dn) && (*dn == '\0'))
	  return(1);

	if (tolower((int) *dn) == tolower((int) *desc_dn)) {
	  desc_dn_prev = *desc_dn;
	  dn_prev = *dn;
	  desc_dn++;
	}
	else if (is_name_match_sep((int) *dn) && *desc_dn == '-') {
	  desc_dn_prev = 0;
	  dn_prev = 0;
	  desc_dn++;
	}	else if (*desc_dn == '-' && desc_dn_prev != 0
			 && tolower((int) *(desc_dn + 1)) == tolower((int) *dn)
			 && (!isdigit((int) desc_dn_prev) || !isdigit((int) *dn))) {
	  desc_dn_prev = 0;
	  dn_prev = 0;
	  desc_dn += 2;
	}
	else if (is_name_match_sep((int) *dn) && dn_prev != 0
			 && !is_name_match_sep((int) dn_prev)
			 && (tolower((int) *(dn + 1)) == tolower((int) *desc_dn))
			 && (!isdigit((int) dn_prev) || !isdigit((int) *desc_dn))) {
	  desc_dn_prev = 0;
	  dn_prev = 0;
	  desc_dn++;
	  dn++;
	}
	else
	  break;

	dn++;
  }

  return(0);
}

/*
 * Return the digest descriptor for DIGEST_NAME, or NULL if it is not found.
 */
Digest_tab *
sha3_lookup_digest_by_name(const char *digest_name)
{
  Digest_tab *dt;

  for (dt = &digest_tab[0]; dt->name != NULL; dt++) {
	if (digest_name_match(dt, digest_name))
	  return(dt);
  }

  return(NULL);
}

/*
 * Return the digest descriptor for ALG, or NULL if it is not found.
 */
Digest_tab *
sha3_lookup_digest_by_algorithm(Digest_alg alg)
{
  Digest_tab *dt;

  for (dt = &digest_tab[0]; dt->name != NULL; dt++) {
	if (dt->alg == alg)
	  return(dt);
  }

  return(NULL);
}

/*
 * Return the digest size (in bytes) for DIGEST_NAME, or 0 if it is not found.
 */
unsigned int
sha3_lookup_digest_size(const char *digest_name)
{
  Digest_tab *dt;

  if ((dt = sha3_lookup_digest_by_name(digest_name)) == NULL)
	return(0);

  return(dt->digest_size);
}

/*
 * Initialize a context for digest size of BITS bits.
 */
static void
keccak_init(SHA3_ctx *ctx, unsigned int nbits)
{
  unsigned int rate;

  rate = 1600 - nbits * 2;
  if (rate > 1600 || (rate % 64) != 0) {
	log_msg((LOG_ERROR_LEVEL, "Bug: invalid rate"));
	abort();
  }

  ctx->rate = rate;
  ctx->block_size = rate / 8;
  ctx->digest_bits = nbits;
  ctx->rest = 0;
  ctx->bit_padding = 0;

  memset(ctx->hash, 0, sizeof(ctx->hash));
  memset(ctx->message, 0, sizeof(ctx->message));
}

static SHA3_ctx *
do_sha3_init(Digest_tab *dt, SHA3_ctx *octx, unsigned int *digest_size)
{
  SHA3_ctx *ctx;

  ctx = (octx == NULL) ? ALLOC(SHA3_ctx) : octx;

  ctx->dt = dt;

  keccak_init(ctx, dt->digest_size * 8);

  if (digest_size != NULL)
	*digest_size = dt->digest_size;

  return(ctx);
}

SHA3_ctx *
sha3_init(Digest_alg alg, SHA3_ctx *octx, unsigned int *digest_size)
{
  Digest_tab *dt;

  if ((dt = sha3_lookup_digest_by_algorithm(alg)) == NULL)
	return(NULL);

  return(do_sha3_init(dt, octx, digest_size));
}

SHA3_ctx *
sha3_init_by_name(const char *digest_name, SHA3_ctx *octx,
				  unsigned int *digest_size)
{
  Digest_tab *dt;

  if ((dt = sha3_lookup_digest_by_name(digest_name)) == NULL)
	return(NULL);

  return(do_sha3_init(dt, octx, digest_size));
}

/* Keccak theta() transformation */
static void
keccak_theta(uint64_t *A)
{
  unsigned int x;
  uint64_t C[5], D[5];

  for (x = 0; x < 5; x++)
	C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];

  D[0] = ROTL64(C[1], 1) ^ C[4];
  D[1] = ROTL64(C[2], 1) ^ C[0];
  D[2] = ROTL64(C[3], 1) ^ C[1];
  D[3] = ROTL64(C[4], 1) ^ C[2];
  D[4] = ROTL64(C[0], 1) ^ C[3];

  for (x = 0; x < 5; x++) {
	A[x]      ^= D[x];
	A[x + 5]  ^= D[x];
	A[x + 10] ^= D[x];
	A[x + 15] ^= D[x];
	A[x + 20] ^= D[x];
  }
}

/* Keccak pi() transformation */
static void
keccak_pi(uint64_t *A)
{
  uint64_t A1;

  A1 = A[1];
  A[ 1] = A[ 6];
  A[ 6] = A[ 9];
  A[ 9] = A[22];
  A[22] = A[14];
  A[14] = A[20];
  A[20] = A[ 2];
  A[ 2] = A[12];
  A[12] = A[13];
  A[13] = A[19];
  A[19] = A[23];
  A[23] = A[15];
  A[15] = A[ 4];
  A[ 4] = A[24];
  A[24] = A[21];
  A[21] = A[ 8];
  A[ 8] = A[16];
  A[16] = A[ 5];
  A[ 5] = A[ 3];
  A[ 3] = A[18];
  A[18] = A[17];
  A[17] = A[11];
  A[11] = A[ 7];
  A[ 7] = A[10];
  A[10] = A1;
  /* A[ 0] is left as is. */
}

/* Keccak chi() transformation */
static void
keccak_chi(uint64_t *A)
{
  int i;

  for (i = 0; i < 25; i += 5) {
	uint64_t A0 = A[0 + i], A1 = A[1 + i];

	A[0 + i] ^= ~A1 & A[2 + i];
	A[1 + i] ^= ~A[2 + i] & A[3 + i];
	A[2 + i] ^= ~A[3 + i] & A[4 + i];
	A[3 + i] ^= ~A[4 + i] & A0;
	A[4 + i] ^= ~A0 & A1;
  }
}

#ifdef NOTDEF
static Digest_ctx *
digest_make_ctx(Digest_tab *dt)
{
  Digest_ctx *ctx;

  ctx = ALLOC(Digest_ctx);
  ctx->dt = dt;

  keccak_init(&ctx->sha3_ctx, dt->digest_size * 8);

  return(ctx);
}
#endif

static void
sha3_permutation(uint64_t *state)
{
  int round;

  for (round = 0; round < SHA3_NUMBER_OF_ROUNDS; round++) {
	keccak_theta(state);

	/* Apply Keccak rho() transformation. */
	state[ 1] = ROTL64(state[ 1],  1);
	state[ 2] = ROTL64(state[ 2], 62);
	state[ 3] = ROTL64(state[ 3], 28);
	state[ 4] = ROTL64(state[ 4], 27);
	state[ 5] = ROTL64(state[ 5], 36);
	state[ 6] = ROTL64(state[ 6], 44);
	state[ 7] = ROTL64(state[ 7],  6);
	state[ 8] = ROTL64(state[ 8], 55);
	state[ 9] = ROTL64(state[ 9], 20);
	state[10] = ROTL64(state[10],  3);
	state[11] = ROTL64(state[11], 10);
	state[12] = ROTL64(state[12], 43);
	state[13] = ROTL64(state[13], 25);
	state[14] = ROTL64(state[14], 39);
	state[15] = ROTL64(state[15], 41);
	state[16] = ROTL64(state[16], 45);
	state[17] = ROTL64(state[17], 15);
	state[18] = ROTL64(state[18], 21);
	state[19] = ROTL64(state[19],  8);
	state[20] = ROTL64(state[20], 18);
	state[21] = ROTL64(state[21],  2);
	state[22] = ROTL64(state[22], 61);
	state[23] = ROTL64(state[23], 56);
	state[24] = ROTL64(state[24], 14);
		
	keccak_pi(state);
	keccak_chi(state);

	/* Apply iota(state, round). */
	*state ^= keccak_round_constants[round];
  }
}

/*
 * The core transformation: process the specified block of data using state HASH,
 * on message block BLOCK of BLOCK_SIZE bytes.
 */
static void
sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size)
{

  hash[ 0] ^= LE_DEC64(block[ 0]);
  hash[ 1] ^= LE_DEC64(block[ 1]);
  hash[ 2] ^= LE_DEC64(block[ 2]);
  hash[ 3] ^= LE_DEC64(block[ 3]);
  hash[ 4] ^= LE_DEC64(block[ 4]);
  hash[ 5] ^= LE_DEC64(block[ 5]);
  hash[ 6] ^= LE_DEC64(block[ 6]);
  hash[ 7] ^= LE_DEC64(block[ 7]);
  hash[ 8] ^= LE_DEC64(block[ 8]);

  /* If not SHA3-512. */
  if (block_size > 72) {
	hash[ 9] ^= LE_DEC64(block[ 9]);
	hash[10] ^= LE_DEC64(block[10]);
	hash[11] ^= LE_DEC64(block[11]);
	hash[12] ^= LE_DEC64(block[12]);

	/* If not SHA3-384. */
	if (block_size > 104) {
	  hash[13] ^= LE_DEC64(block[13]);
	  hash[14] ^= LE_DEC64(block[14]);
	  hash[15] ^= LE_DEC64(block[15]);
	  hash[16] ^= LE_DEC64(block[16]);

	  /* If not SHA3-256. */
	  if (block_size > 136) {
		hash[17] ^= LE_DEC64(block[17]);

#ifdef FULL_SHA3_FAMILY_SUPPORT
		/* If not SHA3-224. */
		if (block_size > 144) {
		  hash[18] ^= LE_DEC64(block[18]);
		  hash[19] ^= LE_DEC64(block[19]);
		  hash[20] ^= LE_DEC64(block[20]);
		  hash[21] ^= LE_DEC64(block[21]);
		  hash[22] ^= LE_DEC64(block[22]);
		  hash[23] ^= LE_DEC64(block[23]);
		  hash[24] ^= LE_DEC64(block[24]);
		}
#endif
	  }
	}
  }

  sha3_permutation(hash);
}

/*
 * Feed MSG (SIZE bytes long) to the hash function with context CTX.
 */
void
sha3_update(SHA3_ctx *ctx, const unsigned char *msg, size_t size)
{
  size_t block_size, index;

  if (ctx->rest & (SHA3_FINALIZED | SHA3_MUST_FINALIZE))
	return;

  index = (size_t) ctx->rest;
  block_size = (size_t) ctx->block_size;

  ctx->rest = (unsigned int) ((ctx->rest + size) % block_size);

  if (index) {
	size_t left = block_size - index;

	/* Add MSG to the partial block from the previous call. */
	memcpy((char *) ctx->message + index, msg, (size < left) ? size : left);

	/* If the block is still incomplete, we're done for now. */
	if (size < left)
	  return;

	/* Process the completed block. */
	sha3_process_block(ctx->hash, ctx->message, block_size);
	msg  += left;
	size -= left;
  }

  /* Process as many complete blocks as possible. */
  while (size >= block_size) {
	uint64_t *aligned_message_block;

	if (IS_ALIGNED_64(msg)) {
	  /* The most common case: processing an aligned message without copying. */
	  aligned_message_block = (uint64_t *) msg;
	} else {
	  memcpy(ctx->message, msg, block_size);
	  aligned_message_block = ctx->message;
	}

	sha3_process_block(ctx->hash, aligned_message_block, block_size);
	msg  += block_size;
	size -= block_size;
  }

  if (size) {
	/* Save the remaining partial block. */
	memcpy(ctx->message, msg, size);
  }
}

void
sha3_update_bits(SHA3_ctx *ctx, const unsigned char *msg, unsigned int nbits)
{
  unsigned int nbytes;

  if (ctx->rest & (SHA3_FINALIZED | SHA3_MUST_FINALIZE))
	return;

  nbytes = (nbits + 7) / 8;
  sha3_update(ctx, msg, nbytes);

  if ((nbits % 8) != 0) {
	/* Only the final update may not be a multiple of 8 bits. */
	ctx->bit_padding = 8 - ((nbytes * 8) - nbits);
	ctx->rest |= SHA3_MUST_FINALIZE;
  }
}

/*
 * Store the final hash value into RESULT, which is assumed to be large enough.
 */
void
sha3_final(SHA3_ctx *ctx, unsigned char *result)
{
  size_t block_size, digest_length;

  digest_length = 100 - ctx->block_size / 2;		/* in bytes */
  block_size = ctx->block_size;						/* in bytes */

  if (! (ctx->rest & SHA3_FINALIZED)) {
	ctx->rest &= (~SHA3_MUST_FINALIZE);

	/* Zero anything that follows the partial block in the buffer. */
	memset((char *) ctx->message + ctx->rest, 0, block_size - ctx->rest);

	/* Domain separation bits added in FIPS 202, May, 2014 draft document. */
#ifdef ORIG
	((char *) ctx->message)[ctx->rest] |= 0x06;
#else
	/* Padding is needed if the message length is not a multiple of 8. */
	if (ctx->bit_padding == 6) {
	  ((char *) ctx->message)[ctx->rest - 1] |= 0x80;
	  ((char *) ctx->message)[ctx->rest] |= 0x01;
	}
	else if (ctx->bit_padding == 7)
	  ((char *) ctx->message)[ctx->rest] |= 0x03;
	else if (ctx->bit_padding)
	  ((char *) ctx->message)[ctx->rest - 1] |= (0x06 << ctx->bit_padding);
	else
	  ((char *) ctx->message)[ctx->rest] |= 0x06;
#endif

	((char *) ctx->message)[block_size - 1] |= 0x80;

	/* Process the final block. */
	sha3_process_block(ctx->hash, ctx->message, block_size);
	ctx->rest = SHA3_FINALIZED;
  }

  if (block_size <= digest_length) {
	log_msg((LOG_ERROR_LEVEL, "Bug: invalid block_size"));
	abort();
  }

  if (result)
	lendian_enc64_buf(result, ctx->hash, digest_length);
}

int
sha3(Digest_alg alg, const unsigned char *msg, int msglen,
	 unsigned char *result, unsigned int *digest_size)
{
  size_t size;
  SHA3_ctx ctx;

  if (sha3_init(alg, &ctx, digest_size) == NULL)
	return(-1);

  if (msglen < 0)
    size = strlen((const char *) msg);
  else
    size = (size_t) msglen;

  sha3_update(&ctx, msg, size);

  sha3_final(&ctx, result);

  return(0);
}

int
sha3_by_name(const char *digest_name, const unsigned char *msg, int msglen,
			 unsigned char *result, unsigned int *digest_size)
{
  size_t size;
  SHA3_ctx ctx;

  if (sha3_init_by_name(digest_name, &ctx, digest_size) == NULL)
	return(-1);

  if (msglen < 0)
    size = strlen((const char *) msg);
  else
    size = (size_t) msglen;

  sha3_update(&ctx, msg, size);

  sha3_final(&ctx, result);

  return(0);
}

int
sha3_bits(Digest_alg alg, const unsigned char *msg, unsigned int nbits,
		  unsigned char *result, unsigned int *digest_size)
{
  SHA3_ctx ctx;

  if (sha3_init(alg, &ctx, digest_size) == NULL)
	return(-1);

  sha3_update_bits(&ctx, msg, nbits);

  sha3_final(&ctx, result);

  return(0);
}

void
sha3_224(const unsigned char *msg, int msglen, unsigned char *result)
{

  sha3(DIGEST_SHA3_224, msg, msglen, result, NULL);
}

void
sha3_256(const unsigned char *msg, int msglen, unsigned char *result)
{

  sha3(DIGEST_SHA3_256, msg, msglen, result, NULL);
}

void
sha3_384(const unsigned char *msg, int msglen, unsigned char *result)
{

  sha3(DIGEST_SHA3_384, msg, msglen, result, NULL);
}

void
sha3_512(const unsigned char *msg, int msglen, unsigned char *result)
{

  sha3(DIGEST_SHA3_512, msg, msglen, result, NULL);
}

#ifdef TEST
/*
 * NIST FIPS 202 SHA-3 bit-length message tests
 * http://csrc.nist.gov/groups/ST/toolkit/examples.html
 * The zero-length tests are included in the other set.
 *
 * Originally, none of the 1605-bit test vectors matched the published values.
 * Others reported this.  At some point the published values were corrected
 * and now all agree with these tests.
 */
static const char *sha3_bit_tests[] = {
  /* SHA3-{224,256,384,512}_Msg5 */
  "ffbad5da96bad71789330206dc6768ecaeb1b32dca6b3301489674ab",
  "7b0047cf5a456882363cbf0fb05322cf65f4b7059a46365e830132e3b5d957af",
  "737c9b491885e9bf7428e792741a7bf8dca9653471c3e148473f2c236b6a0a6455eb1dce9f779b4b6b237fef171b1c64",
  "a13e01494114c09800622a70288c432121ce70039d753cadd2e006e4d961cb27544c1481e5814bdceb53be6733d5e099795e5e81918addb058e22a9f24883f37",

  /* SHA3-{224,256,384,512}_Msg30 */
  "d666a514cc9dba25ac1ba69ed3930460deaac9851b5f0baab007df3b",
  "c8242fef409e5ae9d1f1c857ae4dc624b92b19809f62aa8c07411c54a078b1d0",
  "955b4dd1be03261bd76f807a7efd432435c417362811b8a50c564e7ee9585e1ac7626dde2fdc030f876196ea267f08c3",
  "9834c05a11e1c5d3da9c740e1c106d9e590a0e530b6f6aaa7830525d075ca5db1bd8a6aa981a28613ac334934a01823cd45f45e49b6d7e6917f2f16778067bab",

  /* SHA3-{224,256,384,512}_Msg1600 */
  "9376816aba503f72f96ce7eb65ac095deee3be4bf9bbc2a1cb7e11e0",
  "79f38adec5c20307a98ef76e8324afbfd46cfd81b22e3973c65fa1bd9de31787",
  "1881de2ca7e41ef95dc4732b8f5f002b189cc1e42b74168ed1732649ce1dbcdd76197a31fd55ee989f2d7050dd473e8f",
  "e76dfad22084a8b1467fcf2ffa58361bec7628edf5f3fdc0e4805dc48caeeca81b7c13c30adf52a3659584739a2df46be589c51ca1a4a8416df6545a1ce8ba00",

  /*
   * SHA3-{224,256,384,512}_Msg1605
   * Note: In the draft, the published vectors used E3 as the final padded byte
   * but they should have used C3.
   * This was corrected in the standard and the updated FIPS 202 example vectors.
   * https://groups.google.com/forum/#!topic/sci.crypt/kU5YMPdnB1s
   */
  "22d2f7bb0b173fd8c19686f9173166e3ee62738047d7eadd69efb228",
  "81ee769bed0950862b1ddded2e84aaa6ab7bfdd3ceaa471be31163d40336363c",
  "a31fdbd8d576551c21fb1191b54bda65b6c5fe97f0f4a69103424b43f7fdb835979fdbeae8b3fe16cb82e587381eb624",
  /* Published val=01541542D1B06EBF5A01BFA35955C5FFB87EC81E64BF1BB8BFEBDF84A6406CFDF9303319D64A2308B6AFF61702E539310F98BF77246E7F7D51CF0D0C01F46023 */
  "fc4a167ccb31a937d698fde82b04348c9539b28f0c9d3b4505709c03812350e4990e9622974f6e575c47861c0d2e638ccfc2023c365bb60a93f528550698786b",

  /* SHA3-{224,256,384,512}_Msg1630 */
  "4e907bb1057861f200a599e9d4f85b02d88453bf5b8ace9ac589134c",
  "52860aa301214c610d922a6b6cab981ccd06012e54ef689d744021e738b9ed20",
  "3485d3b280bd384cf4a777844e94678173055d1cbc40c7c2c3833d9ef12345172d6fcd31923bb8795ac81847d3d8855c",
  "cf9a30ac1f1f6ac0916f9fef1919c595debe2ee80c85421210fdf05f1c6af73aa9cac881d0f91db6d034a2bbadc1cf7fbcb2ecfa9d191d3a5016fb3fad8709c9",

  NULL
}; 

static char *
to_hex(unsigned char *value, size_t nbytes)
{
  int i;
  char *p;
  unsigned char *v;
  static char buf[512];

  v = value;
  p = buf;
  for (i = 0; i < nbytes; i++)
    p += sprintf(p, "%.2x", *v++ & 0xff);

  return(buf);
}

static int
do_sha3_bit_tests(void)
{
  int i, t, testnum;
  char *v;
  unsigned char msg[512];
  unsigned char result[512], result2[512];
  Digest_alg alg;
  SHA3_ctx ctx;

  fprintf(stderr, "\nSHA-3 bit vector tests\n");
  testnum = 0;
  for (t = 0; t < 5; t++) {
	int tbits;

	fprintf(stderr, "SHA-3 bit test vector %d:\n", t);
	switch (t) {
	case 0:
	  {
		/* Msg = 1100 1 */
		const unsigned char test_5bits[1] = { 0x13 };

		memcpy(msg, test_5bits, sizeof(test_5bits));
		tbits = 5;
		break;
	  }

	case 1:
	  {
		const unsigned char test_30bits[4] = { 0x53, 0x58, 0x7b, 0x19 };

		memcpy(msg, test_30bits, sizeof(test_30bits));
		tbits = 30;
		break;
	  }

	case 2:
	  memset(msg, 0xa3, 200);
	  tbits = 1600;
	  break;

	case 3:
	  memset(msg, 0xa3, 200);
	  msg[200] = 0x03;
	  tbits = 1605;
	  break;

	case 4:
	  memset(msg, 0xa3, 203);
	  msg[203] = 0x23;
	  tbits = 1630;
	  break;
	}

	for (i = 0; i < 4; i++) {
	  int bits;

	  switch (i % 4) {
	  case 0:
		sha3_init(DIGEST_SHA3_224, &ctx, NULL);
		bits = 224;
		alg = DIGEST_SHA3_224;
		break;

	  case 1:
		sha3_init(DIGEST_SHA3_256, &ctx, NULL);
		bits = 256;
		alg = DIGEST_SHA3_256;
		break;

	  case 2:
		sha3_init(DIGEST_SHA3_384, &ctx, NULL);
		bits = 384;
		alg = DIGEST_SHA3_384;
		break;

	  case 3:
		sha3_init(DIGEST_SHA3_512, &ctx, NULL);
		bits = 512;
		alg = DIGEST_SHA3_512;
		break;
	  }

	  sha3_update_bits(&ctx, msg, tbits);
	  sha3_final(&ctx, result);

	  v = to_hex(result, bits / 8);
	  fprintf(stderr, "%2d. %s ", testnum, v);
	  if (strcmp(v, sha3_bit_tests[testnum])) {
		fprintf(stderr, "  Failed!\n");
		return(-1);
	  }

	  /* Test an alternate API. */
	  sha3_bits(alg, msg, tbits, result2, NULL);
	  if (memcmp(result, result2, bits / 8)) {
		fprintf(stderr, "  Failed!\n");
		return(-1);
	  }
	  fprintf(stderr, " ok\n");
	  testnum++;
	}
  }

  return(0);
}

typedef struct SHA3_test {
  Digest_alg alg;
  char *msg;
  char *digest_value;
} SHA3_test;

/*
 * Test vectors - see:
 * http://cpansearch.perl.org/src/RHASH/Crypt-RHash-0.91/librhash/test_hashes.c
 * http://www.di-mgt.com.au/sha_testvectors.html
 */

static SHA3_test sha3_tests[] = {
  { DIGEST_SHA3_224, "",
	"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7" },
  { DIGEST_SHA3_256, "",
	"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" },
  { DIGEST_SHA3_384, "",
	"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004" },
  { DIGEST_SHA3_512, "",
	"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26" },

  { DIGEST_SHA3_224, "abc",
	"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf" },
  { DIGEST_SHA3_256, "abc",
	"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" },
  { DIGEST_SHA3_384, "abc",
	"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25" },
  { DIGEST_SHA3_512, "abc", 
	"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0" },

  { DIGEST_SHA3_224, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33" },
  { DIGEST_SHA3_256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376" },
  { DIGEST_SHA3_384, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22" },
  { DIGEST_SHA3_512, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e" },

  { DIGEST_SHA3_224, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
	"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc" },
  { DIGEST_SHA3_256, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
	"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18" },
  { DIGEST_SHA3_384, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
	"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7" },
  { DIGEST_SHA3_512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
	"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185" },

  { DIGEST_NONE, NULL, NULL }
};

static int
test_1M_a(void)
{
  unsigned int digest_size;
  unsigned char a[1000000];
  char *v;
  unsigned char result[512];

  memset(a, (int) 'a', sizeof(a));

  sha3(DIGEST_SHA3_224, (unsigned char *) a, sizeof(a), result, &digest_size);
  fprintf(stderr, "SHA3-224(<1Ma>):\n  ");
  v = to_hex(result, digest_size);
  fprintf(stderr, "%s", v);
#define DIGEST_VALUE_224	"d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c"
  if (strcmp(v, DIGEST_VALUE_224)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "\n");

  sha3(DIGEST_SHA3_256, (unsigned char *) a, sizeof(a), result, &digest_size);
  fprintf(stderr, "SHA3-256(<1Ma>):\n  ");
  v = to_hex(result, digest_size);
  fprintf(stderr, "%s", v);
#define DIGEST_VALUE_256	"5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1"
  if (strcmp(v, DIGEST_VALUE_256)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "\n");

  sha3(DIGEST_SHA3_384, (unsigned char *) a, sizeof(a), result, &digest_size);
  fprintf(stderr, "SHA3-384(<1Ma>):\n  ");
  v = to_hex(result, digest_size);
  fprintf(stderr, "%s", v);
#define DIGEST_VALUE_384	"eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e76847aa0774ddb90a842190d2c558b4b8340"
  if (strcmp(v, DIGEST_VALUE_384)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "\n");

  sha3(DIGEST_SHA3_512, (unsigned char *) a, sizeof(a), result, &digest_size);
  fprintf(stderr, "SHA3-512(<1Ma>):\n  ");
  v = to_hex(result, digest_size);
  fprintf(stderr, "%s", v);
#define DIGEST_VALUE_512	"3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87"
  if (strcmp(v, DIGEST_VALUE_512)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "\n");

  return(0);

#undef DIGEST_VALUE_224
#undef DIGEST_VALUE_256
#undef DIGEST_VALUE_384
#undef DIGEST_VALUE_512
}

static void
do_big_repeat(SHA3_ctx *ctx, char *msg, size_t msglen, unsigned char *result)
{
  int i;

  for (i = 1; i <= 16777216; i++) {
	sha3_update(ctx, (unsigned char *) msg, msglen);
	if ((i % 1000000) == 0)
	  fprintf(stderr, ".");
  }
  fprintf(stderr, "\n");

  sha3_final(ctx, result);
}

static int
test_big_repeat(void)
{
  char *v;
  size_t msglen;
  unsigned char result[512];
  SHA3_ctx ctx;

#define MSG	"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"
  msglen = strlen(MSG);

  sha3_init(DIGEST_SHA3_224, &ctx, NULL);
  fprintf(stderr, "SHA3-224(<BigRepeat>): ");
  do_big_repeat(&ctx, MSG, msglen, result);
  v = to_hex(result, sha3_lookup_digest_size("SHA3_224"));
  fprintf(stderr, "%s ", v);
#define DIGEST_VALUE_224	"c6d66e77ae289566afb2ce39277752d6da2a3c46010f1e0a0970ff60"
  if (strcmp(v, DIGEST_VALUE_224)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "ok\n");

  sha3_init(DIGEST_SHA3_256, &ctx, NULL);
  fprintf(stderr, "SHA3-256(<BigRepeat>): ");
  do_big_repeat(&ctx, MSG, msglen, result);
  v = to_hex(result, sha3_lookup_digest_size("SHA3_256"));
  fprintf(stderr, "%s ", v);
#define DIGEST_VALUE_256	"ecbbc42cbf296603acb2c6bc0410ef4378bafb24b710357f12df607758b33e2b"
  if (strcmp(v, DIGEST_VALUE_256)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "ok\n");

  sha3_init(DIGEST_SHA3_384, &ctx, NULL);
  fprintf(stderr, "SHA3-384(<BigRepeat>): ");
  do_big_repeat(&ctx, MSG, msglen, result);
  v = to_hex(result, sha3_lookup_digest_size("SHA3_384"));
  fprintf(stderr, "%s ", v);
#define DIGEST_VALUE_384	"a04296f4fcaae14871bb5ad33e28dcf69238b04204d9941b8782e816d014bcb7540e4af54f30d578f1a1ca2930847a12"
  if (strcmp(v, DIGEST_VALUE_384)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "ok\n");

  sha3_init(DIGEST_SHA3_512, &ctx, NULL);
  fprintf(stderr, "SHA3-512(<BigRepeat>): ");
  do_big_repeat(&ctx, MSG, msglen, result);
  v = to_hex(result, sha3_lookup_digest_size("SHA3_512"));
  fprintf(stderr, "%s ", v);
#define DIGEST_VALUE_512	"235ffd53504ef836a1342b488f483b396eabbfe642cf78ee0d31feec788b23d0d18d5c339550dd5958a500d4b95363da1b5fa18affc1bab2292dc63b7d85097c"
  if (strcmp(v, DIGEST_VALUE_512)) {
	fprintf(stderr, "FAILED\n");
	return(-1);
  }
  fprintf(stderr, "ok\n");

  return(0);

#undef MSG
#undef DIGEST_VALUE_224
#undef DIGEST_VALUE_256
#undef DIGEST_VALUE_384
#undef DIGEST_VALUE_512
}

static int
do_sha3_tests(void)
{
  int i;
  char *alg_name, *val;
  unsigned int digest_size;
  unsigned char result[512];
  SHA3_test *t;

  digest_size = 0;
  for (i = 0, t = &sha3_tests[0]; t->msg != NULL; i++, t++) {
	sha3(t->alg, (unsigned char *) t->msg, -1, result, &digest_size);

	if (t->alg == DIGEST_SHA3_224)
	  alg_name = "SHA3-224";
	else if (t->alg == DIGEST_SHA3_256)
	  alg_name = "SHA3-256";
	else if (t->alg == DIGEST_SHA3_384)
	  alg_name = "SHA3-384";
	else if (t->alg == DIGEST_SHA3_512)
	  alg_name = "SHA3-512";
	else
	  return(-1);

	fprintf(stderr, "%2d. %s(\"%s\"):\n  ", i + 1, alg_name, t->msg);
	val = to_hex(result, digest_size);
	fprintf(stderr, "%s ", val);
	if (t->digest_value != NULL
		&& strcmp(t->digest_value, val)) {
	  fprintf(stderr, "  Failed!\n");
	  return(-1);
	}
	fprintf(stderr, " ok\n");
  }

  test_1M_a();

  test_big_repeat();

  return(0);
}

#include <unistd.h>

int
main(int argc, char **argv)
{
  char *a, *v;
  unsigned char buf[10240];
  unsigned char result[512];
  ssize_t n;
  SHA3_ctx ctx;

  if (argv[1] == NULL)
    exit(1);

  if (streq(argv[1], "test")) {
    fprintf(stderr, "Doing SHA3 tests:\n");
    if (do_sha3_tests() == -1)
      exit(1);
    if (do_sha3_bit_tests() == -1)
      exit(1);
      fprintf(stderr, "All SHA3 tests succeeded\n\n");

      exit(0);
   }

   if (streq(argv[1], "224")) {
     a = "SHA3-224";
     sha3_init(DIGEST_SHA3_224, &ctx, NULL);
   }
   else if (streq(argv[1], "256")) {
     a = "SHA3-256";
     sha3_init(DIGEST_SHA3_256, &ctx, NULL);
   }
   else if (streq(argv[1], "384")) {
     a = "SHA3-384";
     sha3_init(DIGEST_SHA3_384, &ctx, NULL);
   }
   else if (streq(argv[1], "512")) {
     a = "SHA3-512";
     sha3_init(DIGEST_SHA3_512, &ctx, NULL);
   }
   else
     exit(1);

   while (1) {
     n = read(0, buf, sizeof(buf));
     if (n <= 0)
       break;
     sha3_update(&ctx, buf, n);
   }

   sha3_final(&ctx, result);

   v = to_hex(result, sha3_lookup_digest_size(a));
   printf("%s\n", v);

   exit(0);
}
#endif
