LibISAAC  1.0.0
A modern reimplementation of the ISAAC CPRNG.
Data Structures | Macros | Typedefs | Functions
isaac.h File Reference
#include <stdint.h>
#include <stddef.h>
Include dependency graph for isaac.h:

Go to the source code of this file.

Data Structures

struct  isaac_ctx_t
 Context of the ISAAC CPRNG. More...
 

Macros

#define LIBISAAC_VERSION   "1.0.0"
 Version of the LibISAAC API using semantic versioning.
 
#define ISAAC_BITS   64
 
#define ISAAC_ELEMENTS   256U
 Amount of elements in ISAAC's context arrays.
 
#define ISAAC_SEED_MAX_BYTES   ISAAC_ELEMENTS
 Max bytes supported in the seed.
 

Typedefs

typedef uint64_t isaac_uint_t
 

Functions

void isaac_init (isaac_ctx_t *ctx, const uint8_t *seed, uint16_t seed_bytes)
 Initialises the ISAAC CPRNG with a seed. More...
 
void isaac_stream (isaac_ctx_t *ctx, isaac_uint_t *ints, size_t amount)
 Provides the next pseudo-random integer. More...
 
void isaac_cleanup (isaac_ctx_t *ctx)
 Safely erases the context. More...
 
void isaac_to_little_endian (uint8_t *bytes, const isaac_uint_t *values, size_t amount_of_values)
 Utility function, converting an array of 32-bit/64-bit integers into bytes using little endian byte order. More...
 
void isaac_to_big_endian (uint8_t *bytes, const isaac_uint_t *values, size_t amount_of_values)
 Utility function, converting an array of 32-bit/64-bit integers into bytes using big endian byte order. More...
 

Detailed Description

This library offers the tiny and fast ISAAC cryptographically secure pseudo random number generator (CSPRNG), in its 32-bit and 64-bit version wrapped into a modern, ISO C11, documented API, ready for embedded usage.

Use the ISAAC_BITS macro to compile LibISAAC optimised for 32 or 64 bits. The 32 bit is the classic ISAAC; the 64 bit is ISAAC-64. Note that the output differs between the two and the context grows twice in size when using the 64 bit version, but you also get twice the bytes per reshuffling.

Then the usage of ISAAC is easy:

About ISAAC

Quoting from its web page:

ISAAC (Indirection, Shift, Accumulate, Add, and Count) generates 32-bit random numbers. Averaged out, it requires 18.75 machine cycles to generate each 32-bit value. Cycles are guaranteed to be at least 240 values long, and they are 28295 values long on average. The results are uniformly distributed, unbiased, and unpredictable unless you know the seed. [...] ISAAC-64 generates a different sequence than ISAAC, but it uses the same principles. It uses 64-bit arithmetic. It generates a 64-bit result every 19 instructions. All cycles are at least 272 values, and the average cycle length is 216583.

ISAAC and its original source code is created by Bob Jenkins and released into the public domain.

This implementation is based on the original rand.c and isaac64.c, which uses 32-bit and 64-bit words respectively.

Macro Definition Documentation

◆ ISAAC_BITS

ISAAC_BITS   64

Set it to 32 or 64 to optimise ISAAC for 32 or 64 bit words respectively.

The 32 bit is the classic ISAAC; the 64 bit is ISAAC-64. Note that the output differs between the two and the context grows twice in size when using the 64 bit version, but you also get twice the bytes per reshuffling.

Typedef Documentation

◆ isaac_uint_t

An integer or word used by ISAAC, either a uint32_t or uint64_t.

Function Documentation

◆ isaac_init()

void isaac_init ( isaac_ctx_t ctx,
const uint8_t *  seed,
uint16_t  seed_bytes 
)

Initialises the ISAAC CPRNG with a seed.

The seed is copied value-wise into the ISAAC state, not byte-wise. That means that a uint8_t array {1,2,3,4} is copied into the ctx->result[] isaac_uint_t array as {1,2,3,4,0,...,0}, where each value is a isaac_uint_t value. Looking at the bytes and assuming little Endian byte order, the result is {1,2,3,4} --> {1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,0,...,0}.

The reason behind this choice is to avoid issues with endianness; as ISAAC works on isaac_uint_t values rather than their bytes, setting the isaac_uint_t values and not their bytes, shall produce the same CPRNG stream on architectures with different endianness. An isaac_uint_t* could also be a valid choice as seed input, but seeds are usually cryptographic keys and those are byte arrays, so a developer could be confused on how to insert a uint8_t* seed into a isaac_uint_t*.

Maps to void randinit(randctx *r, word flag) from the original implementation. Equivalent to a true flag with a seed provided. The false flag is not available, as it should not be used for security purposes.

Warning
Failing to provide a seed (NULL or long 0 bytes), will make the whole CSPRNG insecure as a zero-seed is used instead. This is only useful if a non-cryptographic PRNG is required.
Providing a seed with low entropy will result in the whole CSPRNG to be weak.
Parameters
[in,out]ctxthe ISAAC state to be initialised. Does nothing when NULL.
[in]seedpointer to the seed to use, which is copied into the context.
  • If NULL, then a zero seed is used instead (insecure!)
[in]seed_bytesamount of bytes in the seed, max ISAAC_SEED_MAX_BYTES.

◆ isaac_stream()

void isaac_stream ( isaac_ctx_t ctx,
isaac_uint_t ints,
size_t  amount 
)

Provides the next pseudo-random integer.

Because ISAAC works on 32 or 64 bit values, the stream is in integers instead of bytes. To convert them to bytes:

Every ISAAC_ELEMENTS values generated it will automatically reshuffle the ISAAC state to cache ISAAC_ELEMENTS new elements. This means that the first ISAAC_ELEMENTS values after seeding are very cheap (just copying values from the state) and the ISAAC_ELEMENTS+1st value is more expensive and so on.

Parameters
[in,out]ctxthe ISAAC state, already initialised. Does nothing when NULL.
[out]intspseudo-random integers. Does nothing when NULL.
[in]amountquantity of 32-bit/64-bit integers to generate.

◆ isaac_cleanup()

void isaac_cleanup ( isaac_ctx_t ctx)

Safely erases the context.

Useful to avoid leaking information about the seed or the state after finishing using ISAAC.

There is no need to call this function before using isaac_init(), including when re-initing an existing context.

Parameters
[in,out]ctxthe ISAAC state to cleanup. Does nothing when NULL.

◆ isaac_to_little_endian()

void isaac_to_little_endian ( uint8_t *  bytes,
const isaac_uint_t values,
size_t  amount_of_values 
)

Utility function, converting an array of 32-bit/64-bit integers into bytes using little endian byte order.

Useful to convert a stream of 32-bit/64-bit integers to 8-bit values.

Parameters
[out]bytes8-bit integers. Must be at least amount_of_values*4 bytes long. Does nothing when NULL.
[in]values32-bit/64-bit integers, as obtained from isaac_stream(). Does nothing when NULL.
[in]amount_of_valuesquantity of 32-bit/64-bit integers in the values buffer.

◆ isaac_to_big_endian()

void isaac_to_big_endian ( uint8_t *  bytes,
const isaac_uint_t values,
size_t  amount_of_values 
)

Utility function, converting an array of 32-bit/64-bit integers into bytes using big endian byte order.

Useful to convert a stream of 32-bit/64-bit integers to 8-bit values.

Parameters
[out]bytes8-bit integers. Must be at least amount_of_values*4 bytes long. Does nothing when NULL.
[in]values32-bit/64-bit integers, as obtained from isaac_stream(). Does nothing when NULL.
[in]amount_of_valuesquantity of 32-bit/64-bit integers in the values buffer.