cet-t/urng

Rust

0

151 commits

updated Oct 2, 2026

See the code

See what people are saying

SourceMessageScoreDate

I made a RNG trait where the output width is part of the type (r/rust)

I recently finished my RNG project, `urng`, and extracted its core trait into a small standalone crate named `urng_core`. The main idea is to represent an RNG's native output width with an associated `Word` type. For example, a `u32` RNG only needs to implement `nextu() -> u32`. It's a small,…

0

Oct 6, 2026

README

crates.io docs.rs github

Universal RNG

A collection of efficient pseudo-random number generators (PRNGs) implemented in pure Rust. This crate provides a wide variety of algorithms, ranging from standard Mersenne Twister to modern high-performance generators like Xoshiro and Philox.

Supported Generators

Generators are divided into standard generators, portable wide generators, and AVX-accelerated SIMD generators. Standard generators implement the unified Rng trait (Word = u32 or Word = u64; SIMD/counter-based variants return fixed-size arrays instead). Portable wide generators require the wide feature and expose safe fixed-array bulk APIs. AVX generators expose a bulk-generation API and are listed separately; they require the simd feature.

32-bit Generators (urng::)

StructAlgorithmPeriod / State
Mt19937Mersenne Twister$2^{19937}-1$
Sfmt607SFMT$2^{607}-1$
Sfmt1279SFMT$2^{1279}-1$
Sfmt2281SFMT$2^{2281}-1$
Sfmt4253SFMT$2^{4253}-1$
Sfmt11213SFMT$2^{11213}-1$
Sfmt19937SFMT$2^{19937}-1$
Sfmt44497SFMT$2^{44497}-1$
Sfmt86243SFMT$2^{86243}-1$
Sfmt132049SFMT$2^{132049}-1$
Sfmt216091SFMT$2^{216091}-1$
Sfc32SFC32$2^{127}-1$
Sfc32x4SFC32 x4$2^{127}-1$
Pcg32PCG-XSH-RR$2^{64}$
Philox32x4Philox 4x32-
SplitMix32SplitMix32$2^{32}$
XorwowXORWOW$2^{192}-2^{32}$
Xorshift32Xorshift$2^{32}-1$
Xorshift128Xorshift128$2^{128}-1$
Xoshiro128Ppxoshiro128++$2^{128}-1$
Xoshiro128Ssxoshiro128**$2^{128}-1$
Xoroshiro64Ssxoroshiro64**$2^{64}-1$
Threefry32x4Threefry 4x32-
Threefry32x2Threefry 2x32-
Squares32Squares-
Jsf32JSF32-

64-bit Generators (urng::)

StructAlgorithmPeriod / State
Xoshiro256Ppxoshiro256++$2^{256}-1$
Xoshiro256Ssxoshiro256**$2^{256}-1$
SplitMix64SplitMix64$2^{64}$
Sfc64SFC64$2^{256}$ approx
Mt1993764Mersenne Twister 64$2^{19937}-1$
Sfmt1993764SFMT 64$2^{19937}-1$
Philox64Philox 2x64-
Xorshift64Xorshift64$2^{64}-1$
Xoroshiro128Ppxoroshiro128++$2^{128}-1$
Xoroshiro128Ssxoroshiro128**$2^{128}-1$
TwistedGFSRTGFSR$2^{800}$ approx
Cet64CET$2^{64}$
Cet256CET$2^{256}$
Threefish256Threefish-256-
Biski64Biski64$2^{64}$

Portable Wide Generators (urng::wide)

Requires the wide feature.

These generators use the portable wide crate and expose safe nextu, nextf, randi, and randf methods returning fixed-size arrays.

