mod-rand 0.9.3

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.
Documentation
# mod-rand — Project Specification (REPS)

> Rust Engineering Project Specification.
> Normative language follows RFC 2119.

## 1. Purpose

`mod-rand` MUST provide random number generation at three quality
tiers in a single zero-dependency library. Users pick the tier
appropriate to their threat model.

## 2. The three tiers

### Tier 1: Fast deterministic PRNG

MUST be:
- Seedable from a single `u64`
- Reproducible (same seed produces same stream)
- Fast (target: ~1ns per `u64` on commodity hardware)
- Available in `no_std`
- Algorithm: xoshiro256\*\* with splitmix64 seeding

MUST NOT be:
- Used for security-sensitive randomness
- Marketed as cryptographically secure

### Tier 2: Process-unique seeds

MUST be:
- Different across calls within a process (counter-guaranteed)
- Different across processes with extremely high probability
- Fast (target: <100ns per call)
- Available when `std` feature is enabled
- Algorithm: PID + nanosecond timestamp + atomic counter, mixed
  with a fast mixing function (xorshift rounds or similar)

MUST NOT be:
- Used for security-sensitive randomness
- Used where two simultaneous calls returning the same value would
  cause correctness bugs (the counter prevents this, but only within
  a single process)

### Tier 3: OS-backed cryptographic random

MUST be:
- Backed by the OS's secure random source:
  - Linux: `getrandom(2)` syscall
  - macOS: `getentropy(3)`
  - Windows: `BCryptGenRandom`
- Cryptographically secure (output unpredictable by an attacker)
- Available when `std` feature is enabled
- Resilient to fork/snapshot/VM-resume (no internal state to mix)

MUST NOT be:
- Optimized for speed at the cost of security
- Allowed to silently fall back to a weaker source on syscall failure
  (must return an error instead)

## 3. API surface

### Tier 1

```rust
pub struct Xoshiro256 { /* private */ }

impl Xoshiro256 {
    pub fn seed_from_u64(seed: u64) -> Self;
    pub fn next_u64(&mut self) -> u64;
}
```

### Tier 2

```rust
pub fn unique_u64() -> u64;
pub fn unique_name(len: usize) -> String;
```

### Tier 3

```rust
pub fn fill_bytes(buf: &mut [u8]) -> io::Result<()>;
pub fn random_u64() -> io::Result<u64>;
pub fn random_hex(bytes: usize) -> io::Result<String>;
```

Additional convenience constructors (bounded integers, range
selection, etc.) MAY land in `0.9.x` or later.

## 4. Determinism

- Tier 1 output MUST be deterministic given a seed.
- Tier 2 output MUST be unique across calls within a process.
- Tier 3 output MUST be non-deterministic.

## 5. Dependencies

This crate MUST NOT have runtime dependencies outside of `std` (when
the `std` feature is enabled). Platform-specific FFI declarations
SHOULD be inlined rather than pulled in via `libc`.

The point: this crate exists partly to break the `getrandom`-induced
MSRV ratchet. We can't replace one MSRV-locking dep with another.

## 6. Stability

Through `0.9.x` the public API MAY shift. The `1.0` release pins the
API and the tier definitions.

## 7. Out of scope

- Generic distribution types (Normal, Poisson, etc.) — that's
  `rand_distr` territory.
- Trait-heavy abstraction (`Rng` / `RngCore` / `SeedableRng`) — we
  expose concrete types.
- Hardware random sources (RDRAND, RDSEED) — out of scope for
  initial release; may revisit if there's demand.
- Multi-thread coordination (shared atomic-state RNGs) — Tier 2's
  atomic counter is enough; if users want shared Tier 1, they wrap
  one themselves.