absolucy / nanorand-rs Goto Github PK
View Code? Open in Web Editor NEWA tiny, fast, zero-dep library for random number generation
License: zlib License
A tiny, fast, zero-dep library for random number generation
License: zlib License
rng.generate::<i8>() < 0
works, but having explicit support for random generation of bool
might be useful.
Haven't had a deep look into the code of nanorand-rs yet, but the generate_range seems to incorrectly start the range at 1 less than it should with signed integers.
let mut rand = WyRand::new();
// prints: [1, 0, 0, 1, 0, 1, 0, 0, 0, 1]
println!(
"{:?}",
vec![0; 10]
.into_iter()
.map(|_| rand.generate_range(1_i32..=2))
.collect::<Vec<i32>>()
);
// Shifting to u32 prints it correctly as: [2, 1, 1, 2, 1, 2, 1, 1, 1, 2]
Apologies for asking a question by using an issue - I'm new to rust, and I wasn't sure how to deal with this myself.
I am wanting to reliably reproduce/shuffle vast quantities of data in wasm (yew-rs) by way of a seed provided by a server:
let mut rng = WyRand::new_seed(server_seed);
rng.shuffle(&renumber);
I don't think I need an additional source of entropy, since WyRand reproduces the same data for the same seed?
error[E0425]: cannot find function `backup_entropy` in this scope
--> /home/krolaw/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.6.1/src/entropy/mod.rs:51:2
|
51 | backup_entropy(out);
| ^^^^^^^^^^^^^^ not found in this scope
Cargo.toml entry:
nanorand = { version = "0.6.1", features = ["wyrand"] }
Thanks.
I'm trying out this lovely library but encountered this panic when calling rng.generate_range<u16>(8192..)
on a WyRand
RNG:
thread 'protocol::tests::sim_connect_to_peers' panicked at 'attempt to add with overflow', /home/cloudhead/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.6.1/src/gen.rs:108:1
stack backtrace:
0: rust_begin_unwind
at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/std/src/panicking.rs:515:5
1: core::panicking::panic_fmt
at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/panicking.rs:92:14
2: core::panicking::panic
at /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/panicking.rs:50:5
3: <u16 as nanorand::gen::RandomRange<R>>::random_range
at /home/cloudhead/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.6.1/src/gen.rs:50:21
4: nanorand::rand::Rng::generate_range
at /home/cloudhead/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.6.1/src/rand/mod.rs:57:3
Any idea why this is happening? I call the RNG in a lot of places and this seems to be the only thing failing.
3b0042a corrupted the emoji in the readme: 3b0042a#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R62-R64
I have a program depended on nanorand, when upgraded to 0.6 verison, compiling get a link error on CentOS 7.
After downgrade the nanorand verison to 0.5, the compiling is OK.
Perhaps it's because CentOS 7 lacks the getrandom system call.
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-m64" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-Wl,--as-needed" "-L" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/root/rust-srv/web-connect/target/release/deps/web_connect-af0db03b26adaefa.web_connect.4hmo5qbh-cgu.0.rcgu.o" "-o" "/root/rust-srv/web-connect/target/release/deps/web_connect-af0db03b26adaefa" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-Wl,-O1" "-nodefaultlibs" "-L" "/root/rust-srv/web-connect/target/release/deps" "-L" "/root/rust-srv/web-connect/target/release/build/brotli-sys-60c0e082e3c3c651/out" "-L" "/root/rust-srv/web-connect/target/release/build/rust-crypto-698176e25e4afa68/out" "-L" "/root/rust-srv/web-connect/target/release/build/jemalloc-sys-1026c0f16ced73f7/out/build/lib" "-L" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/tmp/rustcYFvyx8/libjemalloc_sys-10752eb33d554d19.rlib" "/tmp/rustcYFvyx8/libcrypto-2446112925d5256b.rlib" "/tmp/rustcYFvyx8/libbrotli_sys-3f42712b13ffc0ac.rlib" "-Wl,--start-group" "-Wl,--end-group" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-c4d9a5b072ee3191.rlib" "-Wl,-Bdynamic" "-lpthread" "-lssl" "-lcrypto" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc"
= note: /root/rust-srv/web-connect/target/release/deps/web_connect-af0db03b26adaefa.web_connect.4hmo5qbh-cgu.0.rcgu.o: In function `_$LT$ntex..ws..stream..StreamEncoder$LT$S$GT$$u20$as$u20$futures_sink..Sink$LT$core..result..Result$LT$ntex..ws..codec..Message$C$E$GT$$GT$$GT$::start_send::ha01b650f1d21cef0':
web_connect.4hmo5qbh-cgu.0:(.text._ZN143_$LT$ntex..ws..stream..StreamEncoder$LT$S$GT$$u20$as$u20$futures_sink..Sink$LT$core..result..Result$LT$ntex..ws..codec..Message$C$E$GT$$GT$$GT$10start_send17ha01b650f1d21cef0E+0x989): undefined reference to `getrandom'
web_connect.4hmo5qbh-cgu.0:(.text._ZN143_$LT$ntex..ws..stream..StreamEncoder$LT$S$GT$$u20$as$u20$futures_sink..Sink$LT$core..result..Result$LT$ntex..ws..codec..Message$C$E$GT$$GT$$GT$10start_send17ha01b650f1d21cef0E+0x1111): undefined reference to `getrandom'
/root/rust-srv/web-connect/target/release/deps/web_connect-af0db03b26adaefa.web_connect.4hmo5qbh-cgu.0.rcgu.o: In function `ntex::ws::frame::Parser::write_message::h32afb0c81fac90ca':
web_connect.4hmo5qbh-cgu.0:(.text._ZN4ntex2ws5frame6Parser13write_message17h32afb0c81fac90caE+0x35c): undefined reference to `getrandom'
/root/rust-srv/web-connect/target/release/deps/web_connect-af0db03b26adaefa.web_connect.4hmo5qbh-cgu.0.rcgu.o: In function `ntex::ws::frame::Parser::write_message::haff1caf320801bae':
web_connect.4hmo5qbh-cgu.0:(.text._ZN4ntex2ws5frame6Parser13write_message17haff1caf320801baeE+0x10c): undefined reference to `getrandom'
collect2: error: ld returned 1 exit status
Would you be open to a PR? The ChaCha reference allows for initializing the counter to arbitrary values, but the current API doesn't allow this. I expect this would be a fairly simple change to the following code...
/// Initialize the ChaCha internal state, with a 256-bit key and 64-bit nonce.
pub const fn chacha_init(key: [u8; 32], nonce: [u8; 8]) -> [u32; 16] {
let mut state = [0u32; 16];
state[0] = chacha_pack(CHACHA_TAU, 0);
state[1] = chacha_pack(CHACHA_TAU, 4);
state[2] = chacha_pack(CHACHA_TAU, 8);
state[3] = chacha_pack(CHACHA_TAU, 12);
state[4] = chacha_pack(&key, 0);
state[5] = chacha_pack(&key, 4);
state[6] = chacha_pack(&key, 8);
state[7] = chacha_pack(&key, 12);
state[8] = chacha_pack(&key, 16);
state[9] = chacha_pack(&key, 20);
state[10] = chacha_pack(&key, 24);
state[11] = chacha_pack(&key, 28);
// 64-bit counter
state[12] = 0;
state[13] = 0;
// Nonce
state[14] = chacha_pack(&nonce, 0);
state[15] = chacha_pack(&nonce, 4);
state
}
As one the maintainers of getrandom
, I would advise against your getrandom_custom
feature. Generally speaking, this feature is set by a user who is registering a custom handler (as explained in our docs) and not by a library that just calls getrandom::getrandom
. The reason for this is because if a user enables the feature, but does not register a handler, they will get a confusing linker error.
It seems like this feature addition was done to reexport the register_custom_getrandom
macro, but a user of nanorand-rs can already just register a handler by just directly depending on getrandom
. It should also be noted that directly exporting our macro creates a dependency hazard, as the macro requires a function that returns getrandom::Error
. So you would not be able to internally update your version of getrandom
(say from 0.2
to 1.0
) without having a breaking change yourself. Without this feature, you would be able to update getrandom
without needing to release a breaking change in nanorand
.
I couldn't find any discussion or PR about why 34ba243 was added. However, it seems like none of the released versions include it yet, so it could be reverted without too much issue.
All the other uses of getrandom
's features seem reasonable to me. You could probably unconditionally enable the rdrand
feature (even on non-x86 targets) as it has no effect on those targets. Keeping the js
feature enabling separate is a good idea due to issues around feature unification and tkaitchuck/aHash#95 (comment)
I'm not sure how this would align with nanorand's to-the-point philosophy, but it would be nice to offer the same functionality as https://docs.rs/rand/latest/rand/seq/index.html does.
Particularly the SliceRandom and IteratorRandom utils are useful in many situations and their implementations don't seem to introduce any excessive complexity or unnecessary dependencies.
I wouldn't mind contributing code for this if there's a green light ๐
So I currently get this when trying to compile nanorand on my Windows box:
= note: libnanorand-3df99cf1d4f057c6.rlib(nanorand-3df99cf1d4f057c6.nanorand.3usfjb36-cgu.13.rcgu.o) : error LNK2019: unresolved external symbol BCryptGenRandom referenced in function _ZN8nanorand7entropy7windows19entropy_from_system17heb014656c23127ddE
This appears to be due to this being a non-uwp platform. Note that this happens even if the getrandom
feature is enabled, because the windows
entryopy module is still included with #[cfg(windows)]
, causing it to be linked in.
This appears to be the cfg
that should be checked for to make sure BCryptGenRandom
is available.
#[cfg(all(windows, target_vendor = "uwp"))]
OTOH, all the necessary platform detection already appears to be implemented in getrandom
, so maybe we should just be relying on it instead? There's also some error handling being done which does not seem to be reproduced in nanorand as well.
Generating an isize
in the range [0, 192) produces values in the range [0, 96) heavily biased towards 0. Meanwhile, generating an i32
generates values outside the requested range.
Since unsigned integers are unaffected by this, a way around the issue for now is generating unsigned integers from 0 to max - min
, casting the result to a signed integer, and then adding min
back in.
// As an example, I'm using WyRand
fn generate_signed_range(rng: &mut WyRand, min: isize, max: isize) -> isize {
rng.generate_range::<usize>(0, (max - min) as usize) as isize + min
}
I saw that this is being addressed in another branch, but I wanted to make this issue more visible for other users of this library.
ChaCha20 is relatively simple to implement, in addition to being cryptographically secure and fast on just about any platform.
Would be a good way to scrape off that annoying disclaimer from the readme.
Hi, one of my dependencies (wasmium-random) is using nanorand crate v0.6.1, my cargo throws an error while trying to build it, is there a way to change the v of nanorand inside of the other dep, also does the nanorand v0.7.0 solves this problem or are there any other solutions you could provide?
error: could not compile "nanorand" due to previous error
nanorand uses the naive shuffling algorithm that is biased: https://blog.codinghorror.com/the-danger-of-naivete/
Instead it should use proper Fisher-Yates.
Compare nanorand's implementation:
Line 69 in 92a5c71
Example to show the problem:
use nanorand::{WyRand, Rng};
// use rand::{thread_rng, seq::SliceRandom};
fn main() {
let mut h = std::collections::HashMap::new();
let mut rng = WyRand::new();
// let mut rng = thread_rng();
for _i in 0..600000 {
let mut v = vec![1, 2, 3];
rng.shuffle(&mut v);
// v.shuffle(&mut rng);
let count = h.entry(v).or_insert(0);
*count += 1
}
println!("{:?}", h.values().collect::<Vec<_>>());
}
Expected output (rand):
[100075, 99739, 99808, 100459, 99995, 99924]
Actual output (nanorand):
[88976, 88802, 111499, 88925, 111185, 110613]
error[E0433]: failed to resolve: use of undeclared crate or module `std`
--> /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.5.2/src/entropy/darwin.rs:1:5
|
1 | use std::ffi::c_void;
| ^^^ use of undeclared crate or module `std`
error[E0433]: failed to resolve: use of undeclared crate or module `std`
--> /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.5.2/src/entropy/darwin.rs:10:30
|
10 | unsafe { SecRandomCopyBytes(std::ptr::null(), out.len(), out.as_mut_ptr()) == 0 }
| ^^^ use of undeclared crate or module `std`
error[E0412]: cannot find type `c_void` in this scope
--> /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/nanorand-0.5.2/src/entropy/darwin.rs:5:36
|
5 | fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> u32;
| ^^^^^^ not found in this scope
|
help: consider importing this enum
|
1 | use core::ffi::c_void;
|
Would it be better to add macOS ci build target ?
It would be cool to add float support to this function. So that we can generate random floats with custom ranges.
Example:
let rng = nanorand::tls_rng();
let rand_num: f64 = rng.generate_range(-3.0..5.5);
WyRand::new().generate_range::<u32>(0, 1);
seems to always return 0
, while the common understanding is that the upper
parameter should be inclusive.
This seems to be the understanding of the crate's author as well, as in shuffle
implementation:
fn shuffle<I, S: AsMut<[I]>>(&mut self, mut target: S) {
let target = target.as_mut();
let target_len = target.len();
for idx in 0..target_len {
let random_idx = self.generate_range::<usize>(0, target_len - 1);
target.swap(idx, random_idx);
}
}
target_len - 1
basically means the last value in slice will never be selected as swap target, leading to some bizarre behavior, like shuffling a slice of len 2 always returns reversed slice, instead of giving roughly 50/50 distribution of original and reversed.
If the upper
parameter was indeed meant to be non-inclusive, then I guess the docs should be updated and shuffle
implementation fixed. If it was not, then the generate_range
function has to be fixed.
Tested on crate v 0.5.2, Rust 1.48.0
EDIT: typos, formatting
Building feature rdseed or --all-features fails on 32-bit x86:
error[E0432]: unresolved import `core::arch::x86::_rdseed64_step`
--> src/entropy.rs:58:6
|
58 | use core::arch::x86::_rdseed64_step as rdseed;
| ^^^^^^^^^^^^^^^^^--------------^^^^^^^^^^
| | |
| | help: a similar name exists in the module: `_rdseed16_step`
| no `_rdseed64_step` in `core_arch::arch::x86`
Compilation failed on Mac OS X on travis CI.
Undefined symbols for architecture x86_64:
"_getrandom", referenced from:
nanorand::entropy::unix::entropy_from_system::h55951253ee7e2e83 in libnanorand-a83c92296e1a29be.rlib(nanorand-a83c92296e1a29be.nanorand.ow5fw3sw-cgu.6.rcgu.o)
ld: symbol(s) not found for architecture x86_64
Link: https://travis-ci.org/github/Kogia-sima/sailfish/jobs/750030765
Also, getrandom
syscall is only available if the kernel supports. We must check the availability on runtime.
https://github.com/rust-random/getrandom/blob/master/src/linux_android.rs#L27-L38
Software | Version |
---|---|
rustc | 1.48.0 (stable) |
OS | Mac OS X 10.13.6 |
Hej ๐
The documentation does not say anything about the distribution of the values, though one would assume that primitive values ought to be uniformly distributed. This is not the case for f32 and f64 based on
nanorand-rs/nanorand/src/gen.rs
Line 97 in 5e4ea40
nanorand-rs/nanorand/src/gen.rs
Line 103 in 5e4ea40
Floats above a certain value lose prevision, so using, say, u32::MAX
and u32::MAX - 42
as the numerator both yield 1.0
, which leads to a bias of the generated floats towards 1.0. This playground illustrates it a bit more: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=465eb2dcf33851195dde9f3a6601ea22
If you want to fix that, a solution would be to use the "safe" value provided by <float>::MANTISSA_DIGITS
as the max instead of <int>::MAX
. I could ope a PR for that if you like.
Example:
use nanorand::{tls_rng, RNG};
fn main() {
println!("{}", tls_rng().generate_range::<usize>(3, 0));
}
Produces this output:
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', C:\Users\Andrew\.cargo\registry\src\github.com-1ecc6299db9ec823\nanorand-0.5.2\src\gen.rs:51:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fn example(){
use nanorand::{Rng, WyRand};
let mut rng = WyRand::new();
println!("Random number: {}", rng.generate_range(1..=3));
println!("Random number: {}", rng.generate_range(1..=3));
println!("Random number: {}", rng.generate_range(1..=3));
println!("Random number: {}", rng.generate_range(1..=3));
println!("Random number: {}", rng.generate_range(1..=3));
println!("Random number: {}", rng.generate_range(1..=3));
}
prints:
Random number: 1
Random number: 2
Random number: 1
Random number: 1
Random number: 0
Random number: 2
I was trying to generate some uuids and it seems that fill() just takes mutable references to temporary copies of the bytes in an array. I have to map the initial zeroed array and just use generate() to get it to work.
let mut rng = nanorand::tls_rng();
let random_bytes = [0; 16];
let random_bytes = random_bytes.map(|_| rng.generate::<u8>());
the above works
rng.fill(random_bytes);
rng.fill_bytes(random_bytes);
the above two do nothing, regardless of the declared mutability of random_bytes
Due to the implementation of tls_rand
& TlsWyRand
, the following code is unsound, yet compiles:
use nanorand::tls_rng;
fn main() {
// `x` and `y` both hold pointers to the same data in TLS (via `Rc`)
let mut x = tls_rng();
let mut y = tls_rng();
// `TlsWyrand`'s `DerefMut` implementation turns this pointer into a mutable reference unconditionally
let x_ref = &mut *x;
let y_ref = &mut *y;
// x_ref & y_ref now are both references to the same thing
assert!(std::ptr::eq(x_ref, y_ref));
}
It would be nice if it was possible to use nanorand to generate floats.
I know nothing about random number generation - would this be hard to implement?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.