| Crates.io | bitcoinleveldb-rand |
| lib.rs | bitcoinleveldb-rand |
| version | 0.1.19 |
| created_at | 2023-01-18 05:40:43.609131+00 |
| updated_at | 2025-12-01 16:59:47.998065+00 |
| description | Deterministic LevelDB-compatible Park–Miller pseudo-random number generator for tests and internal randomized decisions; small, fast, and non-cryptographic. |
| homepage | |
| repository | https://github.com/klebs6/bitcoin-rs |
| max_upload_size | |
| id | 761528 |
| size | 194,183 |
A small, deterministic pseudo-random number generator (PRNG) that reproduces the behavior of LevelDB's historical Random implementation. This crate exists to make the LevelDB-compatible RNG available as an independent, well-documented Rust component.
LevelDB (and derivatives) rely on a trivial but deterministic PRNG for tests and some internal randomized decisions. When re-implementing LevelDB in Rust—such as in the bitcoin-rs project—it is often desirable to:
bitcoinleveldb-rand provides that: a single-struct PRNG with LevelDB semantics.
This crate is not intended for cryptography or security-sensitive randomness. It is a simple linear congruential generator designed for reproducible test data and randomized algorithm steps where statistical quality is secondary to determinism and compatibility.
The generator is a classical Park–Miller LCG:
seed in the range ([1, M-1])where A is a fixed multiplier (matching LevelDB's choice). This recurrence produces a full-period sequence over ([1, M-1]) if seed is not 0 or M and A is chosen correctly.
The implementation uses the classic Park–Miller trick to avoid overflow and to compute the modulus efficiently, mirroring LevelDB's util/random.h exactly.
no_std-friendly (aside from logging macros, which can be compiled out or adapted depending on your feature set).debug!, trace!, and error!/warn! calls around edge cases for easier debugging in larger systems.Again, this PRNG is not cryptographically secure and must not be used for secrets, key generation, or adversarial settings.
Add to Cargo.toml:
[dependencies]
bitcoinleveldb-rand = "0.1.19"
use bitcoinleveldb_rand::Random;
fn main() {
// Seed with an arbitrary 32-bit value. The implementation normalizes it
// into the internal 31-bit domain, avoiding degenerate seeds.
let mut rng = Random::new(0x1234_5678);
// Raw 31-bit-ish pseudo-random values
let a = rng.next();
let b = rng.next();
println!("a = {a}, b = {b}");
}
use bitcoinleveldb_rand::Random;
fn main() {
let mut rng = Random::new(1);
// Uniform in [0, 99]
let sample = rng.uniform(100);
assert!(sample < 100);
}
Important contract:
uniform(n) requires n > 0. If n <= 0, it logs an error and returns 0.one_in(n)use bitcoinleveldb_rand::Random;
fn main() {
let mut rng = Random::new(42);
// ~1/10 chance of true each call
if rng.one_in(10) {
println!("Hit");
} else {
println!("Miss");
}
}
Semantics:
one_in(n) logically returns true with probability approximately 1/n and false otherwise.n > 0. If n <= 0, it logs an error and returns false.Internally it computes next() % n == 0.
skewed(max_log)use bitcoinleveldb_rand::Random;
fn main() {
let mut rng = Random::new(7);
// Exponentially biased towards small integers, but bounded above by 2^max_log - 1.
let v = rng.skewed(10);
assert!(v < (1u32 << 10));
}
Semantics in detail:
base uniformly from [0, effective_max_log] where effective_max_log = min(max_log, 30).range = 1 << base.[0, range-1] by uniform(range as i32).Thus the distribution over (v) is piecewise-uniform with an exponential bias toward smaller values. Most draws are small; large draws become exponentially rare. This mirrors LevelDB's method for choosing skewed random sizes, e.g., for randomized tests.
Contracts and edge handling:
max_log >= 0. If max_log < 0, it logs an error and returns 0.max_log >= 31, it logs a warning and caps the effective exponent at 30 to avoid overflow and keep 1u32 << base well-defined on all platforms.You construct a Random as:
pub fn new(s: u32) -> Random
s is first masked with the internal modulus M = 0x7fffffff (31 bits).seed is 0 or M, the constructor overwrites it with 1 and logs a warning. These two pathological seeds would otherwise collapse the sequence to a fixed point (all subsequent values would be 0 or M).This treatment preserves the full-period property of the Park–Miller LCG.
Because this is a pure integer-state LCG with a fixed modulus and multiplier, the sequence is entirely deterministic once the seed is set. For any given seed:
Random::new(seed).next() will always yield the same first value.uniform, one_in, and skewed: their behavior depends only on the internal state transitions from next().This is especially useful when you want to:
pub struct Random {
seed: u32,
}
impl Random {
/// Create a new RNG seeded from `s`.
///
/// The seed is normalized to 31 bits and coerced away from the
/// degenerate 0 and M states.
pub fn new(s: u32) -> Self;
/// Advance the internal state and return the next pseudo-random `u32`.
///
/// The returned value is effectively a 31-bit number in (0, M],
/// matching LevelDB's intent.
pub fn next(&mut self) -> u32;
/// Return an integer uniformly distributed in `[0, n-1]`.
///
/// Requires `n > 0`. On invalid input, logs and returns `0`.
pub fn uniform(&mut self, n: i32) -> u32;
/// Return `true` with probability approximately `1/n`.
///
/// Requires `n > 0`. On invalid input, logs and returns `false`.
pub fn one_in(&mut self, n: i32) -> bool;
/// Return an exponentially biased random value in
/// `[0, 2^max_log - 1]`, heavily skewed toward smaller values.
///
/// Requires `max_log >= 0`. On invalid input, logs and returns `0`.
/// For `max_log >= 31`, caps the effective exponent at 30.
pub fn skewed(&mut self, max_log: i32) -> u32;
}
log-style macros (debug!, trace!, warn!, error!). To see diagnostic output, configure a logger in your binary or test harness (e.g., env_logger, tracing, or a custom adapter).no_std environments if logging is either disabled or redirected. Check the crate features and your target environment; if you are compiling for a constrained platform, you may want to compile with logging turned off.bitcoin-rsThis crate lives in the bitcoin-rs repository and primarily serves the LevelDB re-implementation embedded there. Extracting this RNG into its own crate allows:
This crate is distributed under the MIT license.
See the repository for full license text and contribution guidelines.