Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / support / RandUtils.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2013-2017 Nest Labs, Inc.
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
19 /**
20  *    @file
21  *      This file implements utility functions for deriving random integers.
22  *
23  *  @note These utility functions do not generate cryptographically strong
24  *        random number. To get cryptographically strong random data use
25  *        chip::Platform::Security::GetSecureRandomData().
26  *
27  */
28
29 #include "RandUtils.h"
30
31 #include <limits.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34
35 #ifndef __STDC_LIMIT_MACROS
36 #define __STDC_LIMIT_MACROS
37 #endif
38
39 namespace chip {
40
41 /**
42  *  @def NORMALIZED_RAND_RANGE(reqRange)
43  *
44  *  This macro calculates normalized range for the output of rand() function
45  *  based on the requested random range [0, reqRange].
46  *
47  *  @note
48  *  For most of the platforms we support, RAND_MAX is usually 0x7FFF or 0x7FFFFFFF.
49  *  In these cases normalization for ranges [0, UINT8_MAX] or [0, UINT16_MAX]
50  *  is not needed.
51  *
52  *  @param[in] reqRange  The requested random number range.
53  *
54  *  @return              normalized random range.
55  *
56  */
57 #define NORMALIZED_RAND_RANGE(reqRange) (((reqRange) + 1) * ((RAND_MAX + 1) / ((reqRange) + 1)))
58
59 #if RAND_MAX < UINT8_MAX
60 #error "RAND_MAX value is too small. RandUtils functions assume that RAND_MAX is greater or equal to UINT8_MAX."
61 #endif
62
63 uint64_t GetRandU64()
64 {
65     // rand() returns int, which is always smaller than the size of uint64_t
66     // and rand() cannot be used directly to generate random uint64_t number.
67     return static_cast<uint64_t>(GetRandU32()) ^ (static_cast<uint64_t>(GetRandU32()) << (sizeof(uint32_t) * CHAR_BIT));
68 }
69
70 uint32_t GetRandU32()
71 {
72     // Check if (RAND_MAX == UINT32_MAX) but it is unlikely because rand() returns signed int,
73     // which maximum possible value is 0x7FFFFFFF (smaller that UINT32_MAX = 0xFFFFFFFF).
74 #if RAND_MAX == UINT32_MAX
75     return static_cast<uint32_t>(rand());
76 #else
77     return static_cast<uint32_t>(GetRandU16()) ^ (static_cast<uint32_t>(GetRandU16()) << (sizeof(uint16_t) * CHAR_BIT));
78 #endif
79 }
80
81 uint16_t GetRandU16()
82 {
83 #if RAND_MAX >= UINT16_MAX
84 #if (RAND_MAX == INT_MAX) || (RAND_MAX == NORMALIZED_RAND_RANGE(UINT16_MAX))
85     // rand() random output range normalization is not needed.
86     return static_cast<uint16_t>(rand());
87 #else
88     // Otherwise, Normilize the output range of rand() and reject rand() outputs outside of that range.
89     while (true)
90     {
91         int r = rand();
92         if (r < NORMALIZED_RAND_RANGE(UINT16_MAX))
93             return static_cast<uint16_t>(r);
94     }
95 #endif
96 #else
97     return static_cast<uint16_t>(GetRandU8()) ^ (static_cast<uint16_t>(GetRandU8()) << CHAR_BIT);
98 #endif
99 }
100
101 uint8_t GetRandU8()
102 {
103 #if (RAND_MAX == INT_MAX) || (RAND_MAX == NORMALIZED_RAND_RANGE(UINT8_MAX))
104     // rand() random output range normalization is not needed.
105     return static_cast<uint8_t>(rand());
106 #else
107     // Otherwise, Normilize the output range of rand() and reject rand() outputs outside of that range.
108     while (true)
109     {
110         int r = rand();
111         if (r < NORMALIZED_RAND_RANGE(UINT8_MAX))
112             return static_cast<uint8_t>(r);
113     }
114 #endif
115 }
116
117 } // namespace chip