Packages

Keccak-f[1600] asynchronous port driver

Current section

Files

Jump to
Raw

c_src/shake.c

// -*- mode: c; tab-width: 8; indent-tabs-mode: 1; st-rulers: [70] -*-
// vim: ts=8 sw=8 ft=c noet
/**
* @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.
*/
/**
* The MIT License (MIT)
*
* Copyright (c) 2011 Stanford University.
* Copyright (c) 2014 Cryptography Research, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */
#define _BSD_SOURCE 1 /* for endian */
#include <assert.h>
#include <stdint.h>
#include <string.h>
/* to open and read from /dev/urandom */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.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, client;
} kparams_t[1];
typedef struct keccak_sponge_s {
kdomain_t state;
kparams_t params;
} keccak_sponge_s, 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. */
#define REPEAT5(e) e e e e e
#define FOR51(v, e) v = 0; REPEAT5(e; v += 1;)
// #ifndef SHAKE_NO_UNROLL_LOOPS
// # 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
__attribute__((noinline))
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, FOR51(x, b[x] ^= a[x + y]; ))
FOR55(y, FOR51(x,
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, i;
uint8_t* state = &sponge->state->b[sponge->params->position];
if (cando > len) {
for (i = 0; i < len; i += 1) state[i] ^= in[i];
sponge->params->position += len;
return;
} else {
for (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) { decaf_bzero(sponge, sizeof(keccak_sponge_t)); }
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 };
#define DEFSHA3(n) \
const struct kparams_s SHA3_##n##_params_s = \
{ 0, FLAG_ABSORBING, 200-n/4, 0, 0x01, 0x80, n/8, 0 };
size_t sponge_default_output_bytes (
const keccak_sponge_t s
) {
return (s->params->maxOut == 0xFF)
? (200-s->params->rate)
: ((200-s->params->rate)/2);
}
DEFSHAKE(128)
DEFSHAKE(256)
DEFSHA3(224)
DEFSHA3(256)
DEFSHA3(384)
DEFSHA3(512)
/* FUTURE: Keyak instances, etc */