1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2010-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #include "rand.h"
22 #include "bn.h"
23 
strong_rand_bytes_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])24 ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
25 {/* (Bytes) */
26     unsigned bytes;
27     unsigned char* data;
28     ERL_NIF_TERM ret;
29 
30     ASSERT(argc == 1);
31 
32     if (!enif_get_uint(env, argv[0], &bytes))
33         goto bad_arg;
34     if (bytes > INT_MAX)
35         goto bad_arg;
36 
37     if ((data = enif_make_new_binary(env, bytes, &ret)) == NULL)
38         goto err;
39     if (RAND_bytes(data, (int)bytes) != 1)
40         goto err;
41 
42     ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes);
43     return ret;
44 
45  bad_arg:
46     return enif_make_badarg(env);
47 
48  err:
49     return atom_false;
50 }
51 
strong_rand_range_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])52 ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
53 {/* (Range) */
54     BIGNUM *bn_range = NULL, *bn_rand = NULL;
55     ERL_NIF_TERM ret;
56 
57     ASSERT(argc == 1);
58 
59     if (!get_bn_from_bin(env, argv[0], &bn_range))
60         goto bad_arg;
61 
62     if ((bn_rand = BN_new()) == NULL)
63         goto err;
64     if (!BN_rand_range(bn_rand, bn_range))
65         goto err;
66 
67     if ((ret = bin_from_bn(env, bn_rand)) == atom_error)
68         goto err;
69     goto done;
70 
71  bad_arg:
72     return enif_make_badarg(env);
73 
74  err:
75     ret = atom_false;
76 
77  done:
78     if (bn_rand)
79         BN_free(bn_rand);
80     if (bn_range)
81         BN_free(bn_range);
82     return ret;
83 }
84 
rand_uniform_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])85 ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
86 {/* (Lo,Hi) */
87     BIGNUM *bn_from = NULL, *bn_to = NULL, *bn_rand = NULL;
88     unsigned char* data;
89     int dlen;
90     ERL_NIF_TERM ret;
91 
92     ASSERT(argc == 2);
93 
94     if (!get_bn_from_mpint(env, argv[0], &bn_from))
95         goto bad_arg;
96     if (!get_bn_from_mpint(env, argv[1], &bn_rand))
97         goto bad_arg;
98 
99     if ((bn_to = BN_new()) == NULL)
100         goto err;
101 
102     if (!BN_sub(bn_to, bn_rand, bn_from))
103         goto err;
104     if (!BN_pseudo_rand_range(bn_rand, bn_to))
105         goto err;
106     if (!BN_add(bn_rand, bn_rand, bn_from))
107         goto err;
108 
109     if ((dlen = BN_num_bytes(bn_rand)) < 0)
110         goto err;
111     if ((data = enif_make_new_binary(env, (size_t)dlen+4, &ret)) == NULL)
112         goto err;
113 
114     put_uint32(data, (unsigned int)dlen);
115     BN_bn2bin(bn_rand, data+4);
116     ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen);
117     goto done;
118 
119  bad_arg:
120  err:
121     ret = enif_make_badarg(env);
122 
123  done:
124     if (bn_rand)
125         BN_free(bn_rand);
126     if (bn_from)
127         BN_free(bn_from);
128     if (bn_to)
129         BN_free(bn_to);
130     return ret;
131 }
132 
rand_seed_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])133 ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
134 {/* (Seed) */
135     ErlNifBinary seed_bin;
136 
137     ASSERT(argc == 1);
138 
139     if (!enif_inspect_binary(env, argv[0], &seed_bin))
140         goto bad_arg;
141     if (seed_bin.size > INT_MAX)
142         goto bad_arg;
143 
144     RAND_seed(seed_bin.data, (int)seed_bin.size);
145     return atom_ok;
146 
147  bad_arg:
148     return enif_make_badarg(env);
149 }
150