Struct familyAlgorithmOutput variants
SplitMix32x*SplitMix324×/8×/16×u32
Jsf32x*JSF324×/8×/16×u32
Pcg32x*PCG-XSH-RR4×/8×/16×u32
Sfc32x*SFC324×/8×/16×u32
Xoroshiro64Ssx*xoroshiro64**4×/8×/16×u32
Xorshift32x*Xorshift324×/8×/16×u32
Xorshift128x*Xorshift1284×/8×/16×u32
Xorwowx*XORWOW4×/8×/16×u32
Xoshiro128Ppx*xoshiro128++4×/8×/16×u32
Xoshiro128Ssx*xoshiro128**4×/8×/16×u32

Example:

use urng::wide::{WRng, Xoshiro128Ppx16};

let mut rng = Xoshiro128Ppx16::new(1);
let values: [u32; 16] = rng.nextu();
let floats: [f32; 16] = rng.nextf();

SIMD Generators (AVX)

These generators expose a bulk-generation API and require AVX support at runtime.

AVX2 (avx2)

StructAlgorithmOutput
Sfc32x8SFC32 x88×u32
Jsf32x8JSF32 x88×u32
Xoroshiro64Ssx8xoroshiro64** x88×u32

AVX-512 (avx512f)

StructAlgorithmOutput
Pcg32x8PCG-XSH-RR x88×u32
Philox32x4x4Philox 4x32 x416×u32
SplitMix32x16SplitMix32 x1616×u32
Squares32x8Squares x88×u32
Xoshiro128Ppx16xoshiro128++ x1616×u32
Xoshiro128Ssx16xoshiro128** x1616×u32
Jsf32x16JSF32 x1616×u32
Sfc32x16SFC32 x1616×u32
Xoroshiro64Ssx16xoroshiro64** x1616×u32
Xoshiro256Ssx2xoshiro256** x22×u64
Sfc64x8SFC64 x88×u64
Cet64x8CET64 x88×u64
Cet256x2CET256 x22×u64
Biski64x8Biski64 x88×u64

Sampler

Requires the sampler feature.

Weighted random index selection. Two implementations are provided for each bit-width, both implementing the Sampler trait (urng::Sampler).

StructModuleAlgorithmBuildSample
Bst32urng::Cumulative BSTO(n)O(log n)
Alias32urng::Walker's AliasO(n)O(1)
Bst64urng::Cumulative BSTO(n)O(log n)
Alias64urng::Walker's AliasO(n)O(1)

SeedGen

Requires the seedgen feature.

Hardware-noise-assisted seed generation. Wraps an existing Rng and mixes in hardware noise (RDSEED/RDRAND on x86/x86_64, timestamp fallback elsewhere) via a Murmur3-style hash.

StructModuleInput RNGOutput
SeedGenurng::seedgenRng<Word = u32> / Rng<Word = u64>(u32, u32) / (u64, u64) pair

next_seed_pair() returns (raw, processed) — the raw hardware value and the mixed seed.

Testing

Statistical validation of RNG quality is handled by the external cribler crate, a batteries-included randomness-test toolkit. cribler ships every engine (chi-squared, Monte Carlo π, serial correlation, runs, Kolmogorov–Smirnov, birthday spacing, a NIST SP 800-22 subset, and a paranoid battery aggregator) and offers zero-feature integration: any generator plugs in via a plain FnMut() -> f64 / FnMut() -> u64 sampler closure.

Enable the urng feature on cribler for pre-built typed convenience that works directly against urng's Rng generators:

[dependencies]
urng = "1.0.0"
cribler = { version = "0.3", features = ["urng"] }

The suites construct each named case from a seed, so no generator instance needs to be passed in:

use cribler::Suite;
use urng::Rng;

let results = cribler::Suite::default()
    .from_urng32::<urng::Sfc32>()?
    .from_rand::<rand_sfc::Sfc32>()?
    .run()?;

for r in results.iter() {
    println!("{}", serde_json::to_string_pretty(&r)?);
}

from_urng32::<R>() / from_urng64::<R>() register a urng::Rng<Word = u32> / urng::Rng<Word = u64> R, built from the suite's seed. The rand feature provides from_rand::<R>() for rand_core::Rng types, and from_custom(source) accepts anything else via a WordSource adapter.

