Skip to content

Commit 4de7bc5

Browse files
authored
[random] introduce template-based NonCrypto random APIs (openthread#13142)
This commit introduces a new set of template-based APIs for non-cryptographic random number generation in the `Random::NonCrypto` namespace. These new methods provide a cleaner, type-safe, and more robust interface compared to the previous methods. Key additions: - `Generate<UintType>()`: Returns a random value of the given unsigned integer type (`uint8_t`, `uint16_t`, or `uint32_t`). - `GenerateUpToExcluding<UintType>(aMax)`: Returns a random value in the range `[0, aMax)`. - `GenerateFromMinUpToExcluding<UintType>(aMin, aMax)`: Returns a random value in the range `[aMin, aMax)`. - `GenerateInClosedRange<UintType>(aMin, aMax)`: Returns a random value in the closed range `[aMin, aMax]`. The introduction of `GenerateInClosedRange` is an improvement as it safely handles ranges up to the maximum value of the integer type (e.g., `0xffff`) without the risk of overflow. All call sites across the OpenThread core stack and tests have been updated to adopt these new APIs. The public `otRandomNonCrypto` functions are also updated to leverage the new internal methods. Doxygen documentation is added for all new template methods, detailing their behavior, including edge cases where the upper bound is smaller than or equal to the lower bound.
1 parent 9d95a19 commit 4de7bc5

46 files changed

Lines changed: 383 additions & 131 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/core/api/random_noncrypto_api.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,25 @@
3737

3838
using namespace ot;
3939

40-
uint32_t otRandomNonCryptoGetUint32(void) { return Random::NonCrypto::GetUint32(); }
40+
uint32_t otRandomNonCryptoGetUint32(void) { return Random::NonCrypto::Generate<uint32_t>(); }
4141

42-
uint8_t otRandomNonCryptoGetUint8(void) { return Random::NonCrypto::GetUint8(); }
42+
uint8_t otRandomNonCryptoGetUint8(void) { return Random::NonCrypto::Generate<uint8_t>(); }
4343

44-
uint16_t otRandomNonCryptoGetUint16(void) { return Random::NonCrypto::GetUint16(); }
44+
uint16_t otRandomNonCryptoGetUint16(void) { return Random::NonCrypto::Generate<uint16_t>(); }
4545

4646
uint8_t otRandomNonCryptoGetUint8InRange(uint8_t aMin, uint8_t aMax)
4747
{
48-
return Random::NonCrypto::GetUint8InRange(aMin, aMax);
48+
return Random::NonCrypto::GenerateFromMinUpToExcluding(aMin, aMax);
4949
}
5050

5151
uint16_t otRandomNonCryptoGetUint16InRange(uint16_t aMin, uint16_t aMax)
5252
{
53-
return Random::NonCrypto::GetUint16InRange(aMin, aMax);
53+
return Random::NonCrypto::GenerateFromMinUpToExcluding(aMin, aMax);
5454
}
5555

5656
uint32_t otRandomNonCryptoGetUint32InRange(uint32_t aMin, uint32_t aMax)
5757
{
58-
return Random::NonCrypto::GetUint32InRange(aMin, aMax);
58+
return Random::NonCrypto::GenerateFromMinUpToExcluding(aMin, aMax);
5959
}
6060

6161
void otRandomNonCryptoFillBuffer(uint8_t *aBuffer, uint16_t aSize) { Random::NonCrypto::FillBuffer(aBuffer, aSize); }

src/core/backbone_router/bbr_leader.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,7 @@ void Config::AdjustMlrTimeout(void)
6363

6464
uint16_t Config::SelectRandomReregistrationDelay(void) const
6565
{
66-
uint16_t delay = 1;
67-
68-
VerifyOrExit(mReregistrationDelay > 1);
69-
delay = 1 + Random::NonCrypto::GetUint16InRange(0, mReregistrationDelay);
70-
71-
exit:
72-
return delay;
66+
return Random::NonCrypto::GenerateInClosedRange<uint16_t>(1, mReregistrationDelay);
7367
}
7468

7569
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)

