1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-22 15:39:07 +00:00

Merge branch 'master' into make-dilithium

This commit is contained in:
Douglas Stebila 2019-02-08 10:02:24 -05:00
commit f1f0c1d332
8 changed files with 394 additions and 31 deletions

View File

@ -4,47 +4,58 @@ dist: xenial
matrix: matrix:
include: include:
- os: linux - name: "Linux + GCC + Linting + Metadata"
os: linux
compiler: gcc compiler: gcc
env: env:
- MAKETARGET="test-all tidy-all check-format check-metadata check-license-files" - MAKETARGET="test-all tidy-all check-format check-metadata check-license-files"
addons: addons:
apt: apt:
packages: packages:
- valgrind
- python3 - python3
- python3-setuptools - python3-yaml
- python3-pip - valgrind
- os: linux - name: "Linux + Clang"
os: linux
compiler: clang compiler: clang
env: env:
- MAKETARGET=test-all - MAKETARGET=test-all
addons: addons:
apt: apt:
packages: packages:
- valgrind
- python3 - python3
- python3-setuptools - python3-yaml
- python3-pip - valgrind
- os: osx - name: "Run tests on qemu-ppc"
os: linux
services: docker
env:
- MAKETARGET="run-functest-all run-testvectors-all run-sanitizer-all run-symbol-namespace-all"
script: # TODO: should we do this in a Dockerfile instead?
- docker run --rm --privileged multiarch/qemu-user-static:register --reset
- docker run --rm -v `pwd`:`pwd` -w `pwd` "twiggers/debian-sid-powerpc" /bin/bash -c "uname -a &&
make ${MAKETARGET}"
- name: "MacOS + Clang"
os: osx
osx_image: xcode10.1 osx_image: xcode10.1
compiler: clang compiler: clang
before_install:
- pip3 install -r requirements.txt
env: env:
- MAKETARGET=test-all - MAKETARGET=test-all
- os: osx - name: "MacOS + GCC8"
os: osx
osx_image: xcode10.1 osx_image: xcode10.1
compiler: gcc compiler: gcc
addons: addons:
homebrew: homebrew:
packages: packages:
- gcc@8 - gcc@8
before_install:
- pip3 install -r requirements.txt
env: env:
- MAKETARGET=test-all - MAKETARGET=test-all
before_install:
- python3 --version
- pip3 install -r requirements.txt
script: script:
- make ${MAKETARGET} - make ${MAKETARGET}

View File

