/* * Copyright (C) 2016 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann, * and Peter Schwabe. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "newhope_noise.h" typedef struct private_newhope_noise_t private_newhope_noise_t; static const int seed_len = 32; /* 256 bits */ static const int nonce_len = 12; /* 96 bits */ /** * Private data of an newhope_noise_t object. */ struct private_newhope_noise_t { /** * Public newhope_noise_t interface. */ newhope_noise_t public; /** * 256 bit seed and 96 bit nonce (44 bytes) */ chunk_t seed; /** * ChaCha20 stream */ xof_t *xof; }; METHOD(newhope_noise_t, get_uniform_bytes, uint8_t*, private_newhope_noise_t *this, uint8_t nonce, uint16_t n) { uint8_t *bytes; this->seed.ptr[seed_len] = nonce; if (!this->xof->set_seed(this->xof, this->seed)) { DBG1(DBG_LIB, "could not set seed of CHACHA20 XOF"); return NULL; } /* allocate dynamic memory for the noise polynomial */ bytes = (uint8_t*)malloc(n); if (!this->xof->get_bytes(this->xof, n, bytes)) { DBG1(DBG_LIB, "could not get bytes from SHAKE128 XOF"); free(bytes); return NULL; } return bytes; } METHOD(newhope_noise_t, get_binomial_words, uint32_t*, private_newhope_noise_t *this, uint8_t nonce, uint16_t n, uint16_t q) { uint32_t *np, a, b, d, t; uint8_t x[4]; int i = 0, j; this->seed.ptr[seed_len] = nonce; if (!this->xof->set_seed(this->xof, this->seed)) { DBG1(DBG_LIB, "could not set seed of CHACHA20 XOF"); return NULL; } /* allocate dynamic memory for the noise polynomial */ np = (uint32_t*)malloc(n * sizeof(uint32_t)); for (i = 0; i < n; i++) { if (!this->xof->get_bytes(this->xof, sizeof(x), x)) { DBG1(DBG_LIB, "could not get bytes from SHAKE128 XOF"); free(np); return NULL; } /* Treat x as a 32 bit unsigned little endian integer */ t = uletoh32(x); /* Compute Psi_16 distribution */ d = 0; for (j = 0; j < 8; j++) { d += (t >> j) & 0x01010101; } a = ((d >> 8) & 0xff) + (d & 0xff); b = ((d >> 16) & 0xff) + (d >> 24); np[i] = (a >= b) ? a - b : a + q - b; } return np; } METHOD(newhope_noise_t, destroy, void, private_newhope_noise_t *this) { this->xof->destroy(this->xof); chunk_free(&this->seed); free(this); } /* * Described in header. */ newhope_noise_t *newhope_noise_create(chunk_t seed) { private_newhope_noise_t *this; xof_t *xof; if (seed.len != seed_len) { DBG1(DBG_LIB, "seed for ChaCha20 stream must be 256 bits"); return NULL; } xof = lib->crypto->create_xof(lib->crypto, XOF_CHACHA20); if (!xof) { DBG1(DBG_LIB, "could not instantiate ChaCha20 stream"); return NULL; } INIT(this, .public = { .get_uniform_bytes = _get_uniform_bytes, .get_binomial_words = _get_binomial_words, .destroy = _destroy, }, .xof = xof, .seed = chunk_alloc(seed_len + nonce_len), ); /* initialize seed for ChaCha 20 stream */ memcpy(this->seed.ptr, seed.ptr, seed_len); memset(this->seed.ptr + seed_len, 0x00, nonce_len); return &this->public; }