blob: add0c635b71c7225563fddf7083d51929a00f3eb [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file implements utility functions for deriving random integers.
*
* @note These utility functions do not generate cryptographically strong
* random number. To get cryptographically strong random data use
* nl::Weave::Platform::Security::GetSecureRandomData().
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include "RandUtils.h"
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
namespace nl {
namespace Weave {
/**
* @def NORMALIZED_RAND_RANGE(reqRange)
*
* This macro calculates normalized range for the output of rand() function
* based on the requested random range [0, reqRange].
*
* @note
* For most of the platforms we support, RAND_MAX is usually 0x7FFF or 0x7FFFFFFF.
* In these cases normalization for ranges [0, UINT8_MAX] or [0, UINT16_MAX]
* is not needed.
*
* @param[in] reqRange The requested random number range.
*
* @return normalized random range.
*
*/
#define NORMALIZED_RAND_RANGE(reqRange) (((reqRange) + 1) * ((RAND_MAX + 1) / ((reqRange) + 1)))
#if RAND_MAX < UINT8_MAX
#error "RAND_MAX value is too small. RandUtils functions assume that RAND_MAX is greater or equal to UINT8_MAX."
#endif
uint64_t GetRandU64()
{
// rand() returns int, which is always smaller than the size of uint64_t
// and rand() cannot be used directly to generate random uint64_t number.
return static_cast<uint64_t>(GetRandU32()) ^
(static_cast<uint64_t>(GetRandU32()) << (sizeof(uint32_t) * CHAR_BIT));
}
uint32_t GetRandU32()
{
// Check if (RAND_MAX == UINT32_MAX) but it is unlikely because rand() returns signed int,
// which maximum possible value is 0x7FFFFFFF (smaller that UINT32_MAX = 0xFFFFFFFF).
#if RAND_MAX == UINT32_MAX
return static_cast<uint32_t>(rand());
#else
return static_cast<uint32_t>(GetRandU16()) ^
(static_cast<uint32_t>(GetRandU16()) << (sizeof(uint16_t) * CHAR_BIT));
#endif
}
uint16_t GetRandU16()
{
#if RAND_MAX >= UINT16_MAX
#if (RAND_MAX == INT_MAX) || (RAND_MAX == NORMALIZED_RAND_RANGE(UINT16_MAX))
// rand() random output range normalization is not needed.
return static_cast<uint16_t>(rand());
#else
// Otherwise, Normilize the output range of rand() and reject rand() outputs outside of that range.
while (true)
{
int r = rand();
if (r < NORMALIZED_RAND_RANGE(UINT16_MAX))
return static_cast<uint16_t>(r);
}
#endif
#else
return static_cast<uint16_t>(GetRandU8()) ^
(static_cast<uint16_t>(GetRandU8()) << CHAR_BIT);
#endif
}
uint8_t GetRandU8()
{
#if (RAND_MAX == INT_MAX) || (RAND_MAX == NORMALIZED_RAND_RANGE(UINT8_MAX))
// rand() random output range normalization is not needed.
return static_cast<uint8_t>(rand());
#else
// Otherwise, Normilize the output range of rand() and reject rand() outputs outside of that range.
while (true)
{
int r = rand();
if (r < NORMALIZED_RAND_RANGE(UINT8_MAX))
return static_cast<uint8_t>(r);
}
#endif
}
} // namespace Weave
} // namespace nl