xref: /freebsd/crypto/libecc/src/nn/nn_rand.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
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  */
nn_get_random_len(nn_t out,u16 len)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  */
nn_get_random_maxlen(nn_t out,u16 max_len)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  */
nn_get_random_mod(nn_t out,nn_src_t q)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