1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8*f0865ec9SKyle Evans * 9*f0865ec9SKyle Evans * Contributors: 10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12*f0865ec9SKyle Evans * 13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 15*f0865ec9SKyle Evans */ 16*f0865ec9SKyle Evans #include <libecc/nn/nn_rand.h> 17*f0865ec9SKyle Evans #include <libecc/nn/nn_add.h> 18*f0865ec9SKyle Evans #include <libecc/nn/nn_logical.h> 19*f0865ec9SKyle Evans /* Include the "internal" header as we use non public API here */ 20*f0865ec9SKyle Evans #include "../nn/nn_div.h" 21*f0865ec9SKyle Evans 22*f0865ec9SKyle Evans 23*f0865ec9SKyle Evans #include <libecc/external_deps/rand.h> 24*f0865ec9SKyle Evans 25*f0865ec9SKyle Evans /* 26*f0865ec9SKyle Evans * The function initializes nn structure pointed by 'out' to a random value of 27*f0865ec9SKyle Evans * byte length 'len'. The resulting nn will have a uniformly random value in 28*f0865ec9SKyle Evans * [0, 2^(8 * len)[. Provided length 'len' parameter must be less than or equal 29*f0865ec9SKyle Evans * to NN_MAX_BYTE_LEN. The function returns -1 on error and 0 on success. 30*f0865ec9SKyle Evans */ 31*f0865ec9SKyle Evans int nn_get_random_len(nn_t out, u16 len) 32*f0865ec9SKyle Evans { 33*f0865ec9SKyle Evans int ret; 34*f0865ec9SKyle Evans 35*f0865ec9SKyle Evans MUST_HAVE((len <= NN_MAX_BYTE_LEN), ret, err); 36*f0865ec9SKyle Evans 37*f0865ec9SKyle Evans ret = nn_init(out, len); EG(ret, err); 38*f0865ec9SKyle Evans ret = get_random((u8*) out->val, len); 39*f0865ec9SKyle Evans 40*f0865ec9SKyle Evans err: 41*f0865ec9SKyle Evans return ret; 42*f0865ec9SKyle Evans } 43*f0865ec9SKyle Evans 44*f0865ec9SKyle Evans /* 45*f0865ec9SKyle Evans * The function initializes nn structure pointed by 'out' to a random value of 46*f0865ec9SKyle Evans * *random* byte length less than or equal to 'max_len'. Unlike the function 47*f0865ec9SKyle Evans * above (nn_get_random_len()), the resulting nn will have a uniformly random 48*f0865ec9SKyle Evans * value in in [0, 2^(8 * len)[ *with* length selected at random in 49*f0865ec9SKyle Evans * [0, max_len]. The function returns -1 on error and 0 on success. 50*f0865ec9SKyle Evans * 51*f0865ec9SKyle Evans * !! NOTE !!: think twice before using this function for anything other than 52*f0865ec9SKyle Evans * testing purposes. Its main goal is to generate nn with random length, not 53*f0865ec9SKyle Evans * random numbers. For instance, for a given value of max_len, the function 54*f0865ec9SKyle Evans * returns a nn with a value of 0 w/ probability 1/max_len. 55*f0865ec9SKyle Evans */ 56*f0865ec9SKyle Evans int nn_get_random_maxlen(nn_t out, u16 max_len) 57*f0865ec9SKyle Evans { 58*f0865ec9SKyle Evans u16 len; 59*f0865ec9SKyle Evans int ret; 60*f0865ec9SKyle Evans 61*f0865ec9SKyle Evans MUST_HAVE((max_len <= NN_MAX_BYTE_LEN), ret, err); 62*f0865ec9SKyle Evans 63*f0865ec9SKyle Evans ret = get_random((u8 *)&len, 2); EG(ret, err); 64*f0865ec9SKyle Evans 65*f0865ec9SKyle Evans len = (u16)(len % (max_len + 1)); 66*f0865ec9SKyle Evans 67*f0865ec9SKyle Evans ret = nn_get_random_len(out, len); 68*f0865ec9SKyle Evans 69*f0865ec9SKyle Evans err: 70*f0865ec9SKyle Evans return ret; 71*f0865ec9SKyle Evans } 72*f0865ec9SKyle Evans 73*f0865ec9SKyle Evans /* 74*f0865ec9SKyle Evans * On success, the return value of the function is 0 and 'out' parameter 75*f0865ec9SKyle Evans * is initialized to an unbiased random value in ]0,q[. On error, the 76*f0865ec9SKyle Evans * function returns -1. Due to the generation process described below, 77*f0865ec9SKyle Evans * the size of q is limited by NN_MAX_BYTE_LEN / 2. Aliasing is supported. 78*f0865ec9SKyle Evans * 79*f0865ec9SKyle Evans * Generating a random value in ]0,q[ is done by reducing a large random 80*f0865ec9SKyle Evans * value modulo q. The random value is taken with a length twice the one 81*f0865ec9SKyle Evans * of q to ensure the reduction does not produce a biased value. 82*f0865ec9SKyle Evans * 83*f0865ec9SKyle Evans * Even if this is unlikely to happen, the reduction can produce a null 84*f0865ec9SKyle Evans * result; this specific case would require to repeat the whole process. 85*f0865ec9SKyle Evans * For that reason, the algorithm we implement works in the following 86*f0865ec9SKyle Evans * way: 87*f0865ec9SKyle Evans * 88*f0865ec9SKyle Evans * 1) compute q' = q - 1 (note: q is neither 0 nor 1) 89*f0865ec9SKyle Evans * 2) generate a random value tmp_rand twice the size of q 90*f0865ec9SKyle Evans * 3) compute out = tmp_rand mod q' (note: out is in [0, q-2]) 91*f0865ec9SKyle Evans * 4) compute out += 1 (note: out is in [1, q-1]) 92*f0865ec9SKyle Evans * 93*f0865ec9SKyle Evans * Aliasing is supported. 94*f0865ec9SKyle Evans */ 95*f0865ec9SKyle Evans int nn_get_random_mod(nn_t out, nn_src_t q) 96*f0865ec9SKyle Evans { 97*f0865ec9SKyle Evans nn tmp_rand, qprime; 98*f0865ec9SKyle Evans bitcnt_t q_bit_len, q_len; 99*f0865ec9SKyle Evans int ret, isone; 100*f0865ec9SKyle Evans qprime.magic = tmp_rand.magic = WORD(0); 101*f0865ec9SKyle Evans 102*f0865ec9SKyle Evans /* Check q is initialized and get its bit length */ 103*f0865ec9SKyle Evans ret = nn_check_initialized(q); EG(ret, err); 104*f0865ec9SKyle Evans ret = nn_bitlen(q, &q_bit_len); EG(ret, err); 105*f0865ec9SKyle Evans q_len = (bitcnt_t)BYTECEIL(q_bit_len); 106*f0865ec9SKyle Evans 107*f0865ec9SKyle Evans /* Check q is neither 0, nor 1 and its size is ok */ 108*f0865ec9SKyle Evans MUST_HAVE((q_len) && (q_len <= (NN_MAX_BYTE_LEN / 2)), ret, err); 109*f0865ec9SKyle Evans MUST_HAVE((!nn_isone(q, &isone)) && (!isone), ret, err); 110*f0865ec9SKyle Evans 111*f0865ec9SKyle Evans /* 1) compute q' = q - 1 */ 112*f0865ec9SKyle Evans ret = nn_copy(&qprime, q); EG(ret, err); 113*f0865ec9SKyle Evans ret = nn_dec(&qprime, &qprime); EG(ret, err); 114*f0865ec9SKyle Evans 115*f0865ec9SKyle Evans /* 2) generate a random value tmp_rand twice the size of q */ 116*f0865ec9SKyle Evans ret = nn_init(&tmp_rand, (u16)(2 * q_len)); EG(ret, err); 117*f0865ec9SKyle Evans ret = get_random((u8 *)tmp_rand.val, (u16)(2 * q_len)); EG(ret, err); 118*f0865ec9SKyle Evans 119*f0865ec9SKyle Evans /* 3) compute out = tmp_rand mod q' */ 120*f0865ec9SKyle Evans ret = nn_init(out, (u16)q_len); EG(ret, err); 121*f0865ec9SKyle Evans 122*f0865ec9SKyle Evans /* Use nn_mod_notrim to avoid exposing the generated random length */ 123*f0865ec9SKyle Evans ret = nn_mod_notrim(out, &tmp_rand, &qprime); EG(ret, err); 124*f0865ec9SKyle Evans 125*f0865ec9SKyle Evans /* 4) compute out += 1 */ 126*f0865ec9SKyle Evans ret = nn_inc(out, out); 127*f0865ec9SKyle Evans 128*f0865ec9SKyle Evans err: 129*f0865ec9SKyle Evans nn_uninit(&qprime); 130*f0865ec9SKyle Evans nn_uninit(&tmp_rand); 131*f0865ec9SKyle Evans 132*f0865ec9SKyle Evans return ret; 133*f0865ec9SKyle Evans } 134