Usage Examples

Most generators expose the same basic workflow: create an instance with new, then use nextu, nextf, randi, randf, or choice depending on the output type you need. SIMD and counter-based generators return fixed-size arrays instead of single values.

Scalar generators (both 32-bit and 64-bit; SIMD variants are not included) also implement Default, seeding themselves from a time-based, per-call mix so no explicit seed is required:

use urng::*;

let mut rng = Sfc32::default();
let _ = Rng::nextu(&mut rng);

Basic Usage

use urng::*;

fn main() {
    // 1. Initialize with a seed
    let mut rng = Xoshiro256Pp::new(12345);

    // 2. Generate random numbers
    let val_u64 = rng.nextu();
    println!("u64: {}", val_u64);

    let val_f64 = rng.nextf(); // [0.0, 1.0)
    println!("f64: {}", val_f64);

    // 3. Generate within a range
    let val_range = rng.randi(1, 100);
    println!("Integer (1-100): {}", val_range);

    // 4. Seeding with SplitMix64 (common pattern)
    // If you need to seed a large state generator from a single u64
    let mut sm = SplitMix64::new(9999);
    let seed_val = sm.nextu();
    let mut rng2 = Xoshiro256Pp::new(seed_val);
}

C ABI

This crate exports a C-compatible ABI generic interface. Each generator has corresponding:

  • _new
  • _free
  • _next_uXXs (bulk generation)
  • _next_fXXs (bulk generation)
  • _rand_iXXs (bulk generation)
  • _rand_fXXs (bulk generation)

Example for Mt19937:

void* mt19937_new(uint32_t seed, size_t warm);
void mt19937_next_u32s(void* ptr, uint32_t* out, size_t count);
void mt19937_rand_f32s(void* ptr, float* out, size_t count, float min, float max);
void mt19937_free(void* ptr);
prng
prng-algorithms
prng-implementations
prngs
rng
rng-engine
rngs
simd
simd-programming

cet-t/urng

Rust

0

151 commits

updated Oct 2, 2026

See the code

See what people are saying

SourceMessageScoreDate

I made a RNG trait where the output width is part of the type (r/rust)

I recently finished my RNG project, `urng`, and extracted its core trait into a small standalone crate named `urng_core`. The main idea is to represent an RNG's native output width with an associated `Word` type. For example, a `u32` RNG only needs to implement `nextu() -&gt; u32`. It's a small,…

0

Oct 6, 2026

README

crates.io docs.rs github

Universal RNG

A collection of efficient pseudo-random number generators (PRNGs) implemented in pure Rust. This crate provides a wide variety of algorithms, ranging from standard Mersenne Twister to modern high-performance generators like Xoshiro and Philox.

Supported Generators

Generators are divided into standard generators, portable wide generators, and AVX-accelerated SIMD generators. Standard generators implement the unified Rng trait (Word = u32 or Word = u64; SIMD/counter-based variants return fixed-size arrays instead). Portable wide generators require the wide feature and expose safe fixed-array bulk APIs. AVX generators expose a bulk-generation API and are listed separately; they require the simd feature.

32-bit Generators (urng::)

StructAlgorithmPeriod / State
Mt19937Mersenne Twister$2^{19937}-1$
Sfmt607SFMT$2^{607}-1$
Sfmt1279SFMT$2^{1279}-1$
Sfmt2281SFMT$2^{2281}-1$
Sfmt4253SFMT$2^{4253}-1$
Sfmt11213SFMT$2^{11213}-1$
Sfmt19937SFMT$2^{19937}-1$
Sfmt44497SFMT$2^{44497}-1$
Sfmt86243SFMT$2^{86243}-1$
Sfmt132049SFMT$2^{132049}-1$
Sfmt216091SFMT$2^{216091}-1$
Sfc32SFC32$2^{127}-1$
Sfc32x4SFC32 x4$2^{127}-1$
Pcg32PCG-XSH-RR$2^{64}$
Philox32x4Philox 4x32-
SplitMix32SplitMix32$2^{32}$
XorwowXORWOW$2^{192}-2^{32}$
Xorshift32Xorshift$2^{32}-1$
Xorshift128Xorshift128$2^{128}-1$
Xoshiro128Ppxoshiro128++$2^{128}-1$
Xoshiro128Ssxoshiro128**$2^{128}-1$
Xoroshiro64Ssxoroshiro64**$2^{64}-1$
Threefry32x4Threefry 4x32-
Threefry32x2Threefry 2x32-
Squares32Squares-
Jsf32JSF32-

64-bit Generators (urng::)

StructAlgorithmPeriod / State
Xoshiro256Ppxoshiro256++$2^{256}-1$
Xoshiro256Ssxoshiro256**$2^{256}-1$
SplitMix64SplitMix64$2^{64}$
Sfc64SFC64$2^{256}$ approx
Mt1993764Mersenne Twister 64$2^{19937}-1$
Sfmt1993764SFMT 64$2^{19937}-1$
Philox64Philox 2x64-
Xorshift64Xorshift64$2^{64}-1$
Xoroshiro128Ppxoroshiro128++$2^{128}-1$
Xoroshiro128Ssxoroshiro128**$2^{128}-1$
TwistedGFSRTGFSR$2^{800}$ approx
Cet64CET$2^{64}$
Cet256CET$2^{256}$
Threefish256Threefish-256-
Biski64Biski64$2^{64}$

Portable Wide Generators (urng::wide)

Requires the wide feature.

These generators use the portable wide crate and expose safe nextu, nextf, randi, and randf methods returning fixed-size arrays.

Struct familyAlgorithmOutput variants
SplitMix32x*SplitMix324×/8×/16×u32
Jsf32x*JSF324×/8×/16×u32
Pcg32x*PCG-XSH-RR4×/8×/16×u32
Sfc32x*SFC324×/8×/16×u32
Xoroshiro64Ssx*xoroshiro64**4×/8×/16×u32
Xorshift32x*Xorshift324×/8×/16×u32
Xorshift128x*Xorshift1284×/8×/16×u32
Xorwowx*XORWOW4×/8×/16×u32
Xoshiro128Ppx*xoshiro128++4×/8×/16×u32
Xoshiro128Ssx*xoshiro128**4×/8×/16×u32

Example:

use urng::wide::{WRng, Xoshiro128Ppx16};

let mut rng = Xoshiro128Ppx16::new(1);
let values: [u32; 16] = rng.nextu();
let floats: [f32; 16] = rng.nextf();

SIMD Generators (AVX)

These generators expose a bulk-generation API and require AVX support at runtime.

AVX2 (avx2)

StructAlgorithmOutput
Sfc32x8SFC32 x88×u32
Jsf32x8JSF32 x88×u32
Xoroshiro64Ssx8xoroshiro64** x88×u32

AVX-512 (avx512f)

StructAlgorithmOutput
Pcg32x8PCG-XSH-RR x88×u32
Philox32x4x4Philox 4x32 x416×u32
SplitMix32x16SplitMix32 x1616×u32
Squares32x8Squares x88×u32
Xoshiro128Ppx16xoshiro128++ x1616×u32
Xoshiro128Ssx16xoshiro128** x1616×u32
Jsf32x16JSF32 x1616×u32
Sfc32x16SFC32 x1616×u32
Xoroshiro64Ssx16xoroshiro64** x1616×u32
Xoshiro256Ssx2xoshiro256** x22×u64
Sfc64x8SFC64 x88×u64
Cet64x8CET64 x88×u64
Cet256x2CET256 x22×u64
Biski64x8Biski64 x88×u64

Sampler

Requires the sampler feature.

Weighted random index selection. Two implementations are provided for each bit-width, both implementing the Sampler trait (urng::Sampler).

