Skip to content

jamesgober/mod-rand

Repository files navigation

Rust logo
mod-rand
TIERED RANDOM NUMBER GENERATION FOR RUST

crates.io downloads docs.rs MSRV CI

Fast PRNG, process-unique seeds, and OS-backed cryptographic random
in one zero-dependency library. Pick the tier appropriate to your threat model.


What it does

Random number generation in Rust today forces a choice: pull in the heavy rand ecosystem (multiple crates, opinionated traits, generic overhead) or write your own. mod-rand is the middle ground — three clearly-tiered random sources in one library, zero external dependencies, MSRV 1.75.

The three tiers

use mod_rand::{tier1, tier2, tier3};

// Tier 1: Fast deterministic PRNG — for simulations and test fixtures.
let mut rng = tier1::Xoshiro256::seed_from_u64(42);
let n: u64 = rng.next_u64();

// Tier 2: Process-unique seeds — for tempdir names and request IDs.
let name: String = tier2::unique_name(8);

// Tier 3: Cryptographic random — for tokens and keys.
let token: String = tier3::random_hex(16)?;
# Ok::<(), std::io::Error>(())

Bounded ranges — every tier exposes a parallel family of bounded-range methods using Rust's range syntax (.. half-open, ..= inclusive). All variants use Lemire's "Nearly Divisionless" rejection sampling, so output is uniformly distributed with no modulo bias:

use mod_rand::tier1::Xoshiro256;
use mod_rand::{tier2, tier3};

let mut rng = Xoshiro256::seed_from_u64(42);

let pct: u32 = rng.gen_range_u32(0..100);          // [0, 100)
let die: u32 = rng.gen_range_inclusive_u32(1..=6); // [1, 6]

let id     = tier2::range_inclusive_u32(1..=1_000);
let secret = tier3::random_range_inclusive_u64(0..=u64::MAX)?;
# Ok::<(), std::io::Error>(())
Tier Algorithm Use case Crypto-safe
1 xoshiro256** (splitmix64-seeded) Simulation, fixtures, shuffling No
2 PID + nanos + counter + Stafford-mix-13 Tempdir names, request IDs No
3 OS syscall (getrandom/BCryptGenRandom/getentropy) Tokens, keys, session IDs Yes

Performance

Microbenchmarked on x86_64 (cargo bench):

Op Tier 1 Tier 2 Tier 3 (Windows)
Single 64-bit value ~0.6 ns ~20 ns ~35 ns
32 random bytes ~2 ns ~55 ns
16-byte hex token ~45 ns ~100 ns
Bounded gen_range_u64(0..100) ~0.9 ns ~22 ns ~35 ns
Die roll ..=6 (worst-case bias trap) ~0.9 ns ~22 ns ~35 ns

Tier 1 hits ~0.6 ns/u64 — better than the 1 ns/u64 target. Tier 3 latency on Linux/macOS is kernel-dependent; expect 100–500 ns.

Why this library exists

  • Zero dependencies. No rand, no getrandom crate, no libc. Just std. Tier 1 even works in no_std.
  • Explicit threat model. You pick the tier; you know what guarantees you're getting.
  • Lower MSRV than the alternatives. Works on Rust 1.75; many random crates today require 1.85+.
  • Fast. Tier 1 is ~0.6 ns/u64. Tier 2 is ~20 ns. Tier 3 is one syscall.

Feature flags

[dependencies]
mod-rand = { version = "0.9.5", default-features = false }   # tier1 only, no_std
mod-rand = { version = "0.9.5", features = ["tier2"] }       # + process-unique
mod-rand = "0.9.5"                                             # all three tiers (default)

Status

The 0.9.x line ships the real algorithms — full xoshiro256** with splitmix64 seeding (Tier 1), Stafford-mix-13 over PID + nanos + atomic counter (Tier 2), and direct platform syscalls (getrandom(2) / BCryptGenRandom / getentropy(3)) for Tier 3. The API is stable through the 0.9.x series; 1.0 will pin it.

For tier-by-tier semantics, performance targets, and guarantees, see docs/API.md.

Minimum supported Rust version

1.75 — pinned in Cargo.toml and verified by CI.

License

Apache-2.0. See LICENSE.


Copyright © 2026 James Gober.

About

Tiered random number generation for Rust. Fast PRNG, process-unique seeds, and OS-backed cryptographic random in one zero-dependency library. Pick the tier appropriate to your threat model.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages