mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Add secure_rand_below function
It works by masking the numbers and the using rejection sampling to ensure a uniform generation.
This commit is contained in:
parent
22ef342ffc
commit
782c826381
|
@ -2203,6 +2203,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST)
|
|||
netaddr.cpp
|
||||
packer.cpp
|
||||
prng.cpp
|
||||
secure_random.cpp
|
||||
sorted_array.cpp
|
||||
str.cpp
|
||||
strip_path_and_extension.cpp
|
||||
|
|
|
@ -3608,6 +3608,34 @@ int secure_rand(void)
|
|||
return (int)(i % RAND_MAX);
|
||||
}
|
||||
|
||||
// From https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2.
|
||||
static unsigned int find_next_power_of_two_minus_one(unsigned int n)
|
||||
{
|
||||
n--;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 4;
|
||||
n |= n >> 16;
|
||||
return n;
|
||||
}
|
||||
|
||||
int secure_rand_below(int below)
|
||||
{
|
||||
unsigned int mask = find_next_power_of_two_minus_one(below);
|
||||
dbg_assert(below > 0, "below must be positive");
|
||||
while(1)
|
||||
{
|
||||
unsigned int n;
|
||||
secure_random_fill(&n, sizeof(n));
|
||||
n &= mask;
|
||||
if((int)n < below)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2193,6 +2193,16 @@ void secure_random_fill(void *bytes, unsigned length);
|
|||
*/
|
||||
int secure_rand(void);
|
||||
|
||||
/*
|
||||
Function: secure_rand_below
|
||||
Returns a random nonnegative integer below the given number,
|
||||
with a uniform distribution.
|
||||
|
||||
Parameters:
|
||||
below - Upper limit (exclusive) of integers to return.
|
||||
*/
|
||||
int secure_rand_below(int below);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
35
src/test/secure_random.cpp
Normal file
35
src/test/secure_random.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "test.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <base/system.h>
|
||||
|
||||
TEST(SecureRandom, Fill)
|
||||
{
|
||||
unsigned int Bits = 0;
|
||||
while(~Bits)
|
||||
{
|
||||
unsigned int Random;
|
||||
secure_random_fill(&Random, sizeof(Random));
|
||||
Bits |= Random;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SecureRandom, Below1)
|
||||
{
|
||||
EXPECT_EQ(secure_rand_below(1), 0);
|
||||
}
|
||||
|
||||
TEST(SecureRandom, Below)
|
||||
{
|
||||
int BOUNDS[] = {2, 3, 4, 5, 10, 100, 127, 128, 129};
|
||||
for(int i = 0; i < sizeof(BOUNDS) / sizeof(BOUNDS[0]); i++)
|
||||
{
|
||||
int Below = BOUNDS[i];
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
int Random = secure_rand_below(Below);
|
||||
EXPECT_GE(Random, 0);
|
||||
EXPECT_LT(Random, Below);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,5 +15,10 @@ int main(int argc, char **argv)
|
|||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
net_init();
|
||||
if(secure_random_init())
|
||||
{
|
||||
fprintf(stderr, "random init failed\n");
|
||||
return 1;
|
||||
}
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue