| Crates.io | xoroshiro256-full |
| lib.rs | xoroshiro256-full |
| version | 0.1.4 |
| created_at | 2025-10-06 07:06:19.07771+00 |
| updated_at | 2025-10-06 07:33:53.157799+00 |
| description | β‘ **Fast**, π§ͺ **deterministic**, and π§° **ergonomic** implementation of **xoroshiro256**** with **no bit waste**. |
| homepage | |
| repository | https://github.com/Borderliner/xoroshiro256-full |
| max_upload_size | |
| id | 1869832 |
| size | 35,371 |
β‘ Fast, π§ͺ deterministic, and π§° ergonomic implementation of xoroshiro256** with no bit waste. Not cryptographically secure. For CSPRNG, enable the
cryptofeature and useCryptoRng256(ChaCha20).
π xoroshiro256 core with 256-bit state (4 Γ u64).
π§© Optional integrations via Cargo features:
rand_core β implements rand_core::RngCore and SeedableRng.serde β enables Serialize/Deserialize for Xoroshiro256State (core state only).crypto β provides CryptoRng256 (ChaCha20) for cryptographic use.β»οΈ No bit waste when rand_core is enabled:
next_u32() returns the high 32 bits first and caches the low 32 for the next call.fill_bytes() caches any unused tail (β€ 7 bytes) and reuses them on the next call.π§± #![forbid(unsafe_code)] β zero unsafe.
π§ͺ Comprehensive tests incl. determinism, buffer behavior, and anti-waste checks.
βΉοΈ The internal caches for anti-waste are not serialized with
serde; only the 256-bit xoroshiro state is preserved. See details below.
[dependencies]
xoroshiro256-full = "0.1"
# Cargo.toml
[dependencies]
xoroshiro256-full = { version = "0.1", features = ["rand_core", "serde", "crypto"] }
| Feature | What you get |
|---|---|
rand_core |
RngCore/SeedableRng impls, antiβbit-waste behavior for next_u32/fill_bytes |
serde |
Serialize/Deserialize for Xoroshiro256State (caches are skipped) |
crypto |
CryptoRng256 (ChaCha20) for secure randomness (requires rand_core) |
use xoroshiro256_full::Xoroshiro256State;
let mut rng = Xoroshiro256State::init([1, 2, 3, 4], 4);
let x = rng.next_u64(); // fast, deterministic
rand ecosystem (enable rand_core)# #[cfg(feature="rand_core")] {
use rand_core::{RngCore, SeedableRng};
use xoroshiro256_full::Xoroshiro256State;
let mut rng = Xoroshiro256State::seed_from_u64(42);
let _ = rng.next_u32();
# }
crypto)# #[cfg(feature="crypto")] {
use xoroshiro256_full::CryptoRng256;
let mut crng = CryptoRng256::from_os();
let x = crng.next_u64();
# }
Xoroshiro256StateState: parts: [u64; 4] (256 bits).
Constructors:
init([u64; 4], key_length: usize) β seed with up to 4 words; missing words are derived with an LCG. All-zero state is auto-fixed with a non-zero constant.rand_core) seed_from_u64(u64) β SplitMix64-like expansion into 256 bits.rand_core) from_seed([u8; 32]) β exact little-endian seeds.Core step: next_u64() -> u64 β xoroshiro256** starstar output.
State dump: genrand_uint256_to_buf(&mut [u8]) β current 256-bit state in little-endian order (does not step the generator).
CryptoRng256 (feature = crypto)Wrapper around ChaCha20Rng with:
from_os() β seed from OS entropy.from_seed([u8; 32]) β deterministic seed.fill_bytes, next_u64, next_u32 via RngCore.When rand_core is enabled, this crate adds two ephemeral caches inside Xoroshiro256State:
u32_spare: Option<u32> β
next_u32() generates one u64 and returns the high 32 bits immediately, caching the low 32 for the next call. Two next_u32() calls equal one next_u64().byte_spare: [u8; 8] + byte_spare_len: u8 β
fill_bytes() writes full u64 chunks, then uses a tail from a new u64 if needed. Any leftover bytes (β€ 7) are cached and prepended on the next fill_bytes() call.Serialization note (serde): these caches are not part of the algorithmic state and are skipped during serialization. Only the 256-bit xoroshiro state is serialized, which is what you want for reproducibility.
CryptoRng256 for security-sensitive contexts.unsafe.This repository includes:
rand_core integration tests for variable buffer lengths.next_u32() and fill_bytes() consume exactly what next_u64() would.crypto tests for basic behavior and reproducibility with fixed seeds.Run locally:
# All features (recommended)
cargo test --all-features
# Feature combinations (example)
cargo test --features serde,rand_core
CI runs formatting, clippy (deny warnings), OS matrix builds (Linux/macOS/Windows), nightly smoke tests, and a feature matrix. See ci.yml.
use xoroshiro256_full::Xoroshiro256State;
// Only the first word provided; remaining words are derived via LCG.
let mut rng = Xoroshiro256State::init([0xDEAD_BEEF_CAFE_BABE, 0, 0, 0], 1);
let a = rng.next_u64();
let b = rng.next_u64();
assert_ne!(a, b);
serde)# #[cfg(feature = "serde")] {
use xoroshiro256_full::Xoroshiro256State;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Save {
rng: Xoroshiro256State,
}
let s = Save { rng: Xoroshiro256State::init([1,2,3,4], 4) };
let json = serde_json::to_string(&s).unwrap();
let mut s2: Save = serde_json::from_str(&json).unwrap();
let _ = s2.rng.next_u64();
# }
rand_core)# #[cfg(feature="rand_core")] {
use rand_core::RngCore;
use xoroshiro256_full::Xoroshiro256State;
let mut rng = Xoroshiro256State::seed_from_u64(2024);
let mut a = [0u8; 3];
let mut b = [0u8; 5];
let mut all = [0u8; 8];
rng.fill_bytes(&mut a);
rng.fill_bytes(&mut b); // reuses the 5 leftover bytes from the previous call
all[..3].copy_from_slice(&a);
all[3..].copy_from_slice(&b);
let mut control = [0u8; 8];
Xoroshiro256State::seed_from_u64(2024).fill_bytes(&mut control);
assert_eq!(all, control);
# }
next_u32() pairs to one u64 (feature = rand_core)# #[cfg(feature="rand_core")] {
use rand_core::RngCore;
use xoroshiro256_full::Xoroshiro256State;
let mut a = Xoroshiro256State::seed_from_u64(9999);
let mut b = Xoroshiro256State::seed_from_u64(9999);
let x = a.next_u64();
let hi = b.next_u32() as u64;
let lo = b.next_u32() as u64;
assert_eq!((hi << 32) | lo, x);
# }
edition = "2024".Xoroshiro256State is not cryptographically secure.crypto and use CryptoRng256 (ChaCha20-based) seeded via from_os() when possible.PRs, issues, and suggestions are welcome! Please run:
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
Licensed under Apache-2.0