Commit f4c76b74 authored by Michael Hamburg's avatar Michael Hamburg

SHAKE and SHA3 instances (experimental) based on code from David Leon Gil. ...

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.
parent 994812cf
......@@ -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
......
/**
* @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__ */
/**
* @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 */
/**
* @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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment