mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
stdlib/rand: replace weak LCG with xorshift32 PRNG
The existing first-order LCG (seed = 470001 * seed % 999563) has several quality problems: - Output range limited to [1, 999562] (~20 bits) instead of full 32-bit - Lower bits have very short periods (8-bit period = 1, 16-bit = 105) - Overall period only ~1M, far too short for many applications - Causes mbedtls_rsa_gen_key to loop forever when rand() consumption aligns with the cycle length (issue #16760) Replace the entire order-based LCG implementation (CONFIG_LIBC_RAND_ORDER 0-3) with Marsaglia's xorshift32: - Full 32-bit output range - Period 2^32 - 1 (~4.29 billion) - Fast: just three XOR/shift operations - No floating-point math needed - No CONFIG_LIBC_RAND_ORDER configuration required Remove the CONFIG_LIBC_RAND_ORDER Kconfig option and clean up all defconfig references (12 boards) and related comments. Signed-off-by: hanzhijian <hanzhijian@zepp.com>
This commit is contained in:
parent
140ad8b305
commit
502feadb3d
15 changed files with 46 additions and 239 deletions
|
|
@ -17,7 +17,6 @@ CONFIG_BOARD_LOOPSPERMSEC=5483
|
|||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEFAULT_SMALL=y
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_LIBC_RAND_ORDER=2
|
||||
CONFIG_LINE_MAX=80
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=1024
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ CONFIG_BOARD_LOOPSPERMSEC=5483
|
|||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEFAULT_SMALL=y
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_LIBC_RAND_ORDER=2
|
||||
CONFIG_LINE_MAX=80
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=1024
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ CONFIG_I2C=y
|
|||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_LCD=y
|
||||
CONFIG_LCD_SHARP_MEMLCD=y
|
||||
CONFIG_LIBC_RAND_ORDER=2
|
||||
CONFIG_LINE_MAX=80
|
||||
CONFIG_MQ_MAXMSGSIZE=64
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ CONFIG_CDCACM_TXBUFSIZE=256
|
|||
CONFIG_DEFAULT_SMALL=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_LIBC_RAND_ORDER=2
|
||||
CONFIG_LINE_MAX=80
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=1024
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ CONFIG_EXAMPLES_HELLO=y
|
|||
CONFIG_FILE_STREAM=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_LIBC_RAND_ORDER=0
|
||||
CONFIG_LIBM=y
|
||||
CONFIG_LINE_MAX=80
|
||||
CONFIG_MTD=y
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ CONFIG_FS_FAT=y
|
|||
CONFIG_FS_NXFFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="configdata_main"
|
||||
CONFIG_LIBC_RAND_ORDER=3
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_BYTE_WRITE=y
|
||||
CONFIG_MTD_CONFIG=y
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ CONFIG_FS_FAT=y
|
|||
CONFIG_FS_NXFFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="nxffs_main"
|
||||
CONFIG_LIBC_RAND_ORDER=3
|
||||
CONFIG_MTD=y
|
||||
CONFIG_NXFFS_SCAN_VOLUME=y
|
||||
CONFIG_RAMMTD=y
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ CONFIG_EXAMPLES_MTDPART=y
|
|||
CONFIG_FS_FAT=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="mtdpart_main"
|
||||
CONFIG_LIBC_RAND_ORDER=3
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_PARTITION=y
|
||||
CONFIG_RAMMTD=y
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ CONFIG_EXAMPLES_MTDRWB=y
|
|||
CONFIG_FS_FAT=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="mtdrwb_main"
|
||||
CONFIG_LIBC_RAND_ORDER=3
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_PARTITION=y
|
||||
CONFIG_MTD_READAHEAD=y
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ CONFIG_FS_FAT=y
|
|||
CONFIG_FS_NXFFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="nxffs_main"
|
||||
CONFIG_LIBC_RAND_ORDER=3
|
||||
CONFIG_MTD=y
|
||||
CONFIG_NXFFS_SCAN_VOLUME=y
|
||||
CONFIG_RAMMTD=y
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ CONFIG_DISABLE_PTHREAD=y
|
|||
CONFIG_FS_SPIFFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="fstest_main"
|
||||
CONFIG_LIBC_RAND_ORDER=3
|
||||
CONFIG_MTD=y
|
||||
CONFIG_RAMMTD=y
|
||||
CONFIG_RAMMTD_FLASHSIM=y
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ CONFIG_IOB_BUFSIZE=400
|
|||
CONFIG_IOB_NBUFFERS=100
|
||||
CONFIG_IOB_NCHAINS=32
|
||||
CONFIG_IOB_THROTTLE=40
|
||||
CONFIG_LIBC_RAND_ORDER=2
|
||||
CONFIG_LINE_MAX=255
|
||||
CONFIG_MBEDTLS_APPS=y
|
||||
CONFIG_MBEDTLS_APP_BENCHMARK=y
|
||||
|
|
|
|||
|
|
@ -43,12 +43,10 @@ config DEV_URANDOM_XORSHIFT128
|
|||
config DEV_URANDOM_CONGRUENTIAL
|
||||
bool "Congruential"
|
||||
---help---
|
||||
Use the same congruential general used with srand(). This algorithm
|
||||
is computationally more intense and uses double precision floating
|
||||
point. NOTE: Good randomness from the congruential generator also
|
||||
requires that you also select CONFIG_LIBC_RAND_ORDER > 2
|
||||
Use the same PRNG used with srand()/rand(). Uses the system
|
||||
random number generator (xorshift32).
|
||||
|
||||
NOTE: Not cyptographically secure
|
||||
NOTE: Not cryptographically secure
|
||||
|
||||
config DEV_URANDOM_RANDOM_POOL
|
||||
bool "Entropy pool"
|
||||
|
|
|
|||
|
|
@ -5,15 +5,6 @@
|
|||
|
||||
menu "stdlib Options"
|
||||
|
||||
config LIBC_RAND_ORDER
|
||||
int "Order of the random number generate"
|
||||
default 1
|
||||
range 0 3
|
||||
---help---
|
||||
The order of the random number generator. 0=fast but very bad random
|
||||
numbers, 3=slow but very good random numbers.
|
||||
0 just use integer generation, 1-3 use floating point generation
|
||||
|
||||
config LIBC_HOMEDIR
|
||||
string "Home directory"
|
||||
default "/"
|
||||
|
|
|
|||
|
|
@ -27,231 +27,62 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nuttx/lib/lib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* First, second, and thired order congruential generators are supported */
|
||||
|
||||
#ifndef CONFIG_LIBC_RAND_ORDER
|
||||
# define CONFIG_LIBC_RAND_ORDER 1
|
||||
#endif
|
||||
|
||||
#if CONFIG_LIBC_RAND_ORDER > 3
|
||||
# undef CONFIG_LIBC_RAND_ORDER
|
||||
# define CONFIG_LIBC_RAND_ORDER 3
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_HAVE_DOUBLE
|
||||
typedef float float_t;
|
||||
#else
|
||||
typedef double float_t;
|
||||
#endif
|
||||
|
||||
/* Values needed by the random number generator */
|
||||
|
||||
#define RND1_CONSTK 470001
|
||||
#define RND1_CONSTP 999563
|
||||
#define RND2_CONSTK1 366528
|
||||
#define RND2_CONSTK2 508531
|
||||
#define RND2_CONSTP 998917
|
||||
#define RND3_CONSTK1 360137
|
||||
#define RND3_CONSTK2 519815
|
||||
#define RND3_CONSTK3 616087
|
||||
#define RND3_CONSTP 997783
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* First order congruential generators */
|
||||
|
||||
static inline unsigned long fgenerate1(FAR unsigned long *seed);
|
||||
#if (CONFIG_LIBC_RAND_ORDER == 1)
|
||||
static float_t frand1(FAR unsigned long *seed);
|
||||
#endif
|
||||
|
||||
/* Second order congruential generators */
|
||||
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 1)
|
||||
static inline unsigned long fgenerate2(void);
|
||||
#if (CONFIG_LIBC_RAND_ORDER == 2)
|
||||
static float_t frand2(void);
|
||||
#endif
|
||||
|
||||
/* Third order congruential generators */
|
||||
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 2)
|
||||
static inline unsigned long fgenerate3(void);
|
||||
static float_t frand3(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static unsigned long g_randint1;
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 1)
|
||||
static unsigned long g_randint2;
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 2)
|
||||
static unsigned long g_randint3;
|
||||
#endif
|
||||
#endif
|
||||
static uint32_t g_randstate = 1;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* First order congruential generators */
|
||||
/****************************************************************************
|
||||
* Name: xorshift32
|
||||
*
|
||||
* Description:
|
||||
* Marsaglia's xorshift32 PRNG. Period 2^32 - 1 (about 4.29 billion).
|
||||
* Much better statistical properties than a simple LCG with a small
|
||||
* modulus, while remaining fast (three XOR/shift operations).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline unsigned long fgenerate1(FAR unsigned long *seed)
|
||||
static inline uint32_t xorshift32(FAR uint32_t *state)
|
||||
{
|
||||
unsigned long randint;
|
||||
uint32_t x = *state;
|
||||
|
||||
/* First order congruential generator. One may be added to the result of
|
||||
* the generated value to avoid the value zero. This would be fatal for
|
||||
* the first order random number generator.
|
||||
/* State must never be zero, otherwise the generator is stuck.
|
||||
* The seed path (srand / rand_r) already guards against this, but we
|
||||
* check here as well for safety.
|
||||
*/
|
||||
|
||||
randint = (RND1_CONSTK * (*seed)) % RND1_CONSTP;
|
||||
*seed = (randint == 0 ? 1 : randint);
|
||||
return randint;
|
||||
}
|
||||
|
||||
#if (CONFIG_LIBC_RAND_ORDER == 1)
|
||||
static float_t frand1(FAR unsigned long *seed)
|
||||
{
|
||||
/* First order congruential generator. */
|
||||
|
||||
unsigned long randint = fgenerate1(seed);
|
||||
|
||||
/* Construct an floating point value in the range from 0.0 up to 1.0 */
|
||||
|
||||
return ((float_t)randint) / ((float_t)RND1_CONSTP);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Second order congruential generators */
|
||||
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 1)
|
||||
static inline unsigned long fgenerate2(void)
|
||||
{
|
||||
unsigned long randint;
|
||||
|
||||
/* Second order congruential generator. */
|
||||
|
||||
randint = (RND2_CONSTK1 * g_randint1 +
|
||||
RND2_CONSTK2 * g_randint2) % RND2_CONSTP;
|
||||
|
||||
g_randint2 = g_randint1;
|
||||
g_randint1 = randint;
|
||||
|
||||
/* We cannot permit both values to become zero. That would be fatal for
|
||||
* the second order random number generator.
|
||||
*/
|
||||
|
||||
if (g_randint2 == 0 && g_randint1 == 0)
|
||||
if (x == 0)
|
||||
{
|
||||
g_randint2 = 1;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
return randint;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
|
||||
*state = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
#if (CONFIG_LIBC_RAND_ORDER == 2)
|
||||
static float_t frand2(void)
|
||||
{
|
||||
/* Second order congruential generator */
|
||||
|
||||
unsigned long randint = fgenerate2();
|
||||
|
||||
/* Construct an floating point value in the range from 0.0 up to 1.0 */
|
||||
|
||||
return ((float_t)randint) / ((float_t)RND2_CONSTP);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Third order congruential generators */
|
||||
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 2)
|
||||
static inline unsigned long fgenerate3(void)
|
||||
{
|
||||
unsigned long randint;
|
||||
|
||||
/* Third order congruential generator. */
|
||||
|
||||
randint = (RND3_CONSTK1 * g_randint1 +
|
||||
RND3_CONSTK2 * g_randint2 +
|
||||
RND3_CONSTK2 * g_randint3) % RND3_CONSTP;
|
||||
|
||||
g_randint3 = g_randint2;
|
||||
g_randint2 = g_randint1;
|
||||
g_randint1 = randint;
|
||||
|
||||
/* We cannot permit all three values to become zero. That would be fatal
|
||||
* for the third order random number generator.
|
||||
*/
|
||||
|
||||
if (g_randint3 == 0 && g_randint2 == 0 && g_randint1 == 0)
|
||||
{
|
||||
g_randint3 = 1;
|
||||
}
|
||||
|
||||
return randint;
|
||||
}
|
||||
|
||||
static float_t frand3(void)
|
||||
{
|
||||
/* Third order congruential generator */
|
||||
|
||||
unsigned long randint = fgenerate3();
|
||||
|
||||
/* Construct an floating point value in the range from 0.0 up to 1.0 */
|
||||
|
||||
return ((float_t)randint) / ((float_t)RND3_CONSTP);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static unsigned long nrand_r(unsigned long limit,
|
||||
FAR unsigned long *seed)
|
||||
FAR uint32_t *state)
|
||||
{
|
||||
#if CONFIG_LIBC_RAND_ORDER > 0
|
||||
unsigned long result;
|
||||
float_t ratio;
|
||||
uint32_t randval = xorshift32(state);
|
||||
|
||||
/* Loop to be sure a legal random number is generated */
|
||||
/* Map the 32-bit random value into the range [0, limit).
|
||||
* The modulo bias is negligible for small limits relative to 2^32.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Get a random integer in the range 0.0 - 1.0 */
|
||||
|
||||
# if (CONFIG_LIBC_RAND_ORDER == 1)
|
||||
ratio = frand1(seed);
|
||||
# elif (CONFIG_LIBC_RAND_ORDER == 2)
|
||||
ratio = frand2();
|
||||
# elif (CONFIG_LIBC_RAND_ORDER > 2)
|
||||
ratio = frand3();
|
||||
#endif
|
||||
|
||||
/* Then, produce the return-able value in the requested range */
|
||||
|
||||
result = (unsigned long)(((float_t)limit) * ratio);
|
||||
|
||||
/* Loop because there is an (unlikely) possibility that rounding
|
||||
* could increase the result at the limit value about the limit.
|
||||
*/
|
||||
}
|
||||
while (result >= limit);
|
||||
|
||||
return result;
|
||||
#else
|
||||
return fgenerate1(seed) % limit;
|
||||
#endif
|
||||
return (unsigned long)(randval % (uint32_t)limit);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -262,21 +93,15 @@ static unsigned long nrand_r(unsigned long limit,
|
|||
* Name: srand
|
||||
*
|
||||
* Description:
|
||||
* Seed the congruential random number generator.
|
||||
* Seed the random number generator.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void srand(unsigned int seed)
|
||||
{
|
||||
g_randint1 = seed;
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 1)
|
||||
g_randint2 = seed;
|
||||
fgenerate1(&g_randint1);
|
||||
#if (CONFIG_LIBC_RAND_ORDER > 2)
|
||||
g_randint3 = seed;
|
||||
fgenerate2();
|
||||
#endif
|
||||
#endif
|
||||
/* Avoid a zero state which would make xorshift32 degenerate. */
|
||||
|
||||
g_randstate = (seed == 0) ? 1 : (uint32_t)seed;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -289,7 +114,7 @@ void srand(unsigned int seed)
|
|||
|
||||
unsigned long nrand(unsigned long limit)
|
||||
{
|
||||
return nrand_r(limit, &g_randint1);
|
||||
return nrand_r(limit, &g_randstate);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -308,10 +133,15 @@ unsigned long nrand(unsigned long limit)
|
|||
|
||||
int rand_r(FAR unsigned int *seedp)
|
||||
{
|
||||
unsigned long seed = *seedp;
|
||||
uint32_t state = (uint32_t)*seedp;
|
||||
unsigned long rand;
|
||||
|
||||
rand = nrand_r(INT_MAX, &seed);
|
||||
*seedp = (unsigned int)seed;
|
||||
if (state == 0)
|
||||
{
|
||||
state = 1;
|
||||
}
|
||||
|
||||
rand = nrand_r(INT_MAX, &state);
|
||||
*seedp = (unsigned int)state;
|
||||
return (int)rand;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue