/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15#include <libecc/nn/nn_rand.h>16#include <libecc/nn/nn_add.h>17#include <libecc/nn/nn_logical.h>18/* Include the "internal" header as we use non public API here */19#include "../nn/nn_div.h"202122#include <libecc/external_deps/rand.h>2324/*25* The function initializes nn structure pointed by 'out' to a random value of26* byte length 'len'. The resulting nn will have a uniformly random value in27* [0, 2^(8 * len)[. Provided length 'len' parameter must be less than or equal28* to NN_MAX_BYTE_LEN. The function returns -1 on error and 0 on success.29*/30int nn_get_random_len(nn_t out, u16 len)31{32int ret;3334MUST_HAVE((len <= NN_MAX_BYTE_LEN), ret, err);3536ret = nn_init(out, len); EG(ret, err);37ret = get_random((u8*) out->val, len);3839err:40return ret;41}4243/*44* The function initializes nn structure pointed by 'out' to a random value of45* *random* byte length less than or equal to 'max_len'. Unlike the function46* above (nn_get_random_len()), the resulting nn will have a uniformly random47* value in in [0, 2^(8 * len)[ *with* length selected at random in48* [0, max_len]. The function returns -1 on error and 0 on success.49*50* !! NOTE !!: think twice before using this function for anything other than51* testing purposes. Its main goal is to generate nn with random length, not52* random numbers. For instance, for a given value of max_len, the function53* returns a nn with a value of 0 w/ probability 1/max_len.54*/55int nn_get_random_maxlen(nn_t out, u16 max_len)56{57u16 len;58int ret;5960MUST_HAVE((max_len <= NN_MAX_BYTE_LEN), ret, err);6162ret = get_random((u8 *)&len, 2); EG(ret, err);6364len = (u16)(len % (max_len + 1));6566ret = nn_get_random_len(out, len);6768err:69return ret;70}7172/*73* On success, the return value of the function is 0 and 'out' parameter74* is initialized to an unbiased random value in ]0,q[. On error, the75* function returns -1. Due to the generation process described below,76* the size of q is limited by NN_MAX_BYTE_LEN / 2. Aliasing is supported.77*78* Generating a random value in ]0,q[ is done by reducing a large random79* value modulo q. The random value is taken with a length twice the one80* of q to ensure the reduction does not produce a biased value.81*82* Even if this is unlikely to happen, the reduction can produce a null83* result; this specific case would require to repeat the whole process.84* For that reason, the algorithm we implement works in the following85* way:86*87* 1) compute q' = q - 1 (note: q is neither 0 nor 1)88* 2) generate a random value tmp_rand twice the size of q89* 3) compute out = tmp_rand mod q' (note: out is in [0, q-2])90* 4) compute out += 1 (note: out is in [1, q-1])91*92* Aliasing is supported.93*/94int nn_get_random_mod(nn_t out, nn_src_t q)95{96nn tmp_rand, qprime;97bitcnt_t q_bit_len, q_len;98int ret, isone;99qprime.magic = tmp_rand.magic = WORD(0);100101/* Check q is initialized and get its bit length */102ret = nn_check_initialized(q); EG(ret, err);103ret = nn_bitlen(q, &q_bit_len); EG(ret, err);104q_len = (bitcnt_t)BYTECEIL(q_bit_len);105106/* Check q is neither 0, nor 1 and its size is ok */107MUST_HAVE((q_len) && (q_len <= (NN_MAX_BYTE_LEN / 2)), ret, err);108MUST_HAVE((!nn_isone(q, &isone)) && (!isone), ret, err);109110/* 1) compute q' = q - 1 */111ret = nn_copy(&qprime, q); EG(ret, err);112ret = nn_dec(&qprime, &qprime); EG(ret, err);113114/* 2) generate a random value tmp_rand twice the size of q */115ret = nn_init(&tmp_rand, (u16)(2 * q_len)); EG(ret, err);116ret = get_random((u8 *)tmp_rand.val, (u16)(2 * q_len)); EG(ret, err);117118/* 3) compute out = tmp_rand mod q' */119ret = nn_init(out, (u16)q_len); EG(ret, err);120121/* Use nn_mod_notrim to avoid exposing the generated random length */122ret = nn_mod_notrim(out, &tmp_rand, &qprime); EG(ret, err);123124/* 4) compute out += 1 */125ret = nn_inc(out, out);126127err:128nn_uninit(&qprime);129nn_uninit(&tmp_rand);130131return ret;132}133134135