Browse Source

SHAKE and SHA3 instances (experimental) based on code from David Leon Gil. Tested by hand but needs automatic KAT. I might also want to include Keyak or some similar duplex construction eventually.

master
Michael Hamburg 10 years ago
parent
commit
f4c76b7487
4 changed files with 451 additions and 1 deletions
  1. +4
    -1
      Makefile
  2. +132
    -0
      include/shake.h
  3. +252
    -0
      src/shake.c
  4. +63
    -0
      test/shakesum.c

+ 4
- 1
Makefile View File

@@ -76,7 +76,7 @@ BENCHCOMPONENTS=build/bench.o
BATBASE=ed448goldilocks-bats-$(TODAY)
BATNAME=build/$(BATBASE)

all: lib build/test build/bench
all: lib build/test build/bench build/shakesum

scan: clean
scan-build --use-analyzer=`which clang` \
@@ -89,6 +89,9 @@ build/bench: $(LIBCOMPONENTS) $(BENCHCOMPONENTS)

build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS)
$(LD) $(LDFLAGS) -o $@ $^ -lgmp
build/shakesum: build/shakesum.o build/shake.o
$(LD) $(LDFLAGS) -o $@ $^

lib: build/goldilocks.so



+ 132
- 0
include/shake.h View File

@@ -0,0 +1,132 @@
/**
* @file shake.h
* @copyright
* Based on CC0 code by David Leon Gil, 2015 \n
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief SHA-3-n and SHAKE-n instances.
* @warning EXPERIMENTAL! The names, parameter orders etc are likely to change.
*/

#ifndef __SHAKE_H__
#define __SHAKE_H__

#include <stdint.h>

#ifndef INTERNAL_SPONGE_STRUCT
typedef struct keccak_sponge_s {
uint64_t opaque[26];
} keccak_sponge_t[1];
struct kparams_s;
#endif

/**
* @brief Initialize a sponge context object.
* @param [out] sponge The object to initialize.
* @param [in] params The sponge's parameter description.
*/
void sponge_init (
keccak_sponge_t sponge,
const struct kparams_s *params
);

/**
* @brief Absorb data into a SHA3 or SHAKE hash context.
* @param [inout] sponge The context.
* @param [in] in The input data.
* @param [in] len The input data's length in bytes.
*/
void sha3_update (
struct keccak_sponge_s * __restrict__ sponge,
const uint8_t *in,
size_t len
);

/**
* @brief Squeeze output data from a SHA3 or SHAKE hash context.
* This does not destroy or re-initialize the hash context, and
* sha3 output can be called more times.
*
* @param [inout] sponge The context.
* @param [out] in The output data.
* @param [in] len The requested output data length in bytes.
*/
void sha3_output (
keccak_sponge_t sponge,
uint8_t * __restrict__ out,
size_t len
);

/**
* @brief Destroy a SHA3 or SHAKE sponge context by overwriting it with 0.
* @param [out] sponge The context.
*/
void sponge_destroy (
keccak_sponge_t sponge
);


/**
* @brief Hash (in) to (out)
* @param [in] in The input data.
* @param [in] inlen The length of the input data.
* @param [out] out A buffer for the output data.
* @param [in] outlen The length of the output data.
*/
void sponge_hash (
const uint8_t *in,
size_t inlen,
uint8_t *out,
size_t outlen,
const struct kparams_s *params
);

/* TODO: expand/doxygenate individual SHAKE/SHA3 instances? */

#define DECSHAKE(n) \
extern const struct kparams_s *SHAKE##n##_params; \
static inline void shake##n##_init(keccak_sponge_t sponge) { \
sponge_init(sponge, SHAKE##n##_params); \
} \
static inline void shake##n##_update(keccak_sponge_t sponge, const uint8_t *in, size_t inlen ) { \
sha3_update(sponge, in, inlen); \
} \
static inline void shake##n##_final(keccak_sponge_t sponge, uint8_t *out, size_t outlen ) { \
sha3_output(sponge, out, outlen); \
sponge_init(sponge, SHAKE##n##_params); \
} \
static inline void shake##n##_hash(const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen ) { \
sponge_hash(in,inlen,out,outlen,SHAKE##n##_params); \
} \
static inline void shake##n##_destroy( keccak_sponge_t sponge ) { \
sponge_destroy(sponge); \
}
#define DECSHA3(n) \
extern const struct kparams_s *SHA3_##n##_params; \
static inline void sha3_##n##_init(keccak_sponge_t sponge) { \
sponge_init(sponge, SHA3_##n##_params); \
} \
static inline void sha3_##n##_update(keccak_sponge_t sponge, const uint8_t *in, size_t inlen ) { \
sha3_update(sponge, in, inlen); \
} \
static inline void sha3_##n##_final(keccak_sponge_t sponge, uint8_t *out, size_t outlen ) { \
sha3_output(sponge, out, outlen); \
sponge_init(sponge, SHA3_##n##_params); \
} \
static inline void sha3_##n##_hash(const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen ) { \
sponge_hash(in,inlen,out,outlen,SHA3_##n##_params); \
} \
static inline void sha3_##n##_destroy( keccak_sponge_t sponge ) { \
sponge_destroy(sponge); \
}

DECSHAKE(128)
DECSHAKE(256)
DECSHA3(224)
DECSHA3(256)
DECSHA3(384)
DECSHA3(512)
#endif /* __SHAKE_H__ */

+ 252
- 0
src/shake.c View File

@@ -0,0 +1,252 @@
/**
* @cond internal
* @file shake.c
* @copyright
* Uses public domain code by Mathias Panzenböck \n
* Uses CC0 code by David Leon Gil, 2015 \n
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief SHA-3-n and SHAKE-n instances.
* @warning EXPERIMENTAL! The names, parameter orders etc are likely to change.
*/

#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */
#include <assert.h>
#include <stdint.h>
#include <string.h>

/* Subset of Mathias Panzenböck's portable endian code, public domain */
#if defined(__linux__) || defined(__CYGWIN__)
# include <endian.h>
#elif defined(__OpenBSD__)
# include <sys/endian.h>
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define htole64(x) OSSwapHostToLittleInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
# define le64toh(x) letoh64(x)
#elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
# include <winsock2.h>
# include <sys/param.h>
# if BYTE_ORDER == LITTLE_ENDIAN
# define htole64(x) (x)
# define le64toh(x) (x)
# elif BYTE_ORDER == BIG_ENDIAN
# define htole64(x) __builtin_bswap64(x)
# define le64toh(x) __builtin_bswap64(x)
# else
# error byte order not supported
# endif
#else
# error platform not supported
#endif

/* The internal, non-opaque definition of the sponge struct. */
typedef union {
uint64_t w[25]; uint8_t b[25*8];
} kdomain_t[1];

typedef struct kparams_s {
uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, _;
} kparams_t[1];

typedef struct keccak_sponge_s {
kdomain_t state;
kparams_t params;
} keccak_sponge_t[1];

#define INTERNAL_SPONGE_STRUCT 1
#include "shake.h"

#define FLAG_ABSORBING 'A'
#define FLAG_SQUEEZING 'Z'

/** Constants. **/
static const uint8_t pi[24] = {
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
};

#define RC_B(x,n) ((((x##ull)>>n)&1)<<((1<<n)-1))
#define RC_X(x) (RC_B(x,0)|RC_B(x,1)|RC_B(x,2)|RC_B(x,3)|RC_B(x,4)|RC_B(x,5)|RC_B(x,6))
static const uint64_t RC[24] = {
RC_X(0x01), RC_X(0x1a), RC_X(0x5e), RC_X(0x70), RC_X(0x1f), RC_X(0x21),
RC_X(0x79), RC_X(0x55), RC_X(0x0e), RC_X(0x0c), RC_X(0x35), RC_X(0x26),
RC_X(0x3f), RC_X(0x4f), RC_X(0x5d), RC_X(0x53), RC_X(0x52), RC_X(0x48),
RC_X(0x16), RC_X(0x66), RC_X(0x79), RC_X(0x58), RC_X(0x21), RC_X(0x74)
};

static inline uint64_t rol(uint64_t x, int s) {
return (x << s) | (x >> (64 - s));
}

/* Helper macros to unroll the permutation. TODO: opt tradeoffs. */
#define REPEAT5(e) e e e e e
#define FOR51(v, e) v = 0; REPEAT5(e; v += 1;)
#if (defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__))
# define FOR55(v, e) v = 0; REPEAT5(e; v += 5;)
# define REPEAT24(e) e e e e e e e e e e e e e e e e e e e e e e e e
#else
# define FOR55(v, e) for (v=0; v<25; v+= 5) { e; }
# define REPEAT24(e) {int _j=0; for (_j=0; _j<24; _j++) { e }}
#endif

/*** The Keccak-f[1600] permutation ***/
static void keccakf(kdomain_t state, uint8_t startRound) {
uint64_t* a = state->w;
uint64_t b[5] = {0}, t, u;
uint8_t x, y, i;
for (i=0; i<25; i++) a[i] = le64toh(a[i]);

for (i = startRound; i < 24; i++) {
FOR51(x, b[x] = 0; FOR55(y, b[x] ^= a[x + y];))
FOR51(x, FOR55(y,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1);
))
// Rho and pi
t = a[1];
x = y = 0;
REPEAT24(u = a[pi[x]]; y += x+1; a[pi[x]] = rol(t, y % 64); t = u; x++; )
// Chi
FOR55(y,
FOR51(x, b[x] = a[y + x];)
FOR51(x, a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]);)
)
// Iota
a[0] ^= RC[i];
}

for (i=0; i<25; i++) a[i] = htole64(a[i]);
}

static inline void dokeccak (keccak_sponge_t sponge) {
keccakf(sponge->state, sponge->params->startRound);
sponge->params->position = 0;
}