@ -2,6 +2,8 @@
CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -g $(EXTRAFLAGS) CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -g $(EXTRAFLAGS)
ALL_SCHEMES=$(filter-out crypto_%.c, $(wildcard crypto_*/*)) ALL_SCHEMES=$(filter-out crypto_%.c, $(wildcard crypto_*/*))
COMMON_FILES = common/fips202.c common/sha2.c
RANDOM_IMPL = common/randombytes.c
default: help default: help
@ -19,8 +21,9 @@ bin/functest_$(subst /,_,$(SCHEME)): test/$(dir $(SCHEME))functest.c $(wildcard
-iquote "./common/" \ -iquote "./common/" \
-iquote "$(SCHEME)/clean/" \ -iquote "$(SCHEME)/clean/" \
-o bin/functest_$(subst /,_,$(SCHEME)) \ -o bin/functest_$(subst /,_,$(SCHEME)) \
common/*.c \
$(SCHEME)/clean/*.c \ $(SCHEME)/clean/*.c \
$(COMMON_FILES) \
$(RANDOM_IMPL) \
$< $<
.PHONY: functest .PHONY: functest
@ -45,7 +48,8 @@ bin/sanitizer_$(subst /,_,$(SCHEME)): test/$(dir $(SCHEME))functest.c $(wildcard
-iquote "./common/" \ -iquote "./common/" \
-iquote "$(SCHEME)/clean/" \ -iquote "$(SCHEME)/clean/" \
-o bin/sanitizer_$(subst /,_,$(SCHEME)) \ -o bin/sanitizer_$(subst /,_,$(SCHEME)) \
common/*.c \ $(COMMON_FILES) \
$(RANDOM_IMPL) \
$(SCHEME)/clean/*.c \ $(SCHEME)/clean/*.c \
$< $<
@ -59,7 +63,8 @@ bin/testvectors_$(subst /,_,$(SCHEME)): test/$(dir $(SCHEME))testvectors.c $(wil
-iquote "./common/" \ -iquote "./common/" \
-iquote "$(SCHEME)/clean/" \ -iquote "$(SCHEME)/clean/" \
-o bin/testvectors_$(subst /,_,$(SCHEME)) \ -o bin/testvectors_$(subst /,_,$(SCHEME)) \
common/*.c \ $(COMMON_FILES) \
common/notrandombytes.c \
$(SCHEME)/clean/*.c \ $(SCHEME)/clean/*.c \
$< $<

View File

@ -4,9 +4,9 @@
[![Build status](https://ci.appveyor.com/api/projects/status/186ky7yb9mlqj3io?svg=true)](https://ci.appveyor.com/project/PQClean/pqclean) [![Build status](https://ci.appveyor.com/api/projects/status/186ky7yb9mlqj3io?svg=true)](https://ci.appveyor.com/project/PQClean/pqclean)
**PQClean**, in short, is an effort to collect **clean** implementations of the post-quantum **PQClean**, in short, is an effort to collect **clean** implementations of the post-quantum
schemes that are in the schemes that are in the
[NIST post-quantum project](https://csrc.nist.gov/projects/post-quantum-cryptography). [NIST post-quantum project](https://csrc.nist.gov/projects/post-quantum-cryptography).
The goal of PQClean is to provide *standalone implementations* that The goal of PQClean is to provide *standalone implementations* that
* can easily be integrated into libraries such as [liboqs](https://openquantumsafe.org/#liboqs) or [libpqcrypto](https://libpqcrypto.org/); * can easily be integrated into libraries such as [liboqs](https://openquantumsafe.org/#liboqs) or [libpqcrypto](https://libpqcrypto.org/);
* can efficiently upstream into higher-level protocol integration efforts such as [Open Quantum Safe](https://openquantumsafe.org/#integrations); * can efficiently upstream into higher-level protocol integration efforts such as [Open Quantum Safe](https://openquantumsafe.org/#integrations);
@ -23,7 +23,7 @@ What PQClean is **not** aiming for is
* including integration into higher-level applications or protocols. * including integration into higher-level applications or protocols.
As a first main target, we are collecting C implementations that fulfill the requirements As a first main target, we are collecting C implementations that fulfill the requirements
listed below. listed below.
## Requirements on C implementations that are automatically checked ## Requirements on C implementations that are automatically checked
@ -77,7 +77,7 @@ _The checking of items on this list is still being developed. Checked items shou
## Clean C implementations currently in PQClean ## Clean C implementations currently in PQClean
Currently, the continuous-integration and testing environment of PQClean is still work in progress Currently, the continuous-integration and testing environment of PQClean is still work in progress
and as a consequence PQClean does not yet have many implementations. and as a consequence PQClean does not yet have many implementations.
<!-- <!--
@ -94,7 +94,7 @@ and as a consequence PQClean does not yet have many implementations.
## API used by PQClean ## API used by PQClean
PQClean is essentially using the same API as required for the NIST reference implementations, PQClean is essentially using the same API as required for the NIST reference implementations,
which is also used by SUPERCOP and by libpqcrypto. The only two differences to that API are which is also used by SUPERCOP and by libpqcrypto. The only two differences to that API are
the following: the following:
* All lengths are passed as type `size_t` instead of `unsigned long long`; and * All lengths are passed as type `size_t` instead of `unsigned long long`; and
@ -121,7 +121,7 @@ Each implementation directory in PQClean (e.g., crypto\_kem/kyber768\clean) can
Regarding #2, adding the files to your project's build system, each implementation in PQClean is accompanied by example two makefiles that show how one could build the files for that implementation: Regarding #2, adding the files to your project's build system, each implementation in PQClean is accompanied by example two makefiles that show how one could build the files for that implementation:
- The file `GNUmakefile` which can be used with GNU Make. - The file `Makefile` which can be used with GNU Make, BSD Make, and possibly others.
- The file `Makefile.Microsoft_nmake` which can be used with Visual Studio's nmake. - The file `Makefile.Microsoft_nmake` which can be used with Visual Studio's nmake.
## License ## License

View File

@ -56,7 +56,7 @@ static void surf(void) {
} }
} }
void randombytes(uint8_t *x, uint64_t xlen) { int randombytes(uint8_t *buf, size_t xlen) {
while (xlen > 0) { while (xlen > 0) {
if (!outleft) { if (!outleft) {
if (!++in[0]) { if (!++in[0]) {
@ -69,8 +69,9 @@ void randombytes(uint8_t *x, uint64_t xlen) {
surf(); surf();
outleft = 8; outleft = 8;
} }
*x = out[--outleft]; *buf = out[--outleft];
++x; ++buf;
--xlen; --xlen;
} }
return 0;
} }

323
common/randombytes.c Normal file
View File

@ -0,0 +1,323 @@
/*
The MIT License
Copyright (c) 2017 Daan Sprenkels <hello@dsprenkels.com>
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.
*/
// In the case that are compiling on linux, we need to define _GNU_SOURCE
// *before* randombytes.h is included. Otherwise SYS_getrandom will not be
// declared.
#if defined(__linux__)
# define _GNU_SOURCE
#endif /* defined(__linux__) */
#include "randombytes.h"
#if defined(_WIN32)
/* Windows */
# include <windows.h>
# include <wincrypt.h> /* CryptAcquireContext, CryptGenRandom */
#endif /* defined(_WIN32) */
#if defined(__linux__)
/* Linux */
// We would need to include <linux/random.h>, but not every target has access
// to the linux headers. We only need RNDGETENTCNT, so we instead inline it.
// RNDGETENTCNT is originally defined in `include/uapi/linux/random.h` in the
// linux repo.
# define RNDGETENTCNT 0x80045200
# include <assert.h>
# include <errno.h>
# include <fcntl.h>
# include <poll.h>
# include <stdint.h>
# include <stdio.h>
# include <sys/ioctl.h>
# include <sys/stat.h>
# include <sys/syscall.h>
# include <sys/types.h>
# include <unistd.h>
// We need SSIZE_MAX as the maximum read len from /dev/urandom
# if !defined(SSIZE_MAX)
# define SSIZE_MAX (SIZE_MAX / 2 - 1)
# endif /* defined(SSIZE_MAX) */
#endif /* defined(__linux__) */
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
/* Dragonfly, FreeBSD, NetBSD, OpenBSD (has arc4random) */
# include <sys/param.h>
# if defined(BSD)
# include <stdlib.h>
# endif
#endif
#if defined(__EMSCRIPTEN__)
# include <assert.h>
# include <emscripten.h>
# include <errno.h>
# include <stdbool.h>
#endif /* defined(__EMSCRIPTEN__) */
#if defined(_WIN32)
static int randombytes_win32_randombytes(void* buf, const size_t n)
{
HCRYPTPROV ctx;
BOOL tmp;
tmp = CryptAcquireContext(&ctx, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT);
if (tmp == FALSE) return -1;
tmp = CryptGenRandom(ctx, n, (BYTE*) buf);
if (tmp == FALSE) return -1;
tmp = CryptReleaseContext(ctx, 0);
if (tmp == FALSE) return -1;
return 0;
}
#endif /* defined(_WIN32) */
#if defined(__linux__) && defined(SYS_getrandom)
static int randombytes_linux_randombytes_getrandom(void *buf, size_t n)
{
/* I have thought about using a separate PRF, seeded by getrandom, but
* it turns out that the performance of getrandom is good enough
* (250 MB/s on my laptop).
*/
size_t offset = 0, chunk;
int ret;
while (n > 0) {
/* getrandom does not allow chunks larger than 33554431 */
chunk = n <= 33554431 ? n : 33554431;
do {
ret = syscall(SYS_getrandom, (char *)buf + offset, chunk, 0);
} while (ret == -1 && errno == EINTR);
if (ret < 0) {
return ret;
}
offset += ret;
n -= ret;
}
assert(n == 0);
return 0;
}
#endif /* defined(__linux__) && defined(SYS_getrandom) */
#if defined(__linux__) && !defined(SYS_getrandom)
static int randombytes_linux_read_entropy_ioctl(int device, int *entropy)
{
return ioctl(device, RNDGETENTCNT, entropy);
}
static int randombytes_linux_read_entropy_proc(FILE *stream, int *entropy)
{
int retcode;
do {
rewind(stream);
retcode = fscanf(stream, "%d", entropy);
} while (retcode != 1 && errno == EINTR);
if (retcode != 1) {
return -1;
}
return 0;
}
static int randombytes_linux_wait_for_entropy(int device)
{
/* We will block on /dev/random, because any increase in the OS' entropy
* level will unblock the request. I use poll here (as does libsodium),
* because we don't *actually* want to read from the device. */
enum { IOCTL, PROC } strategy = IOCTL;
const int bits = 128;
struct pollfd pfd;
int fd;
FILE *proc_file;
int retcode, retcode_error = 0; // Used as return codes throughout this function
int entropy = 0;
/* If the device has enough entropy already, we will want to return early */
retcode = randombytes_linux_read_entropy_ioctl(device, &entropy);
if (retcode != 0 && errno == ENOTTY) {
/* The ioctl call on /dev/urandom has failed due to a ENOTTY (i.e.
* unsupported action). We will fall back to reading from
* `/proc/sys/kernel/random/entropy_avail`. This is obviously less
* ideal, but at this point it seems we have no better option. */
strategy = PROC;
// Open the entropy count file
proc_file = fopen("/proc/sys/kernel/random/entropy_avail", "r");
} else if (retcode != 0) {
// Unrecoverable ioctl error
return -1;
}
if (entropy >= bits) {
return 0;
}
do {
fd = open("/dev/random", O_RDONLY);
} while (fd == -1 && errno == EINTR); /* EAGAIN will not occur */
if (fd == -1) {
/* Unrecoverable IO error */
return -1;
}
pfd.fd = fd;
pfd.events = POLLIN;
for (;;) {
retcode = poll(&pfd, 1, -1);
if (retcode == -1 && (errno == EINTR || errno == EAGAIN)) {
continue;
} else if (retcode == 1) {
if (strategy == IOCTL) {
retcode = randombytes_linux_read_entropy_ioctl(device, &entropy);
} else if (strategy == PROC) {
retcode = randombytes_linux_read_entropy_proc(proc_file, &entropy);
} else {
return -1; // Unreachable
}
if (retcode != 0) {
// Unrecoverable I/O error
retcode_error = retcode;
break;
}
if (entropy >= bits) {
break;
}
} else {
// Unreachable: poll() should only return -1 or 1
retcode_error = -1;
break;
}
}
do {
retcode = close(fd);
} while (retcode == -1 && errno == EINTR);
if (strategy == PROC) {
do {
retcode = fclose(proc_file);
} while (retcode == -1 && errno == EINTR);
}
if (retcode_error != 0) {
return retcode_error;
}
return retcode;
}
static int randombytes_linux_randombytes_urandom(void *buf, size_t n)
{
int fd;
size_t offset = 0, count;
ssize_t tmp;
do {
fd = open("/dev/urandom", O_RDONLY);
} while (fd == -1 && errno == EINTR);
if (fd == -1) return -1;
if (randombytes_linux_wait_for_entropy(fd) == -1) return -1;
while (n > 0) {
count = n <= SSIZE_MAX ? n : SSIZE_MAX;
tmp = read(fd, (char *)buf + offset, count);
if (tmp == -1 && (errno == EAGAIN || errno == EINTR)) {
continue;
}
if (tmp == -1) return -1; /* Unrecoverable IO error */
offset += tmp;
n -= tmp;
}
assert(n == 0);
return 0;
}
#endif /* defined(__linux__) && !defined(SYS_getrandom) */
#if defined(BSD)
static int randombytes_bsd_randombytes(void *buf, size_t n)
{
arc4random_buf(buf, n);
return 0;
}
#endif /* defined(BSD) */
#if defined(__EMSCRIPTEN__)
static int randombytes_js_randombytes_nodejs(void *buf, size_t n) {
const int ret = EM_ASM_INT({
var crypto;
try {
crypto = require('crypto');
} catch (error) {
return -2;
}
try {
writeArrayToMemory(crypto.randomBytes($1), $0);
return 0;
} catch (error) {
return -1;
}
}, buf, n);
switch (ret) {
case 0:
return 0;
case -1:
errno = EINVAL;
return -1;
case -2:
errno = ENOSYS;
return -1;
}
assert(false); // Unreachable
}
#endif /* defined(__EMSCRIPTEN__) */
int randombytes(uint8_t *buf, size_t n)
{
#if defined(__EMSCRIPTEN__)
return randombytes_js_randombytes_nodejs(buf, n);
#elif defined(__linux__)
# if defined(SYS_getrandom)
/* Use getrandom system call */
return randombytes_linux_randombytes_getrandom(buf, n);
# else
/* When we have enough entropy, we can read from /dev/urandom */
return randombytes_linux_randombytes_urandom(buf, n);
# endif
#elif defined(BSD)
/* Use arc4random system call */
return randombytes_bsd_randombytes(buf, n);
#elif defined(_WIN32)
/* Use windows API */
return randombytes_win32_randombytes(buf, n);
#else
# error "randombytes(...) is not supported on this platform"
#endif
}

View File

@ -2,6 +2,12 @@
#define RANDOMBYTES_H #define RANDOMBYTES_H
#include <stdint.h> #include <stdint.h>
void randombytes(uint8_t *x, uint64_t xlen); #ifdef _WIN32
# include <CRTDEFS.H>
#else
# include <unistd.h>
#endif
int randombytes(uint8_t *buf, size_t xlen);
#endif #endif

View File

@ -0,0 +1,15 @@
# This Makefile has been tested with GNU Make and BSD Make
LIB=libkyber768_clean.a
OBJECTS=cbd.o indcpa.o kem.o kex.o ntt.o poly.o polyvec.o precomp.o reduce.o verify.o
CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)
all: $(LIB)
$(LIB): $(OBJECTS)
$(AR) -r $@ $(OBJECTS)
clean:
$(RM) $(OBJECTS)
$(RM) $(LIB)

View File

@ -1,5 +1,7 @@
LIB=libkyber768_clean.lib # This Makefile can be used with Microsoft Visual Studio's nmake using the command:
# nmake /f Makefile.Microsoft_nmake
LIB=libkyber768_clean.lib
OBJECTS=cbd.obj indcpa.obj kem.obj kex.obj ntt.obj poly.obj polyvec.obj precomp.obj reduce.obj verify.obj OBJECTS=cbd.obj indcpa.obj kem.obj kex.obj ntt.obj poly.obj polyvec.obj precomp.obj reduce.obj verify.obj
CFLAGS=/I ..\..\..\common /W1 /WX # FIXME: ideally would use /W4 instead of /W1, but too many failures in Kyber right now CFLAGS=/I ..\..\..\common /W1 /WX # FIXME: ideally would use /W4 instead of /W1, but too many failures in Kyber right now
@ -7,8 +9,8 @@ CFLAGS=/I ..\..\..\common /W1 /WX # FIXME: ideally would use /W4 instead of /W1,
all: $(LIB) all: $(LIB)
$(LIB): $(OBJECTS) $(LIB): $(OBJECTS)
LIB.EXE /OUT:$@ $** LIB.EXE /OUT:$@ $**
clean: clean:
DEL $(OBJECTS) DEL $(OBJECTS)
DEL $(LIB) DEL $(LIB)