StructModuleAlgorithmBuildSample
Bst32urng::Cumulative BSTO(n)O(log n)
Alias32urng::Walker's AliasO(n)O(1)
Bst64urng::Cumulative BSTO(n)O(log n)
Alias64urng::Walker's AliasO(n)O(1)

SeedGen

Requires the seedgen feature.

Hardware-noise-assisted seed generation. Wraps an existing Rng and mixes in hardware noise (RDSEED/RDRAND on x86/x86_64, timestamp fallback elsewhere) via a Murmur3-style hash.

StructModuleInput RNGOutput
SeedGenurng::seedgenRng<Word = u32> / Rng<Word = u64>(u32, u32) / (u64, u64) pair

next_seed_pair() returns (raw, processed) — the raw hardware value and the mixed seed.

Testing

Statistical validation of RNG quality is handled by the external cribler crate, a batteries-included randomness-test toolkit. cribler ships every engine (chi-squared, Monte Carlo π, serial correlation, runs, Kolmogorov–Smirnov, birthday spacing, a NIST SP 800-22 subset, and a paranoid battery aggregator) and offers zero-feature integration: any generator plugs in via a plain FnMut() -> f64 / FnMut() -> u64 sampler closure.

Enable the urng feature on cribler for pre-built typed convenience that works directly against urng's Rng generators:

[dependencies]
urng = "1.0.0"
cribler = { version = "0.3", features = ["urng"] }

The suites construct each named case from a seed, so no generator instance needs to be passed in:

use cribler::Suite;
use urng::Rng;

let results = cribler::Suite::default()
    .from_urng32::<urng::Sfc32>()?
    .from_rand::<rand_sfc::Sfc32>()?
    .run()?;

for r in results.iter() {
    println!("{}", serde_json::to_string_pretty(&r)?);
}

from_urng32::<R>() / from_urng64::<R>() register a urng::Rng<Word = u32> / urng::Rng<Word = u64> R, built from the suite's seed. The rand feature provides from_rand::<R>() for rand_core::Rng types, and from_custom(source) accepts anything else via a WordSource adapter.

Usage Examples

Most generators expose the same basic workflow: create an instance with new, then use nextu, nextf, randi, randf, or choice depending on the output type you need. SIMD and counter-based generators return fixed-size arrays instead of single values.

Scalar generators (both 32-bit and 64-bit; SIMD variants are not included) also implement Default, seeding themselves from a time-based, per-call mix so no explicit seed is required:

use urng::*;

let mut rng = Sfc32::default();
let _ = Rng::nextu(&mut rng);

Basic Usage

use urng::*;

fn main() {
    // 1. Initialize with a seed
    let mut rng = Xoshiro256Pp::new(12345);

    // 2. Generate random numbers
    let val_u64 = rng.nextu();
    println!("u64: {}", val_u64);

    let val_f64 = rng.nextf(); // [0.0, 1.0)
    println!("f64: {}", val_f64);

    // 3. Generate within a range
    let val_range = rng.randi(1, 100);
    println!("Integer (1-100): {}", val_range);

    // 4. Seeding with SplitMix64 (common pattern)
    // If you need to seed a large state generator from a single u64
    let mut sm = SplitMix64::new(9999);
    let seed_val = sm.nextu();
    let mut rng2 = Xoshiro256Pp::new(seed_val);
}

C ABI

This crate exports a C-compatible ABI generic interface. Each generator has corresponding:

  • _new
  • _free
  • _next_uXXs (bulk generation)
  • _next_fXXs (bulk generation)
  • _rand_iXXs (bulk generation)
  • _rand_fXXs (bulk generation)

Example for Mt19937:

void* mt19937_new(uint32_t seed, size_t warm);
void mt19937_next_u32s(void* ptr, uint32_t* out, size_t count);
void mt19937_rand_f32s(void* ptr, float* out, size_t count, float min, float max);
void mt19937_free(void* ptr);
prng
prng-algorithms
prng-implementations
prngs
rng
rng-engine
rngs
simd
simd-programming