/* * Copyright (C) 2014 FH Bielefeld * * This file is part of a FH Bielefeld project. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "context.h" #include "err.h" #include "rand.h" #include "poly.h" #include #include #include #include #include #include #include #include #include /* * static declarations */ static mp_digit get_urnd_int_small(int *sign); static mp_digit get_rnd_int_small(int *sign); static mp_digit get_urnd_int_big(int *sign); static mp_digit get_rnd_int_big(int *sign); static mp_digit read_int_dev_random(); static mp_digit make_small_int(mp_digit random_int, int* sign); static mp_digit make_big_int(mp_digit random_int, int* sign); /** * Reads a single mp_digit out of /dev/random and returns this mp_digit * * @return the randomly chosen integer */ static mp_digit read_int_dev_random() { int random_data; mp_digit random_int; size_t randomDataLen = 0; random_data = open("/dev/random", O_RDONLY); while (randomDataLen < sizeof(random_int)) { ssize_t result = read(random_data, ((char*) &random_int) + randomDataLen, (sizeof(random_int)) - randomDataLen); if (result < 0) { NTRU_ABORT("Unable to read /dev/random.\n"); } randomDataLen += result; } close(random_data); return random_int; } /** * Makes a small integer from the set {-1, 0, 1} * out of a randomly chosen integer. * * @param random_int a randomly chosen mp_digit * @param sign a integer to store the sign (1==positiv) * @return random small integer from the set {-1, 0, 1} */ static mp_digit make_small_int(mp_digit random_int, int* sign) { random_int = random_int % 3; if (random_int == 1) { *sign = 0; } else if (random_int == 2) { random_int = 1; *sign = 1; } else { *sign = 0; } return random_int; } /** * Gets a random small integer * from the set {-1, 0, 1} using /dev/random. * A zero is signed positiv. * *sig == 1 means positiv integer. * * @param sign stores the signness [out] * @return random small integer */ static mp_digit get_rnd_int_small(int *sign) { mp_digit random_int = read_int_dev_random(); random_int = make_small_int(random_int, sign); return random_int; } /** * Gets a random polynomial with coefficients * from the set {-1 ,0 ,1} using /dev/random. * * @param ctx the NTRU context * @return newly allocated polynomial, must be freed with delete_polynom() */ pb_poly *ntru_get_rnd_poly_small(ntru_context *ctx) { mp_int chara; init_integer(&chara); pb_poly *poly = malloc(sizeof(pb_poly)); init_polynom_size(poly, &chara, ctx->N); mp_clear(&chara); for (unsigned int i = 0; i < ctx->N; i++) { int sign; int c = get_rnd_int_small(&sign); mp_set(&(poly->terms[i]), (mp_digit) c); if (sign == 1) poly->terms[i].sign = 1; } poly->used = ctx->N; pb_clamp(poly); return poly; } /** * Reads a single mp_digit out of /dev/urandom and returns this mp_digit * * @return the randomly chosen integer */ static mp_digit read_int_dev_urandom() { int random_data; mp_digit random_int; ssize_t result; random_data = open("/dev/urandom", O_RDONLY); if ((result = read(random_data, &random_int, sizeof(random_int))) < 0) NTRU_ABORT("Unable to read /dev/urandom.\n"); close(random_data); return random_int; } /** * Gets a random small integer * from the set {-1, 0, 1} using /dev/urandom. * A zero is signed positiv. * *sig == 1 means positiv integer. * * @param sign stores the signness [out] * @return random small integer */ static mp_digit get_urnd_int_small(int *sign) { mp_digit random_int = read_int_dev_urandom(); random_int = make_small_int(random_int, sign); return random_int; } /** * Gets a random polynomial with coefficients * from the set {-1 ,0 ,1} using /dev/urandom. * * @param ctx the NTRU context * @return newly allocated polynomial, must be freed with delete_polynom() */ pb_poly *ntru_get_urnd_poly_small(ntru_context *ctx) { mp_int chara; init_integer(&chara); pb_poly *poly = malloc(sizeof(pb_poly)); init_polynom_size(poly, &chara, ctx->N); mp_clear(&chara); for (unsigned int i = 0; i < ctx->N; i++) { int sign; int c = get_urnd_int_small(&sign); mp_set(&(poly->terms[i]), (mp_digit) c); if (sign == 1) poly->terms[i].sign = 1; } poly->used = ctx->N; pb_clamp(poly); return poly; } /** * Makes a big integer from the borders of BIG_RAND_MAX * and BIG_RAND_MIN out of a randomly chosen integer. * * @param random_int a randomly chosen mp_digit * @param sign a integer to store the sign (1==positiv) * @return random small integer from the set {-1, 0, 1} */ static mp_digit make_big_int(mp_digit random_int, int* sign) { random_int = random_int % abs(BIG_RAND_MAX - BIG_RAND_MIN); if (random_int < BIG_RAND_MAX) { *sign = 1; } else if (random_int > BIG_RAND_MAX) { *sign = 0; random_int -= BIG_RAND_MAX; } else if (random_int == BIG_RAND_MAX) { random_int = abs(BIG_RAND_MIN); *sign = 0; } else { NTRU_ABORT("Error while parsing big random Integer.\n"); } return random_int; } /** * Gets a random big integer * from the borders of BIG_RAND_MAX and * BIG_RAND_MIN using /dev/random. * A zero is signed positiv. * *sig == 1 means positiv integer. * * @param sign stores the signness [out] * @return random small integer */ static mp_digit get_rnd_int_big(int *sign) { mp_digit random_int = read_int_dev_random(); random_int = make_big_int(random_int, sign); return random_int; } /** * Gets a random polynomial with coefficients * from the borders of BIG_RAND_MAX and * BIG_RAND_MIN using /dev/random. * * @param ctx the NTRU context * @return newly allocated polynomial, must be freed with delete_polynom() */ pb_poly *ntru_get_rnd_poly_big(ntru_context *ctx) { mp_int chara; init_integer(&chara); pb_poly *poly = malloc(sizeof(pb_poly)); init_polynom_size(poly, &chara, ctx->N); mp_clear(&chara); for (unsigned int i = 0; i < ctx->N; i++) { int sign; int c = get_rnd_int_big(&sign); mp_set(&(poly->terms[i]), (mp_digit) c); if (sign == 1) poly->terms[i].sign = 1; } poly->used = ctx->N; pb_clamp(poly); return poly; } /** * Gets a random big integer * from the borders of BIG_RAND_MAX and * BIG_RAND_MIN using /dev/urandom. * A zero is signed positiv. * *sig == 1 means positiv integer. * * @param sign stores the signness [out] * @return random small integer */ static mp_digit get_urnd_int_big(int *sign) { mp_digit random_int = read_int_dev_urandom(); random_int = random_int % abs(BIG_RAND_MAX - BIG_RAND_MIN); random_int = make_big_int(random_int, sign); return random_int; } /** * Gets a random polynomial with coefficients * from the borders of BIG_RAND_MAX and * BIG_RAND_MIN using /dev/urandom. * * @param ctx the NTRU context * @return newly allocated polynomial, must be freed with delete_polynom() */ pb_poly *ntru_get_urnd_poly_big(ntru_context *ctx) { mp_int chara; init_integer(&chara); pb_poly *poly = malloc(sizeof(pb_poly)); init_polynom_size(poly, &chara, ctx->N); mp_clear(&chara); for (unsigned int i = 0; i < ctx->N; i++) { int sign; int c = get_urnd_int_big(&sign); mp_set(&(poly->terms[i]), (mp_digit) c); if (sign == 1) poly->terms[i].sign = 1; } poly->used = ctx->N; pb_clamp(poly); return poly; }