summaryrefslogtreecommitdiffstats
path: root/src/prng.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/prng.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/prng.c b/src/prng.c
new file mode 100644
index 0000000..45c6cb7
--- /dev/null
+++ b/src/prng.c
@@ -0,0 +1,252 @@
+/*
+ * prng.c: Pseudo Random Number Generator abstractions for nwipe.
+ *
+ * Copyright Darik Horn <dajhorn-dban@vanadac.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "nwipe.h"
+#include "prng.h"
+#include "context.h"
+#include "logging.h"
+
+#include "mt19937ar-cok/mt19937ar-cok.h"
+#include "isaac_rand/isaac_rand.h"
+#include "isaac_rand/isaac64.h"
+
+nwipe_prng_t nwipe_twister = { "Mersenne Twister (mt19937ar-cok)", nwipe_twister_init, nwipe_twister_read };
+
+nwipe_prng_t nwipe_isaac = { "ISAAC (rand.c 20010626)", nwipe_isaac_init, nwipe_isaac_read };
+nwipe_prng_t nwipe_isaac64 = { "ISAAC-64 (isaac64.c)", nwipe_isaac64_init, nwipe_isaac64_read };
+
+/* Print given number of bytes from unsigned integer number to a byte stream buffer starting with low-endian. */
+static inline void u32_to_buffer( u8* restrict buffer, u32 val, const int len )
+{
+ for( int i = 0; i < len; ++i )
+ {
+ buffer[i] = (u8) ( val & 0xFFUL );
+ val >>= 8;
+ }
+}
+static inline void u64_to_buffer( u8* restrict buffer, u64 val, const int len )
+{
+ for( int i = 0; i < len; ++i )
+ {
+ buffer[i] = (u8) ( val & 0xFFULL );
+ val >>= 8;
+ }
+}
+static inline u32 isaac_nextval( randctx* restrict ctx )
+{
+ if( ctx->randcnt == 0 )
+ {
+ isaac( ctx );
+ ctx->randcnt = RANDSIZ;
+ }
+ ctx->randcnt--;
+ return ctx->randrsl[ctx->randcnt];
+}
+static inline u64 isaac64_nextval( rand64ctx* restrict ctx )
+{
+ if( ctx->randcnt == 0 )
+ {
+ isaac64( ctx );
+ ctx->randcnt = RANDSIZ;
+ }
+ ctx->randcnt--;
+ return ctx->randrsl[ctx->randcnt];
+}
+
+int nwipe_twister_init( NWIPE_PRNG_INIT_SIGNATURE )
+{
+ nwipe_log( NWIPE_LOG_NOTICE, "Initialising Mersenne Twister prng" );
+
+ if( *state == NULL )
+ {
+ /* This is the first time that we have been called. */
+ *state = malloc( sizeof( twister_state_t ) );
+ }
+ twister_init( (twister_state_t*) *state, (u32*) ( seed->s ), seed->length / sizeof( u32 ) );
+ return 0;
+}
+
+int nwipe_twister_read( NWIPE_PRNG_READ_SIGNATURE )
+{
+ u8* restrict bufpos = buffer;
+ size_t words = count / SIZE_OF_TWISTER; // the values of twister_genrand_int32 is strictly 4 bytes
+
+ /* Twister returns 4-bytes per call, so progress by 4 bytes. */
+ for( size_t ii = 0; ii < words; ++ii )
+ {
+ u32_to_buffer( bufpos, twister_genrand_int32( (twister_state_t*) *state ), SIZE_OF_TWISTER );
+ bufpos += SIZE_OF_TWISTER;
+ }
+
+ /* If there is some remainder copy only relevant number of bytes to not
+ * overflow the buffer. */
+ const size_t remain = count % SIZE_OF_TWISTER; // SIZE_OF_TWISTER is strictly 4 bytes
+ if( remain > 0 )
+ {
+ u32_to_buffer( bufpos, twister_genrand_int32( (twister_state_t*) *state ), remain );
+ }
+
+ return 0;
+}
+
+int nwipe_isaac_init( NWIPE_PRNG_INIT_SIGNATURE )
+{
+ int count;
+ randctx* isaac_state = *state;
+
+ nwipe_log( NWIPE_LOG_NOTICE, "Initialising Isaac prng" );
+
+ if( *state == NULL )
+ {
+ /* This is the first time that we have been called. */
+ *state = malloc( sizeof( randctx ) );
+ isaac_state = *state;
+
+ /* Check the memory allocation. */
+ if( isaac_state == 0 )
+ {
+ nwipe_perror( errno, __FUNCTION__, "malloc" );
+ nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the isaac state." );
+ return -1;
+ }
+ }
+
+ /* Take the minimum of the isaac seed size and available entropy. */
+ if( sizeof( isaac_state->randrsl ) < seed->length )
+ {
+ count = sizeof( isaac_state->randrsl );
+ }
+ else
+ {
+ memset( isaac_state->randrsl, 0, sizeof( isaac_state->randrsl ) );
+ count = seed->length;
+ }
+
+ if( count == 0 )
+ {
+ /* Start ISACC without a seed. */
+ randinit( isaac_state, 0 );
+ }
+ else
+ {
+ /* Seed the ISAAC state with entropy. */
+ memcpy( isaac_state->randrsl, seed->s, count );
+
+ /* The second parameter indicates that randrsl is non-empty. */
+ randinit( isaac_state, 1 );
+ }
+
+ return 0;
+}
+
+int nwipe_isaac_read( NWIPE_PRNG_READ_SIGNATURE )
+{
+ randctx* isaac_state = *state;
+ u8* restrict bufpos = buffer;
+ size_t words = count / SIZE_OF_ISAAC; // the values of isaac is strictly 4 bytes
+
+ /* Isaac returns 4-bytes per call, so progress by 4 bytes. */
+ for( size_t ii = 0; ii < words; ++ii )
+ {
+ /* get the next 32bit random number */
+ u32_to_buffer( bufpos, isaac_nextval( isaac_state ), SIZE_OF_ISAAC );
+ bufpos += SIZE_OF_ISAAC;
+ }
+
+ /* If there is some remainder copy only relevant number of bytes to not overflow the buffer. */
+ const size_t remain = count % SIZE_OF_ISAAC; // SIZE_OF_ISAAC is strictly 4 bytes
+ if( remain > 0 )
+ {
+ u32_to_buffer( bufpos, isaac_nextval( isaac_state ), remain );
+ }
+
+ return 0;
+}
+
+int nwipe_isaac64_init( NWIPE_PRNG_INIT_SIGNATURE )
+{
+ int count;
+ rand64ctx* isaac_state = *state;
+
+ nwipe_log( NWIPE_LOG_NOTICE, "Initialising ISAAC-64 prng" );
+
+ if( *state == NULL )
+ {
+ /* This is the first time that we have been called. */
+ *state = malloc( sizeof( rand64ctx ) );
+ isaac_state = *state;
+
+ /* Check the memory allocation. */
+ if( isaac_state == 0 )
+ {
+ nwipe_perror( errno, __FUNCTION__, "malloc" );
+ nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the isaac state." );
+ return -1;
+ }
+ }
+
+ /* Take the minimum of the isaac seed size and available entropy. */
+ if( sizeof( isaac_state->randrsl ) < seed->length )
+ {
+ count = sizeof( isaac_state->randrsl );
+ }
+ else
+ {
+ memset( isaac_state->randrsl, 0, sizeof( isaac_state->randrsl ) );
+ count = seed->length;
+ }
+
+ if( count == 0 )
+ {
+ /* Start ISACC without a seed. */
+ rand64init( isaac_state, 0 );
+ }
+ else
+ {
+ /* Seed the ISAAC state with entropy. */
+ memcpy( isaac_state->randrsl, seed->s, count );
+
+ /* The second parameter indicates that randrsl is non-empty. */
+ rand64init( isaac_state, 1 );
+ }
+
+ return 0;
+}
+
+int nwipe_isaac64_read( NWIPE_PRNG_READ_SIGNATURE )
+{
+ rand64ctx* isaac_state = *state;
+ u8* restrict bufpos = buffer;
+ size_t words = count / SIZE_OF_ISAAC64; // the values of ISAAC-64 is strictly 8 bytes
+
+ for( size_t ii = 0; ii < words; ++ii )
+ {
+ u64_to_buffer( bufpos, isaac64_nextval( isaac_state ), SIZE_OF_ISAAC64 );
+ bufpos += SIZE_OF_ISAAC64;
+ }
+
+ /* If there is some remainder copy only relevant number of bytes to not overflow the buffer. */
+ const size_t remain = count % SIZE_OF_ISAAC64; // SIZE_OF_ISAAC64 is strictly 8 bytes
+ if( remain > 0 )
+ {
+ u64_to_buffer( bufpos, isaac64_nextval( isaac_state ), remain );
+ }
+
+ return 0;
+}