Packages

libdecaf NIF for ECDH (X25519, X448), EdDSA (Ed25519, Ed25519ctx, Ed25519ph, Ed448, Ed448ph), curve25519, curve448, spongerng

Current section

Files

Jump to
libdecaf c_deps ed448goldilocks src spongerng.c
Raw

c_deps/ed448goldilocks/src/spongerng.c

/**
* @cond internal
* @file spongerng.c
* @copyright
* Copyright (c) 2015-2017 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief Spongerng instances (STROBE removed)
* @warning The SpongeRNG code isn't stable. Future versions are likely to
* have different outputs. Of course, this only matters in deterministic mode.
*/
#if defined(_MSC_VER)
#define _CRT_RAND_S
#include <stdlib.h>
# include <io.h>
#include <BaseTsd.h>
#define open _open
#define read _read
#define close _close
typedef SSIZE_T ssize_t;
#else
# include <unistd.h>
#endif
#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "keccak_internal.h"
#include <decaf/spongerng.h>
/* to open and read from /dev/urandom */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/** Get entropy from a CPU, preferably in the form of RDRAND, but possibly instead from RDTSC. */
static void get_cpu_entropy(uint8_t *entropy, size_t len) {
# if (defined(__i386__) || defined(__x86_64__))
static char tested = 0, have_rdrand = 0;
if (!tested) {
uint32_t a,b,c,d;
#if defined(__i386__) && defined(__PIC__)
/* Don't clobber ebx. The compiler doesn't like when when __PIC__ */
__asm__("mov %%ebx, %[not_ebx]\n\t"
"cpuid\n\t"
"xchg %%ebx, %[not_ebx]" : "=a"(a), [not_ebx]"=r"(b), "=c"(c), "=d"(d) : "0"(1));
#elif defined(__x86_64__) && defined(__PIC__)
/* Don't clobber rbx. The compiler doesn't like when when __PIC__ */
uint64_t b64;
__asm__("mov %%rbx, %[not_rbx]\n\t"
"cpuid\n\t"
"xchg %%rbx, %[not_rbx]" : "=a"(a), [not_rbx]"=r"(b64), "=c"(c), "=d"(d) : "0"(1));
b = b64;
#else
__asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1));
#endif
(void)a; (void)b; (void)d;
have_rdrand = (c>>30)&1;
tested = 1;
}
if (have_rdrand) {
# if defined(__x86_64__)
uint64_t out, a=0, *eo = (uint64_t *)entropy;
# elif defined(__i386__)
uint32_t out, a=0, *eo = (uint32_t *)entropy;
#endif
len /= sizeof(out);
uint32_t tries;
for (tries = 100+len; tries && len; len--, eo++) {
for (a = 0; tries && !a; tries--) {
__asm__ __volatile__ ("rdrand %0\n\tsetc %%al" : "=r"(out), "+a"(a) :: "cc" );
}
*eo ^= out;
}
} else if (len>=8) {
#ifndef __has_builtin
#define __has_builtin(X) 0
#endif
#if defined(__clang__) && __has_builtin(__builtin_readcyclecounter)
*(uint64_t*) entropy ^= __builtin_readcyclecounter();
#elif defined(__x86_64__)
uint32_t lobits, hibits;
__asm__ __volatile__ ("rdtsc" : "=a"(lobits), "=d"(hibits));
*(uint64_t*) entropy ^= (lobits | ((uint64_t)(hibits) << 32));
#elif defined(__i386__)
uint64_t __value;
__asm__ __volatile__ ("rdtsc" : "=A"(__value));
*(uint64_t*) entropy ^= __value;
#endif
}
#else
(void) entropy;
(void) len;
#endif
}
void decaf_spongerng_next (
decaf_keccak_prng_t prng,
uint8_t * __restrict__ out,
size_t len
) {
if (prng->sponge->params->remaining) {
/* nondet */
uint8_t cpu_entropy[32] = {0};
get_cpu_entropy(cpu_entropy, sizeof(cpu_entropy));
decaf_spongerng_stir(prng,cpu_entropy,sizeof(cpu_entropy));
decaf_bzero(cpu_entropy,sizeof(cpu_entropy));
}
uint8_t lenx[8];
size_t len1 = len;
for (unsigned i=0; i<sizeof(lenx); i++) {
lenx[i] = (uint8_t)len1;
len1 >>= 8;
}
decaf_sha3_update(prng->sponge,lenx,sizeof(lenx));
decaf_sha3_output(prng->sponge,out,len);
const uint8_t nope;
decaf_spongerng_stir(prng,&nope,0);
}
void decaf_spongerng_stir (
decaf_keccak_prng_t prng,
const uint8_t * __restrict__ in,
size_t len
) {
uint8_t seed[32];
decaf_sha3_output(prng->sponge,seed,sizeof(seed));
uint8_t nondet = prng->sponge->params->remaining;
decaf_sha3_reset(prng->sponge);
decaf_sha3_update(prng->sponge,seed,sizeof(seed));
decaf_sha3_update(prng->sponge,in,len);
prng->sponge->params->remaining = nondet;
decaf_bzero(seed,sizeof(seed));
}
void decaf_spongerng_init_from_buffer (
decaf_keccak_prng_t prng,
const uint8_t * __restrict__ in,
size_t len,
int deterministic
) {
decaf_sha3_init(prng->sponge,&DECAF_SHAKE256_params_s);
prng->sponge->params->remaining = !deterministic; /* A bit of a hack; this param is ignored for SHAKE */
decaf_spongerng_stir(prng, in, len);
}
decaf_error_t decaf_spongerng_init_from_file (
decaf_keccak_prng_t prng,
const char *file,
size_t len,
int deterministic
) {
decaf_sha3_init(prng->sponge,&DECAF_SHAKE256_params_s);
prng->sponge->params->remaining = !deterministic; /* A bit of a hack; this param is ignored for SHAKE */
if (!len) return DECAF_FAILURE;
#if defined _MSC_VER
/* no /dev/urandom on windows, use rand_s instead */
if (strcmp(file, "/dev/urandom") == 0) {
unsigned int r;
uint8_t buffer[sizeof(unsigned int)];
errno_t err;
while (len) {
int i;
err = rand_s(&r);
if (err != 0) {
return DECAF_FAILURE;
}
for (i = 0; i < sizeof(unsigned int); i++) {
buffer[i] = (uint8_t)(r & 0xff);
r >>= 8;
}
size_t consumed = (len > sizeof(buffer)) ? sizeof(buffer) : len;
decaf_sha3_update(prng->sponge, buffer, consumed);
len -= consumed;
}
} else {
#endif /* _MSC_VER */
int fd = open(file, O_RDONLY);
if (fd < 0) return DECAF_FAILURE;
uint8_t buffer[128];
while (len) {
ssize_t red = read(fd, buffer, (len > sizeof(buffer)) ? sizeof(buffer) : (unsigned int)len);
if (red <= 0) {
close(fd);
return DECAF_FAILURE;
}
decaf_sha3_update(prng->sponge,buffer,red);
len -= red;
};
close(fd);
#if defined _MSC_VER
}
#endif /* _MSC_VER */
const uint8_t nope;
decaf_spongerng_stir(prng,&nope,0);
return DECAF_SUCCESS;
}
decaf_error_t decaf_spongerng_init_from_dev_urandom (
decaf_keccak_prng_t decaf_sponge
) {
return decaf_spongerng_init_from_file(decaf_sponge, "/dev/urandom", 64, 0);
}