src/core/backbone_router/bbr_local.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Local::Local(Instance &aInstance)
4747
: InstanceLocator(aInstance)
4848
, mIsServiceAdded(false)
4949
, mState(kStateDisabled)
50-
, mSequenceNumber(Random::NonCrypto::GetUint8() % 127)
50+
, mSequenceNumber(Random::NonCrypto::GenerateUpToExcluding<uint8_t>(127))
5151
, mRegistrationJitter(kDefaultRegistrationJitter)
5252
, mReregistrationDelay(kDefaultRegistrationDelay)
5353
, mRegistrationTimeout(0)
@@ -266,8 +266,7 @@ void Local::UpdateState(void)
266266
}
267267
else
268268
{
269-
mRegistrationTimeout =
270-
1 + Random::NonCrypto::GetUint16InRange(0, static_cast<uint16_t>(mRegistrationJitter));
269+
mRegistrationTimeout = Random::NonCrypto::GenerateInClosedRange<uint16_t>(1, mRegistrationJitter);
271270
Get<TimeTicker>().RegisterReceiver(TimeTicker::kBbrLocal);
272271
}
273272
}

src/core/border_router/dhcp6_pd_client.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ void Dhcp6PdClient::EnterState(State aState)
120120
case kStateToSolicit:
121121
ClearServerDuid();
122122
ClearPdPrefix();
123-
mTimer.Start(Random::NonCrypto::GetUint32InRange(0, kMaxDelayFirstSolicit));
123+
mTimer.Start(Random::NonCrypto::GenerateUpToExcluding(kMaxDelayFirstSolicit));
124124
break;
125125

126126
case kStateSoliciting:
@@ -1183,11 +1183,11 @@ uint32_t Dhcp6PdClient::RetxTracker::AddJitter(uint32_t aValue, JitterMode aJitt
11831183
switch (aJitterMode)
11841184
{
11851185
case kPositiveJitter:
1186-
randomizedValue += Random::NonCrypto::GetUint32InRange(0, jitter);
1186+
randomizedValue += Random::NonCrypto::GenerateUpToExcluding<uint32_t>(jitter);
11871187
break;
11881188

11891189
case kFullJitter:
1190-
randomizedValue += Random::NonCrypto::GetUint32InRange(0, 2 * jitter) - jitter;
1190+
randomizedValue += Random::NonCrypto::GenerateUpToExcluding<uint32_t>(2 * jitter) - jitter;
11911191
break;
11921192
}
11931193

src/core/border_router/routing_manager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ void RoutingManager::OmrPrefixManager::Evaluate(void)
986986
{
987987
case kNotAdded:
988988
{
989-
uint32_t delay = Random::NonCrypto::GetUint32InRange(kMinDelayToAdd, kMaxDelayToAdd);
989+
uint32_t delay = Random::NonCrypto::GenerateInClosedRange(kMinDelayToAdd, kMaxDelayToAdd);
990990

991991
mLocalInNetDataState = kToAdd;
992992
mTimer.Start(delay);

src/core/border_router/rx_ra_tracker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,7 @@ void RxRaTracker::RsSender::Start(void)
18061806

18071807
VerifyOrExit(!IsInProgress());
18081808

1809-
delay = Random::NonCrypto::GetUint32InRange(0, kMaxStartDelay);
1809+
delay = Random::NonCrypto::GenerateUpToExcluding(kMaxStartDelay);
18101810

18111811
LogInfo("RsSender: Starting - will send first RS in %lu msec", ToUlong(delay));
18121812

src/core/coap/coap.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ CoapBase::CoapBase(Instance &aInstance, Transmitter aTransmitter)
124124
, mResponseCache(aInstance)
125125
, mResourceHandler(nullptr)
126126
, mTransmitter(aTransmitter)
127-
, mMessageId(Random::NonCrypto::GetUint16())
127+
, mMessageId(Random::NonCrypto::Generate<uint16_t>())
128128
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
129129
, mLastResponse(nullptr)
130130
#endif
@@ -2045,8 +2045,8 @@ Error TxParameters::ValidateFor(const Msg &aMsg) const
20452045

20462046
uint32_t TxParameters::CalculateInitialRetransmissionTimeout(void) const
20472047
{
2048-
return Random::NonCrypto::GetUint32InRange(
2049-
mAckTimeout, mAckTimeout * mAckRandomFactorNumerator / mAckRandomFactorDenominator + 1);
2048+
return Random::NonCrypto::GenerateInClosedRange<uint32_t>(mAckTimeout, mAckTimeout * mAckRandomFactorNumerator /
2049+
mAckRandomFactorDenominator);
20502050
}
20512051

20522052
uint32_t TxParameters::CalculateExchangeLifetime(void) const

src/core/common/random.cpp

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
#include "common/code_utils.hpp"
3939
#include "common/debug.hpp"
40+
#include "common/num_utils.hpp"
41+
#include "common/numeric_limits.hpp"
4042

4143
namespace ot {
4244
namespace Random {
@@ -129,30 +131,64 @@ uint32_t Manager::NonCryptoPrng::GetNext(void)
129131

130132
namespace NonCrypto {
131133

132-
uint8_t GetUint8InRange(uint8_t aMin, uint8_t aMax)
134+
static uint32_t GenerateInRange(uint32_t aMin, uint32_t aMax)
133135
{
134-
OT_ASSERT(aMax > aMin);
136+
uint32_t value;
137+
uint32_t range;
135138

136-
return (aMin + (GetUint8() % (aMax - aMin)));
139+
VerifyOrExit(aMin < aMax, value = aMin);
140+
141+
value = Generate<uint32_t>();
142+
143+
range = aMax - aMin;
144+
145+
VerifyOrExit(range < NumericLimits<uint32_t>::kMax);
146+
147+
value = aMin + (value % (range + 1));
148+
149+
exit:
150+
return value;
151+
}
152+
153+
template <typename UintType> UintType GenerateUpToExcluding(UintType aMax)
154+
{
155+
return GenerateFromMinUpToExcluding<UintType>(0, aMax);
137156
}
138157

139-
uint16_t GetUint16InRange(uint16_t aMin, uint16_t aMax)
158+
template <typename UintType> UintType GenerateFromMinUpToExcluding(UintType aMin, UintType aMax)
140159
{
141-
OT_ASSERT(aMax > aMin);
142-
return (aMin + (GetUint16() % (aMax - aMin)));
160+
if (aMax > 0)
161+
{
162+
aMax--;
163+
}
164+
165+
return GenerateInClosedRange<UintType>(aMin, aMax);
143166
}
144167

145-
uint32_t GetUint32InRange(uint32_t aMin, uint32_t aMax)
168+
template <typename UintType> UintType GenerateInClosedRange(UintType aMin, UintType aMax)
146169
{
147-
OT_ASSERT(aMax > aMin);
148-
return (aMin + (GetUint32() % (aMax - aMin)));
170+
return static_cast<UintType>(GenerateInRange(aMin, aMax));
149171
}
150172

173+
// Explicit instantiations
174+
175+
template uint8_t GenerateUpToExcluding<uint8_t>(uint8_t aMax);
176+
template uint16_t GenerateUpToExcluding<uint16_t>(uint16_t aMax);
177+
template uint32_t GenerateUpToExcluding<uint32_t>(uint32_t aMax);
178+
179+
template uint8_t GenerateFromMinUpToExcluding<uint8_t>(uint8_t aMin, uint8_t aMax);
180+
template uint16_t GenerateFromMinUpToExcluding<uint16_t>(uint16_t aMin, uint16_t aMax);
181+
template uint32_t GenerateFromMinUpToExcluding<uint32_t>(uint32_t aMin, uint32_t aMax);
182+
183+
template uint8_t GenerateInClosedRange<uint8_t>(uint8_t aMin, uint8_t aMax);
184+
template uint16_t GenerateInClosedRange<uint16_t>(uint16_t aMin, uint16_t aMax);
185+
template uint32_t GenerateInClosedRange<uint32_t>(uint32_t aMin, uint32_t aMax);
186+
151187
void FillBuffer(uint8_t *aBuffer, uint16_t aSize)
152188
{
153189
while (aSize-- != 0)
154190
{
155-
*aBuffer++ = GetUint8();
191+
*aBuffer++ = Generate<uint8_t>();
156192
}
157193
}
158194

@@ -163,7 +199,7 @@ uint32_t AddJitter(uint32_t aValue, uint16_t aJitter)
163199
VerifyOrExit(aValue != 0);
164200

165201
aJitter = (aJitter <= aValue) ? aJitter : static_cast<uint16_t>(aValue);
166-
delay = aValue + GetUint32InRange(0, 2 * aJitter + 1) - aJitter;
202+
delay = aValue + GenerateUpToExcluding<uint32_t>(2 * aJitter + 1) - aJitter;
167203

168204
exit:
169205
return delay;

src/core/common/random.hpp

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -101,60 +101,53 @@ class Manager : private NonCopyable
101101
namespace NonCrypto {
102102

103103
/**
104-
* Generates and returns a random `uint32_t` value.
104+
* Generates and returns a random value of a given unsigned integer type.
105105
*
106-
* @returns A random `uint32_t` value.
107-
*/
108-
inline uint32_t GetUint32(void) { return Manager::NonCryptoGetUint32(); }
109-
110-
/**
111-
* Generates and returns a random byte.
106+
* @tparam UintType The unsigned integer type to generate (must be `uint8_t`, `uint16_t`, or `uint32_t`).
112107
*
113-
* @returns A random `uint8_t` value.
108+
* @returns A random `UintType` value.
114109
*/
115-
inline uint8_t GetUint8(void) { return static_cast<uint8_t>(GetUint32() & 0xff); }
110+
template <typename UintType> inline UintType Generate(void)
111+
{
112+
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int");
113+
static_assert(!TypeTraits::IsSame<UintType, uint64_t>::kValue, "UintType cannot be `uint64_t`");
116114

117-
/**
118-
* Generates and returns a random `uint16_t` value.
119-
*
120-
* @returns A random `uint16_t` value.
121-
*/
122-
inline uint16_t GetUint16(void) { return static_cast<uint16_t>(GetUint32() & 0xffff); }
115+
return static_cast<UintType>(Manager::NonCryptoGetUint32());
116+
}
123117

124118
/**
125-
* Generates and returns a random `uint8_t` value within a given range `[aMin, aMax)`.
119+
* Generates and returns a random value of a given unsigned integer type within range `[0, aMax)`.
120+
*
121+
* @tparam UintType The unsigned integer type to generate (must be `uint8_t`, `uint16_t`, or `uint32_t`).
126122
*
127-
* @param[in] aMin A minimum value (this value can be included in returned random result).
128-
* @param[in] aMax A maximum value (this value is excluded from returned random result).
123+
* @param[in] aMax The upper bound (exclusive). If zero, zero is returned.
129124
*
130-
* @returns A random `uint8_t` value in the given range (i.e., aMin <= random value < aMax).
125+
* @returns A random `UintType` value in the range `[0, aMax)`.
131126
*/
132-
uint8_t GetUint8InRange(uint8_t aMin, uint8_t aMax);
133-
127+
template <typename UintType> UintType GenerateUpToExcluding(UintType aMax);
134128
/**
135-
* Generates and returns a random `uint16_t` value within a given range `[aMin, aMax)`.
129+
* Generates and returns a random value of a given unsigned integer type within range `[aMin, aMax)`.
136130
*
137-
* @note The returned random value can include the @p aMin value but excludes the @p aMax.
131+
* @tparam UintType The unsigned integer type to generate (must be `uint8_t`, `uint16_t`, or `uint32_t`).
138132
*
139-
* @param[in] aMin A minimum value (this value can be included in returned random result).
140-
* @param[in] aMax A maximum value (this value is excluded from returned random result).
133+
* @param[in] aMin The lower bound (inclusive).
134+
* @param[in] aMax The upper bound (exclusive). If @p aMax <= @p aMin, @p aMin is returned.
141135
*
142-
* @returns A random `uint16_t` value in the given range (i.e., aMin <= random value < aMax).
136+
* @returns A random `UintType` value in the range `[aMin, aMax)`.
143137
*/
144-
uint16_t GetUint16InRange(uint16_t aMin, uint16_t aMax);
138+
template <typename UintType> UintType GenerateFromMinUpToExcluding(UintType aMin, UintType aMax);
145139

146140
/**
147-
* Generates and returns a random `uint32_t` value within a given range `[aMin, aMax)`.
141+
* Generates and returns a random value of a given unsigned integer type within a closed range `[aMin, aMax]`.
148142
*
149-
* @note The returned random value can include the @p aMin value but excludes the @p aMax.
143+
* @tparam UintType The unsigned integer type to generate (must be `uint8_t`, `uint16_t`, or `uint32_t`).
150144
*
151-
* @param[in] aMin A minimum value (this value can be included in returned random result).
152-
* @param[in] aMax A maximum value (this value is excluded from returned random result).
145+
* @param[in] aMin The lower bound (inclusive).
146+
* @param[in] aMax The upper bound (inclusive). If @p aMax < @p aMin, @p aMin is returned.
153147
*
154-
* @returns A random `uint32_t` value in the given range (i.e., aMin <= random value < aMax).
148+
* @returns A random `UintType` value in the range `[aMin, aMax]`.
155149
*/
156-
uint32_t GetUint32InRange(uint32_t aMin, uint32_t aMax);
157-
150+
template <typename UintType> UintType GenerateInClosedRange(UintType aMin, UintType aMax);
158151
/**
159152
* Fills a given buffer with random bytes.
160153
*

src/core/common/time_ticker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void TimeTicker::RegisterReceiver(Receiver aReceiver)
5050

5151
if (!mTimer.IsRunning())
5252
{
53-
mTimer.Start(Random::NonCrypto::GetUint32InRange(0, kTickInterval + 1));
53+
mTimer.Start(Random::NonCrypto::GenerateInClosedRange<uint32_t>(0, kTickInterval));
5454
}
5555
}
5656

0 commit comments

Comments
 (0)