void sha3_update (
struct keccak_sponge_s * __restrict__ sponge,
const uint8_t *in,
size_t len
) {
if (!len) return;
assert(sponge->params->position < sponge->params->rate);
assert(sponge->params->rate < sizeof(sponge->state));
assert(sponge->params->flags == FLAG_ABSORBING);
while (len) {
size_t cando = sponge->params->rate - sponge->params->position;
uint8_t* state = &sponge->state->b[sponge->params->position];
if (cando > len) {
for (size_t i = 0; i < len; i += 1) state[i] ^= in[i];
sponge->params->position += len;
return;
} else {
for (size_t i = 0; i < cando; i += 1) state[i] ^= in[i];
dokeccak(sponge);
len -= cando;
in += cando;
}
}
}

void sha3_output (
keccak_sponge_t sponge,
uint8_t * __restrict__ out,
size_t len
) {
assert(sponge->params->position < sponge->params->rate);
assert(sponge->params->rate < sizeof(sponge->state));
if (sponge->params->maxOut != 0xFF) {
assert(sponge->params->maxOut >= len);
sponge->params->maxOut -= len;
}
switch (sponge->params->flags) {
case FLAG_SQUEEZING: break;
case FLAG_ABSORBING:
{
uint8_t* state = sponge->state->b;
state[sponge->params->position] ^= sponge->params->pad;
state[sponge->params->rate - 1] ^= sponge->params->ratePad;
dokeccak(sponge);
break;
}
default:
assert(0);
}
while (len) {
size_t cando = sponge->params->rate - sponge->params->position;
uint8_t* state = &sponge->state->b[sponge->params->position];
if (cando > len) {
memcpy(out, state, len);
sponge->params->position += len;
return;
} else {
memcpy(out, state, cando);
dokeccak(sponge);
len -= cando;
out += cando;
}
}
}

void sponge_destroy (
keccak_sponge_t sponge
) {
#ifdef __STDC_LIB_EXT1__
memset_s(sponge, sizeof(sponge), 0, sizeof(sponge));
#else
volatile uint64_t *destroy = (volatile uint64_t *)sponge;
unsigned i;
for (i=0; i<sizeof(keccak_sponge_t)/8; i++) {
destroy[i] = 0;
}
#endif
}

void sponge_init (
keccak_sponge_t sponge,
const struct kparams_s *params
) {
memset(sponge->state, 0, sizeof(sponge->state));
sponge->params[0] = params[0];
}

void sponge_hash (
const uint8_t *in,
size_t inlen,
uint8_t *out,
size_t outlen,
const struct kparams_s *params
) {
keccak_sponge_t sponge;
sponge_init(sponge, params);
sha3_update(sponge, in, inlen);
sha3_output(sponge, out, outlen);
sponge_destroy(sponge);
}

#define DEFSHAKE(n) \
const struct kparams_s SHAKE##n##_params_s = \
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x1f, 0x80, 0xFF, 0 }, \
*SHAKE##n##_params = &SHAKE##n##_params_s;
#define DEFSHA3(n) \
const struct kparams_s SHA3_##n##_params_s = \
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x06, 0x80, n/8, 0 }, \
*SHA3_##n##_params = &SHA3_##n##_params_s;

DEFSHAKE(128)
DEFSHAKE(256)
DEFSHA3(224)
DEFSHA3(256)
DEFSHA3(384)
DEFSHA3(512)

/* TODO: Keyak instances, etc */

+ 63
- 0
test/shakesum.c View File

@@ -0,0 +1,63 @@
/**
* @cond internal
* @file shakesum.c
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief SHA3 utility, to be combined with test vectors eventually...
*/

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "shake.h"

int main(int argc, char **argv) {
(void)argc; (void)argv;

keccak_sponge_t sponge;
unsigned char buf[1024];
unsigned int outlen = 512;
shake256_init(sponge);

/* Sloppy. Real utility would parse --algo, --size ... */
if (argc > 1) {
if (!strcmp(argv[1], "shake256") || !strcmp(argv[1], "SHAKE256")) {
outlen = 512;
shake256_init(sponge);
} else if (!strcmp(argv[1], "shake128") || !strcmp(argv[1], "SHAKE128")) {
outlen = 512;
shake128_init(sponge);
} else if (!strcmp(argv[1], "sha3-224") || !strcmp(argv[1], "SHA3-224")) {
outlen = 224/8;
sha3_224_init(sponge);
} else if (!strcmp(argv[1], "sha3-256") || !strcmp(argv[1], "SHA3-256")) {
outlen = 256/8;
sha3_256_init(sponge);
} else if (!strcmp(argv[1], "sha3-384") || !strcmp(argv[1], "SHA3-384")) {
outlen = 384/8;
sha3_384_init(sponge);
} else if (!strcmp(argv[1], "sha3-512") || !strcmp(argv[1], "SHA3-512")) {
outlen = 512/8;
sha3_512_init(sponge);
}
}

ssize_t red;
do {
red = read(0, buf, sizeof(buf));
if (red>0) sha3_update(sponge,buf,red);
} while (red>0);

sha3_output(sponge,buf,outlen);
sponge_destroy(sponge);
unsigned i;
for (i=0; i<outlen; i++) {
printf("%02x", buf[i]);
}
printf("\n");

return 0;
}

Loading…
Cancel
Save