Random API
The random module exposes an opaque deterministic pseudo-random number generator (PRNG).
Type
typedef struct GrimoireRandom_t GrimoireRandom_t;
#define GrimoireRandom GrimoireRandom_t*
GrimoireRandomis a pointer handle.- The internal state layout is intentionally hidden.
Lifecycle Functions
GrimoireRandom_CreateNew
GRIMOIRE_API GrimoireRandom GrimoireRandom_CreateNew();
Creates a new instance with a non-deterministic seed source.
- Returns: a valid
GrimoireRandomorNULLon allocation/initialization failure.
GrimoireRandom_CreateSeed
GRIMOIRE_API GrimoireRandom GrimoireRandom_CreateSeed(hash_t seed);
Creates a deterministic instance.
- Parameters:
seeddeterministic 32-bit seed (hash_t). - Returns: a valid
GrimoireRandomorNULLon failure.
GrimoireRandom_Destroy
GRIMOIRE_API void GrimoireRandom_Destroy(GrimoireRandom random);
Releases resources owned by the instance.
- Safe with
NULL. - Must be called exactly once for each successful
Create*result.
Sampling Functions
GrimoireRandom_Next
GRIMOIRE_API int32_t GrimoireRandom_Next(GrimoireRandom random);
Returns a pseudo-random signed 32-bit integer.
- Interval:
[0, INT32_MAX)
GrimoireRandom_NextRange
GRIMOIRE_API int32_t GrimoireRandom_NextRange(GrimoireRandom random, int32_t min, int32_t max);
Returns a pseudo-random integer in [min, max).
- Precondition:
min < max.
GrimoireRandom_NextMax
GRIMOIRE_API int32_t GrimoireRandom_NextMax(GrimoireRandom random, int32_t max);
Equivalent to GrimoireRandom_NextRange(random, 0, max).
- Precondition:
max > 0.
GrimoireRandom_NextDouble
GRIMOIRE_API double GrimoireRandom_NextDouble(GrimoireRandom random);
Returns a uniform floating-point value in [0.0, 1.0).
GrimoireRandom_NextBytes
GRIMOIRE_API void GrimoireRandom_NextBytes(GrimoireRandom random, void* buffer, size_t length);
Fills length bytes at buffer with pseudo-random data.
buffermust point to writable memory of at leastlengthbytes.
State and Cloning Functions
GrimoireRandom_Serialize
GRIMOIRE_API void GrimoireRandom_Serialize(GrimoireRandom random, uint8_t* buffer);
Serializes current state into a caller-provided byte buffer.
- Buffer size for this release: 228 bytes.
- Serialized layout is implementation-defined.
GrimoireRandom_Deserialize
GRIMOIRE_API GrimoireRandom GrimoireRandom_Deserialize(const uint8_t* buffer);
Creates a new instance from serialized state.
- Input buffer must come from
GrimoireRandom_Serialize. - Returns: cloned state as new handle or
NULLon failure.
GrimoireRandom_CloneInto
GRIMOIRE_API void GrimoireRandom_CloneInto(const GrimoireRandom source, GrimoireRandom destination);
Copies state from source into an existing destination instance.
GrimoireRandom_Clone
GRIMOIRE_API GrimoireRandom GrimoireRandom_Clone(const GrimoireRandom source);
Allocates and returns a new state-identical clone.
Determinism and Reproducibility
- Identical seed and call sequence produce identical outputs.
- Cloned or deserialized states continue sequence from the same point.
- Mixing deterministic and non-deterministic creation in one path will break reproducibility.
Ownership and Safety Checklist
- Always check
Create*,Clone, andDeserializeforNULL. - Destroy every created handle.
- Validate range inputs before calling
NextRange. - Keep serialized state buffers version-paired with this release.
- Do not use for cryptographic purposes.
Example: Checkpoint and Resume Stream
#include <stddef.h>
#include <grimoire-pcg/random.h>
enum { GRIMOIRE_RANDOM_STATE_SIZE = 228 };
typedef struct RngCheckpoint
{
uint32_t version;
uint32_t size;
uint8_t state[GRIMOIRE_RANDOM_STATE_SIZE];
} RngCheckpoint;
static bool checkpoint_save(GrimoireRandom rng, RngCheckpoint* outCp)
{
if (!rng || !outCp) {
return false;
}
outCp->version = 1;
outCp->size = GRIMOIRE_RANDOM_STATE_SIZE;
GrimoireRandom_Serialize(rng, outCp->state);
return true;
}
static GrimoireRandom checkpoint_load(const RngCheckpoint* cp)
{
if (!cp || cp->version != 1 || cp->size != GRIMOIRE_RANDOM_STATE_SIZE) {
return NULL;
}
return GrimoireRandom_Deserialize(cp->state);
}
void sample_resume(void)
{
RngCheckpoint cp;
GrimoireRandom a = GrimoireRandom_CreateSeed(42);
if (!a) return;
(void)GrimoireRandom_Next(a);
if (!checkpoint_save(a, &cp)) {
GrimoireRandom_Destroy(a);
return;
}
GrimoireRandom b = checkpoint_load(&cp);
if (b) {
int32_t v1 = GrimoireRandom_Next(a);
int32_t v2 = GrimoireRandom_Next(b);
(void)v1;
(void)v2;
GrimoireRandom_Destroy(b);
}
GrimoireRandom_Destroy(a);
}
Example: Branching a Deterministic Stream
#include <grimoire-pcg/random.h>
void generate_two_paths(hash_t seed)
{
GrimoireRandom base = GrimoireRandom_CreateSeed(seed);
if (!base) return;
GrimoireRandom branchA = GrimoireRandom_Clone(base);
GrimoireRandom branchB = GrimoireRandom_Clone(base);
if (branchA && branchB) {
int32_t a0 = GrimoireRandom_NextRange(branchA, 0, 100);
int32_t b0 = GrimoireRandom_NextRange(branchB, 0, 100);
(void)a0;
(void)b0;
}
GrimoireRandom_Destroy(branchB);
GrimoireRandom_Destroy(branchA);
GrimoireRandom_Destroy(base);
}