From 07e20479ad68a0f6e02ef957cf33db99a2604d71 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 17 Jul 2016 07:56:25 -0600 Subject: [PATCH] /dev/random: Add configuration option to use the congruential PRNG. --- drivers/Kconfig | 20 +++++++++++ drivers/dev_urandom.c | 66 +++++++++++++++++++++++++++++++---- include/nuttx/lib.h | 6 +++- libc/stdlib/Make.defs | 4 +-- libc/stdlib/lib_rand.c | 63 ++++++++++++++++++++++++++++++++++ libc/stdlib/lib_srand.c | 76 +++++++++++++++++++++++------------------ 6 files changed, 193 insertions(+), 42 deletions(-) create mode 100644 libc/stdlib/lib_rand.c diff --git a/drivers/Kconfig b/drivers/Kconfig index 819183c4806..aba608676c9 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -33,10 +33,30 @@ config DEV_RANDOM config DEV_URANDOM bool "Enable /dev/urandom" default n + +if DEV_URANDOM + +choice + prompt "/dev/urandom algorithm" + default DEV_URANDOM_XORSHIFT128 + +config DEV_URANDOM_XORSHIFT128 + bool "xorshift128" ---help--- xorshift128 is a pseudorandom number generator that's simple, portable, and can also be used on 8-bit and 16-bit MCUs. +config DEV_URANDOM_CONGRUENTIAL + bool "Conguential" + ---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_LIB_RAND_ORDER > 2 + +endchoice # /dev/urandom algorithm +endif # DEV_URANDOM + source drivers/loop/Kconfig menu "Buffering" diff --git a/drivers/dev_urandom.c b/drivers/dev_urandom.c index 0c85d8cfa4c..b1ea3696650 100644 --- a/drivers/dev_urandom.c +++ b/drivers/dev_urandom.c @@ -45,11 +45,29 @@ #include #include +#include #include #include #include + +#include #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_DEV_URANDOM_CONGRUENTIAL) && \ + !defined(CONFIG_DEV_URANDOM_XORSHIFT128) +# define CONFIG_DEV_URANDOM_XORSHIFT128 1 +#endif + +#ifdef CONFIG_DEV_URANDOM_XORSHIFT128 +# define PRNG() xorshift128() +#else /* CONFIG_DEV_URANDOM_CONGRUENTIAL */ +# define PRNG() congruential() +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -101,12 +119,19 @@ static const struct file_operations devurand_fops = #endif }; +#ifdef CONFIG_DEV_URANDOM_XORSHIFT128 static xorshift128_state_t prng; +#endif /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: xorshift128 + ****************************************************************************/ + +#ifdef CONFIG_DEV_URANDOM_XORSHIFT128 static uint32_t xorshift128(void) { uint32_t t = prng.x; @@ -123,6 +148,22 @@ static uint32_t xorshift128(void) return prng.w; } +#endif + +/**************************************************************************** + * Name: congruential + ****************************************************************************/ + +#ifdef CONFIG_DEV_URANDOM_CONGRUENTIAL +static uint32_t congruential(void) +{ + /* REVISIT: We could probably generate a 32-bit value with a single + * call to nrand(). + */ + + return (uint32_t)nrand(65536L) << (uint32_t)nrand(65536L); +} +#endif /**************************************************************************** * Name: devurand_read @@ -138,13 +179,13 @@ static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer, /* Align buffer pointer to 4-byte boundry */ - if (((unsigned)buffer & 0x03) != 0) + if (((uintptr_t)buffer & 0x03) != 0) { /* Generate a pseudo random number */ - rnd = xorshift128(); + rnd = PRNG(); - while (((unsigned)buffer & 0x03) != 0) + while (((uintptr_t)buffer & 0x03) != 0) { if (n <= 0) { @@ -161,7 +202,7 @@ static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer, while (n >= 4) { - *(uint32_t *) buffer = xorshift128(); + *(uint32_t *)buffer = PRNG(); buffer += 4; n -= 4; } @@ -172,7 +213,7 @@ static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer, { /* Generate a pseudo random number */ - rnd = xorshift128(); + rnd = PRNG(); do { @@ -192,11 +233,20 @@ static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer, static ssize_t devurand_write(FAR struct file *filep, FAR const char *buffer, size_t len) { - /* Write can be used to seed the PRNG state */ + /* Write can be used to re-seed the PRNG state. */ +#ifdef CONFIG_DEV_URANDOM_CONGRUENTIAL + unsigned int seed = 0; + + len = min(len, sizeof(unsigned int)); + memcpy(&seed, buffer, len); + srand(seed); + return len; +#else len = min(len, sizeof(prng.u)); memcpy(&prng.u, buffer, len); return len; +#endif } /**************************************************************************** @@ -234,12 +284,16 @@ static int devurand_poll(FAR struct file *filep, FAR struct pollfd *fds, void devurandom_register(void) { +#ifdef CONFIG_DEV_URANDOM_CONGRUENTIAL + srand(10197); +#else /* Seed the PRNG */ prng.w = 97; prng.x = 101; prng.y = prng.w << 17; prng.z = prng.x << 25; +#endif (void)register_driver("/dev/urandom", &devurand_fops, 0666, NULL); } diff --git a/include/nuttx/lib.h b/include/nuttx/lib.h index 609f4f86f7e..24c1a8aec29 100644 --- a/include/nuttx/lib.h +++ b/include/nuttx/lib.h @@ -2,7 +2,7 @@ * include/nuttx/lib.h * Non-standard, internal APIs available in lib/. * - * Copyright (C) 2007-2009, 2012-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012-2014, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -77,6 +77,10 @@ void lib_stream_initialize(FAR struct task_group_s *group); void lib_stream_release(FAR struct task_group_s *group); #endif +/* Functions defined in lib_srand.c *****************************************/ + +unsigned long nrand(unsigned long limit); + #undef EXTERN #ifdef __cplusplus } diff --git a/libc/stdlib/Make.defs b/libc/stdlib/Make.defs index ecf8f5fefab..618b16a5450 100644 --- a/libc/stdlib/Make.defs +++ b/libc/stdlib/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # libc/stdlib/Make.defs # -# Copyright (C) 2012, 2015 Gregory Nutt. All rights reserved. +# Copyright (C) 2012, 2015-2016 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -37,7 +37,7 @@ CSRCS += lib_abs.c lib_abort.c lib_div.c lib_ldiv.c lib_lldiv.c CSRCS += lib_imaxabs.c lib_itoa.c lib_labs.c lib_llabs.c -CSRCS += lib_bsearch.c lib_srand.c lib_qsort.c +CSRCS += lib_bsearch.c lib_rand.c lib_qsort.c lib_srand.c CSRCS += lib_strtol.c lib_strtoll.c lib_strtoul.c lib_strtoull.c CSRCS += lib_strtod.c lib_checkbase.c diff --git a/libc/stdlib/lib_rand.c b/libc/stdlib/lib_rand.c new file mode 100644 index 00000000000..440372fe72e --- /dev/null +++ b/libc/stdlib/lib_rand.c @@ -0,0 +1,63 @@ +/**************************************************************************** + * libc/stdlib/lib_rand.c + * + * Copyright (C) 2007, 2011, 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rand + * + * Description: + * Generate a non-negative, integer random number in the range of 0 through + * (RAND_MAX - 1) + * + ****************************************************************************/ + +int rand(void) +{ + return (int)nrand(32768L); +} diff --git a/libc/stdlib/lib_srand.c b/libc/stdlib/lib_srand.c index 726b4ab0f75..8586afca117 100644 --- a/libc/stdlib/lib_srand.c +++ b/libc/stdlib/lib_srand.c @@ -37,12 +37,17 @@ * Included Files ****************************************************************************/ +#include + #include #include +#include + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* First, second, and thired order congruential generators are supported */ #ifndef CONFIG_LIB_RAND_ORDER @@ -70,8 +75,6 @@ * Private Function Prototypes ****************************************************************************/ -static unsigned int nrand(unsigned int limit); - /* First order congruential generators */ static inline unsigned long fgenerate1(void); @@ -111,34 +114,6 @@ static unsigned long g_randint3; * Private Functions ****************************************************************************/ -static unsigned int nrand(unsigned int limit) -{ - unsigned long result; - double_t ratio; - - /* Loop to be sure a legal random number is generated */ - - do - { - /* Get a random integer in the requested range */ - -#if (CONFIG_LIB_RAND_ORDER == 1) - ratio = frand1(); -#elif (CONFIG_LIB_RAND_ORDER == 2) - ratio = frand2(); -#else /* if (CONFIG_LIB_RAND_ORDER > 2) */ - ratio = frand3(); -#endif - - /* Then, produce the return-able value */ - - result = (unsigned long)(((double_t)limit) * ratio); - } - while (result >= (unsigned long)limit); - - return (unsigned int)result; -} - /* First order congruential generators */ static inline unsigned long fgenerate1(void) @@ -255,7 +230,11 @@ static double_t frand3(void) ****************************************************************************/ /**************************************************************************** - * Function: srand, rand + * Name: srand + * + * Description: + * Seed the confluent hypergeometric random number generator. + * ****************************************************************************/ void srand(unsigned int seed) @@ -271,7 +250,38 @@ void srand(unsigned int seed) #endif } -int rand(void) +/**************************************************************************** + * Name: nrand + * + * Description: + * Return a random unsigned long value in the range of 0 to (limit - 1) + * + ****************************************************************************/ + +unsigned long nrand(unsigned long limit) { - return (int)nrand(32768); + unsigned long result; + double_t ratio; + + /* Loop to be sure a legal random number is generated */ + + do + { + /* Get a random integer in the requested range */ + +#if (CONFIG_LIB_RAND_ORDER == 1) + ratio = frand1(); +#elif (CONFIG_LIB_RAND_ORDER == 2) + ratio = frand2(); +#else /* if (CONFIG_LIB_RAND_ORDER > 2) */ + ratio = frand3(); +#endif + + /* Then, produce the return-able value */ + + result = (unsigned long)(((double_t)limit) * ratio); + } + while (result >= limit); + + return result; }