├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── compile-issue.md │ ├── feature_request.md │ ├── other.md │ └── suggest-a-change.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── benches.yml │ ├── gh-pages.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── COPYRIGHT ├── Cargo.lock.msrv ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── SECURITY.md ├── benches ├── Cargo.toml ├── benches │ ├── array.rs │ ├── bool.rs │ ├── generators.rs │ ├── seq_choose.rs │ ├── shuffle.rs │ ├── simd.rs │ ├── standard.rs │ ├── uniform.rs │ ├── uniform_float.rs │ └── weighted.rs └── rustfmt.toml ├── clippy.toml ├── examples ├── monte-carlo.rs ├── monty-hall.rs └── rayon-monte-carlo.rs ├── rand_chacha ├── CHANGELOG.md ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── chacha.rs │ ├── guts.rs │ └── lib.rs ├── rand_core ├── CHANGELOG.md ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── block.rs │ ├── impls.rs │ ├── le.rs │ ├── lib.rs │ └── os.rs ├── rand_pcg ├── CHANGELOG.md ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src │ ├── lib.rs │ ├── pcg128.rs │ ├── pcg128cm.rs │ └── pcg64.rs └── tests │ ├── lcg128cmdxsm64.rs │ ├── lcg128xsl64.rs │ ├── lcg64xsh32.rs │ └── mcg128xsl64.rs ├── src ├── distr │ ├── bernoulli.rs │ ├── distribution.rs │ ├── float.rs │ ├── integer.rs │ ├── mod.rs │ ├── other.rs │ ├── slice.rs │ ├── uniform.rs │ ├── uniform_float.rs │ ├── uniform_int.rs │ ├── uniform_other.rs │ ├── utils.rs │ └── weighted │ │ ├── mod.rs │ │ └── weighted_index.rs ├── lib.rs ├── prelude.rs ├── rng.rs ├── rngs │ ├── mock.rs │ ├── mod.rs │ ├── reseeding.rs │ ├── small.rs │ ├── std.rs │ ├── thread.rs │ ├── xoshiro128plusplus.rs │ └── xoshiro256plusplus.rs └── seq │ ├── coin_flipper.rs │ ├── increasing_uniform.rs │ ├── index.rs │ ├── iterator.rs │ ├── mod.rs │ └── slice.rs └── utils └── redirect.html /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: dhardy 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something doesn't work as expected 4 | title: '' 5 | labels: X-bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Summary 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | What behaviour is expected, and why? 15 | 16 | ## Code sample 17 | 18 | ```rust 19 | // Code demonstrating the problem 20 | ``` 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/compile-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Compile issue 3 | about: Report / ask about a compilation issue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Common issues 11 | 12 | **Problem**: `rand_hc::Hc128Rng: rand_core::SeedableRng` (or other RNG) 13 | 14 | **Quick solution**: `cargo update` 15 | 16 | **Details**: This happens when multiple versions of the `rand_core` crate are in use. Check your `Cargo.lock` file for all versions of `rand_core`. Note that some versions (0.2.2 and 0.3.1) are compatibility shims and are not a problem by themselves. 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Background 11 | 12 | **What is your motivation?** 13 | 14 | **What type of application is this?** (E.g. cryptography, game, numerical simulation) 15 | 16 | ## Feature request 17 | 18 |
19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/other.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Other 3 | about: empty template 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/suggest-a-change.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggest a change 3 | about: Describe this issue template's purpose here. 4 | title: 'CHANGE: ' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | A change request is considered a (small) Request-For-Comment, and requires a concrete proposal and motivation. 11 | 12 | ## Summary 13 | 14 | How does this affect the API / end-user? (Include API-breaking changes, value-breaking changes and API additions.) 15 | 16 | ## Details 17 | 18 | What changes does this require internally? 19 | 20 | ## Motivation 21 | 22 | What is the motivation for this change? 23 | 24 | Since every change has a cost (even if just API churn or extra code size), every change must have sufficient motivation. This is arguably the most important part of the RFC. 25 | 26 | ## Alternatives 27 | 28 | Which alternatives might be considered, and why or why not? 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] Added a `CHANGELOG.md` entry 2 | 3 | # Summary 4 | 5 | # Motivation 6 | 7 | # Details 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/workflows/benches.yml: -------------------------------------------------------------------------------- 1 | name: Benches 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: 7 | - "**.md" 8 | - "examples/**" 9 | pull_request: 10 | branches: [ master ] 11 | paths-ignore: 12 | - "**.md" 13 | - "examples/**" 14 | 15 | defaults: 16 | run: 17 | working-directory: ./benches 18 | 19 | jobs: 20 | clippy-fmt: 21 | name: "Benches: Check Clippy and rustfmt" 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v4 25 | - uses: dtolnay/rust-toolchain@master 26 | with: 27 | toolchain: stable 28 | components: clippy, rustfmt 29 | - name: Rustfmt 30 | run: cargo fmt -- --check 31 | - name: Clippy 32 | run: cargo clippy --all-targets -- -D warnings 33 | benches: 34 | name: "Benches: Test" 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: dtolnay/rust-toolchain@master 39 | with: 40 | toolchain: nightly 41 | - name: Test 42 | run: RUSTFLAGS=-Dwarnings cargo test --benches 43 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: gh-pages 2 | 3 | permissions: 4 | contents: read 5 | pages: write 6 | id-token: write 7 | 8 | on: 9 | push: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | deploy: 15 | name: GH-pages documentation 16 | runs-on: ubuntu-latest 17 | environment: 18 | name: github-pages 19 | url: https://rust-random.github.io/rand/ 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | 25 | - name: Install toolchain 26 | uses: dtolnay/rust-toolchain@nightly 27 | 28 | - name: Build docs 29 | env: 30 | RUSTDOCFLAGS: --cfg doc_cfg 31 | # --all builds all crates, but with default features for other crates (okay in this case) 32 | run: | 33 | cargo doc --all --all-features --no-deps 34 | cp utils/redirect.html target/doc/index.html 35 | rm target/doc/.lock 36 | 37 | - name: Setup Pages 38 | uses: actions/configure-pages@v5 39 | 40 | - name: Upload artifact 41 | uses: actions/upload-pages-artifact@v3 42 | with: 43 | path: './target/doc' 44 | 45 | - name: Deploy to GitHub Pages 46 | id: deployment 47 | uses: actions/deploy-pages@v4 48 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Main tests 2 | 3 | on: 4 | push: 5 | branches: [ master, '0.[0-9]+' ] 6 | paths-ignore: 7 | - "**.md" 8 | - "benches/**" 9 | pull_request: 10 | branches: [ master, '0.[0-9]+' ] 11 | paths-ignore: 12 | - "**.md" 13 | - "benches/**" 14 | 15 | permissions: 16 | contents: read # to fetch code (actions/checkout) 17 | 18 | jobs: 19 | clippy-fmt: 20 | name: Check Clippy and rustfmt 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: dtolnay/rust-toolchain@master 25 | with: 26 | toolchain: stable 27 | components: clippy, rustfmt 28 | - name: Check Clippy 29 | run: cargo clippy --workspace -- -D warnings 30 | - name: Check rustfmt 31 | run: cargo fmt --all -- --check 32 | 33 | check-doc: 34 | name: Check doc 35 | runs-on: ubuntu-latest 36 | env: 37 | RUSTDOCFLAGS: "-Dwarnings --cfg docsrs -Zunstable-options --generate-link-to-definition" 38 | steps: 39 | - uses: actions/checkout@v4 40 | - name: Install toolchain 41 | uses: dtolnay/rust-toolchain@master 42 | with: 43 | toolchain: nightly 44 | - name: rand 45 | run: cargo doc --all-features --no-deps 46 | - name: rand_core 47 | run: cargo doc --all-features --package rand_core --no-deps 48 | - name: rand_chacha 49 | run: cargo doc --all-features --package rand_chacha --no-deps 50 | - name: rand_pcg 51 | run: cargo doc --all-features --package rand_pcg --no-deps 52 | 53 | test: 54 | runs-on: ${{ matrix.os }} 55 | strategy: 56 | fail-fast: false 57 | matrix: 58 | include: 59 | - os: ubuntu-latest 60 | target: x86_64-unknown-linux-gnu 61 | toolchain: stable 62 | - os: macos-latest 63 | target: x86_64-apple-darwin 64 | toolchain: stable 65 | # TODO: also aarch64 / M1 66 | - os: windows-latest 67 | target: x86_64-pc-windows-gnu 68 | toolchain: stable 69 | - os: windows-latest 70 | target: x86_64-pc-windows-msvc 71 | toolchain: beta 72 | # Test both windows-gnu and windows-msvc; use beta rust on one 73 | - os: ubuntu-latest 74 | target: x86_64-unknown-linux-gnu 75 | variant: MSRV 76 | toolchain: 1.63.0 77 | - os: ubuntu-latest 78 | deps: sudo apt-get update ; sudo apt install gcc-multilib 79 | target: i686-unknown-linux-gnu 80 | toolchain: nightly 81 | - os: ubuntu-latest 82 | target: x86_64-unknown-linux-gnu 83 | toolchain: nightly 84 | variant: minimal_versions 85 | 86 | steps: 87 | - uses: actions/checkout@v4 88 | - name: MSRV 89 | if: ${{ matrix.variant == 'MSRV' }} 90 | run: cp Cargo.lock.msrv Cargo.lock 91 | - name: Install toolchain 92 | uses: dtolnay/rust-toolchain@master 93 | with: 94 | target: ${{ matrix.target }} 95 | toolchain: ${{ matrix.toolchain }} 96 | - run: ${{ matrix.deps }} 97 | - name: Maybe minimal versions 98 | if: ${{ matrix.variant == 'minimal_versions' }} 99 | run: | 100 | cargo generate-lockfile -Z minimal-versions 101 | - name: Maybe nightly 102 | if: ${{ matrix.toolchain == 'nightly' }} 103 | run: | 104 | cargo test --target ${{ matrix.target }} --features=nightly 105 | cargo test --target ${{ matrix.target }} --all-features 106 | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features 107 | - name: Test rand 108 | run: | 109 | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features 110 | cargo build --target ${{ matrix.target }} --no-default-features --features alloc,os_rng,small_rng,unbiased 111 | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features --features=alloc,os_rng,small_rng 112 | cargo test --target ${{ matrix.target }} --examples 113 | - name: Test rand (all stable features) 114 | run: | 115 | cargo test --target ${{ matrix.target }} --features=serde,log,small_rng 116 | - name: Test rand_core 117 | run: | 118 | cargo test --target ${{ matrix.target }} --manifest-path rand_core/Cargo.toml 119 | cargo test --target ${{ matrix.target }} --manifest-path rand_core/Cargo.toml --no-default-features 120 | cargo test --target ${{ matrix.target }} --manifest-path rand_core/Cargo.toml --no-default-features --features=os_rng 121 | - name: Test rand_pcg 122 | run: cargo test --target ${{ matrix.target }} --manifest-path rand_pcg/Cargo.toml --features=serde 123 | - name: Test rand_chacha 124 | run: cargo test --target ${{ matrix.target }} --manifest-path rand_chacha/Cargo.toml --features=serde 125 | 126 | test-cross: 127 | runs-on: ${{ matrix.os }} 128 | strategy: 129 | fail-fast: false 130 | matrix: 131 | include: 132 | - os: ubuntu-latest 133 | target: powerpc-unknown-linux-gnu 134 | toolchain: stable 135 | 136 | steps: 137 | - uses: actions/checkout@v4 138 | - name: Install toolchain 139 | uses: dtolnay/rust-toolchain@master 140 | with: 141 | target: ${{ matrix.target }} 142 | toolchain: ${{ matrix.toolchain }} 143 | - name: Cache cargo plugins 144 | uses: actions/cache@v4 145 | with: 146 | path: ~/.cargo/bin/ 147 | key: ${{ runner.os }}-cargo-plugins 148 | - name: Install cross 149 | run: cargo install cross || true 150 | - name: Test 151 | run: | 152 | # all stable features: 153 | cross test --no-fail-fast --target ${{ matrix.target }} --features=serde,log,small_rng 154 | cross test --no-fail-fast --target ${{ matrix.target }} --examples 155 | cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_core/Cargo.toml 156 | cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_pcg/Cargo.toml --features=serde 157 | cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_chacha/Cargo.toml 158 | 159 | test-miri: 160 | runs-on: ubuntu-latest 161 | steps: 162 | - uses: actions/checkout@v4 163 | - name: Install toolchain 164 | run: | 165 | rustup toolchain install nightly --component miri 166 | rustup override set nightly 167 | cargo miri setup 168 | - name: Test rand 169 | run: | 170 | cargo miri test --no-default-features --lib --tests 171 | cargo miri test --features=log,small_rng 172 | cargo miri test --manifest-path rand_core/Cargo.toml 173 | cargo miri test --manifest-path rand_core/Cargo.toml --features=serde 174 | cargo miri test --manifest-path rand_core/Cargo.toml --no-default-features 175 | cargo miri test --manifest-path rand_pcg/Cargo.toml --features=serde 176 | cargo miri test --manifest-path rand_chacha/Cargo.toml --no-default-features 177 | 178 | test-no-std: 179 | runs-on: ubuntu-latest 180 | steps: 181 | - uses: actions/checkout@v4 182 | - name: Install toolchain 183 | uses: dtolnay/rust-toolchain@nightly 184 | with: 185 | target: thumbv6m-none-eabi 186 | - name: Build top-level only 187 | run: cargo build --target=thumbv6m-none-eabi --no-default-features 188 | 189 | # Disabled due to lack of known working compiler versions (not older than our MSRV) 190 | # test-avr: 191 | # runs-on: ubuntu-latest 192 | # steps: 193 | # - uses: actions/checkout@v4 194 | # - name: Install toolchain 195 | # uses: dtolnay/rust-toolchain@nightly 196 | # with: 197 | # components: rust-src 198 | # - name: Build top-level only 199 | # run: cargo build -Z build-std=core --target=avr-unknown-gnu-atmega328 --no-default-features 200 | 201 | test-ios: 202 | runs-on: macos-latest 203 | steps: 204 | - uses: actions/checkout@v4 205 | - name: Install toolchain 206 | uses: dtolnay/rust-toolchain@nightly 207 | with: 208 | target: aarch64-apple-ios 209 | - name: Build top-level only 210 | run: cargo build --target=aarch64-apple-ios 211 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | rand_wasm_bindgen_test*.[tj]s 4 | rand_wasm_bindgen_test*.wasm 5 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the Rand project are retained by their contributors. No 2 | copyright assignment is required to contribute to the Rand project. 3 | 4 | For full authorship information, see the version control history. 5 | 6 | Except as otherwise noted (below and/or in individual files), Rand is 7 | licensed under the Apache License, Version 2.0 or 8 | or the MIT license 9 | or , at your option. 10 | 11 | The Rand project includes code from the Rust project 12 | published under these same licenses. 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rand" 3 | version = "0.9.1" 4 | authors = ["The Rand Project Developers", "The Rust Project Developers"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "README.md" 7 | repository = "https://github.com/rust-random/rand" 8 | documentation = "https://docs.rs/rand" 9 | homepage = "https://rust-random.github.io/book" 10 | description = """ 11 | Random number generators and other randomness functionality. 12 | """ 13 | keywords = ["random", "rng"] 14 | categories = ["algorithms", "no-std"] 15 | autobenches = true 16 | edition = "2021" 17 | rust-version = "1.63" 18 | include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"] 19 | 20 | [package.metadata.docs.rs] 21 | # To build locally: 22 | # RUSTDOCFLAGS="--cfg docsrs -Zunstable-options --generate-link-to-definition" cargo +nightly doc --all --all-features --no-deps --open 23 | all-features = true 24 | rustdoc-args = ["--generate-link-to-definition"] 25 | 26 | [package.metadata.playground] 27 | features = ["small_rng", "serde"] 28 | 29 | [features] 30 | # Meta-features: 31 | default = ["std", "std_rng", "os_rng", "small_rng", "thread_rng"] 32 | nightly = [] # some additions requiring nightly Rust 33 | serde = ["dep:serde", "rand_core/serde"] 34 | 35 | # Option (enabled by default): without "std" rand uses libcore; this option 36 | # enables functionality expected to be available on a standard platform. 37 | std = ["rand_core/std", "rand_chacha?/std", "alloc"] 38 | 39 | # Option: "alloc" enables support for Vec and Box when not using "std" 40 | alloc = [] 41 | 42 | # Option: enable OsRng 43 | os_rng = ["rand_core/os_rng"] 44 | 45 | # Option (requires nightly Rust): experimental SIMD support 46 | simd_support = [] 47 | 48 | # Option (enabled by default): enable StdRng 49 | std_rng = ["dep:rand_chacha"] 50 | 51 | # Option: enable SmallRng 52 | small_rng = [] 53 | 54 | # Option: enable ThreadRng and rng() 55 | thread_rng = ["std", "std_rng", "os_rng"] 56 | 57 | # Option: use unbiased sampling for algorithms supporting this option: Uniform distribution. 58 | # By default, bias affecting no more than one in 2^48 samples is accepted. 59 | # Note: enabling this option is expected to affect reproducibility of results. 60 | unbiased = [] 61 | 62 | # Option: enable logging 63 | log = ["dep:log"] 64 | 65 | [workspace] 66 | members = [ 67 | "rand_core", 68 | "rand_chacha", 69 | "rand_pcg", 70 | ] 71 | exclude = ["benches", "distr_test"] 72 | 73 | [dependencies] 74 | rand_core = { path = "rand_core", version = "0.9.0", default-features = false } 75 | log = { version = "0.4.4", optional = true } 76 | serde = { version = "1.0.103", features = ["derive"], optional = true } 77 | rand_chacha = { path = "rand_chacha", version = "0.9.0", default-features = false, optional = true } 78 | 79 | [dev-dependencies] 80 | rand_pcg = { path = "rand_pcg", version = "0.9.0" } 81 | # Only to test serde 82 | bincode = "1.2.1" 83 | rayon = "1.7" 84 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2018 Developers of the Rand project 2 | Copyright (c) 2014 The Rust Project Developers 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rand 2 | 3 | [![Test Status](https://github.com/rust-random/rand/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-random/rand/actions) 4 | [![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand) 5 | [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) 6 | [![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand) 7 | [![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand) 8 | 9 | Rand is a set of crates supporting (pseudo-)random generators: 10 | 11 | - Built over a standard RNG trait: [`rand_core::RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html) 12 | - With fast implementations of both [strong](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and 13 | [small](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators: [`rand::rngs`](https://docs.rs/rand/latest/rand/rngs/index.html), and more RNGs: [`rand_chacha`](https://docs.rs/rand_chacha), [`rand_xoshiro`](https://docs.rs/rand_xoshiro/), [`rand_pcg`](https://docs.rs/rand_pcg/), [rngs repo](https://github.com/rust-random/rngs/) 14 | - [`rand::rng`](https://docs.rs/rand/latest/rand/fn.rng.html) is an asymptotically-fast, automatically-seeded and reasonably strong generator available on all `std` targets 15 | - Direct support for seeding generators from the [getrandom] crate 16 | 17 | With broad support for random value generation and random processes: 18 | 19 | - [`StandardUniform`](https://docs.rs/rand/latest/rand/distr/struct.StandardUniform.html) random value sampling, 20 | [`Uniform`](https://docs.rs/rand/latest/rand/distr/struct.Uniform.html)-ranged value sampling 21 | and [more](https://docs.rs/rand/latest/rand/distr/index.html) 22 | - Samplers for a large number of non-uniform random number distributions via our own 23 | [`rand_distr`](https://docs.rs/rand_distr) and via 24 | the [`statrs`](https://docs.rs/statrs) 25 | - Random processes (mostly choose and shuffle) via [`rand::seq`](https://docs.rs/rand/latest/rand/seq/index.html) traits 26 | 27 | All with: 28 | 29 | - [Portably reproducible output](https://rust-random.github.io/book/portability.html) 30 | - `#[no_std]` compatibility (partial) 31 | - *Many* performance optimisations thanks to contributions from the wide 32 | user-base 33 | 34 | Rand **is not**: 35 | 36 | - Small (LoC). Most low-level crates are small, but the higher-level `rand` 37 | and `rand_distr` each contain a lot of functionality. 38 | - Simple (implementation). We have a strong focus on correctness, speed and flexibility, but 39 | not simplicity. If you prefer a small-and-simple library, there are 40 | alternatives including [fastrand](https://crates.io/crates/fastrand) 41 | and [oorandom](https://crates.io/crates/oorandom). 42 | - Primarily a cryptographic library. `rand` does provide some generators which 43 | aim to support unpredictable value generation under certain constraints; 44 | see [SECURITY.md](https://github.com/rust-random/rand/blob/master/SECURITY.md) for details. 45 | Users are expected to determine for themselves 46 | whether `rand`'s functionality meets their own security requirements. 47 | 48 | Documentation: 49 | 50 | - [The Rust Rand Book](https://rust-random.github.io/book) 51 | - [API reference (master branch)](https://rust-random.github.io/rand) 52 | - [API reference (docs.rs)](https://docs.rs/rand) 53 | 54 | 55 | ## Versions 56 | 57 | Rand is *mature* (suitable for general usage, with infrequent breaking releases 58 | which minimise breakage) but not yet at 1.0. Current `MAJOR.MINOR` versions are: 59 | 60 | - Version 0.9 was released in January 2025. 61 | 62 | See the [CHANGELOG](https://github.com/rust-random/rand/blob/master/CHANGELOG.md) or [Upgrade Guide](https://rust-random.github.io/book/update.html) for more details. 63 | 64 | ## Crate Features 65 | 66 | Rand is built with these features enabled by default: 67 | 68 | - `std` enables functionality dependent on the `std` lib 69 | - `alloc` (implied by `std`) enables functionality requiring an allocator 70 | - `os_rng` (implied by `std`) enables `rngs::OsRng`, using the [getrandom] crate 71 | - `std_rng` enables inclusion of `StdRng`, `ThreadRng` 72 | - `small_rng` enables inclusion of the `SmallRng` PRNG 73 | 74 | Optionally, the following dependencies can be enabled: 75 | 76 | - `log` enables logging via [log](https://crates.io/crates/log) 77 | 78 | Additionally, these features configure Rand: 79 | 80 | - `nightly` includes some additions requiring nightly Rust 81 | - `simd_support` (experimental) enables sampling of SIMD values 82 | (uniformly random SIMD integers and floats), requiring nightly Rust 83 | - `unbiased` use unbiased sampling for algorithms supporting this option: Uniform distribution. 84 | 85 | (By default, bias affecting no more than one in 2^48 samples is accepted.) 86 | 87 | Note: enabling this option is expected to affect reproducibility of results. 88 | 89 | Note that nightly features are not stable and therefore not all library and 90 | compiler versions will be compatible. This is especially true of Rand's 91 | experimental `simd_support` feature. 92 | 93 | Rand supports limited functionality in `no_std` mode (enabled via 94 | `default-features = false`). In this case, `OsRng` and `from_os_rng` are 95 | unavailable (unless `os_rng` is enabled), large parts of `seq` are 96 | unavailable (unless `alloc` is enabled), and `ThreadRng` is unavailable. 97 | 98 | ## Portability and platform support 99 | 100 | Many (but not all) algorithms are intended to have reproducible output. Read more in the book: [Portability](https://rust-random.github.io/book/portability.html). 101 | 102 | The Rand library supports a variety of CPU architectures. Platform integration is outsourced to [getrandom]. 103 | 104 | ### WebAssembly support 105 | 106 | The [WASI](https://github.com/WebAssembly/WASI/tree/main) and Emscripten 107 | targets are directly supported. The `wasm32-unknown-unknown` target is not 108 | *automatically* supported. To enable support for this target, refer to the 109 | [`getrandom` documentation for WebAssembly](https://docs.rs/getrandom/latest/getrandom/#webassembly-support). 110 | Alternatively, the `os_rng` feature may be disabled. 111 | 112 | # License 113 | 114 | Rand is distributed under the terms of both the MIT license and the 115 | Apache License (Version 2.0). 116 | 117 | See [LICENSE-APACHE](https://github.com/rust-random/rand/blob/master/LICENSE-APACHE) and [LICENSE-MIT](https://github.com/rust-random/rand/blob/master/LICENSE-MIT), and 118 | [COPYRIGHT](https://github.com/rust-random/rand/blob/master/COPYRIGHT) for details. 119 | 120 | [getrandom]: https://crates.io/crates/getrandom 121 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Disclaimer 4 | 5 | Rand is a community project and cannot provide legally-binding guarantees of 6 | security. 7 | 8 | ## Security premises 9 | 10 | ### Marker traits 11 | 12 | Rand provides the marker traits `CryptoRng`, `TryCryptoRng` and 13 | `CryptoBlockRng`. Generators (RNGs) implementing one of these traits which are 14 | used according to these additional constraints: 15 | 16 | - The generator may be constructed using `std::default::Default` where the 17 | generator supports this trait. Note that generators should *only* support 18 | `Default` where the `default()` instance is appropriately seeded: for 19 | example `OsRng` has no state and thus has a trivial `default()` instance 20 | while `ThreadRng::default()` returns a handle to a thread-local instance 21 | seeded using `OsRng`. 22 | - The generator may be constructed using `rand_core::SeedableRng` in any of 23 | the following ways where the generator supports this trait: 24 | 25 | - Via `SeedableRng::from_seed` using a cryptographically secure seed value 26 | - Via `SeedableRng::from_rng` or `try_from_rng` using a cryptographically 27 | secure source `rng` 28 | - Via `SeedableRng::from_os_rng` or `try_from_os_rng` 29 | - The state (memory) of the generator and its seed value (or source `rng`) are 30 | not exposed 31 | 32 | are expected to provide the following: 33 | 34 | - An attacker cannot predict the output with more accuracy than what would be 35 | expected through pure chance since each possible output value of any method 36 | under the above traits which generates output bytes (including 37 | `RngCore::next_u32`, `RngCore::next_u64`, `RngCore::fill_bytes`, 38 | `TryRngCore::try_next_u32`, `TryRngCore::try_next_u64`, 39 | `TryRngCore::try_fill_bytes` and `BlockRngCore::generate`) should be equally 40 | likely 41 | - Knowledge of prior outputs from the generator does not aid an attacker in 42 | predicting future outputs 43 | 44 | ### Specific generators 45 | 46 | `OsRng` is a stateless "generator" implemented via [getrandom]. As such, it has 47 | no possible state to leak and cannot be improperly seeded. 48 | 49 | `StdRng` is a `CryptoRng` and `SeedableRng` using a pseudo-random algorithm 50 | selected for good security and performance qualities. Since it does not offer 51 | reproducibility of output, its algorithm may be changed in any release version. 52 | 53 | `ChaCha12Rng` and `ChaCha20Rng` are selected pseudo-random generators 54 | distributed by the `rand` project which meet the requirements of the `CryptoRng` 55 | trait and implement `SeedableRng` with a commitment to reproducibility of 56 | results. 57 | 58 | `ThreadRng` is a conveniently-packaged generator over `StdRng` offering 59 | automatic seeding from `OsRng`, periodic reseeding and thread locality. 60 | This random source is intended to offer a good compromise between cryptographic 61 | security, fast generation with reasonably low memory and initialization cost 62 | overheads, and robustness against misuse. 63 | 64 | [getrandom]: https://crates.io/crates/getrandom 65 | 66 | ### Distributions 67 | 68 | Methods of the `Rng` trait, functionality of the `rand::seq` module and 69 | implementators of the `Distribution` trait are expected, while using a 70 | cryptographically secure `CryptoRng` instance meeting the above constraints, 71 | to not introduce significant bias to their operation beyond what would be 72 | expected of the operation. Note that the usage of 'significant' here permits 73 | some bias, as noted for example in the documentation of the `Uniform` 74 | distribution. 75 | 76 | ## Supported Versions 77 | 78 | We aim to provide security fixes in the form of a new patch version for the 79 | latest release version of `rand` and its dependencies `rand_core` and 80 | `rand_chacha`, as well as for prior major and minor releases which were, at some 81 | time during the previous 12 months, the latest release version. 82 | 83 | ## Reporting a Vulnerability 84 | 85 | If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. 86 | 87 | Please disclose it at [security advisory](https://github.com/rust-random/rand/security/advisories/new). 88 | 89 | This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. 90 | -------------------------------------------------------------------------------- /benches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "benches" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [features] 8 | # Option (requires nightly Rust): experimental SIMD support 9 | simd_support = ["rand/simd_support"] 10 | 11 | [dependencies] 12 | 13 | [dev-dependencies] 14 | rand = { path = "..", features = ["small_rng", "nightly"] } 15 | rand_pcg = { path = "../rand_pcg" } 16 | rand_chacha = { path = "../rand_chacha" } 17 | criterion = "0.5" 18 | criterion-cycles-per-byte = "0.6" 19 | 20 | [[bench]] 21 | name = "array" 22 | harness = false 23 | 24 | [[bench]] 25 | name = "bool" 26 | harness = false 27 | 28 | [[bench]] 29 | name = "generators" 30 | harness = false 31 | 32 | [[bench]] 33 | name = "seq_choose" 34 | harness = false 35 | 36 | [[bench]] 37 | name = "shuffle" 38 | harness = false 39 | 40 | [[bench]] 41 | name = "simd" 42 | harness = false 43 | 44 | [[bench]] 45 | name = "standard" 46 | harness = false 47 | 48 | [[bench]] 49 | name = "uniform" 50 | harness = false 51 | 52 | [[bench]] 53 | name = "uniform_float" 54 | harness = false 55 | 56 | [[bench]] 57 | name = "weighted" 58 | harness = false 59 | -------------------------------------------------------------------------------- /benches/benches/array.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Generating/filling arrays and iterators of output 10 | 11 | use criterion::{criterion_group, criterion_main, Criterion}; 12 | use rand::distr::StandardUniform; 13 | use rand::prelude::*; 14 | use rand_pcg::Pcg64Mcg; 15 | 16 | criterion_group!( 17 | name = benches; 18 | config = Criterion::default(); 19 | targets = bench 20 | ); 21 | criterion_main!(benches); 22 | 23 | pub fn bench(c: &mut Criterion) { 24 | let mut g = c.benchmark_group("random_1kb"); 25 | g.throughput(criterion::Throughput::Bytes(1024)); 26 | 27 | g.bench_function("u16_iter_repeat", |b| { 28 | use core::iter; 29 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 30 | b.iter(|| { 31 | let v: Vec = iter::repeat(()).map(|()| rng.random()).take(512).collect(); 32 | v 33 | }); 34 | }); 35 | 36 | g.bench_function("u16_sample_iter", |b| { 37 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 38 | b.iter(|| { 39 | let v: Vec = StandardUniform.sample_iter(&mut rng).take(512).collect(); 40 | v 41 | }); 42 | }); 43 | 44 | g.bench_function("u16_gen_array", |b| { 45 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 46 | b.iter(|| { 47 | let v: [u16; 512] = rng.random(); 48 | v 49 | }); 50 | }); 51 | 52 | g.bench_function("u16_fill", |b| { 53 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 54 | let mut buf = [0u16; 512]; 55 | b.iter(|| { 56 | rng.fill(&mut buf[..]); 57 | buf 58 | }); 59 | }); 60 | 61 | g.bench_function("u64_iter_repeat", |b| { 62 | use core::iter; 63 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 64 | b.iter(|| { 65 | let v: Vec = iter::repeat(()).map(|()| rng.random()).take(128).collect(); 66 | v 67 | }); 68 | }); 69 | 70 | g.bench_function("u64_sample_iter", |b| { 71 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 72 | b.iter(|| { 73 | let v: Vec = StandardUniform.sample_iter(&mut rng).take(128).collect(); 74 | v 75 | }); 76 | }); 77 | 78 | g.bench_function("u64_gen_array", |b| { 79 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 80 | b.iter(|| { 81 | let v: [u64; 128] = rng.random(); 82 | v 83 | }); 84 | }); 85 | 86 | g.bench_function("u64_fill", |b| { 87 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 88 | let mut buf = [0u64; 128]; 89 | b.iter(|| { 90 | rng.fill(&mut buf[..]); 91 | buf 92 | }); 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /benches/benches/bool.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Generating/filling arrays and iterators of output 10 | 11 | use criterion::{criterion_group, criterion_main, Criterion}; 12 | use rand::distr::Bernoulli; 13 | use rand::prelude::*; 14 | use rand_pcg::Pcg32; 15 | 16 | criterion_group!( 17 | name = benches; 18 | config = Criterion::default(); 19 | targets = bench 20 | ); 21 | criterion_main!(benches); 22 | 23 | pub fn bench(c: &mut Criterion) { 24 | let mut g = c.benchmark_group("random_bool"); 25 | g.sample_size(1000); 26 | g.warm_up_time(core::time::Duration::from_millis(500)); 27 | g.measurement_time(core::time::Duration::from_millis(1000)); 28 | 29 | g.bench_function("standard", |b| { 30 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 31 | b.iter(|| rng.sample::(rand::distr::StandardUniform)) 32 | }); 33 | 34 | g.bench_function("const", |b| { 35 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 36 | b.iter(|| rng.random_bool(0.18)) 37 | }); 38 | 39 | g.bench_function("var", |b| { 40 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 41 | let p = rng.random(); 42 | b.iter(|| rng.random_bool(p)) 43 | }); 44 | 45 | g.bench_function("ratio_const", |b| { 46 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 47 | b.iter(|| rng.random_ratio(2, 3)) 48 | }); 49 | 50 | g.bench_function("ratio_var", |b| { 51 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 52 | let d = rng.random_range(1..=100); 53 | let n = rng.random_range(0..=d); 54 | b.iter(|| rng.random_ratio(n, d)); 55 | }); 56 | 57 | g.bench_function("bernoulli_const", |b| { 58 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 59 | let d = Bernoulli::new(0.18).unwrap(); 60 | b.iter(|| rng.sample(d)) 61 | }); 62 | 63 | g.bench_function("bernoulli_var", |b| { 64 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 65 | let p = rng.random(); 66 | let d = Bernoulli::new(p).unwrap(); 67 | b.iter(|| rng.sample(d)) 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /benches/benches/generators.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use core::time::Duration; 10 | use criterion::measurement::WallTime; 11 | use criterion::{black_box, criterion_group, criterion_main, BenchmarkGroup, Criterion}; 12 | use rand::prelude::*; 13 | use rand::rngs::OsRng; 14 | use rand::rngs::ReseedingRng; 15 | use rand_chacha::rand_core::UnwrapErr; 16 | use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng}; 17 | use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg}; 18 | 19 | criterion_group!( 20 | name = benches; 21 | config = Criterion::default(); 22 | targets = random_bytes, random_u32, random_u64, init_gen, init_from_u64, init_from_seed, reseeding_bytes 23 | ); 24 | criterion_main!(benches); 25 | 26 | pub fn random_bytes(c: &mut Criterion) { 27 | let mut g = c.benchmark_group("random_bytes"); 28 | g.warm_up_time(Duration::from_millis(500)); 29 | g.measurement_time(Duration::from_millis(1000)); 30 | g.throughput(criterion::Throughput::Bytes(1024)); 31 | 32 | fn bench(g: &mut BenchmarkGroup, name: &str, mut rng: impl Rng) { 33 | g.bench_function(name, |b| { 34 | let mut buf = [0u8; 1024]; 35 | b.iter(|| { 36 | rng.fill_bytes(&mut buf); 37 | black_box(buf); 38 | }); 39 | }); 40 | } 41 | 42 | bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng())); 43 | bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng())); 44 | bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng())); 45 | bench(&mut g, "pcg64dxsm", Pcg64Dxsm::from_rng(&mut rand::rng())); 46 | bench(&mut g, "chacha8", ChaCha8Rng::from_rng(&mut rand::rng())); 47 | bench(&mut g, "chacha12", ChaCha12Rng::from_rng(&mut rand::rng())); 48 | bench(&mut g, "chacha20", ChaCha20Rng::from_rng(&mut rand::rng())); 49 | bench(&mut g, "std", StdRng::from_rng(&mut rand::rng())); 50 | bench(&mut g, "small", SmallRng::from_rng(&mut rand::rng())); 51 | bench(&mut g, "os", UnwrapErr(OsRng)); 52 | bench(&mut g, "thread", rand::rng()); 53 | 54 | g.finish() 55 | } 56 | 57 | pub fn random_u32(c: &mut Criterion) { 58 | let mut g = c.benchmark_group("random_u32"); 59 | g.sample_size(1000); 60 | g.warm_up_time(Duration::from_millis(500)); 61 | g.measurement_time(Duration::from_millis(1000)); 62 | g.throughput(criterion::Throughput::Bytes(4)); 63 | 64 | fn bench(g: &mut BenchmarkGroup, name: &str, mut rng: impl Rng) { 65 | g.bench_function(name, |b| { 66 | b.iter(|| rng.random::()); 67 | }); 68 | } 69 | 70 | bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng())); 71 | bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng())); 72 | bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng())); 73 | bench(&mut g, "pcg64dxsm", Pcg64Dxsm::from_rng(&mut rand::rng())); 74 | bench(&mut g, "chacha8", ChaCha8Rng::from_rng(&mut rand::rng())); 75 | bench(&mut g, "chacha12", ChaCha12Rng::from_rng(&mut rand::rng())); 76 | bench(&mut g, "chacha20", ChaCha20Rng::from_rng(&mut rand::rng())); 77 | bench(&mut g, "std", StdRng::from_rng(&mut rand::rng())); 78 | bench(&mut g, "small", SmallRng::from_rng(&mut rand::rng())); 79 | bench(&mut g, "os", UnwrapErr(OsRng)); 80 | bench(&mut g, "thread", rand::rng()); 81 | 82 | g.finish() 83 | } 84 | 85 | pub fn random_u64(c: &mut Criterion) { 86 | let mut g = c.benchmark_group("random_u64"); 87 | g.sample_size(1000); 88 | g.warm_up_time(Duration::from_millis(500)); 89 | g.measurement_time(Duration::from_millis(1000)); 90 | g.throughput(criterion::Throughput::Bytes(8)); 91 | 92 | fn bench(g: &mut BenchmarkGroup, name: &str, mut rng: impl Rng) { 93 | g.bench_function(name, |b| { 94 | b.iter(|| rng.random::()); 95 | }); 96 | } 97 | 98 | bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng())); 99 | bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng())); 100 | bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng())); 101 | bench(&mut g, "pcg64dxsm", Pcg64Dxsm::from_rng(&mut rand::rng())); 102 | bench(&mut g, "chacha8", ChaCha8Rng::from_rng(&mut rand::rng())); 103 | bench(&mut g, "chacha12", ChaCha12Rng::from_rng(&mut rand::rng())); 104 | bench(&mut g, "chacha20", ChaCha20Rng::from_rng(&mut rand::rng())); 105 | bench(&mut g, "std", StdRng::from_rng(&mut rand::rng())); 106 | bench(&mut g, "small", SmallRng::from_rng(&mut rand::rng())); 107 | bench(&mut g, "os", UnwrapErr(OsRng)); 108 | bench(&mut g, "thread", rand::rng()); 109 | 110 | g.finish() 111 | } 112 | 113 | pub fn init_gen(c: &mut Criterion) { 114 | let mut g = c.benchmark_group("init_gen"); 115 | g.warm_up_time(Duration::from_millis(500)); 116 | g.measurement_time(Duration::from_millis(1000)); 117 | 118 | fn bench(g: &mut BenchmarkGroup, name: &str) { 119 | g.bench_function(name, |b| { 120 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 121 | b.iter(|| R::from_rng(&mut rng)); 122 | }); 123 | } 124 | 125 | bench::(&mut g, "pcg32"); 126 | bench::(&mut g, "pcg64"); 127 | bench::(&mut g, "pcg64mcg"); 128 | bench::(&mut g, "pcg64dxsm"); 129 | bench::(&mut g, "chacha8"); 130 | bench::(&mut g, "chacha12"); 131 | bench::(&mut g, "chacha20"); 132 | bench::(&mut g, "std"); 133 | bench::(&mut g, "small"); 134 | 135 | g.finish() 136 | } 137 | 138 | pub fn init_from_u64(c: &mut Criterion) { 139 | let mut g = c.benchmark_group("init_from_u64"); 140 | g.warm_up_time(Duration::from_millis(500)); 141 | g.measurement_time(Duration::from_millis(1000)); 142 | 143 | fn bench(g: &mut BenchmarkGroup, name: &str) { 144 | g.bench_function(name, |b| { 145 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 146 | let seed = rng.random(); 147 | b.iter(|| R::seed_from_u64(black_box(seed))); 148 | }); 149 | } 150 | 151 | bench::(&mut g, "pcg32"); 152 | bench::(&mut g, "pcg64"); 153 | bench::(&mut g, "pcg64mcg"); 154 | bench::(&mut g, "pcg64dxsm"); 155 | bench::(&mut g, "chacha8"); 156 | bench::(&mut g, "chacha12"); 157 | bench::(&mut g, "chacha20"); 158 | bench::(&mut g, "std"); 159 | bench::(&mut g, "small"); 160 | 161 | g.finish() 162 | } 163 | 164 | pub fn init_from_seed(c: &mut Criterion) { 165 | let mut g = c.benchmark_group("init_from_seed"); 166 | g.warm_up_time(Duration::from_millis(500)); 167 | g.measurement_time(Duration::from_millis(1000)); 168 | 169 | fn bench(g: &mut BenchmarkGroup, name: &str) 170 | where 171 | rand::distr::StandardUniform: Distribution<::Seed>, 172 | { 173 | g.bench_function(name, |b| { 174 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 175 | let seed = rng.random(); 176 | b.iter(|| R::from_seed(black_box(seed.clone()))); 177 | }); 178 | } 179 | 180 | bench::(&mut g, "pcg32"); 181 | bench::(&mut g, "pcg64"); 182 | bench::(&mut g, "pcg64mcg"); 183 | bench::(&mut g, "pcg64dxsm"); 184 | bench::(&mut g, "chacha8"); 185 | bench::(&mut g, "chacha12"); 186 | bench::(&mut g, "chacha20"); 187 | bench::(&mut g, "std"); 188 | bench::(&mut g, "small"); 189 | 190 | g.finish() 191 | } 192 | 193 | pub fn reseeding_bytes(c: &mut Criterion) { 194 | let mut g = c.benchmark_group("reseeding_bytes"); 195 | g.warm_up_time(Duration::from_millis(500)); 196 | g.throughput(criterion::Throughput::Bytes(1024 * 1024)); 197 | 198 | fn bench(g: &mut BenchmarkGroup, thresh: u64) { 199 | let name = format!("chacha20_{}k", thresh); 200 | g.bench_function(name.as_str(), |b| { 201 | let mut rng = ReseedingRng::::new(thresh * 1024, OsRng).unwrap(); 202 | let mut buf = [0u8; 1024 * 1024]; 203 | b.iter(|| { 204 | rng.fill_bytes(&mut buf); 205 | black_box(&buf); 206 | }); 207 | }); 208 | } 209 | 210 | bench(&mut g, 4); 211 | bench(&mut g, 16); 212 | bench(&mut g, 32); 213 | bench(&mut g, 64); 214 | bench(&mut g, 256); 215 | bench(&mut g, 1024); 216 | 217 | g.finish() 218 | } 219 | -------------------------------------------------------------------------------- /benches/benches/seq_choose.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 10 | use rand::prelude::*; 11 | use rand::SeedableRng; 12 | use rand_pcg::Pcg32; 13 | 14 | criterion_group!( 15 | name = benches; 16 | config = Criterion::default(); 17 | targets = bench 18 | ); 19 | criterion_main!(benches); 20 | 21 | pub fn bench(c: &mut Criterion) { 22 | c.bench_function("seq_slice_choose_1_of_100", |b| { 23 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 24 | let mut buf = [0i32; 100]; 25 | rng.fill(&mut buf); 26 | let x = black_box(&mut buf); 27 | 28 | b.iter(|| x.choose(&mut rng).unwrap()); 29 | }); 30 | 31 | let lens = [(1, 1000), (950, 1000), (10, 100), (90, 100)]; 32 | for (amount, len) in lens { 33 | let name = format!("seq_slice_choose_multiple_{}_of_{}", amount, len); 34 | c.bench_function(name.as_str(), |b| { 35 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 36 | let mut buf = [0i32; 1000]; 37 | rng.fill(&mut buf); 38 | let x = black_box(&buf[..len]); 39 | 40 | let mut results_buf = [0i32; 950]; 41 | let y = black_box(&mut results_buf[..amount]); 42 | let amount = black_box(amount); 43 | 44 | b.iter(|| { 45 | // Collect full result to prevent unwanted shortcuts getting 46 | // first element (in case sample_indices returns an iterator). 47 | for (slot, sample) in y.iter_mut().zip(x.choose_multiple(&mut rng, amount)) { 48 | *slot = *sample; 49 | } 50 | y[amount - 1] 51 | }) 52 | }); 53 | } 54 | 55 | let lens = [(1, 1000), (950, 1000), (10, 100), (90, 100)]; 56 | for (amount, len) in lens { 57 | let name = format!("seq_slice_choose_multiple_weighted_{}_of_{}", amount, len); 58 | c.bench_function(name.as_str(), |b| { 59 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 60 | let mut buf = [0i32; 1000]; 61 | rng.fill(&mut buf); 62 | let x = black_box(&buf[..len]); 63 | 64 | let mut results_buf = [0i32; 950]; 65 | let y = black_box(&mut results_buf[..amount]); 66 | let amount = black_box(amount); 67 | 68 | b.iter(|| { 69 | // Collect full result to prevent unwanted shortcuts getting 70 | // first element (in case sample_indices returns an iterator). 71 | let samples_iter = x.choose_multiple_weighted(&mut rng, amount, |_| 1.0).unwrap(); 72 | for (slot, sample) in y.iter_mut().zip(samples_iter) { 73 | *slot = *sample; 74 | } 75 | y[amount - 1] 76 | }) 77 | }); 78 | } 79 | 80 | c.bench_function("seq_iter_choose_multiple_10_of_100", |b| { 81 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 82 | let mut buf = [0i32; 100]; 83 | rng.fill(&mut buf); 84 | let x = black_box(&buf); 85 | b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10)) 86 | }); 87 | 88 | c.bench_function("seq_iter_choose_multiple_fill_10_of_100", |b| { 89 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 90 | let mut buf = [0i32; 100]; 91 | rng.fill(&mut buf); 92 | let x = black_box(&buf); 93 | let mut buf = [0; 10]; 94 | b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf)) 95 | }); 96 | 97 | bench_rng::(c, "ChaCha20"); 98 | bench_rng::(c, "Pcg32"); 99 | bench_rng::(c, "Pcg64"); 100 | } 101 | 102 | fn bench_rng(c: &mut Criterion, rng_name: &'static str) { 103 | for length in [1, 2, 3, 10, 100, 1000].map(black_box) { 104 | let name = format!("choose_size-hinted_from_{length}_{rng_name}"); 105 | c.bench_function(name.as_str(), |b| { 106 | let mut rng = Rng::seed_from_u64(123); 107 | b.iter(|| choose_size_hinted(length, &mut rng)) 108 | }); 109 | 110 | let name = format!("choose_stable_from_{length}_{rng_name}"); 111 | c.bench_function(name.as_str(), |b| { 112 | let mut rng = Rng::seed_from_u64(123); 113 | b.iter(|| choose_stable(length, &mut rng)) 114 | }); 115 | 116 | let name = format!("choose_unhinted_from_{length}_{rng_name}"); 117 | c.bench_function(name.as_str(), |b| { 118 | let mut rng = Rng::seed_from_u64(123); 119 | b.iter(|| choose_unhinted(length, &mut rng)) 120 | }); 121 | 122 | let name = format!("choose_windowed_from_{length}_{rng_name}"); 123 | c.bench_function(name.as_str(), |b| { 124 | let mut rng = Rng::seed_from_u64(123); 125 | b.iter(|| choose_windowed(length, 7, &mut rng)) 126 | }); 127 | } 128 | } 129 | 130 | fn choose_size_hinted(max: usize, rng: &mut R) -> Option { 131 | let iterator = 0..max; 132 | iterator.choose(rng) 133 | } 134 | 135 | fn choose_stable(max: usize, rng: &mut R) -> Option { 136 | let iterator = 0..max; 137 | iterator.choose_stable(rng) 138 | } 139 | 140 | fn choose_unhinted(max: usize, rng: &mut R) -> Option { 141 | let iterator = UnhintedIterator { iter: (0..max) }; 142 | iterator.choose(rng) 143 | } 144 | 145 | fn choose_windowed(max: usize, window_size: usize, rng: &mut R) -> Option { 146 | let iterator = WindowHintedIterator { 147 | iter: (0..max), 148 | window_size, 149 | }; 150 | iterator.choose(rng) 151 | } 152 | 153 | #[derive(Clone)] 154 | struct UnhintedIterator { 155 | iter: I, 156 | } 157 | impl Iterator for UnhintedIterator { 158 | type Item = I::Item; 159 | 160 | fn next(&mut self) -> Option { 161 | self.iter.next() 162 | } 163 | } 164 | 165 | #[derive(Clone)] 166 | struct WindowHintedIterator { 167 | iter: I, 168 | window_size: usize, 169 | } 170 | impl Iterator for WindowHintedIterator { 171 | type Item = I::Item; 172 | 173 | fn next(&mut self) -> Option { 174 | self.iter.next() 175 | } 176 | 177 | fn size_hint(&self) -> (usize, Option) { 178 | (core::cmp::min(self.iter.len(), self.window_size), None) 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /benches/benches/shuffle.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 10 | use rand::prelude::*; 11 | use rand::SeedableRng; 12 | use rand_pcg::Pcg32; 13 | 14 | criterion_group!( 15 | name = benches; 16 | config = Criterion::default(); 17 | targets = bench 18 | ); 19 | criterion_main!(benches); 20 | 21 | pub fn bench(c: &mut Criterion) { 22 | c.bench_function("seq_shuffle_100", |b| { 23 | let mut rng = Pcg32::from_rng(&mut rand::rng()); 24 | let mut buf = [0i32; 100]; 25 | rng.fill(&mut buf); 26 | let x = black_box(&mut buf); 27 | b.iter(|| { 28 | x.shuffle(&mut rng); 29 | x[0] 30 | }) 31 | }); 32 | 33 | bench_rng::(c, "ChaCha12"); 34 | bench_rng::(c, "Pcg32"); 35 | bench_rng::(c, "Pcg64"); 36 | } 37 | 38 | fn bench_rng(c: &mut Criterion, rng_name: &'static str) { 39 | for length in [1, 2, 3, 10, 100, 1000, 10000].map(black_box) { 40 | c.bench_function(format!("shuffle_{length}_{rng_name}").as_str(), |b| { 41 | let mut rng = Rng::seed_from_u64(123); 42 | let mut vec: Vec = (0..length).collect(); 43 | b.iter(|| { 44 | vec.shuffle(&mut rng); 45 | vec[0] 46 | }) 47 | }); 48 | 49 | if length >= 10 { 50 | let name = format!("partial_shuffle_{length}_{rng_name}"); 51 | c.bench_function(name.as_str(), |b| { 52 | let mut rng = Rng::seed_from_u64(123); 53 | let mut vec: Vec = (0..length).collect(); 54 | b.iter(|| { 55 | vec.partial_shuffle(&mut rng, length / 2); 56 | vec[0] 57 | }) 58 | }); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /benches/benches/simd.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Generating SIMD / wide types 10 | 11 | #![cfg_attr(feature = "simd_support", feature(portable_simd))] 12 | 13 | use criterion::{criterion_group, criterion_main, Criterion}; 14 | 15 | criterion_group!( 16 | name = benches; 17 | config = Criterion::default(); 18 | targets = simd 19 | ); 20 | criterion_main!(benches); 21 | 22 | #[cfg(not(feature = "simd_support"))] 23 | pub fn simd(_: &mut Criterion) {} 24 | 25 | #[cfg(feature = "simd_support")] 26 | pub fn simd(c: &mut Criterion) { 27 | use rand::prelude::*; 28 | use rand_pcg::Pcg64Mcg; 29 | 30 | let mut g = c.benchmark_group("random_simd"); 31 | 32 | g.bench_function("u128", |b| { 33 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 34 | b.iter(|| rng.random::()); 35 | }); 36 | 37 | g.bench_function("m128i", |b| { 38 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 39 | b.iter(|| rng.random::()); 40 | }); 41 | 42 | g.bench_function("m256i", |b| { 43 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 44 | b.iter(|| rng.random::()); 45 | }); 46 | 47 | g.bench_function("m512i", |b| { 48 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 49 | b.iter(|| rng.random::()); 50 | }); 51 | 52 | g.bench_function("u64x2", |b| { 53 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 54 | b.iter(|| rng.random::()); 55 | }); 56 | 57 | g.bench_function("u32x4", |b| { 58 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 59 | b.iter(|| rng.random::()); 60 | }); 61 | 62 | g.bench_function("u32x8", |b| { 63 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 64 | b.iter(|| rng.random::()); 65 | }); 66 | 67 | g.bench_function("u16x8", |b| { 68 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 69 | b.iter(|| rng.random::()); 70 | }); 71 | 72 | g.bench_function("u8x16", |b| { 73 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 74 | b.iter(|| rng.random::()); 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /benches/benches/standard.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use core::time::Duration; 10 | use criterion::measurement::WallTime; 11 | use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion}; 12 | use rand::distr::{Alphabetic, Alphanumeric, Open01, OpenClosed01, StandardUniform}; 13 | use rand::prelude::*; 14 | use rand_pcg::Pcg64Mcg; 15 | 16 | criterion_group!( 17 | name = benches; 18 | config = Criterion::default(); 19 | targets = bench 20 | ); 21 | criterion_main!(benches); 22 | 23 | fn bench_ty(g: &mut BenchmarkGroup, name: &str) 24 | where 25 | D: Distribution + Default, 26 | { 27 | g.throughput(criterion::Throughput::Bytes(core::mem::size_of::() as u64)); 28 | g.bench_function(name, |b| { 29 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng()); 30 | 31 | b.iter(|| rng.sample::(D::default())); 32 | }); 33 | } 34 | 35 | pub fn bench(c: &mut Criterion) { 36 | let mut g = c.benchmark_group("StandardUniform"); 37 | g.sample_size(1000); 38 | g.warm_up_time(Duration::from_millis(500)); 39 | g.measurement_time(Duration::from_millis(1000)); 40 | 41 | macro_rules! do_ty { 42 | ($t:ty) => { 43 | bench_ty::<$t, StandardUniform>(&mut g, stringify!($t)); 44 | }; 45 | ($t:ty, $($tt:ty),*) => { 46 | do_ty!($t); 47 | do_ty!($($tt),*); 48 | }; 49 | } 50 | 51 | do_ty!(i8, i16, i32, i64, i128); 52 | do_ty!(f32, f64); 53 | do_ty!(char); 54 | 55 | bench_ty::(&mut g, "Alphabetic"); 56 | bench_ty::(&mut g, "Alphanumeric"); 57 | 58 | bench_ty::(&mut g, "Open01/f32"); 59 | bench_ty::(&mut g, "Open01/f64"); 60 | bench_ty::(&mut g, "OpenClosed01/f32"); 61 | bench_ty::(&mut g, "OpenClosed01/f64"); 62 | 63 | g.finish(); 64 | } 65 | -------------------------------------------------------------------------------- /benches/benches/uniform.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Implement benchmarks for uniform distributions over integer types 10 | 11 | #![cfg_attr(feature = "simd_support", feature(portable_simd))] 12 | 13 | use core::time::Duration; 14 | use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; 15 | use rand::distr::uniform::{SampleRange, Uniform}; 16 | use rand::prelude::*; 17 | use rand_chacha::ChaCha8Rng; 18 | use rand_pcg::{Pcg32, Pcg64}; 19 | #[cfg(feature = "simd_support")] 20 | use std::simd::{num::SimdUint, Simd}; 21 | 22 | const WARM_UP_TIME: Duration = Duration::from_millis(1000); 23 | const MEASUREMENT_TIME: Duration = Duration::from_secs(3); 24 | const SAMPLE_SIZE: usize = 100_000; 25 | const N_RESAMPLES: usize = 10_000; 26 | 27 | macro_rules! sample { 28 | (@range $T:ty, $U:ty, 1, $rng:ident) => {{ 29 | assert_eq!(<$T>::BITS, <$U>::BITS); 30 | let bits = (<$T>::BITS / 2); 31 | let mask = (1 as $U).wrapping_neg() >> bits; 32 | let x = $rng.random::<$U>(); 33 | ((x >> bits) * (x & mask)) as $T 34 | }}; 35 | 36 | (@range $T:ty, $U:ty, $len:tt, $rng:ident) => {{ 37 | let bits = (<$T>::BITS / 2); 38 | let mask = Simd::splat((1 as $U).wrapping_neg() >> bits); 39 | let bits = Simd::splat(bits as $U); 40 | let x = $rng.random::>(); 41 | ((x >> bits) * (x & mask)).cast() 42 | }}; 43 | 44 | (@MIN $T:ty, 1) => { 45 | <$T>::MIN 46 | }; 47 | 48 | (@MIN $T:ty, $len:tt) => { 49 | Simd::<$T, $len>::splat(<$T>::MIN) 50 | }; 51 | 52 | (@wrapping_add $lhs:expr, $rhs:expr, 1) => { 53 | $lhs.wrapping_add($rhs) 54 | }; 55 | 56 | (@wrapping_add $lhs:expr, $rhs:expr, $len:tt) => { 57 | ($lhs + $rhs) 58 | }; 59 | 60 | ($R:ty, $T:ty, $U:ty, $len:tt, $g:expr) => { 61 | $g.bench_function(BenchmarkId::new(stringify!($R), "single"), |b| { 62 | let mut rng = <$R>::from_rng(&mut rand::rng()); 63 | let range = sample!(@range $T, $U, $len, rng); 64 | let low = sample!(@MIN $T, $len); 65 | let high = sample!(@wrapping_add low, range, $len); 66 | 67 | b.iter(|| (low..=high).sample_single(&mut rng)); 68 | }); 69 | 70 | $g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| { 71 | let mut rng = <$R>::from_rng(&mut rand::rng()); 72 | let range = sample!(@range $T, $U, $len, rng); 73 | let low = sample!(@MIN $T, $len); 74 | let high = sample!(@wrapping_add low, range, $len); 75 | let dist = Uniform::new_inclusive(low, high).unwrap(); 76 | 77 | b.iter(|| dist.sample(&mut rng)); 78 | }); 79 | }; 80 | 81 | // Entrypoint: 82 | // $T is the output type (integer) 83 | // $U is the unsigned version of the output type 84 | // $len is the width for SIMD or 1 for non-SIMD 85 | ($c:expr, $T:ty, $U:ty, $len:tt) => {{ 86 | let mut g = $c.benchmark_group(concat!("sample_", stringify!($T), "x", stringify!($len))); 87 | g.sample_size(SAMPLE_SIZE); 88 | g.warm_up_time(WARM_UP_TIME); 89 | g.measurement_time(MEASUREMENT_TIME); 90 | g.nresamples(N_RESAMPLES); 91 | sample!(SmallRng, $T, $U, $len, g); 92 | sample!(ChaCha8Rng, $T, $U, $len, g); 93 | sample!(Pcg32, $T, $U, $len, g); 94 | sample!(Pcg64, $T, $U, $len, g); 95 | g.finish(); 96 | }}; 97 | } 98 | 99 | fn sample(c: &mut Criterion) { 100 | sample!(c, i8, u8, 1); 101 | sample!(c, i16, u16, 1); 102 | sample!(c, i32, u32, 1); 103 | sample!(c, i64, u64, 1); 104 | sample!(c, i128, u128, 1); 105 | #[cfg(feature = "simd_support")] 106 | sample!(c, u8, u8, 8); 107 | #[cfg(feature = "simd_support")] 108 | sample!(c, u8, u8, 16); 109 | #[cfg(feature = "simd_support")] 110 | sample!(c, u8, u8, 32); 111 | #[cfg(feature = "simd_support")] 112 | sample!(c, u8, u8, 64); 113 | #[cfg(feature = "simd_support")] 114 | sample!(c, i16, u16, 8); 115 | #[cfg(feature = "simd_support")] 116 | sample!(c, i16, u16, 16); 117 | #[cfg(feature = "simd_support")] 118 | sample!(c, i16, u16, 32); 119 | } 120 | 121 | criterion_group! { 122 | name = benches; 123 | config = Criterion::default(); 124 | targets = sample 125 | } 126 | criterion_main!(benches); 127 | -------------------------------------------------------------------------------- /benches/benches/uniform_float.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Implement benchmarks for uniform distributions over FP types 10 | //! 11 | //! Sampling methods compared: 12 | //! 13 | //! - sample: current method: (x12 - 1.0) * (b - a) + a 14 | 15 | use core::time::Duration; 16 | use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; 17 | use rand::distr::uniform::{SampleUniform, Uniform, UniformSampler}; 18 | use rand::prelude::*; 19 | use rand_chacha::ChaCha8Rng; 20 | use rand_pcg::{Pcg32, Pcg64}; 21 | 22 | const WARM_UP_TIME: Duration = Duration::from_millis(1000); 23 | const MEASUREMENT_TIME: Duration = Duration::from_secs(3); 24 | const SAMPLE_SIZE: usize = 100_000; 25 | const N_RESAMPLES: usize = 10_000; 26 | 27 | macro_rules! single_random { 28 | ($R:ty, $T:ty, $g:expr) => { 29 | $g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| { 30 | let mut rng = <$R>::from_rng(&mut rand::rng()); 31 | let (mut low, mut high); 32 | loop { 33 | low = <$T>::from_bits(rng.random()); 34 | high = <$T>::from_bits(rng.random()); 35 | if (low < high) && (high - low).is_normal() { 36 | break; 37 | } 38 | } 39 | 40 | b.iter(|| <$T as SampleUniform>::Sampler::sample_single_inclusive(low, high, &mut rng)); 41 | }); 42 | }; 43 | 44 | ($c:expr, $T:ty) => {{ 45 | let mut g = $c.benchmark_group("uniform_single"); 46 | g.sample_size(SAMPLE_SIZE); 47 | g.warm_up_time(WARM_UP_TIME); 48 | g.measurement_time(MEASUREMENT_TIME); 49 | g.nresamples(N_RESAMPLES); 50 | single_random!(SmallRng, $T, g); 51 | single_random!(ChaCha8Rng, $T, g); 52 | single_random!(Pcg32, $T, g); 53 | single_random!(Pcg64, $T, g); 54 | g.finish(); 55 | }}; 56 | } 57 | 58 | fn single_random(c: &mut Criterion) { 59 | single_random!(c, f32); 60 | single_random!(c, f64); 61 | } 62 | 63 | macro_rules! distr_random { 64 | ($R:ty, $T:ty, $g:expr) => { 65 | $g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| { 66 | let mut rng = <$R>::from_rng(&mut rand::rng()); 67 | let dist = loop { 68 | let low = <$T>::from_bits(rng.random()); 69 | let high = <$T>::from_bits(rng.random()); 70 | if let Ok(dist) = Uniform::<$T>::new_inclusive(low, high) { 71 | break dist; 72 | } 73 | }; 74 | 75 | b.iter(|| dist.sample(&mut rng)); 76 | }); 77 | }; 78 | 79 | ($c:expr, $T:ty) => {{ 80 | let mut g = $c.benchmark_group("uniform_distribution"); 81 | g.sample_size(SAMPLE_SIZE); 82 | g.warm_up_time(WARM_UP_TIME); 83 | g.measurement_time(MEASUREMENT_TIME); 84 | g.nresamples(N_RESAMPLES); 85 | distr_random!(SmallRng, $T, g); 86 | distr_random!(ChaCha8Rng, $T, g); 87 | distr_random!(Pcg32, $T, g); 88 | distr_random!(Pcg64, $T, g); 89 | g.finish(); 90 | }}; 91 | } 92 | 93 | fn distr_random(c: &mut Criterion) { 94 | distr_random!(c, f32); 95 | distr_random!(c, f64); 96 | } 97 | 98 | criterion_group! { 99 | name = benches; 100 | config = Criterion::default(); 101 | targets = single_random, distr_random 102 | } 103 | criterion_main!(benches); 104 | -------------------------------------------------------------------------------- /benches/benches/weighted.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 10 | use rand::distr::weighted::WeightedIndex; 11 | use rand::prelude::*; 12 | use rand::seq::index::sample_weighted; 13 | 14 | criterion_group!( 15 | name = benches; 16 | config = Criterion::default(); 17 | targets = bench 18 | ); 19 | criterion_main!(benches); 20 | 21 | pub fn bench(c: &mut Criterion) { 22 | c.bench_function("weighted_index_creation", |b| { 23 | let mut rng = rand::rng(); 24 | let weights = black_box([1u32, 2, 4, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 7]); 25 | b.iter(|| { 26 | let distr = WeightedIndex::new(weights.to_vec()).unwrap(); 27 | rng.sample(distr) 28 | }) 29 | }); 30 | 31 | c.bench_function("weighted_index_modification", |b| { 32 | let mut rng = rand::rng(); 33 | let weights = black_box([1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]); 34 | let mut distr = WeightedIndex::new(weights.to_vec()).unwrap(); 35 | b.iter(|| { 36 | distr.update_weights(&[(2, &4), (5, &1)]).unwrap(); 37 | rng.sample(&distr) 38 | }) 39 | }); 40 | 41 | let lens = [ 42 | (1, 1000, "1k"), 43 | (10, 1000, "1k"), 44 | (100, 1000, "1k"), 45 | (100, 1_000_000, "1M"), 46 | (200, 1_000_000, "1M"), 47 | (400, 1_000_000, "1M"), 48 | (600, 1_000_000, "1M"), 49 | (1000, 1_000_000, "1M"), 50 | ]; 51 | for (amount, length, len_name) in lens { 52 | let name = format!("weighted_sample_indices_{}_of_{}", amount, len_name); 53 | c.bench_function(name.as_str(), |b| { 54 | let length = black_box(length); 55 | let amount = black_box(amount); 56 | let mut rng = SmallRng::from_rng(&mut rand::rng()); 57 | b.iter(|| sample_weighted(&mut rng, length, |idx| (1 + (idx % 100)) as u32, amount)) 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /benches/rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 120 2 | fn_call_width = 108 3 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | # Don't warn about these identifiers when using clippy::doc_markdown. 2 | doc-valid-idents = ["ChaCha", "ChaCha12", "SplitMix64", "ZiB", ".."] 3 | -------------------------------------------------------------------------------- /examples/monte-carlo.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // Copyright 2013-2018 The Rust Project Developers. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | //! # Monte Carlo estimation of π 11 | //! 12 | //! Imagine that we have a square with sides of length 2 and a unit circle 13 | //! (radius = 1), both centered at the origin. The areas are: 14 | //! 15 | //! ```text 16 | //! area of circle = πr² = π * r * r = π 17 | //! area of square = 2² = 4 18 | //! ``` 19 | //! 20 | //! The circle is entirely within the square, so if we sample many points 21 | //! randomly from the square, roughly π / 4 of them should be inside the circle. 22 | //! 23 | //! We can use the above fact to estimate the value of π: pick many points in 24 | //! the square at random, calculate the fraction that fall within the circle, 25 | //! and multiply this fraction by 4. 26 | use rand::distr::{Distribution, Uniform}; 27 | 28 | fn main() { 29 | let range = Uniform::new(-1.0f64, 1.0).unwrap(); 30 | let mut rng = rand::rng(); 31 | 32 | let total = 1_000_000; 33 | let mut in_circle = 0; 34 | 35 | for _ in 0..total { 36 | let a = range.sample(&mut rng); 37 | let b = range.sample(&mut rng); 38 | if a * a + b * b <= 1.0 { 39 | in_circle += 1; 40 | } 41 | } 42 | 43 | // prints something close to 3.14159... 44 | println!( 45 | "π is approximately {}", 46 | 4. * (in_circle as f64) / (total as f64) 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /examples/monty-hall.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // Copyright 2013-2018 The Rust Project Developers. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | //! ## Monty Hall Problem 11 | //! 12 | //! This is a simulation of the [Monty Hall Problem][]: 13 | //! 14 | //! > Suppose you're on a game show, and you're given the choice of three doors: 15 | //! > Behind one door is a car; behind the others, goats. You pick a door, say 16 | //! > No. 1, and the host, who knows what's behind the doors, opens another 17 | //! > door, say No. 3, which has a goat. He then says to you, "Do you want to 18 | //! > pick door No. 2?" Is it to your advantage to switch your choice? 19 | //! 20 | //! The rather unintuitive answer is that you will have a 2/3 chance of winning 21 | //! if you switch and a 1/3 chance of winning if you don't, so it's better to 22 | //! switch. 23 | //! 24 | //! This program will simulate the game show and with large enough simulation 25 | //! steps it will indeed confirm that it is better to switch. 26 | //! 27 | //! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem 28 | 29 | use rand::distr::{Distribution, Uniform}; 30 | use rand::Rng; 31 | 32 | struct SimulationResult { 33 | win: bool, 34 | switch: bool, 35 | } 36 | 37 | // Run a single simulation of the Monty Hall problem. 38 | fn simulate(random_door: &Uniform, rng: &mut R) -> SimulationResult { 39 | let car = random_door.sample(rng); 40 | 41 | // This is our initial choice 42 | let mut choice = random_door.sample(rng); 43 | 44 | // The game host opens a door 45 | let open = game_host_open(car, choice, rng); 46 | 47 | // Shall we switch? 48 | let switch = rng.random(); 49 | if switch { 50 | choice = switch_door(choice, open); 51 | } 52 | 53 | SimulationResult { 54 | win: choice == car, 55 | switch, 56 | } 57 | } 58 | 59 | // Returns the door the game host opens given our choice and knowledge of 60 | // where the car is. The game host will never open the door with the car. 61 | fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 { 62 | use rand::seq::IndexedRandom; 63 | *free_doors(&[car, choice]).choose(rng).unwrap() 64 | } 65 | 66 | // Returns the door we switch to, given our current choice and 67 | // the open door. There will only be one valid door. 68 | fn switch_door(choice: u32, open: u32) -> u32 { 69 | free_doors(&[choice, open])[0] 70 | } 71 | 72 | fn free_doors(blocked: &[u32]) -> Vec { 73 | (0..3).filter(|x| !blocked.contains(x)).collect() 74 | } 75 | 76 | fn main() { 77 | // The estimation will be more accurate with more simulations 78 | let num_simulations = 10000; 79 | 80 | let mut rng = rand::rng(); 81 | let random_door = Uniform::new(0u32, 3).unwrap(); 82 | 83 | let (mut switch_wins, mut switch_losses) = (0, 0); 84 | let (mut keep_wins, mut keep_losses) = (0, 0); 85 | 86 | println!("Running {} simulations...", num_simulations); 87 | for _ in 0..num_simulations { 88 | let result = simulate(&random_door, &mut rng); 89 | 90 | match (result.win, result.switch) { 91 | (true, true) => switch_wins += 1, 92 | (true, false) => keep_wins += 1, 93 | (false, true) => switch_losses += 1, 94 | (false, false) => keep_losses += 1, 95 | } 96 | } 97 | 98 | let total_switches = switch_wins + switch_losses; 99 | let total_keeps = keep_wins + keep_losses; 100 | 101 | println!( 102 | "Switched door {} times with {} wins and {} losses", 103 | total_switches, switch_wins, switch_losses 104 | ); 105 | 106 | println!( 107 | "Kept our choice {} times with {} wins and {} losses", 108 | total_keeps, keep_wins, keep_losses 109 | ); 110 | 111 | // With a large number of simulations, the values should converge to 112 | // 0.667 and 0.333 respectively. 113 | println!( 114 | "Estimated chance to win if we switch: {}", 115 | switch_wins as f32 / total_switches as f32 116 | ); 117 | println!( 118 | "Estimated chance to win if we don't: {}", 119 | keep_wins as f32 / total_keeps as f32 120 | ); 121 | } 122 | -------------------------------------------------------------------------------- /examples/rayon-monte-carlo.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // Copyright 2013-2018 The Rust Project Developers. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | //! # Monte Carlo estimation of π with a chosen seed and rayon for parallelism 11 | //! 12 | //! Imagine that we have a square with sides of length 2 and a unit circle 13 | //! (radius = 1), both centered at the origin. The areas are: 14 | //! 15 | //! ```text 16 | //! area of circle = πr² = π * r * r = π 17 | //! area of square = 2² = 4 18 | //! ``` 19 | //! 20 | //! The circle is entirely within the square, so if we sample many points 21 | //! randomly from the square, roughly π / 4 of them should be inside the circle. 22 | //! 23 | //! We can use the above fact to estimate the value of π: pick many points in 24 | //! the square at random, calculate the fraction that fall within the circle, 25 | //! and multiply this fraction by 4. 26 | //! 27 | //! Note on determinism: 28 | //! It's slightly tricky to build a parallel simulation using Rayon 29 | //! which is both efficient *and* reproducible. 30 | //! 31 | //! Rayon's ParallelIterator api does not guarantee that the work will be 32 | //! batched into identical batches on every run, so we can't simply use 33 | //! map_init to construct one RNG per Rayon batch. 34 | //! 35 | //! Instead, we do our own batching, so that a Rayon work item becomes a 36 | //! batch. Then we can fix our rng stream to the batched work item. 37 | //! Batching amortizes the cost of constructing the Rng from a fixed seed 38 | //! over BATCH_SIZE trials. Manually batching also turns out to be faster 39 | //! for the nondeterministic version of this program as well. 40 | 41 | use rand::distr::{Distribution, Uniform}; 42 | use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; 43 | use rayon::prelude::*; 44 | 45 | static SEED: u64 = 0; 46 | static BATCH_SIZE: u64 = 10_000; 47 | static BATCHES: u64 = 1000; 48 | 49 | fn main() { 50 | let range = Uniform::new(-1.0f64, 1.0).unwrap(); 51 | 52 | let in_circle = (0..BATCHES) 53 | .into_par_iter() 54 | .map(|i| { 55 | let mut rng = ChaCha8Rng::seed_from_u64(SEED); 56 | // We chose ChaCha because it's fast, has suitable statistical properties for simulation, 57 | // and because it supports this set_stream() api, which lets us choose a different stream 58 | // per work item. ChaCha supports 2^64 independent streams. 59 | rng.set_stream(i); 60 | let mut count = 0; 61 | for _ in 0..BATCH_SIZE { 62 | let a = range.sample(&mut rng); 63 | let b = range.sample(&mut rng); 64 | if a * a + b * b <= 1.0 { 65 | count += 1; 66 | } 67 | } 68 | count 69 | }) 70 | .sum::(); 71 | 72 | // assert this is deterministic 73 | assert_eq!(in_circle, 7852263); 74 | 75 | // prints something close to 3.14159... 76 | println!( 77 | "π is approximately {}", 78 | 4. * (in_circle as f64) / ((BATCH_SIZE * BATCHES) as f64) 79 | ); 80 | } 81 | -------------------------------------------------------------------------------- /rand_chacha/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.9.0] - 2025-01-27 8 | ### Dependencies and features 9 | - Update to `rand_core` v0.9.0 (#1558) 10 | - Feature `std` now implies feature `rand_core/std` (#1153) 11 | - Rename feature `serde1` to `serde` (#1477) 12 | - Rename feature `getrandom` to `os_rng` (#1537) 13 | 14 | ### Other changes 15 | - Remove usage of `unsafe` in `fn generate` (#1181) then optimise for AVX2 (~4-7%) (#1192) 16 | - Revise crate docs (#1454) 17 | 18 | ## [0.3.1] - 2021-06-09 19 | - add getters corresponding to existing setters: `get_seed`, `get_stream` (#1124) 20 | - add serde support, gated by the `serde1` feature (#1124) 21 | - ensure expected layout via `repr(transparent)` (#1120) 22 | 23 | ## [0.3.0] - 2020-12-08 24 | - Bump `rand_core` version to 0.6.0 25 | - Bump MSRV to 1.36 (#1011) 26 | - Remove usage of deprecated feature "simd" of `ppv-lite86` (#979), then revert 27 | this change (#1023) since SIMD is only enabled by default from `ppv-lite86 v0.2.10` 28 | - impl PartialEq+Eq for ChaChaXRng and ChaChaXCore (#979) 29 | - Fix panic on block counter wrap that was occurring in debug builds (#980) 30 | 31 | ## [0.2.2] - 2020-03-09 32 | - Integrate `c2-chacha`, reducing dependency count (#931) 33 | - Add CryptoRng to ChaChaXCore (#944) 34 | 35 | ## [0.2.1] - 2019-07-22 36 | - Force enable the `simd` feature of `c2-chacha` (#845) 37 | 38 | ## [0.2.0] - 2019-06-06 39 | - Rewrite based on the much faster `c2-chacha` crate (#789) 40 | 41 | ## [0.1.1] - 2019-01-04 42 | - Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation) 43 | - Update readme and doc links 44 | 45 | ## [0.1.0] - 2018-10-17 46 | - Pulled out of the Rand crate 47 | -------------------------------------------------------------------------------- /rand_chacha/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the Rand project are retained by their contributors. No 2 | copyright assignment is required to contribute to the Rand project. 3 | 4 | For full authorship information, see the version control history. 5 | 6 | Except as otherwise noted (below and/or in individual files), Rand is 7 | licensed under the Apache License, Version 2.0 or 8 | or the MIT license 9 | or , at your option. 10 | 11 | The Rand project includes code from the Rust project 12 | published under these same licenses. 13 | -------------------------------------------------------------------------------- /rand_chacha/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rand_chacha" 3 | version = "0.9.0" 4 | authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "README.md" 7 | repository = "https://github.com/rust-random/rand" 8 | documentation = "https://docs.rs/rand_chacha" 9 | homepage = "https://rust-random.github.io/book" 10 | description = """ 11 | ChaCha random number generator 12 | """ 13 | keywords = ["random", "rng", "chacha"] 14 | categories = ["algorithms", "no-std"] 15 | edition = "2021" 16 | rust-version = "1.63" 17 | 18 | [package.metadata.docs.rs] 19 | all-features = true 20 | rustdoc-args = ["--generate-link-to-definition"] 21 | 22 | [dependencies] 23 | rand_core = { path = "../rand_core", version = "0.9.0" } 24 | ppv-lite86 = { version = "0.2.14", default-features = false, features = ["simd"] } 25 | serde = { version = "1.0", features = ["derive"], optional = true } 26 | 27 | [dev-dependencies] 28 | # Only to test serde 29 | serde_json = "1.0.120" 30 | rand_core = { path = "../rand_core", version = "0.9.0", features = ["os_rng"] } 31 | 32 | [features] 33 | default = ["std"] 34 | os_rng = ["rand_core/os_rng"] 35 | std = ["ppv-lite86/std", "rand_core/std"] 36 | serde = ["dep:serde"] 37 | -------------------------------------------------------------------------------- /rand_chacha/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2018 Developers of the Rand project 2 | Copyright (c) 2014 The Rust Project Developers 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /rand_chacha/README.md: -------------------------------------------------------------------------------- 1 | # rand_chacha 2 | 3 | [![Test Status](https://github.com/rust-random/rand/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-random/rand/actions) 4 | [![Latest version](https://img.shields.io/crates/v/rand_chacha.svg)](https://crates.io/crates/rand_chacha) 5 | [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) 6 | [![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_chacha) 7 | [![API](https://docs.rs/rand_chacha/badge.svg)](https://docs.rs/rand_chacha) 8 | 9 | A cryptographically secure random number generator that uses the ChaCha 10 | algorithm. 11 | 12 | ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use 13 | as an RNG. It is an improved variant of the Salsa20 cipher family, which was 14 | selected as one of the "stream ciphers suitable for widespread adoption" by 15 | eSTREAM[^2]. 16 | 17 | The RNGs provided by this crate are implemented via the fast stream ciphers of 18 | the [`c2-chacha`](https://crates.io/crates/c2-chacha) crate. 19 | 20 | Links: 21 | 22 | - [API documentation (master)](https://rust-random.github.io/rand/rand_chacha) 23 | - [API documentation (docs.rs)](https://docs.rs/rand_chacha) 24 | - [Changelog](https://github.com/rust-random/rand/blob/master/rand_chacha/CHANGELOG.md) 25 | 26 | [rand]: https://crates.io/crates/rand 27 | [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( 28 | https://cr.yp.to/chacha.html) 29 | 30 | [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( 31 | http://www.ecrypt.eu.org/stream/) 32 | 33 | 34 | ## Crate Features 35 | 36 | `rand_chacha` is `no_std` compatible when disabling default features; the `std` 37 | feature can be explicitly required to re-enable `std` support. Using `std` 38 | allows detection of CPU features and thus better optimisation. Using `std` 39 | also enables `os_rng` functionality, such as `ChaCha20Rng::from_os_rng()`. 40 | 41 | 42 | # License 43 | 44 | `rand_chacha` is distributed under the terms of both the MIT license and the 45 | Apache License (Version 2.0). 46 | 47 | See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and 48 | [COPYRIGHT](COPYRIGHT) for details. 49 | -------------------------------------------------------------------------------- /rand_chacha/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! The ChaCha random number generators. 10 | //! 11 | //! These are native Rust implementations of RNGs derived from the 12 | //! [ChaCha stream ciphers] by D J Bernstein. 13 | //! 14 | //! ## Generators 15 | //! 16 | //! This crate provides 8-, 12- and 20-round variants of generators via a "core" 17 | //! implementation (of [`BlockRngCore`]), each with an associated "RNG" type 18 | //! (implementing [`RngCore`]). 19 | //! 20 | //! These generators are all deterministic and portable (see [Reproducibility] 21 | //! in the book), with testing against reference vectors. 22 | //! 23 | //! ## Cryptographic (secure) usage 24 | //! 25 | //! Where secure unpredictable generators are required, it is suggested to use 26 | //! [`ChaCha12Rng`] or [`ChaCha20Rng`] and to seed via 27 | //! [`SeedableRng::from_os_rng`]. 28 | //! 29 | //! See also the [Security] chapter in the rand book. The crate is provided 30 | //! "as is", without any form of guarantee, and without a security audit. 31 | //! 32 | //! ## Seeding (construction) 33 | //! 34 | //! Generators implement the [`SeedableRng`] trait. Any method may be used, 35 | //! but note that `seed_from_u64` is not suitable for usage where security is 36 | //! important. Some suggestions: 37 | //! 38 | //! 1. With a fresh seed, **direct from the OS** (implies a syscall): 39 | //! ``` 40 | //! # use {rand_core::SeedableRng, rand_chacha::ChaCha12Rng}; 41 | //! let rng = ChaCha12Rng::from_os_rng(); 42 | //! # let _: ChaCha12Rng = rng; 43 | //! ``` 44 | //! 2. **From a master generator.** This could be [`rand::rng`] 45 | //! (effectively a fresh seed without the need for a syscall on each usage) 46 | //! or a deterministic generator such as [`ChaCha20Rng`]. 47 | //! Beware that should a weak master generator be used, correlations may be 48 | //! detectable between the outputs of its child generators. 49 | //! ```ignore 50 | //! let rng = ChaCha12Rng::from_rng(&mut rand::rng()); 51 | //! ``` 52 | //! 53 | //! See also [Seeding RNGs] in the book. 54 | //! 55 | //! ## Generation 56 | //! 57 | //! Generators implement [`RngCore`], whose methods may be used directly to 58 | //! generate unbounded integer or byte values. 59 | //! ``` 60 | //! use rand_core::{SeedableRng, RngCore}; 61 | //! use rand_chacha::ChaCha12Rng; 62 | //! 63 | //! let mut rng = ChaCha12Rng::from_seed(Default::default()); 64 | //! let x = rng.next_u64(); 65 | //! assert_eq!(x, 0x53f955076a9af49b); 66 | //! ``` 67 | //! 68 | //! It is often more convenient to use the [`rand::Rng`] trait, which provides 69 | //! further functionality. See also the [Random Values] chapter in the book. 70 | //! 71 | //! [ChaCha stream ciphers]: https://cr.yp.to/chacha.html 72 | //! [Reproducibility]: https://rust-random.github.io/book/crate-reprod.html 73 | //! [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html 74 | //! [Security]: https://rust-random.github.io/book/guide-rngs.html#security 75 | //! [Random Values]: https://rust-random.github.io/book/guide-values.html 76 | //! [`BlockRngCore`]: rand_core::block::BlockRngCore 77 | //! [`RngCore`]: rand_core::RngCore 78 | //! [`SeedableRng`]: rand_core::SeedableRng 79 | //! [`SeedableRng::from_os_rng`]: rand_core::SeedableRng::from_os_rng 80 | //! [`rand::rng`]: https://docs.rs/rand/latest/rand/fn.rng.html 81 | //! [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html 82 | 83 | #![doc( 84 | html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", 85 | html_favicon_url = "https://www.rust-lang.org/favicon.ico", 86 | html_root_url = "https://rust-random.github.io/rand/" 87 | )] 88 | #![forbid(unsafe_code)] 89 | #![deny(missing_docs)] 90 | #![deny(missing_debug_implementations)] 91 | #![doc(test(attr(allow(unused_variables), deny(warnings))))] 92 | #![cfg_attr(not(feature = "std"), no_std)] 93 | 94 | pub use rand_core; 95 | 96 | mod chacha; 97 | mod guts; 98 | 99 | pub use crate::chacha::{ 100 | ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Core, ChaCha8Rng, 101 | }; 102 | 103 | /// ChaCha with 20 rounds 104 | pub type ChaChaRng = ChaCha20Rng; 105 | /// ChaCha with 20 rounds, low-level interface 106 | pub type ChaChaCore = ChaCha20Core; 107 | -------------------------------------------------------------------------------- /rand_core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.9.3] — 2025-02-29 8 | ### Other 9 | - Remove `zerocopy` dependency (#1607) 10 | - Deprecate `rand_core::impls::fill_via_u32_chunks`, `fill_via_u64_chunks` (#1607) 11 | 12 | ## [0.9.2] - 2025-02-22 13 | ### API changes 14 | - Relax `Sized` bound on impls of `TryRngCore`, `TryCryptoRng` and `UnwrapMut` (#1593) 15 | - Add `UnwrapMut::re` to reborrow the inner rng with a tighter lifetime (#1595) 16 | 17 | ## [0.9.1] - 2025-02-16 18 | ### API changes 19 | - Add `TryRngCore::unwrap_mut`, providing an impl of `RngCore` over `&mut rng` (#1589) 20 | 21 | ## [0.9.0] - 2025-01-27 22 | ### Dependencies and features 23 | - Bump the MSRV to 1.63.0 (#1207, #1246, #1269, #1341, #1416, #1536); note that 1.60.0 may work for dependents when using `--ignore-rust-version` 24 | - Update to `getrandom` v0.3.0 (#1558) 25 | - Use `zerocopy` to replace some `unsafe` code (#1349, #1393, #1446, #1502) 26 | - Rename feature `serde1` to `serde` (#1477) 27 | - Rename feature `getrandom` to `os_rng` (#1537) 28 | 29 | ### API changes 30 | - Allow `rand_core::impls::fill_via_u*_chunks` to mutate source (#1182) 31 | - Add fn `RngCore::read_adapter` implementing `std::io::Read` (#1267) 32 | - Add trait `CryptoBlockRng: BlockRngCore`; make `trait CryptoRng: RngCore` replacing `CryptoRngCore` (#1273) 33 | - Add traits `TryRngCore`, `TryCryptoRng` (#1424, #1499) 34 | - Rename `fn SeedableRng::from_rng` -> `try_from_rng` and add infallible variant `fn from_rng` (#1424) 35 | - Rename `fn SeedableRng::from_entropy` -> `from_os_rng` and add fallible variant `fn try_from_os_rng` (#1424) 36 | - Add bounds `Clone` and `AsRef` to associated type `SeedableRng::Seed` (#1491) 37 | 38 | ## [0.6.4] - 2022-09-15 39 | - Fix unsoundness in `::next_u32` (#1160) 40 | - Reduce use of `unsafe` and improve gen_bytes performance (#1180) 41 | - Add `CryptoRngCore` trait (#1187, #1230) 42 | 43 | ## [0.6.3] - 2021-06-15 44 | ### Changed 45 | - Improved bound for `serde` impls on `BlockRng` (#1130) 46 | - Minor doc additions (#1118) 47 | 48 | ## [0.6.2] - 2021-02-12 49 | ### Fixed 50 | - Fixed assertions in `le::read_u32_into` and `le::read_u64_into` which could 51 | have allowed buffers not to be fully populated (#1096) 52 | 53 | ## [0.6.1] - 2021-01-03 54 | ### Fixed 55 | - Avoid panic when using `RngCore::seed_from_u64` with a seed which is not a 56 | multiple of four (#1082) 57 | ### Other 58 | - Enable all stable features in the playground (#1081) 59 | 60 | ## [0.6.0] - 2020-12-08 61 | ### Breaking changes 62 | - Bump MSRV to 1.36, various code improvements (#1011) 63 | - Update to getrandom v0.2 (#1041) 64 | - Fix: `next_u32_via_fill` and `next_u64_via_fill` now use LE as documented (#1061) 65 | 66 | ### Other 67 | - Reduce usage of `unsafe` (#962, #963, #1011) 68 | - Annotate feature-gates in documentation (#1019) 69 | - Document available error codes (#1061) 70 | - Various documentation tweaks 71 | - Fix some clippy warnings (#1036) 72 | - Apply rustfmt (#926) 73 | 74 | ## [0.5.1] - 2019-08-28 75 | - `OsRng` added to `rand_core` (#863) 76 | - `Error::INTERNAL_START` and `Error::CUSTOM_START` constants (#864) 77 | - `Error::raw_os_error` method (#864) 78 | - `Debug` and `Display` formatting for `getrandom` error codes without `std` (#864) 79 | ### Changed 80 | - `alloc` feature in `no_std` is available since Rust 1.36 (#856) 81 | - Added `#[inline]` to `Error` conversion methods (#864) 82 | 83 | ## [0.5.0] - 2019-06-06 84 | ### Changed 85 | - Enable testing with Miri and fix incorrect pointer usages (#779, #780, #781, #783, #784) 86 | - Rewrite `Error` type and adjust API (#800) 87 | - Adjust usage of `#[inline]` for `BlockRng` and `BlockRng64` 88 | 89 | ## [0.4.0] - 2019-01-24 90 | ### Changed 91 | - Disable the `std` feature by default (#702) 92 | 93 | ## [0.3.0] - 2018-09-24 94 | ### Added 95 | - Add `SeedableRng::seed_from_u64` for convenient seeding. (#537) 96 | 97 | ## [0.2.1] - 2018-06-08 98 | ### Added 99 | - References to a `CryptoRng` now also implement `CryptoRng`. (#470) 100 | 101 | ## [0.2.0] - 2018-05-21 102 | ### Changed 103 | - Enable the `std` feature by default. (#409) 104 | - Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public 105 | - Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419) 106 | ### Added 107 | - Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419) 108 | - Implement `std::io::Read` for RngCore. (#434) 109 | 110 | ## [0.1.0] - 2018-04-17 111 | (Split out of the Rand crate, changes here are relative to rand 0.4.2.) 112 | ### Added 113 | - `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) 114 | - Add modules to help implementing RNGs `impl` and `le`. (#209, #228) 115 | - Add `Error` and `ErrorKind`. (#225) 116 | - Add `CryptoRng` marker trait. (#273) 117 | - Add `BlockRngCore` trait. (#281) 118 | - Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) 119 | - Add `RngCore::try_fill_bytes`. (#225) 120 | ### Changed 121 | - Revise the `SeedableRng` trait. (#233) 122 | - Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) 123 | 124 | ## [0.0.1] - 2017-09-14 (yanked) 125 | Experimental version as part of the rand crate refactor. 126 | -------------------------------------------------------------------------------- /rand_core/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the Rand project are retained by their contributors. No 2 | copyright assignment is required to contribute to the Rand project. 3 | 4 | For full authorship information, see the version control history. 5 | 6 | Except as otherwise noted (below and/or in individual files), Rand is 7 | licensed under the Apache License, Version 2.0 or 8 | or the MIT license 9 | or , at your option. 10 | 11 | The Rand project includes code from the Rust project 12 | published under these same licenses. 13 | -------------------------------------------------------------------------------- /rand_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rand_core" 3 | version = "0.9.3" 4 | authors = ["The Rand Project Developers", "The Rust Project Developers"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "README.md" 7 | repository = "https://github.com/rust-random/rand" 8 | documentation = "https://docs.rs/rand_core" 9 | homepage = "https://rust-random.github.io/book" 10 | description = """ 11 | Core random number generator traits and tools for implementation. 12 | """ 13 | keywords = ["random", "rng"] 14 | categories = ["algorithms", "no-std"] 15 | edition = "2021" 16 | rust-version = "1.63" 17 | 18 | [package.metadata.docs.rs] 19 | # To build locally: 20 | # RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --open 21 | all-features = true 22 | rustdoc-args = ["--generate-link-to-definition"] 23 | 24 | [package.metadata.playground] 25 | all-features = true 26 | 27 | [features] 28 | std = ["getrandom?/std"] 29 | os_rng = ["dep:getrandom"] 30 | serde = ["dep:serde"] # enables serde for BlockRng wrapper 31 | 32 | [dependencies] 33 | serde = { version = "1", features = ["derive"], optional = true } 34 | getrandom = { version = "0.3.0", optional = true } 35 | -------------------------------------------------------------------------------- /rand_core/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2018 Developers of the Rand project 2 | Copyright (c) 2014 The Rust Project Developers 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /rand_core/README.md: -------------------------------------------------------------------------------- 1 | # rand_core 2 | 3 | [![Test Status](https://github.com/rust-random/rand/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-random/rand/actions) 4 | [![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core) 5 | [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) 6 | [![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core) 7 | [![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core) 8 | 9 | Core traits and error types of the [rand] library, plus tools for implementing 10 | RNGs. 11 | 12 | This crate is intended for use when implementing the core trait, `RngCore`; it 13 | defines the core traits to be implemented as well as several small functions to 14 | aid in their implementation and types required for error handling. 15 | 16 | The main [rand] crate re-exports most items defined in this crate, along with 17 | tools to convert the integer samples generated by `RngCore` to many different 18 | applications (including sampling from restricted ranges, conversion to floating 19 | point, list permutations and secure initialisation of RNGs). Most users should 20 | prefer to use the main [rand] crate. 21 | 22 | Links: 23 | 24 | - [API documentation (master)](https://rust-random.github.io/rand/rand_core) 25 | - [API documentation (docs.rs)](https://docs.rs/rand_core) 26 | - [Changelog](https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md) 27 | 28 | [rand]: https://crates.io/crates/rand 29 | 30 | 31 | ## Functionality 32 | 33 | The `rand_core` crate provides: 34 | 35 | - base random number generator traits 36 | - error-reporting types 37 | - functionality to aid implementation of RNGs 38 | 39 | The traits and error types are also available via `rand`. 40 | 41 | ## Versions 42 | 43 | The current version is: 44 | 45 | ```toml 46 | rand_core = "0.9.3" 47 | ``` 48 | 49 | 50 | # License 51 | 52 | `rand_core` is distributed under the terms of both the MIT license and the 53 | Apache License (Version 2.0). 54 | 55 | See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and 56 | [COPYRIGHT](COPYRIGHT) for details. 57 | -------------------------------------------------------------------------------- /rand_core/src/impls.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Helper functions for implementing `RngCore` functions. 10 | //! 11 | //! For cross-platform reproducibility, these functions all use Little Endian: 12 | //! least-significant part first. For example, `next_u64_via_u32` takes `u32` 13 | //! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32` 14 | //! from `next_u64` in little-endian order, one should use `next_u64() as u32`. 15 | //! 16 | //! Byte-swapping (like the std `to_le` functions) is only needed to convert 17 | //! to/from byte sequences, and since its purpose is reproducibility, 18 | //! non-reproducible sources (e.g. `OsRng`) need not bother with it. 19 | 20 | use crate::RngCore; 21 | 22 | /// Implement `next_u64` via `next_u32`, little-endian order. 23 | pub fn next_u64_via_u32(rng: &mut R) -> u64 { 24 | // Use LE; we explicitly generate one value before the next. 25 | let x = u64::from(rng.next_u32()); 26 | let y = u64::from(rng.next_u32()); 27 | (y << 32) | x 28 | } 29 | 30 | /// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order. 31 | /// 32 | /// The fastest way to fill a slice is usually to work as long as possible with 33 | /// integers. That is why this method mostly uses `next_u64`, and only when 34 | /// there are 4 or less bytes remaining at the end of the slice it uses 35 | /// `next_u32` once. 36 | pub fn fill_bytes_via_next(rng: &mut R, dest: &mut [u8]) { 37 | let mut left = dest; 38 | while left.len() >= 8 { 39 | let (l, r) = { left }.split_at_mut(8); 40 | left = r; 41 | let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); 42 | l.copy_from_slice(&chunk); 43 | } 44 | let n = left.len(); 45 | if n > 4 { 46 | let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); 47 | left.copy_from_slice(&chunk[..n]); 48 | } else if n > 0 { 49 | let chunk: [u8; 4] = rng.next_u32().to_le_bytes(); 50 | left.copy_from_slice(&chunk[..n]); 51 | } 52 | } 53 | 54 | pub(crate) trait Observable: Copy { 55 | type Bytes: Sized + AsRef<[u8]>; 56 | fn to_le_bytes(self) -> Self::Bytes; 57 | } 58 | impl Observable for u32 { 59 | type Bytes = [u8; 4]; 60 | 61 | fn to_le_bytes(self) -> Self::Bytes { 62 | Self::to_le_bytes(self) 63 | } 64 | } 65 | impl Observable for u64 { 66 | type Bytes = [u8; 8]; 67 | 68 | fn to_le_bytes(self) -> Self::Bytes { 69 | Self::to_le_bytes(self) 70 | } 71 | } 72 | 73 | /// Fill dest from src 74 | /// 75 | /// Returns `(n, byte_len)`. `src[..n]` is consumed, 76 | /// `dest[..byte_len]` is filled. `src[n..]` and `dest[byte_len..]` are left 77 | /// unaltered. 78 | pub(crate) fn fill_via_chunks(src: &[T], dest: &mut [u8]) -> (usize, usize) { 79 | let size = core::mem::size_of::(); 80 | 81 | // Always use little endian for portability of results. 82 | 83 | let mut dest = dest.chunks_exact_mut(size); 84 | let mut src = src.iter(); 85 | 86 | let zipped = dest.by_ref().zip(src.by_ref()); 87 | let num_chunks = zipped.len(); 88 | zipped.for_each(|(dest, src)| dest.copy_from_slice(src.to_le_bytes().as_ref())); 89 | 90 | let byte_len = num_chunks * size; 91 | if let Some(src) = src.next() { 92 | // We have consumed all full chunks of dest, but not src. 93 | let dest = dest.into_remainder(); 94 | let n = dest.len(); 95 | if n > 0 { 96 | dest.copy_from_slice(&src.to_le_bytes().as_ref()[..n]); 97 | return (num_chunks + 1, byte_len + n); 98 | } 99 | } 100 | (num_chunks, byte_len) 101 | } 102 | 103 | /// Implement `fill_bytes` by reading chunks from the output buffer of a block 104 | /// based RNG. 105 | /// 106 | /// The return values are `(consumed_u32, filled_u8)`. 107 | /// 108 | /// `src` is not modified; it is taken as a `&mut` reference for backward 109 | /// compatibility with previous versions that did change it. 110 | /// 111 | /// `filled_u8` is the number of filled bytes in `dest`, which may be less than 112 | /// the length of `dest`. 113 | /// `consumed_u32` is the number of words consumed from `src`, which is the same 114 | /// as `filled_u8 / 4` rounded up. 115 | /// 116 | /// # Example 117 | /// (from `IsaacRng`) 118 | /// 119 | /// ```ignore 120 | /// fn fill_bytes(&mut self, dest: &mut [u8]) { 121 | /// let mut read_len = 0; 122 | /// while read_len < dest.len() { 123 | /// if self.index >= self.rsl.len() { 124 | /// self.isaac(); 125 | /// } 126 | /// 127 | /// let (consumed_u32, filled_u8) = 128 | /// impls::fill_via_u32_chunks(&mut self.rsl[self.index..], 129 | /// &mut dest[read_len..]); 130 | /// 131 | /// self.index += consumed_u32; 132 | /// read_len += filled_u8; 133 | /// } 134 | /// } 135 | /// ``` 136 | #[deprecated(since = "0.9.3", note = "use BlockRng instead")] 137 | pub fn fill_via_u32_chunks(src: &mut [u32], dest: &mut [u8]) -> (usize, usize) { 138 | fill_via_chunks(src, dest) 139 | } 140 | 141 | /// Implement `fill_bytes` by reading chunks from the output buffer of a block 142 | /// based RNG. 143 | /// 144 | /// The return values are `(consumed_u64, filled_u8)`. 145 | /// 146 | /// `src` is not modified; it is taken as a `&mut` reference for backward 147 | /// compatibility with previous versions that did change it. 148 | /// 149 | /// `filled_u8` is the number of filled bytes in `dest`, which may be less than 150 | /// the length of `dest`. 151 | /// `consumed_u64` is the number of words consumed from `src`, which is the same 152 | /// as `filled_u8 / 8` rounded up. 153 | /// 154 | /// See `fill_via_u32_chunks` for an example. 155 | #[deprecated(since = "0.9.3", note = "use BlockRng64 instead")] 156 | pub fn fill_via_u64_chunks(src: &mut [u64], dest: &mut [u8]) -> (usize, usize) { 157 | fill_via_chunks(src, dest) 158 | } 159 | 160 | /// Implement `next_u32` via `fill_bytes`, little-endian order. 161 | pub fn next_u32_via_fill(rng: &mut R) -> u32 { 162 | let mut buf = [0; 4]; 163 | rng.fill_bytes(&mut buf); 164 | u32::from_le_bytes(buf) 165 | } 166 | 167 | /// Implement `next_u64` via `fill_bytes`, little-endian order. 168 | pub fn next_u64_via_fill(rng: &mut R) -> u64 { 169 | let mut buf = [0; 8]; 170 | rng.fill_bytes(&mut buf); 171 | u64::from_le_bytes(buf) 172 | } 173 | 174 | #[cfg(test)] 175 | mod test { 176 | use super::*; 177 | 178 | #[test] 179 | fn test_fill_via_u32_chunks() { 180 | let src_orig = [1u32, 2, 3]; 181 | 182 | let mut src = src_orig; 183 | let mut dst = [0u8; 11]; 184 | assert_eq!(fill_via_chunks(&mut src, &mut dst), (3, 11)); 185 | assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]); 186 | 187 | let mut src = src_orig; 188 | let mut dst = [0u8; 13]; 189 | assert_eq!(fill_via_chunks(&mut src, &mut dst), (3, 12)); 190 | assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]); 191 | 192 | let mut src = src_orig; 193 | let mut dst = [0u8; 5]; 194 | assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 5)); 195 | assert_eq!(dst, [1, 0, 0, 0, 2]); 196 | } 197 | 198 | #[test] 199 | fn test_fill_via_u64_chunks() { 200 | let src_orig = [1u64, 2]; 201 | 202 | let mut src = src_orig; 203 | let mut dst = [0u8; 11]; 204 | assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 11)); 205 | assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]); 206 | 207 | let mut src = src_orig; 208 | let mut dst = [0u8; 17]; 209 | assert_eq!(fill_via_chunks(&mut src, &mut dst), (2, 16)); 210 | assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]); 211 | 212 | let mut src = src_orig; 213 | let mut dst = [0u8; 5]; 214 | assert_eq!(fill_via_chunks(&mut src, &mut dst), (1, 5)); 215 | assert_eq!(dst, [1, 0, 0, 0, 0]); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /rand_core/src/le.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Little-Endian utilities 10 | //! 11 | //! Little-Endian order has been chosen for internal usage; this makes some 12 | //! useful functions available. 13 | 14 | /// Fills `dst: &mut [u32]` from `src` 15 | /// 16 | /// Reads use Little-Endian byte order, allowing portable reproduction of `dst` 17 | /// from a byte slice. 18 | /// 19 | /// # Panics 20 | /// 21 | /// If `src` has insufficient length (if `src.len() < 4*dst.len()`). 22 | #[inline] 23 | #[track_caller] 24 | pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { 25 | assert!(src.len() >= 4 * dst.len()); 26 | for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(4)) { 27 | *out = u32::from_le_bytes(chunk.try_into().unwrap()); 28 | } 29 | } 30 | 31 | /// Fills `dst: &mut [u64]` from `src` 32 | /// 33 | /// # Panics 34 | /// 35 | /// If `src` has insufficient length (if `src.len() < 8*dst.len()`). 36 | #[inline] 37 | #[track_caller] 38 | pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { 39 | assert!(src.len() >= 8 * dst.len()); 40 | for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(8)) { 41 | *out = u64::from_le_bytes(chunk.try_into().unwrap()); 42 | } 43 | } 44 | 45 | #[test] 46 | fn test_read() { 47 | let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 48 | 49 | let mut buf = [0u32; 4]; 50 | read_u32_into(&bytes, &mut buf); 51 | assert_eq!(buf[0], 0x04030201); 52 | assert_eq!(buf[3], 0x100F0E0D); 53 | 54 | let mut buf = [0u32; 3]; 55 | read_u32_into(&bytes[1..13], &mut buf); // unaligned 56 | assert_eq!(buf[0], 0x05040302); 57 | assert_eq!(buf[2], 0x0D0C0B0A); 58 | 59 | let mut buf = [0u64; 2]; 60 | read_u64_into(&bytes, &mut buf); 61 | assert_eq!(buf[0], 0x0807060504030201); 62 | assert_eq!(buf[1], 0x100F0E0D0C0B0A09); 63 | 64 | let mut buf = [0u64; 1]; 65 | read_u64_into(&bytes[7..15], &mut buf); // unaligned 66 | assert_eq!(buf[0], 0x0F0E0D0C0B0A0908); 67 | } 68 | -------------------------------------------------------------------------------- /rand_core/src/os.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Interface to the random number generator of the operating system. 10 | 11 | use crate::{TryCryptoRng, TryRngCore}; 12 | 13 | /// An interface over the operating-system's random data source 14 | /// 15 | /// This is a zero-sized struct. It can be freely constructed with just `OsRng`. 16 | /// 17 | /// The implementation is provided by the [getrandom] crate. Refer to 18 | /// [getrandom] documentation for details. 19 | /// 20 | /// This struct is available as `rand_core::OsRng` and as `rand::rngs::OsRng`. 21 | /// In both cases, this requires the crate feature `os_rng` or `std` 22 | /// (enabled by default in `rand` but not in `rand_core`). 23 | /// 24 | /// # Blocking and error handling 25 | /// 26 | /// It is possible that when used during early boot the first call to `OsRng` 27 | /// will block until the system's RNG is initialised. It is also possible 28 | /// (though highly unlikely) for `OsRng` to fail on some platforms, most 29 | /// likely due to system mis-configuration. 30 | /// 31 | /// After the first successful call, it is highly unlikely that failures or 32 | /// significant delays will occur (although performance should be expected to 33 | /// be much slower than a user-space 34 | /// [PRNG](https://rust-random.github.io/book/guide-gen.html#pseudo-random-number-generators)). 35 | /// 36 | /// # Usage example 37 | /// ``` 38 | /// use rand_core::{TryRngCore, OsRng}; 39 | /// 40 | /// let mut key = [0u8; 16]; 41 | /// OsRng.try_fill_bytes(&mut key).unwrap(); 42 | /// let random_u64 = OsRng.try_next_u64().unwrap(); 43 | /// ``` 44 | /// 45 | /// [getrandom]: https://crates.io/crates/getrandom 46 | #[derive(Clone, Copy, Debug, Default)] 47 | pub struct OsRng; 48 | 49 | /// Error type of [`OsRng`] 50 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 51 | pub struct OsError(getrandom::Error); 52 | 53 | impl core::fmt::Display for OsError { 54 | #[inline] 55 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 56 | self.0.fmt(f) 57 | } 58 | } 59 | 60 | // NOTE: this can use core::error::Error from rustc 1.81.0 61 | #[cfg(feature = "std")] 62 | impl std::error::Error for OsError { 63 | #[inline] 64 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 65 | std::error::Error::source(&self.0) 66 | } 67 | } 68 | 69 | impl OsError { 70 | /// Extract the raw OS error code (if this error came from the OS) 71 | /// 72 | /// This method is identical to [`std::io::Error::raw_os_error()`][1], except 73 | /// that it works in `no_std` contexts. If this method returns `None`, the 74 | /// error value can still be formatted via the `Display` implementation. 75 | /// 76 | /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error 77 | #[inline] 78 | pub fn raw_os_error(self) -> Option { 79 | self.0.raw_os_error() 80 | } 81 | } 82 | 83 | impl TryRngCore for OsRng { 84 | type Error = OsError; 85 | 86 | #[inline] 87 | fn try_next_u32(&mut self) -> Result { 88 | getrandom::u32().map_err(OsError) 89 | } 90 | 91 | #[inline] 92 | fn try_next_u64(&mut self) -> Result { 93 | getrandom::u64().map_err(OsError) 94 | } 95 | 96 | #[inline] 97 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> { 98 | getrandom::fill(dest).map_err(OsError) 99 | } 100 | } 101 | 102 | impl TryCryptoRng for OsRng {} 103 | 104 | #[test] 105 | fn test_os_rng() { 106 | let x = OsRng.try_next_u64().unwrap(); 107 | let y = OsRng.try_next_u64().unwrap(); 108 | assert!(x != 0); 109 | assert!(x != y); 110 | } 111 | 112 | #[test] 113 | fn test_construction() { 114 | assert!(OsRng.try_next_u64().unwrap() != 0); 115 | } 116 | -------------------------------------------------------------------------------- /rand_pcg/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.9.0] - 2025-01-27 8 | ### Dependencies and features 9 | - Update to `rand_core` v0.9.0 (#1558) 10 | - Rename feature `serde1` to `serde` (#1477) 11 | - Rename feature `getrandom` to `os_rng` (#1537) 12 | 13 | ### Other changes 14 | - Add `Lcg128CmDxsm64` generator compatible with NumPy's `PCG64DXSM` (#1202) 15 | - Add examples for initializing the RNGs (#1352) 16 | - Revise crate docs (#1454) 17 | 18 | ## [0.3.1] - 2021-06-15 19 | - Add `advance` methods to RNGs (#1111) 20 | - Document dependencies between streams (#1122) 21 | 22 | ## [0.3.0] - 2020-12-08 23 | - Bump `rand_core` version to 0.6.0 24 | - Bump MSRV to 1.36 (#1011) 25 | - Derive PartialEq+Eq for Lcg64Xsh32, Lcg128Xsl64, and Mcg128Xsl64 (#979) 26 | 27 | ## [0.2.1] - 2019-10-22 28 | - Bump `bincode` version to 1.1.4 to fix minimal-dependency builds 29 | - Removed unused `autocfg` build dependency. 30 | 31 | ## [0.2.0] - 2019-06-12 32 | - Add `Lcg128Xsl64` aka `Pcg64` 33 | - Bump minor crate version since rand_core bump is a breaking change 34 | - Switch to Edition 2018 35 | 36 | ## [0.1.2] - 2019-02-23 37 | - require `bincode` 1.1.2 for i128 auto-detection 38 | - make `bincode` a dev-dependency again #663 39 | - clean up tests and Serde support 40 | 41 | ## [0.1.1] - 2018-10-04 42 | - make `bincode` an explicit dependency when using Serde 43 | 44 | ## [0.1.0] - 2018-10-04 45 | Initial release, including: 46 | 47 | - `Lcg64Xsh32` aka `Pcg32` 48 | - `Mcg128Xsl64` aka `Pcg64Mcg` 49 | -------------------------------------------------------------------------------- /rand_pcg/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the Rand project are retained by their contributors. No 2 | copyright assignment is required to contribute to the Rand project. 3 | 4 | For full authorship information, see the version control history. 5 | 6 | Except as otherwise noted (below and/or in individual files), Rand is 7 | licensed under the Apache License, Version 2.0 or 8 | or the MIT license 9 | or , at your option. 10 | 11 | The Rand project includes code from the Rust project 12 | published under these same licenses. 13 | -------------------------------------------------------------------------------- /rand_pcg/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rand_pcg" 3 | version = "0.9.0" 4 | authors = ["The Rand Project Developers"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "README.md" 7 | repository = "https://github.com/rust-random/rand" 8 | documentation = "https://docs.rs/rand_pcg" 9 | homepage = "https://rust-random.github.io/book" 10 | description = """ 11 | Selected PCG random number generators 12 | """ 13 | keywords = ["random", "rng", "pcg"] 14 | categories = ["algorithms", "no-std"] 15 | edition = "2021" 16 | rust-version = "1.63" 17 | 18 | [package.metadata.docs.rs] 19 | all-features = true 20 | rustdoc-args = ["--generate-link-to-definition"] 21 | 22 | [features] 23 | serde = ["dep:serde"] 24 | os_rng = ["rand_core/os_rng"] 25 | 26 | [dependencies] 27 | rand_core = { path = "../rand_core", version = "0.9.0" } 28 | serde = { version = "1", features = ["derive"], optional = true } 29 | 30 | [dev-dependencies] 31 | # This is for testing serde, unfortunately we can't specify feature-gated dev 32 | # deps yet, see: https://github.com/rust-lang/cargo/issues/1596 33 | # Versions prior to 1.1.4 had incorrect minimal dependencies. 34 | bincode = { version = "1.1.4" } 35 | rand_core = { path = "../rand_core", version = "0.9.0", features = ["os_rng"] } 36 | -------------------------------------------------------------------------------- /rand_pcg/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors 2 | Copyright 2018 Developers of the Rand project 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /rand_pcg/README.md: -------------------------------------------------------------------------------- 1 | # rand_pcg 2 | 3 | [![Test Status](https://github.com/rust-random/rand/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-random/rand/actions) 4 | [![Latest version](https://img.shields.io/crates/v/rand_pcg.svg)](https://crates.io/crates/rand_pcg) 5 | [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) 6 | [![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_pcg) 7 | [![API](https://docs.rs/rand_pcg/badge.svg)](https://docs.rs/rand_pcg) 8 | 9 | Implements a selection of PCG random number generators. 10 | 11 | > PCG is a family of simple fast space-efficient statistically good algorithms 12 | > for random number generation. [Melissa O'Neill, Harvey Mudd College, 2014]. 13 | 14 | The PCG algorithms are not suitable for cryptographic uses, but perform well 15 | in statistical tests, use little memory and are fairly fast. 16 | See the [pcg-random website](http://www.pcg-random.org/). 17 | 18 | This crate depends on [rand_core](https://crates.io/crates/rand_core) and is 19 | part of the [Rand project](https://github.com/rust-random/rand). 20 | 21 | Links: 22 | 23 | - [API documentation (master)](https://rust-random.github.io/rand/rand_pcg) 24 | - [API documentation (docs.rs)](https://docs.rs/rand_pcg) 25 | - [Changelog](https://github.com/rust-random/rand/blob/master/rand_pcg/CHANGELOG.md) 26 | 27 | 28 | ## Crate Features 29 | 30 | `rand_pcg` is `no_std` compatible by default. 31 | 32 | The `serde` feature includes implementations of `Serialize` and `Deserialize` 33 | for the included RNGs. 34 | 35 | ## License 36 | 37 | `rand_pcg` is distributed under the terms of both the MIT license and the 38 | Apache License (Version 2.0). 39 | 40 | See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and 41 | [COPYRIGHT](COPYRIGHT) for details. 42 | -------------------------------------------------------------------------------- /rand_pcg/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! The PCG random number generators. 10 | //! 11 | //! This is a native Rust implementation of a small selection of [PCG generators]. 12 | //! The primary goal of this crate is simple, minimal, well-tested code; in 13 | //! other words it is explicitly not a goal to re-implement all of PCG. 14 | //! 15 | //! ## Generators 16 | //! 17 | //! This crate provides: 18 | //! 19 | //! - [`Pcg32`] aka [`Lcg64Xsh32`], officially known as `pcg32`, a general 20 | //! purpose RNG. This is a good choice on both 32-bit and 64-bit CPUs 21 | //! (for 32-bit output). 22 | //! - [`Pcg64`] aka [`Lcg128Xsl64`], officially known as `pcg64`, a general 23 | //! purpose RNG. This is a good choice on 64-bit CPUs. 24 | //! - [`Pcg64Mcg`] aka [`Mcg128Xsl64`], officially known as `pcg64_fast`, 25 | //! a general purpose RNG using 128-bit multiplications. This has poor 26 | //! performance on 32-bit CPUs but is a good choice on 64-bit CPUs for 27 | //! both 32-bit and 64-bit output. 28 | //! 29 | //! These generators are all deterministic and portable (see [Reproducibility] 30 | //! in the book), with testing against reference vectors. 31 | //! 32 | //! ## Seeding (construction) 33 | //! 34 | //! Generators implement the [`SeedableRng`] trait. All methods are suitable for 35 | //! seeding. Some suggestions: 36 | //! 37 | //! 1. To automatically seed with a unique seed, use [`SeedableRng::from_rng`] 38 | //! with a master generator (here [`rand::rng()`](https://docs.rs/rand/latest/rand/fn.rng.html)): 39 | //! ```ignore 40 | //! use rand_core::SeedableRng; 41 | //! use rand_pcg::Pcg64Mcg; 42 | //! let rng = Pcg64Mcg::from_rng(&mut rand::rng()); 43 | //! # let _: Pcg64Mcg = rng; 44 | //! ``` 45 | //! 2. Seed **from an integer** via `seed_from_u64`. This uses a hash function 46 | //! internally to yield a (typically) good seed from any input. 47 | //! ``` 48 | //! # use {rand_core::SeedableRng, rand_pcg::Pcg64Mcg}; 49 | //! let rng = Pcg64Mcg::seed_from_u64(1); 50 | //! # let _: Pcg64Mcg = rng; 51 | //! ``` 52 | //! 53 | //! See also [Seeding RNGs] in the book. 54 | //! 55 | //! ## Generation 56 | //! 57 | //! Generators implement [`RngCore`], whose methods may be used directly to 58 | //! generate unbounded integer or byte values. 59 | //! ``` 60 | //! use rand_core::{SeedableRng, RngCore}; 61 | //! use rand_pcg::Pcg64Mcg; 62 | //! 63 | //! let mut rng = Pcg64Mcg::seed_from_u64(0); 64 | //! let x = rng.next_u64(); 65 | //! assert_eq!(x, 0x5603f242407deca2); 66 | //! ``` 67 | //! 68 | //! It is often more convenient to use the [`rand::Rng`] trait, which provides 69 | //! further functionality. See also the [Random Values] chapter in the book. 70 | //! 71 | //! [PCG generators]: https://www.pcg-random.org/ 72 | //! [Reproducibility]: https://rust-random.github.io/book/crate-reprod.html 73 | //! [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html 74 | //! [Random Values]: https://rust-random.github.io/book/guide-values.html 75 | //! [`RngCore`]: rand_core::RngCore 76 | //! [`SeedableRng`]: rand_core::SeedableRng 77 | //! [`SeedableRng::from_rng`]: rand_core::SeedableRng#method.from_rng 78 | //! [`rand::rng`]: https://docs.rs/rand/latest/rand/fn.rng.html 79 | //! [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html 80 | //! [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html 81 | 82 | #![doc( 83 | html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", 84 | html_favicon_url = "https://www.rust-lang.org/favicon.ico", 85 | html_root_url = "https://rust-random.github.io/rand/" 86 | )] 87 | #![forbid(unsafe_code)] 88 | #![deny(missing_docs)] 89 | #![deny(missing_debug_implementations)] 90 | #![no_std] 91 | 92 | mod pcg128; 93 | mod pcg128cm; 94 | mod pcg64; 95 | 96 | pub use rand_core; 97 | 98 | pub use self::pcg128::{Lcg128Xsl64, Mcg128Xsl64, Pcg64, Pcg64Mcg}; 99 | pub use self::pcg128cm::{Lcg128CmDxsm64, Pcg64Dxsm}; 100 | pub use self::pcg64::{Lcg64Xsh32, Pcg32}; 101 | -------------------------------------------------------------------------------- /rand_pcg/src/pcg128cm.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2021 Developers of the Rand project. 2 | // Copyright 2017 Paul Dicker. 3 | // Copyright 2014-2017, 2019 Melissa O'Neill and PCG Project contributors 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! PCG random number generators 12 | 13 | // This is the cheap multiplier used by PCG for 128-bit state. 14 | const MULTIPLIER: u64 = 15750249268501108917; 15 | 16 | use core::fmt; 17 | use rand_core::{impls, le, RngCore, SeedableRng}; 18 | #[cfg(feature = "serde")] 19 | use serde::{Deserialize, Serialize}; 20 | 21 | /// A PCG random number generator (CM DXSM 128/64 (LCG) variant). 22 | /// 23 | /// Permuted Congruential Generator with 128-bit state, internal Linear 24 | /// Congruential Generator, and 64-bit output via "double xorshift multiply" 25 | /// output function. 26 | /// 27 | /// This is a 128-bit LCG with explicitly chosen stream with the PCG-DXSM 28 | /// output function. This corresponds to `pcg_engines::cm_setseq_dxsm_128_64` 29 | /// from pcg_cpp and `PCG64DXSM` from NumPy. 30 | /// 31 | /// Despite the name, this implementation uses 32 bytes (256 bit) space 32 | /// comprising 128 bits of state and 128 bits stream selector. These are both 33 | /// set by `SeedableRng`, using a 256-bit seed. 34 | /// 35 | /// Note that while two generators with different stream parameter may be 36 | /// closely correlated, this is [mitigated][upgrading-pcg64] by the DXSM output function. 37 | /// 38 | /// [upgrading-pcg64]: https://numpy.org/doc/stable/reference/random/upgrading-pcg64.html 39 | #[derive(Clone, PartialEq, Eq)] 40 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 41 | pub struct Lcg128CmDxsm64 { 42 | state: u128, 43 | increment: u128, 44 | } 45 | 46 | /// [`Lcg128CmDxsm64`] is also known as `PCG64DXSM`. 47 | pub type Pcg64Dxsm = Lcg128CmDxsm64; 48 | 49 | impl Lcg128CmDxsm64 { 50 | /// Multi-step advance functions (jump-ahead, jump-back) 51 | /// 52 | /// The method used here is based on Brown, "Random Number Generation 53 | /// with Arbitrary Stride,", Transactions of the American Nuclear 54 | /// Society (Nov. 1994). The algorithm is very similar to fast 55 | /// exponentiation. 56 | /// 57 | /// Even though delta is an unsigned integer, we can pass a 58 | /// signed integer to go backwards, it just goes "the long way round". 59 | /// 60 | /// Using this function is equivalent to calling `next_64()` `delta` 61 | /// number of times. 62 | #[inline] 63 | pub fn advance(&mut self, delta: u128) { 64 | let mut acc_mult: u128 = 1; 65 | let mut acc_plus: u128 = 0; 66 | let mut cur_mult = MULTIPLIER as u128; 67 | let mut cur_plus = self.increment; 68 | let mut mdelta = delta; 69 | 70 | while mdelta > 0 { 71 | if (mdelta & 1) != 0 { 72 | acc_mult = acc_mult.wrapping_mul(cur_mult); 73 | acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus); 74 | } 75 | cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus); 76 | cur_mult = cur_mult.wrapping_mul(cur_mult); 77 | mdelta /= 2; 78 | } 79 | self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_plus); 80 | } 81 | 82 | /// Construct an instance compatible with PCG seed and stream. 83 | /// 84 | /// Note that the highest bit of the `stream` parameter is discarded 85 | /// to simplify upholding internal invariants. 86 | /// 87 | /// Note that while two generators with different stream parameter may be 88 | /// closely correlated, this is [mitigated][upgrading-pcg64] by the DXSM output function. 89 | /// 90 | /// PCG specifies the following default values for both parameters: 91 | /// 92 | /// - `state = 0xcafef00dd15ea5e5` 93 | /// - `stream = 0xa02bdbf7bb3c0a7ac28fa16a64abf96` 94 | /// 95 | /// [upgrading-pcg64]: https://numpy.org/doc/stable/reference/random/upgrading-pcg64.html 96 | pub fn new(state: u128, stream: u128) -> Self { 97 | // The increment must be odd, hence we discard one bit: 98 | let increment = (stream << 1) | 1; 99 | Self::from_state_incr(state, increment) 100 | } 101 | 102 | #[inline] 103 | fn from_state_incr(state: u128, increment: u128) -> Self { 104 | let mut pcg = Self { state, increment }; 105 | // Move away from initial value: 106 | pcg.state = pcg.state.wrapping_add(pcg.increment); 107 | pcg.step(); 108 | pcg 109 | } 110 | 111 | #[inline(always)] 112 | fn step(&mut self) { 113 | // prepare the LCG for the next round 114 | self.state = self 115 | .state 116 | .wrapping_mul(MULTIPLIER as u128) 117 | .wrapping_add(self.increment); 118 | } 119 | } 120 | 121 | // Custom Debug implementation that does not expose the internal state 122 | impl fmt::Debug for Lcg128CmDxsm64 { 123 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 124 | write!(f, "Lcg128CmDxsm64 {{}}") 125 | } 126 | } 127 | 128 | impl SeedableRng for Lcg128CmDxsm64 { 129 | type Seed = [u8; 32]; 130 | 131 | /// We use a single 255-bit seed to initialise the state and select a stream. 132 | /// One `seed` bit (lowest bit of `seed[8]`) is ignored. 133 | fn from_seed(seed: Self::Seed) -> Self { 134 | let mut seed_u64 = [0u64; 4]; 135 | le::read_u64_into(&seed, &mut seed_u64); 136 | let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64); 137 | let incr = u128::from(seed_u64[2]) | (u128::from(seed_u64[3]) << 64); 138 | 139 | // The increment must be odd, hence we discard one bit: 140 | Self::from_state_incr(state, incr | 1) 141 | } 142 | } 143 | 144 | impl RngCore for Lcg128CmDxsm64 { 145 | #[inline] 146 | fn next_u32(&mut self) -> u32 { 147 | self.next_u64() as u32 148 | } 149 | 150 | #[inline] 151 | fn next_u64(&mut self) -> u64 { 152 | let res = output_dxsm(self.state); 153 | self.step(); 154 | res 155 | } 156 | 157 | #[inline] 158 | fn fill_bytes(&mut self, dest: &mut [u8]) { 159 | impls::fill_bytes_via_next(self, dest) 160 | } 161 | } 162 | 163 | #[inline(always)] 164 | fn output_dxsm(state: u128) -> u64 { 165 | // See https://github.com/imneme/pcg-cpp/blob/ffd522e7188bef30a00c74dc7eb9de5faff90092/include/pcg_random.hpp#L1016 166 | // for a short discussion of the construction and its original implementation. 167 | let mut hi = (state >> 64) as u64; 168 | let mut lo = state as u64; 169 | 170 | lo |= 1; 171 | hi ^= hi >> 32; 172 | hi = hi.wrapping_mul(MULTIPLIER); 173 | hi ^= hi >> 48; 174 | hi = hi.wrapping_mul(lo); 175 | 176 | hi 177 | } 178 | -------------------------------------------------------------------------------- /rand_pcg/src/pcg64.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // Copyright 2017 Paul Dicker. 3 | // Copyright 2014-2017 Melissa O'Neill and PCG Project contributors 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! PCG random number generators 12 | 13 | use core::fmt; 14 | use rand_core::{impls, le, RngCore, SeedableRng}; 15 | #[cfg(feature = "serde")] 16 | use serde::{Deserialize, Serialize}; 17 | 18 | // This is the default multiplier used by PCG for 64-bit state. 19 | const MULTIPLIER: u64 = 6364136223846793005; 20 | 21 | /// A PCG random number generator (XSH RR 64/32 (LCG) variant). 22 | /// 23 | /// Permuted Congruential Generator with 64-bit state, internal Linear 24 | /// Congruential Generator, and 32-bit output via "xorshift high (bits), 25 | /// random rotation" output function. 26 | /// 27 | /// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR 28 | /// output function. This combination is the standard `pcg32`. 29 | /// 30 | /// Despite the name, this implementation uses 16 bytes (128 bit) space 31 | /// comprising 64 bits of state and 64 bits stream selector. These are both set 32 | /// by `SeedableRng`, using a 128-bit seed. 33 | /// 34 | /// Note that two generators with different stream parameter may be closely 35 | /// correlated. 36 | #[derive(Clone, PartialEq, Eq)] 37 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 38 | pub struct Lcg64Xsh32 { 39 | state: u64, 40 | increment: u64, 41 | } 42 | 43 | /// [`Lcg64Xsh32`] is also officially known as `pcg32`. 44 | pub type Pcg32 = Lcg64Xsh32; 45 | 46 | impl Lcg64Xsh32 { 47 | /// Multi-step advance functions (jump-ahead, jump-back) 48 | /// 49 | /// The method used here is based on Brown, "Random Number Generation 50 | /// with Arbitrary Stride,", Transactions of the American Nuclear 51 | /// Society (Nov. 1994). The algorithm is very similar to fast 52 | /// exponentiation. 53 | /// 54 | /// Even though delta is an unsigned integer, we can pass a 55 | /// signed integer to go backwards, it just goes "the long way round". 56 | /// 57 | /// Using this function is equivalent to calling `next_32()` `delta` 58 | /// number of times. 59 | #[inline] 60 | pub fn advance(&mut self, delta: u64) { 61 | let mut acc_mult: u64 = 1; 62 | let mut acc_plus: u64 = 0; 63 | let mut cur_mult = MULTIPLIER; 64 | let mut cur_plus = self.increment; 65 | let mut mdelta = delta; 66 | 67 | while mdelta > 0 { 68 | if (mdelta & 1) != 0 { 69 | acc_mult = acc_mult.wrapping_mul(cur_mult); 70 | acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus); 71 | } 72 | cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus); 73 | cur_mult = cur_mult.wrapping_mul(cur_mult); 74 | mdelta /= 2; 75 | } 76 | self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_plus); 77 | } 78 | 79 | /// Construct an instance compatible with PCG seed and stream. 80 | /// 81 | /// Note that the highest bit of the `stream` parameter is discarded 82 | /// to simplify upholding internal invariants. 83 | /// 84 | /// Note that two generators with different stream parameters may be closely 85 | /// correlated. 86 | /// 87 | /// PCG specifies the following default values for both parameters: 88 | /// 89 | /// - `state = 0xcafef00dd15ea5e5` 90 | /// - `stream = 0xa02bdbf7bb3c0a7` 91 | // Note: stream is 1442695040888963407u64 >> 1 92 | pub fn new(state: u64, stream: u64) -> Self { 93 | // The increment must be odd, hence we discard one bit: 94 | let increment = (stream << 1) | 1; 95 | Lcg64Xsh32::from_state_incr(state, increment) 96 | } 97 | 98 | #[inline] 99 | fn from_state_incr(state: u64, increment: u64) -> Self { 100 | let mut pcg = Lcg64Xsh32 { state, increment }; 101 | // Move away from initial value: 102 | pcg.state = pcg.state.wrapping_add(pcg.increment); 103 | pcg.step(); 104 | pcg 105 | } 106 | 107 | #[inline] 108 | fn step(&mut self) { 109 | // prepare the LCG for the next round 110 | self.state = self 111 | .state 112 | .wrapping_mul(MULTIPLIER) 113 | .wrapping_add(self.increment); 114 | } 115 | } 116 | 117 | // Custom Debug implementation that does not expose the internal state 118 | impl fmt::Debug for Lcg64Xsh32 { 119 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 120 | write!(f, "Lcg64Xsh32 {{}}") 121 | } 122 | } 123 | 124 | impl SeedableRng for Lcg64Xsh32 { 125 | type Seed = [u8; 16]; 126 | 127 | /// We use a single 127-bit seed to initialise the state and select a stream. 128 | /// One `seed` bit (lowest bit of `seed[8]`) is ignored. 129 | fn from_seed(seed: Self::Seed) -> Self { 130 | let mut seed_u64 = [0u64; 2]; 131 | le::read_u64_into(&seed, &mut seed_u64); 132 | 133 | // The increment must be odd, hence we discard one bit: 134 | Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1) 135 | } 136 | } 137 | 138 | impl RngCore for Lcg64Xsh32 { 139 | #[inline] 140 | fn next_u32(&mut self) -> u32 { 141 | let state = self.state; 142 | self.step(); 143 | 144 | // Output function XSH RR: xorshift high (bits), followed by a random rotate 145 | // Constants are for 64-bit state, 32-bit output 146 | const ROTATE: u32 = 59; // 64 - 5 147 | const XSHIFT: u32 = 18; // (5 + 32) / 2 148 | const SPARE: u32 = 27; // 64 - 32 - 5 149 | 150 | let rot = (state >> ROTATE) as u32; 151 | let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32; 152 | xsh.rotate_right(rot) 153 | } 154 | 155 | #[inline] 156 | fn next_u64(&mut self) -> u64 { 157 | impls::next_u64_via_u32(self) 158 | } 159 | 160 | #[inline] 161 | fn fill_bytes(&mut self, dest: &mut [u8]) { 162 | impls::fill_bytes_via_next(self, dest) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /rand_pcg/tests/lcg128cmdxsm64.rs: -------------------------------------------------------------------------------- 1 | use rand_core::{RngCore, SeedableRng}; 2 | use rand_pcg::{Lcg128CmDxsm64, Pcg64Dxsm}; 3 | 4 | #[test] 5 | fn test_lcg128cmdxsm64_advancing() { 6 | for seed in 0..20 { 7 | let mut rng1 = Lcg128CmDxsm64::seed_from_u64(seed); 8 | let mut rng2 = rng1.clone(); 9 | for _ in 0..20 { 10 | rng1.next_u64(); 11 | } 12 | rng2.advance(20); 13 | assert_eq!(rng1, rng2); 14 | } 15 | } 16 | 17 | #[test] 18 | fn test_lcg128cmdxsm64_construction() { 19 | // Test that various construction techniques produce a working RNG. 20 | #[rustfmt::skip] 21 | let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 22 | 17,18,19,20, 21,22,23,24, 25,26,27,28, 29,30,31,32]; 23 | let mut rng1 = Lcg128CmDxsm64::from_seed(seed); 24 | assert_eq!(rng1.next_u64(), 12201417210360370199); 25 | 26 | let mut rng2 = Lcg128CmDxsm64::from_rng(&mut rng1); 27 | assert_eq!(rng2.next_u64(), 11487972556150888383); 28 | 29 | let mut rng3 = Lcg128CmDxsm64::seed_from_u64(0); 30 | assert_eq!(rng3.next_u64(), 4111470453933123814); 31 | 32 | // This is the same as Lcg128CmDxsm64, so we only have a single test: 33 | let mut rng4 = Pcg64Dxsm::seed_from_u64(0); 34 | assert_eq!(rng4.next_u64(), 4111470453933123814); 35 | } 36 | 37 | #[test] 38 | fn test_lcg128cmdxsm64_reference() { 39 | // Numbers determined using `pcg_engines::cm_setseq_dxsm_128_64` from pcg-cpp. 40 | let mut rng = Lcg128CmDxsm64::new(42, 54); 41 | 42 | let mut results = [0u64; 6]; 43 | for i in results.iter_mut() { 44 | *i = rng.next_u64(); 45 | } 46 | let expected: [u64; 6] = [ 47 | 17331114245835578256, 48 | 10267467544499227306, 49 | 9726600296081716989, 50 | 10165951391103677450, 51 | 12131334649314727261, 52 | 10134094537930450875, 53 | ]; 54 | assert_eq!(results, expected); 55 | } 56 | 57 | #[cfg(feature = "serde")] 58 | #[test] 59 | fn test_lcg128cmdxsm64_serde() { 60 | use bincode; 61 | use std::io::{BufReader, BufWriter}; 62 | 63 | let mut rng = Lcg128CmDxsm64::seed_from_u64(0); 64 | 65 | let buf: Vec = Vec::new(); 66 | let mut buf = BufWriter::new(buf); 67 | bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); 68 | 69 | let buf = buf.into_inner().unwrap(); 70 | let mut read = BufReader::new(&buf[..]); 71 | let mut deserialized: Lcg128CmDxsm64 = 72 | bincode::deserialize_from(&mut read).expect("Could not deserialize"); 73 | 74 | for _ in 0..16 { 75 | assert_eq!(rng.next_u64(), deserialized.next_u64()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /rand_pcg/tests/lcg128xsl64.rs: -------------------------------------------------------------------------------- 1 | use rand_core::{RngCore, SeedableRng}; 2 | use rand_pcg::{Lcg128Xsl64, Pcg64}; 3 | 4 | #[test] 5 | fn test_lcg128xsl64_advancing() { 6 | for seed in 0..20 { 7 | let mut rng1 = Lcg128Xsl64::seed_from_u64(seed); 8 | let mut rng2 = rng1.clone(); 9 | for _ in 0..20 { 10 | rng1.next_u64(); 11 | } 12 | rng2.advance(20); 13 | assert_eq!(rng1, rng2); 14 | } 15 | } 16 | 17 | #[test] 18 | fn test_lcg128xsl64_construction() { 19 | // Test that various construction techniques produce a working RNG. 20 | #[rustfmt::skip] 21 | let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 22 | 17,18,19,20, 21,22,23,24, 25,26,27,28, 29,30,31,32]; 23 | let mut rng1 = Lcg128Xsl64::from_seed(seed); 24 | assert_eq!(rng1.next_u64(), 8740028313290271629); 25 | 26 | let mut rng2 = Lcg128Xsl64::from_rng(&mut rng1); 27 | assert_eq!(rng2.next_u64(), 1922280315005786345); 28 | 29 | let mut rng3 = Lcg128Xsl64::seed_from_u64(0); 30 | assert_eq!(rng3.next_u64(), 2354861276966075475); 31 | 32 | // This is the same as Lcg128Xsl64, so we only have a single test: 33 | let mut rng4 = Pcg64::seed_from_u64(0); 34 | assert_eq!(rng4.next_u64(), 2354861276966075475); 35 | } 36 | 37 | #[test] 38 | fn test_lcg128xsl64_reference() { 39 | // Numbers copied from official test suite (C version). 40 | let mut rng = Lcg128Xsl64::new(42, 54); 41 | 42 | let mut results = [0u64; 6]; 43 | for i in results.iter_mut() { 44 | *i = rng.next_u64(); 45 | } 46 | let expected: [u64; 6] = [ 47 | 0x86b1da1d72062b68, 48 | 0x1304aa46c9853d39, 49 | 0xa3670e9e0dd50358, 50 | 0xf9090e529a7dae00, 51 | 0xc85b9fd837996f2c, 52 | 0x606121f8e3919196, 53 | ]; 54 | assert_eq!(results, expected); 55 | } 56 | 57 | #[cfg(feature = "serde")] 58 | #[test] 59 | fn test_lcg128xsl64_serde() { 60 | use bincode; 61 | use std::io::{BufReader, BufWriter}; 62 | 63 | let mut rng = Lcg128Xsl64::seed_from_u64(0); 64 | 65 | let buf: Vec = Vec::new(); 66 | let mut buf = BufWriter::new(buf); 67 | bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); 68 | 69 | let buf = buf.into_inner().unwrap(); 70 | let mut read = BufReader::new(&buf[..]); 71 | let mut deserialized: Lcg128Xsl64 = 72 | bincode::deserialize_from(&mut read).expect("Could not deserialize"); 73 | 74 | for _ in 0..16 { 75 | assert_eq!(rng.next_u64(), deserialized.next_u64()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /rand_pcg/tests/lcg64xsh32.rs: -------------------------------------------------------------------------------- 1 | use rand_core::{RngCore, SeedableRng}; 2 | use rand_pcg::{Lcg64Xsh32, Pcg32}; 3 | 4 | #[test] 5 | fn test_lcg64xsh32_advancing() { 6 | for seed in 0..20 { 7 | let mut rng1 = Lcg64Xsh32::seed_from_u64(seed); 8 | let mut rng2 = rng1.clone(); 9 | for _ in 0..20 { 10 | rng1.next_u32(); 11 | } 12 | rng2.advance(20); 13 | assert_eq!(rng1, rng2); 14 | } 15 | } 16 | 17 | #[test] 18 | fn test_lcg64xsh32_construction() { 19 | // Test that various construction techniques produce a working RNG. 20 | let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 21 | let mut rng1 = Lcg64Xsh32::from_seed(seed); 22 | assert_eq!(rng1.next_u64(), 1204678643940597513); 23 | 24 | let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1); 25 | assert_eq!(rng2.next_u64(), 12384929573776311845); 26 | 27 | let mut rng3 = Lcg64Xsh32::seed_from_u64(0); 28 | assert_eq!(rng3.next_u64(), 18195738587432868099); 29 | 30 | // This is the same as Lcg64Xsh32, so we only have a single test: 31 | let mut rng4 = Pcg32::seed_from_u64(0); 32 | assert_eq!(rng4.next_u64(), 18195738587432868099); 33 | } 34 | 35 | #[test] 36 | fn test_lcg64xsh32_reference() { 37 | // Numbers copied from official test suite. 38 | let mut rng = Lcg64Xsh32::new(42, 54); 39 | 40 | let mut results = [0u32; 6]; 41 | for i in results.iter_mut() { 42 | *i = rng.next_u32(); 43 | } 44 | let expected: [u32; 6] = [ 45 | 0xa15c02b7, 0x7b47f409, 0xba1d3330, 0x83d2f293, 0xbfa4784b, 0xcbed606e, 46 | ]; 47 | assert_eq!(results, expected); 48 | } 49 | 50 | #[cfg(feature = "serde")] 51 | #[test] 52 | fn test_lcg64xsh32_serde() { 53 | use bincode; 54 | use std::io::{BufReader, BufWriter}; 55 | 56 | let mut rng = Lcg64Xsh32::seed_from_u64(0); 57 | 58 | let buf: Vec = Vec::new(); 59 | let mut buf = BufWriter::new(buf); 60 | bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); 61 | 62 | let buf = buf.into_inner().unwrap(); 63 | let mut read = BufReader::new(&buf[..]); 64 | let mut deserialized: Lcg64Xsh32 = 65 | bincode::deserialize_from(&mut read).expect("Could not deserialize"); 66 | 67 | for _ in 0..16 { 68 | assert_eq!(rng.next_u64(), deserialized.next_u64()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /rand_pcg/tests/mcg128xsl64.rs: -------------------------------------------------------------------------------- 1 | use rand_core::{RngCore, SeedableRng}; 2 | use rand_pcg::{Mcg128Xsl64, Pcg64Mcg}; 3 | 4 | #[test] 5 | fn test_mcg128xsl64_advancing() { 6 | for seed in 0..20 { 7 | let mut rng1 = Mcg128Xsl64::seed_from_u64(seed); 8 | let mut rng2 = rng1.clone(); 9 | for _ in 0..20 { 10 | rng1.next_u64(); 11 | } 12 | rng2.advance(20); 13 | assert_eq!(rng1, rng2); 14 | } 15 | } 16 | 17 | #[test] 18 | fn test_mcg128xsl64_construction() { 19 | // Test that various construction techniques produce a working RNG. 20 | let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 21 | let mut rng1 = Mcg128Xsl64::from_seed(seed); 22 | assert_eq!(rng1.next_u64(), 7071994460355047496); 23 | 24 | let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1); 25 | assert_eq!(rng2.next_u64(), 12300796107712034932); 26 | 27 | let mut rng3 = Mcg128Xsl64::seed_from_u64(0); 28 | assert_eq!(rng3.next_u64(), 6198063878555692194); 29 | 30 | // This is the same as Mcg128Xsl64, so we only have a single test: 31 | let mut rng4 = Pcg64Mcg::seed_from_u64(0); 32 | assert_eq!(rng4.next_u64(), 6198063878555692194); 33 | } 34 | 35 | #[test] 36 | fn test_mcg128xsl64_reference() { 37 | // Numbers copied from official test suite (C version). 38 | let mut rng = Mcg128Xsl64::new(42); 39 | 40 | let mut results = [0u64; 6]; 41 | for i in results.iter_mut() { 42 | *i = rng.next_u64(); 43 | } 44 | let expected: [u64; 6] = [ 45 | 0x63b4a3a813ce700a, 46 | 0x382954200617ab24, 47 | 0xa7fd85ae3fe950ce, 48 | 0xd715286aa2887737, 49 | 0x60c92fee2e59f32c, 50 | 0x84c4e96beff30017, 51 | ]; 52 | assert_eq!(results, expected); 53 | } 54 | 55 | #[cfg(feature = "serde")] 56 | #[test] 57 | fn test_mcg128xsl64_serde() { 58 | use bincode; 59 | use std::io::{BufReader, BufWriter}; 60 | 61 | let mut rng = Mcg128Xsl64::seed_from_u64(0); 62 | 63 | let buf: Vec = Vec::new(); 64 | let mut buf = BufWriter::new(buf); 65 | bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); 66 | 67 | let buf = buf.into_inner().unwrap(); 68 | let mut read = BufReader::new(&buf[..]); 69 | let mut deserialized: Mcg128Xsl64 = 70 | bincode::deserialize_from(&mut read).expect("Could not deserialize"); 71 | 72 | for _ in 0..16 { 73 | assert_eq!(rng.next_u64(), deserialized.next_u64()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/distr/bernoulli.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! The Bernoulli distribution `Bernoulli(p)`. 10 | 11 | use crate::distr::Distribution; 12 | use crate::Rng; 13 | use core::fmt; 14 | 15 | #[cfg(feature = "serde")] 16 | use serde::{Deserialize, Serialize}; 17 | 18 | /// The [Bernoulli distribution](https://en.wikipedia.org/wiki/Bernoulli_distribution) `Bernoulli(p)`. 19 | /// 20 | /// This distribution describes a single boolean random variable, which is true 21 | /// with probability `p` and false with probability `1 - p`. 22 | /// It is a special case of the Binomial distribution with `n = 1`. 23 | /// 24 | /// # Plot 25 | /// 26 | /// The following plot shows the Bernoulli distribution with `p = 0.1`, 27 | /// `p = 0.5`, and `p = 0.9`. 28 | /// 29 | /// ![Bernoulli distribution](https://raw.githubusercontent.com/rust-random/charts/main/charts/bernoulli.svg) 30 | /// 31 | /// # Example 32 | /// 33 | /// ```rust 34 | /// use rand::distr::{Bernoulli, Distribution}; 35 | /// 36 | /// let d = Bernoulli::new(0.3).unwrap(); 37 | /// let v = d.sample(&mut rand::rng()); 38 | /// println!("{} is from a Bernoulli distribution", v); 39 | /// ``` 40 | /// 41 | /// # Precision 42 | /// 43 | /// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`), 44 | /// so only probabilities that are multiples of 2-64 can be 45 | /// represented. 46 | #[derive(Clone, Copy, Debug, PartialEq)] 47 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 48 | pub struct Bernoulli { 49 | /// Probability of success, relative to the maximal integer. 50 | p_int: u64, 51 | } 52 | 53 | // To sample from the Bernoulli distribution we use a method that compares a 54 | // random `u64` value `v < (p * 2^64)`. 55 | // 56 | // If `p == 1.0`, the integer `v` to compare against can not represented as a 57 | // `u64`. We manually set it to `u64::MAX` instead (2^64 - 1 instead of 2^64). 58 | // Note that value of `p < 1.0` can never result in `u64::MAX`, because an 59 | // `f64` only has 53 bits of precision, and the next largest value of `p` will 60 | // result in `2^64 - 2048`. 61 | // 62 | // Also there is a 100% theoretical concern: if someone consistently wants to 63 | // generate `true` using the Bernoulli distribution (i.e. by using a probability 64 | // of `1.0`), just using `u64::MAX` is not enough. On average it would return 65 | // false once every 2^64 iterations. Some people apparently care about this 66 | // case. 67 | // 68 | // That is why we special-case `u64::MAX` to always return `true`, without using 69 | // the RNG, and pay the performance price for all uses that *are* reasonable. 70 | // Luckily, if `new()` and `sample` are close, the compiler can optimize out the 71 | // extra check. 72 | const ALWAYS_TRUE: u64 = u64::MAX; 73 | 74 | // This is just `2.0.powi(64)`, but written this way because it is not available 75 | // in `no_std` mode. 76 | const SCALE: f64 = 2.0 * (1u64 << 63) as f64; 77 | 78 | /// Error type returned from [`Bernoulli::new`]. 79 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 80 | pub enum BernoulliError { 81 | /// `p < 0` or `p > 1`. 82 | InvalidProbability, 83 | } 84 | 85 | impl fmt::Display for BernoulliError { 86 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 87 | f.write_str(match self { 88 | BernoulliError::InvalidProbability => "p is outside [0, 1] in Bernoulli distribution", 89 | }) 90 | } 91 | } 92 | 93 | #[cfg(feature = "std")] 94 | impl std::error::Error for BernoulliError {} 95 | 96 | impl Bernoulli { 97 | /// Construct a new `Bernoulli` with the given probability of success `p`. 98 | /// 99 | /// # Precision 100 | /// 101 | /// For `p = 1.0`, the resulting distribution will always generate true. 102 | /// For `p = 0.0`, the resulting distribution will always generate false. 103 | /// 104 | /// This method is accurate for any input `p` in the range `[0, 1]` which is 105 | /// a multiple of 2-64. (Note that not all multiples of 106 | /// 2-64 in `[0, 1]` can be represented as a `f64`.) 107 | #[inline] 108 | pub fn new(p: f64) -> Result { 109 | if !(0.0..1.0).contains(&p) { 110 | if p == 1.0 { 111 | return Ok(Bernoulli { p_int: ALWAYS_TRUE }); 112 | } 113 | return Err(BernoulliError::InvalidProbability); 114 | } 115 | Ok(Bernoulli { 116 | p_int: (p * SCALE) as u64, 117 | }) 118 | } 119 | 120 | /// Construct a new `Bernoulli` with the probability of success of 121 | /// `numerator`-in-`denominator`. I.e. `new_ratio(2, 3)` will return 122 | /// a `Bernoulli` with a 2-in-3 chance, or about 67%, of returning `true`. 123 | /// 124 | /// return `true`. If `numerator == 0` it will always return `false`. 125 | /// For `numerator > denominator` and `denominator == 0`, this returns an 126 | /// error. Otherwise, for `numerator == denominator`, samples are always 127 | /// true; for `numerator == 0` samples are always false. 128 | #[inline] 129 | pub fn from_ratio(numerator: u32, denominator: u32) -> Result { 130 | if numerator > denominator || denominator == 0 { 131 | return Err(BernoulliError::InvalidProbability); 132 | } 133 | if numerator == denominator { 134 | return Ok(Bernoulli { p_int: ALWAYS_TRUE }); 135 | } 136 | let p_int = ((f64::from(numerator) / f64::from(denominator)) * SCALE) as u64; 137 | Ok(Bernoulli { p_int }) 138 | } 139 | 140 | #[inline] 141 | /// Returns the probability (`p`) of the distribution. 142 | /// 143 | /// This value may differ slightly from the input due to loss of precision. 144 | pub fn p(&self) -> f64 { 145 | if self.p_int == ALWAYS_TRUE { 146 | 1.0 147 | } else { 148 | (self.p_int as f64) / SCALE 149 | } 150 | } 151 | } 152 | 153 | impl Distribution for Bernoulli { 154 | #[inline] 155 | fn sample(&self, rng: &mut R) -> bool { 156 | // Make sure to always return true for p = 1.0. 157 | if self.p_int == ALWAYS_TRUE { 158 | return true; 159 | } 160 | let v: u64 = rng.random(); 161 | v < self.p_int 162 | } 163 | } 164 | 165 | #[cfg(test)] 166 | mod test { 167 | use super::Bernoulli; 168 | use crate::distr::Distribution; 169 | use crate::Rng; 170 | 171 | #[test] 172 | #[cfg(feature = "serde")] 173 | fn test_serializing_deserializing_bernoulli() { 174 | let coin_flip = Bernoulli::new(0.5).unwrap(); 175 | let de_coin_flip: Bernoulli = 176 | bincode::deserialize(&bincode::serialize(&coin_flip).unwrap()).unwrap(); 177 | 178 | assert_eq!(coin_flip.p_int, de_coin_flip.p_int); 179 | } 180 | 181 | #[test] 182 | fn test_trivial() { 183 | // We prefer to be explicit here. 184 | #![allow(clippy::bool_assert_comparison)] 185 | 186 | let mut r = crate::test::rng(1); 187 | let always_false = Bernoulli::new(0.0).unwrap(); 188 | let always_true = Bernoulli::new(1.0).unwrap(); 189 | for _ in 0..5 { 190 | assert_eq!(r.sample::(&always_false), false); 191 | assert_eq!(r.sample::(&always_true), true); 192 | assert_eq!(Distribution::::sample(&always_false, &mut r), false); 193 | assert_eq!(Distribution::::sample(&always_true, &mut r), true); 194 | } 195 | } 196 | 197 | #[test] 198 | #[cfg_attr(miri, ignore)] // Miri is too slow 199 | fn test_average() { 200 | const P: f64 = 0.3; 201 | const NUM: u32 = 3; 202 | const DENOM: u32 = 10; 203 | let d1 = Bernoulli::new(P).unwrap(); 204 | let d2 = Bernoulli::from_ratio(NUM, DENOM).unwrap(); 205 | const N: u32 = 100_000; 206 | 207 | let mut sum1: u32 = 0; 208 | let mut sum2: u32 = 0; 209 | let mut rng = crate::test::rng(2); 210 | for _ in 0..N { 211 | if d1.sample(&mut rng) { 212 | sum1 += 1; 213 | } 214 | if d2.sample(&mut rng) { 215 | sum2 += 1; 216 | } 217 | } 218 | let avg1 = (sum1 as f64) / (N as f64); 219 | assert!((avg1 - P).abs() < 5e-3); 220 | 221 | let avg2 = (sum2 as f64) / (N as f64); 222 | assert!((avg2 - (NUM as f64) / (DENOM as f64)).abs() < 5e-3); 223 | } 224 | 225 | #[test] 226 | fn value_stability() { 227 | let mut rng = crate::test::rng(3); 228 | let distr = Bernoulli::new(0.4532).unwrap(); 229 | let mut buf = [false; 10]; 230 | for x in &mut buf { 231 | *x = rng.sample(distr); 232 | } 233 | assert_eq!( 234 | buf, 235 | [true, false, false, true, false, false, true, true, true, true] 236 | ); 237 | } 238 | 239 | #[test] 240 | fn bernoulli_distributions_can_be_compared() { 241 | assert_eq!(Bernoulli::new(1.0), Bernoulli::new(1.0)); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/distr/slice.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Distributions over slices 10 | 11 | use core::num::NonZeroUsize; 12 | 13 | use crate::distr::uniform::{UniformSampler, UniformUsize}; 14 | use crate::distr::Distribution; 15 | #[cfg(feature = "alloc")] 16 | use alloc::string::String; 17 | 18 | /// A distribution to uniformly sample elements of a slice 19 | /// 20 | /// Like [`IndexedRandom::choose`], this uniformly samples elements of a slice 21 | /// without modification of the slice (so called "sampling with replacement"). 22 | /// This distribution object may be a little faster for repeated sampling (but 23 | /// slower for small numbers of samples). 24 | /// 25 | /// ## Examples 26 | /// 27 | /// Since this is a distribution, [`Rng::sample_iter`] and 28 | /// [`Distribution::sample_iter`] may be used, for example: 29 | /// ``` 30 | /// use rand::distr::{Distribution, slice::Choose}; 31 | /// 32 | /// let vowels = ['a', 'e', 'i', 'o', 'u']; 33 | /// let vowels_dist = Choose::new(&vowels).unwrap(); 34 | /// 35 | /// // build a string of 10 vowels 36 | /// let vowel_string: String = vowels_dist 37 | /// .sample_iter(&mut rand::rng()) 38 | /// .take(10) 39 | /// .collect(); 40 | /// 41 | /// println!("{}", vowel_string); 42 | /// assert_eq!(vowel_string.len(), 10); 43 | /// assert!(vowel_string.chars().all(|c| vowels.contains(&c))); 44 | /// ``` 45 | /// 46 | /// For a single sample, [`IndexedRandom::choose`] may be preferred: 47 | /// ``` 48 | /// use rand::seq::IndexedRandom; 49 | /// 50 | /// let vowels = ['a', 'e', 'i', 'o', 'u']; 51 | /// let mut rng = rand::rng(); 52 | /// 53 | /// println!("{}", vowels.choose(&mut rng).unwrap()); 54 | /// ``` 55 | /// 56 | /// [`IndexedRandom::choose`]: crate::seq::IndexedRandom::choose 57 | /// [`Rng::sample_iter`]: crate::Rng::sample_iter 58 | #[derive(Debug, Clone, Copy)] 59 | pub struct Choose<'a, T> { 60 | slice: &'a [T], 61 | range: UniformUsize, 62 | num_choices: NonZeroUsize, 63 | } 64 | 65 | impl<'a, T> Choose<'a, T> { 66 | /// Create a new `Choose` instance which samples uniformly from the slice. 67 | /// 68 | /// Returns error [`Empty`] if the slice is empty. 69 | pub fn new(slice: &'a [T]) -> Result { 70 | let num_choices = NonZeroUsize::new(slice.len()).ok_or(Empty)?; 71 | 72 | Ok(Self { 73 | slice, 74 | range: UniformUsize::new(0, num_choices.get()).unwrap(), 75 | num_choices, 76 | }) 77 | } 78 | 79 | /// Returns the count of choices in this distribution 80 | pub fn num_choices(&self) -> NonZeroUsize { 81 | self.num_choices 82 | } 83 | } 84 | 85 | impl<'a, T> Distribution<&'a T> for Choose<'a, T> { 86 | fn sample(&self, rng: &mut R) -> &'a T { 87 | let idx = self.range.sample(rng); 88 | 89 | debug_assert!( 90 | idx < self.slice.len(), 91 | "Uniform::new(0, {}) somehow returned {}", 92 | self.slice.len(), 93 | idx 94 | ); 95 | 96 | // Safety: at construction time, it was ensured that the slice was 97 | // non-empty, and that the `Uniform` range produces values in range 98 | // for the slice 99 | unsafe { self.slice.get_unchecked(idx) } 100 | } 101 | } 102 | 103 | /// Error: empty slice 104 | /// 105 | /// This error is returned when [`Choose::new`] is given an empty slice. 106 | #[derive(Debug, Clone, Copy)] 107 | pub struct Empty; 108 | 109 | impl core::fmt::Display for Empty { 110 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 111 | write!( 112 | f, 113 | "Tried to create a `rand::distr::slice::Choose` with an empty slice" 114 | ) 115 | } 116 | } 117 | 118 | #[cfg(feature = "std")] 119 | impl std::error::Error for Empty {} 120 | 121 | #[cfg(feature = "alloc")] 122 | impl super::SampleString for Choose<'_, char> { 123 | fn append_string(&self, rng: &mut R, string: &mut String, len: usize) { 124 | // Get the max char length to minimize extra space. 125 | // Limit this check to avoid searching for long slice. 126 | let max_char_len = if self.slice.len() < 200 { 127 | self.slice 128 | .iter() 129 | .try_fold(1, |max_len, char| { 130 | // When the current max_len is 4, the result max_char_len will be 4. 131 | Some(max_len.max(char.len_utf8())).filter(|len| *len < 4) 132 | }) 133 | .unwrap_or(4) 134 | } else { 135 | 4 136 | }; 137 | 138 | // Split the extension of string to reuse the unused capacities. 139 | // Skip the split for small length or only ascii slice. 140 | let mut extend_len = if max_char_len == 1 || len < 100 { 141 | len 142 | } else { 143 | len / 4 144 | }; 145 | let mut remain_len = len; 146 | while extend_len > 0 { 147 | string.reserve(max_char_len * extend_len); 148 | string.extend(self.sample_iter(&mut *rng).take(extend_len)); 149 | remain_len -= extend_len; 150 | extend_len = extend_len.min(remain_len); 151 | } 152 | } 153 | } 154 | 155 | #[cfg(test)] 156 | mod test { 157 | use super::*; 158 | use core::iter; 159 | 160 | #[test] 161 | fn value_stability() { 162 | let rng = crate::test::rng(651); 163 | let slice = Choose::new(b"escaped emus explore extensively").unwrap(); 164 | let expected = b"eaxee"; 165 | assert!(iter::zip(slice.sample_iter(rng), expected).all(|(a, b)| a == b)); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/distr/weighted/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Weighted (index) sampling 10 | //! 11 | //! Primarily, this module houses the [`WeightedIndex`] distribution. 12 | //! See also [`rand_distr::weighted`] for alternative implementations supporting 13 | //! potentially-faster sampling or a more easily modifiable tree structure. 14 | //! 15 | //! [`rand_distr::weighted`]: https://docs.rs/rand_distr/latest/rand_distr/weighted/index.html 16 | 17 | use core::fmt; 18 | mod weighted_index; 19 | 20 | pub use weighted_index::WeightedIndex; 21 | 22 | /// Bounds on a weight 23 | /// 24 | /// See usage in [`WeightedIndex`]. 25 | pub trait Weight: Clone { 26 | /// Representation of 0 27 | const ZERO: Self; 28 | 29 | /// Checked addition 30 | /// 31 | /// - `Result::Ok`: On success, `v` is added to `self` 32 | /// - `Result::Err`: Returns an error when `Self` cannot represent the 33 | /// result of `self + v` (i.e. overflow). The value of `self` should be 34 | /// discarded. 35 | #[allow(clippy::result_unit_err)] 36 | fn checked_add_assign(&mut self, v: &Self) -> Result<(), ()>; 37 | } 38 | 39 | macro_rules! impl_weight_int { 40 | ($t:ty) => { 41 | impl Weight for $t { 42 | const ZERO: Self = 0; 43 | fn checked_add_assign(&mut self, v: &Self) -> Result<(), ()> { 44 | match self.checked_add(*v) { 45 | Some(sum) => { 46 | *self = sum; 47 | Ok(()) 48 | } 49 | None => Err(()), 50 | } 51 | } 52 | } 53 | }; 54 | ($t:ty, $($tt:ty),*) => { 55 | impl_weight_int!($t); 56 | impl_weight_int!($($tt),*); 57 | } 58 | } 59 | impl_weight_int!(i8, i16, i32, i64, i128, isize); 60 | impl_weight_int!(u8, u16, u32, u64, u128, usize); 61 | 62 | macro_rules! impl_weight_float { 63 | ($t:ty) => { 64 | impl Weight for $t { 65 | const ZERO: Self = 0.0; 66 | 67 | fn checked_add_assign(&mut self, v: &Self) -> Result<(), ()> { 68 | // Floats have an explicit representation for overflow 69 | *self += *v; 70 | Ok(()) 71 | } 72 | } 73 | }; 74 | } 75 | impl_weight_float!(f32); 76 | impl_weight_float!(f64); 77 | 78 | /// Invalid weight errors 79 | /// 80 | /// This type represents errors from [`WeightedIndex::new`], 81 | /// [`WeightedIndex::update_weights`] and other weighted distributions. 82 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 83 | // Marked non_exhaustive to allow a new error code in the solution to #1476. 84 | #[non_exhaustive] 85 | pub enum Error { 86 | /// The input weight sequence is empty, too long, or wrongly ordered 87 | InvalidInput, 88 | 89 | /// A weight is negative, too large for the distribution, or not a valid number 90 | InvalidWeight, 91 | 92 | /// Not enough non-zero weights are available to sample values 93 | /// 94 | /// When attempting to sample a single value this implies that all weights 95 | /// are zero. When attempting to sample `amount` values this implies that 96 | /// less than `amount` weights are greater than zero. 97 | InsufficientNonZero, 98 | 99 | /// Overflow when calculating the sum of weights 100 | Overflow, 101 | } 102 | 103 | #[cfg(feature = "std")] 104 | impl std::error::Error for Error {} 105 | 106 | impl fmt::Display for Error { 107 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 108 | f.write_str(match *self { 109 | Error::InvalidInput => "Weights sequence is empty/too long/unordered", 110 | Error::InvalidWeight => "A weight is negative, too large or not a valid number", 111 | Error::InsufficientNonZero => "Not enough weights > zero", 112 | Error::Overflow => "Overflow when summing weights", 113 | }) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/prelude.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Convenience re-export of common members 10 | //! 11 | //! Like the standard library's prelude, this module simplifies importing of 12 | //! common items. Unlike the standard prelude, the contents of this module must 13 | //! be imported manually: 14 | //! 15 | //! ``` 16 | //! use rand::prelude::*; 17 | //! # let mut r = StdRng::from_rng(&mut rand::rng()); 18 | //! # let _: f32 = r.random(); 19 | //! ``` 20 | 21 | #[doc(no_inline)] 22 | pub use crate::distr::Distribution; 23 | #[cfg(feature = "small_rng")] 24 | #[doc(no_inline)] 25 | pub use crate::rngs::SmallRng; 26 | #[cfg(feature = "std_rng")] 27 | #[doc(no_inline)] 28 | pub use crate::rngs::StdRng; 29 | #[doc(no_inline)] 30 | #[cfg(feature = "thread_rng")] 31 | pub use crate::rngs::ThreadRng; 32 | #[doc(no_inline)] 33 | pub use crate::seq::{IndexedMutRandom, IndexedRandom, IteratorRandom, SliceRandom}; 34 | #[doc(no_inline)] 35 | pub use crate::{CryptoRng, Rng, RngCore, SeedableRng}; 36 | -------------------------------------------------------------------------------- /src/rngs/mock.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Mock random number generator 10 | 11 | #![allow(deprecated)] 12 | 13 | use rand_core::{impls, RngCore}; 14 | 15 | #[cfg(feature = "serde")] 16 | use serde::{Deserialize, Serialize}; 17 | 18 | /// A mock generator yielding very predictable output 19 | /// 20 | /// This generates an arithmetic sequence (i.e. adds a constant each step) 21 | /// over a `u64` number, using wrapping arithmetic. If the increment is 0 22 | /// the generator yields a constant. 23 | /// 24 | /// Other integer types (64-bit and smaller) are produced via cast from `u64`. 25 | /// 26 | /// Other types are produced via their implementation of [`Rng`](crate::Rng) or 27 | /// [`Distribution`](crate::distr::Distribution). 28 | /// Output values may not be intuitive and may change in future releases but 29 | /// are considered 30 | /// [portable](https://rust-random.github.io/book/portability.html). 31 | /// (`bool` output is true when bit `1u64 << 31` is set.) 32 | /// 33 | /// # Example 34 | /// 35 | /// ``` 36 | /// # #![allow(deprecated)] 37 | /// use rand::Rng; 38 | /// use rand::rngs::mock::StepRng; 39 | /// 40 | /// let mut my_rng = StepRng::new(2, 1); 41 | /// let sample: [u64; 3] = my_rng.random(); 42 | /// assert_eq!(sample, [2, 3, 4]); 43 | /// ``` 44 | #[derive(Debug, Clone, PartialEq, Eq)] 45 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 46 | #[deprecated(since = "0.9.2", note = "Deprecated without replacement")] 47 | pub struct StepRng { 48 | v: u64, 49 | a: u64, 50 | } 51 | 52 | impl StepRng { 53 | /// Create a `StepRng`, yielding an arithmetic sequence starting with 54 | /// `initial` and incremented by `increment` each time. 55 | pub fn new(initial: u64, increment: u64) -> Self { 56 | StepRng { 57 | v: initial, 58 | a: increment, 59 | } 60 | } 61 | } 62 | 63 | impl RngCore for StepRng { 64 | #[inline] 65 | fn next_u32(&mut self) -> u32 { 66 | self.next_u64() as u32 67 | } 68 | 69 | #[inline] 70 | fn next_u64(&mut self) -> u64 { 71 | let res = self.v; 72 | self.v = self.v.wrapping_add(self.a); 73 | res 74 | } 75 | 76 | #[inline] 77 | fn fill_bytes(&mut self, dst: &mut [u8]) { 78 | impls::fill_bytes_via_next(self, dst) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/rngs/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Random number generators and adapters 10 | //! 11 | //! This crate provides a small selection of non-[portable] generators. 12 | //! See also [Types of generators] and [Our RNGs] in the book. 13 | //! 14 | //! ## Generators 15 | //! 16 | //! This crate provides a small selection of non-[portable] random number generators: 17 | //! 18 | //! - [`OsRng`] is a stateless interface over the operating system's random number 19 | //! source. This is typically secure with some form of periodic re-seeding. 20 | //! - [`ThreadRng`], provided by [`crate::rng()`], is a handle to a 21 | //! thread-local generator with periodic seeding from [`OsRng`]. Because this 22 | //! is local, it is typically much faster than [`OsRng`]. It should be 23 | //! secure, but see documentation on [`ThreadRng`]. 24 | //! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security 25 | //! (based on reviews, maturity and usage). The current algorithm is ChaCha12, 26 | //! which is well established and rigorously analysed. 27 | //! [`StdRng`] is the deterministic generator used by [`ThreadRng`] but 28 | //! without the periodic reseeding or thread-local management. 29 | //! - [`SmallRng`] is a relatively simple, insecure generator designed to be 30 | //! fast, use little memory, and pass various statistical tests of 31 | //! randomness quality. 32 | //! 33 | //! The algorithms selected for [`StdRng`] and [`SmallRng`] may change in any 34 | //! release and may be platform-dependent, therefore they are not 35 | //! [reproducible][portable]. 36 | //! 37 | //! ### Additional generators 38 | //! 39 | //! - The [`rdrand`] crate provides an interface to the RDRAND and RDSEED 40 | //! instructions available in modern Intel and AMD CPUs. 41 | //! - The [`rand_jitter`] crate provides a user-space implementation of 42 | //! entropy harvesting from CPU timer jitter, but is very slow and has 43 | //! [security issues](https://github.com/rust-random/rand/issues/699). 44 | //! - The [`rand_chacha`] crate provides [portable] implementations of 45 | //! generators derived from the [ChaCha] family of stream ciphers 46 | //! - The [`rand_pcg`] crate provides [portable] implementations of a subset 47 | //! of the [PCG] family of small, insecure generators 48 | //! - The [`rand_xoshiro`] crate provides [portable] implementations of the 49 | //! [xoshiro] family of small, insecure generators 50 | //! 51 | //! For more, search [crates with the `rng` tag]. 52 | //! 53 | //! ## Traits and functionality 54 | //! 55 | //! All generators implement [`RngCore`] and thus also [`Rng`][crate::Rng]. 56 | //! See also the [Random Values] chapter in the book. 57 | //! 58 | //! Secure RNGs may additionally implement the [`CryptoRng`] trait. 59 | //! 60 | //! Use the [`rand_core`] crate when implementing your own RNGs. 61 | //! 62 | //! [portable]: https://rust-random.github.io/book/crate-reprod.html 63 | //! [Types of generators]: https://rust-random.github.io/book/guide-gen.html 64 | //! [Our RNGs]: https://rust-random.github.io/book/guide-rngs.html 65 | //! [Random Values]: https://rust-random.github.io/book/guide-values.html 66 | //! [`Rng`]: crate::Rng 67 | //! [`RngCore`]: crate::RngCore 68 | //! [`CryptoRng`]: crate::CryptoRng 69 | //! [`SeedableRng`]: crate::SeedableRng 70 | //! [`rdrand`]: https://crates.io/crates/rdrand 71 | //! [`rand_jitter`]: https://crates.io/crates/rand_jitter 72 | //! [`rand_chacha`]: https://crates.io/crates/rand_chacha 73 | //! [`rand_pcg`]: https://crates.io/crates/rand_pcg 74 | //! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro 75 | //! [crates with the `rng` tag]: https://crates.io/keywords/rng 76 | //! [chacha]: https://cr.yp.to/chacha.html 77 | //! [PCG]: https://www.pcg-random.org/ 78 | //! [xoshiro]: https://prng.di.unimi.it/ 79 | 80 | mod reseeding; 81 | pub use reseeding::ReseedingRng; 82 | 83 | #[deprecated(since = "0.9.2")] 84 | pub mod mock; // Public so we don't export `StepRng` directly, making it a bit 85 | // more clear it is intended for testing. 86 | 87 | #[cfg(feature = "small_rng")] 88 | mod small; 89 | #[cfg(all( 90 | feature = "small_rng", 91 | any(target_pointer_width = "32", target_pointer_width = "16") 92 | ))] 93 | mod xoshiro128plusplus; 94 | #[cfg(all(feature = "small_rng", target_pointer_width = "64"))] 95 | mod xoshiro256plusplus; 96 | 97 | #[cfg(feature = "std_rng")] 98 | mod std; 99 | #[cfg(feature = "thread_rng")] 100 | pub(crate) mod thread; 101 | 102 | #[cfg(feature = "small_rng")] 103 | pub use self::small::SmallRng; 104 | #[cfg(feature = "std_rng")] 105 | pub use self::std::StdRng; 106 | #[cfg(feature = "thread_rng")] 107 | pub use self::thread::ThreadRng; 108 | 109 | #[cfg(feature = "os_rng")] 110 | pub use rand_core::OsRng; 111 | -------------------------------------------------------------------------------- /src/rngs/small.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! A small fast RNG 10 | 11 | use rand_core::{RngCore, SeedableRng}; 12 | 13 | #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] 14 | type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus; 15 | #[cfg(target_pointer_width = "64")] 16 | type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus; 17 | 18 | /// A small-state, fast, non-crypto, non-portable PRNG 19 | /// 20 | /// This is the "standard small" RNG, a generator with the following properties: 21 | /// 22 | /// - Non-[portable]: any future library version may replace the algorithm 23 | /// and results may be platform-dependent. 24 | /// (For a small portable generator, use the [rand_pcg] or [rand_xoshiro] crate.) 25 | /// - Non-cryptographic: output is easy to predict (insecure) 26 | /// - [Quality]: statistically good quality 27 | /// - Fast: the RNG is fast for both bulk generation and single values, with 28 | /// consistent cost of method calls 29 | /// - Fast initialization 30 | /// - Small state: little memory usage (current state size is 16-32 bytes 31 | /// depending on platform) 32 | /// 33 | /// The current algorithm is 34 | /// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit 35 | /// platforms. Both are also implemented by the [rand_xoshiro] crate. 36 | /// 37 | /// ## Seeding (construction) 38 | /// 39 | /// This generator implements the [`SeedableRng`] trait. All methods are 40 | /// suitable for seeding, but note that, even with a fixed seed, output is not 41 | /// [portable]. Some suggestions: 42 | /// 43 | /// 1. To automatically seed with a unique seed, use [`SeedableRng::from_rng`]: 44 | /// ``` 45 | /// use rand::SeedableRng; 46 | /// use rand::rngs::SmallRng; 47 | /// let rng = SmallRng::from_rng(&mut rand::rng()); 48 | /// # let _: SmallRng = rng; 49 | /// ``` 50 | /// or [`SeedableRng::from_os_rng`]: 51 | /// ``` 52 | /// # use rand::SeedableRng; 53 | /// # use rand::rngs::SmallRng; 54 | /// let rng = SmallRng::from_os_rng(); 55 | /// # let _: SmallRng = rng; 56 | /// ``` 57 | /// 2. To use a deterministic integral seed, use `seed_from_u64`. This uses a 58 | /// hash function internally to yield a (typically) good seed from any 59 | /// input. 60 | /// ``` 61 | /// # use rand::{SeedableRng, rngs::SmallRng}; 62 | /// let rng = SmallRng::seed_from_u64(1); 63 | /// # let _: SmallRng = rng; 64 | /// ``` 65 | /// 3. To seed deterministically from text or other input, use [`rand_seeder`]. 66 | /// 67 | /// See also [Seeding RNGs] in the book. 68 | /// 69 | /// ## Generation 70 | /// 71 | /// The generators implements [`RngCore`] and thus also [`Rng`][crate::Rng]. 72 | /// See also the [Random Values] chapter in the book. 73 | /// 74 | /// [portable]: https://rust-random.github.io/book/crate-reprod.html 75 | /// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html 76 | /// [Random Values]: https://rust-random.github.io/book/guide-values.html 77 | /// [Quality]: https://rust-random.github.io/book/guide-rngs.html#quality 78 | /// [`StdRng`]: crate::rngs::StdRng 79 | /// [rand_pcg]: https://crates.io/crates/rand_pcg 80 | /// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro 81 | /// [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html 82 | /// [`rand_seeder`]: https://docs.rs/rand_seeder/latest/rand_seeder/ 83 | #[derive(Clone, Debug, PartialEq, Eq)] 84 | pub struct SmallRng(Rng); 85 | 86 | impl SeedableRng for SmallRng { 87 | // Fix to 256 bits. Changing this is a breaking change! 88 | type Seed = [u8; 32]; 89 | 90 | #[inline(always)] 91 | fn from_seed(seed: Self::Seed) -> Self { 92 | // This is for compatibility with 32-bit platforms where Rng::Seed has a different seed size 93 | // With MSRV >= 1.77: let seed = *seed.first_chunk().unwrap() 94 | const LEN: usize = core::mem::size_of::<::Seed>(); 95 | let seed = (&seed[..LEN]).try_into().unwrap(); 96 | SmallRng(Rng::from_seed(seed)) 97 | } 98 | 99 | #[inline(always)] 100 | fn seed_from_u64(state: u64) -> Self { 101 | SmallRng(Rng::seed_from_u64(state)) 102 | } 103 | } 104 | 105 | impl RngCore for SmallRng { 106 | #[inline(always)] 107 | fn next_u32(&mut self) -> u32 { 108 | self.0.next_u32() 109 | } 110 | 111 | #[inline(always)] 112 | fn next_u64(&mut self) -> u64 { 113 | self.0.next_u64() 114 | } 115 | 116 | #[inline(always)] 117 | fn fill_bytes(&mut self, dest: &mut [u8]) { 118 | self.0.fill_bytes(dest) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/rngs/std.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! The standard RNG 10 | 11 | use rand_core::{CryptoRng, RngCore, SeedableRng}; 12 | 13 | #[cfg(any(test, feature = "os_rng"))] 14 | pub(crate) use rand_chacha::ChaCha12Core as Core; 15 | 16 | use rand_chacha::ChaCha12Rng as Rng; 17 | 18 | /// A strong, fast (amortized), non-portable RNG 19 | /// 20 | /// This is the "standard" RNG, a generator with the following properties: 21 | /// 22 | /// - Non-[portable]: any future library version may replace the algorithm 23 | /// and results may be platform-dependent. 24 | /// (For a portable version, use the [rand_chacha] crate directly.) 25 | /// - [CSPRNG]: statistically good quality of randomness and [unpredictable] 26 | /// - Fast ([amortized](https://en.wikipedia.org/wiki/Amortized_analysis)): 27 | /// the RNG is fast for bulk generation, but the cost of method calls is not 28 | /// consistent due to usage of an output buffer. 29 | /// 30 | /// The current algorithm used is the ChaCha block cipher with 12 rounds. Please 31 | /// see this relevant [rand issue] for the discussion. This may change as new 32 | /// evidence of cipher security and performance becomes available. 33 | /// 34 | /// ## Seeding (construction) 35 | /// 36 | /// This generator implements the [`SeedableRng`] trait. Any method may be used, 37 | /// but note that `seed_from_u64` is not suitable for usage where security is 38 | /// important. Also note that, even with a fixed seed, output is not [portable]. 39 | /// 40 | /// Using a fresh seed **direct from the OS** is the most secure option: 41 | /// ``` 42 | /// # use rand::{SeedableRng, rngs::StdRng}; 43 | /// let rng = StdRng::from_os_rng(); 44 | /// # let _: StdRng = rng; 45 | /// ``` 46 | /// 47 | /// Seeding via [`rand::rng()`](crate::rng()) may be faster: 48 | /// ``` 49 | /// # use rand::{SeedableRng, rngs::StdRng}; 50 | /// let rng = StdRng::from_rng(&mut rand::rng()); 51 | /// # let _: StdRng = rng; 52 | /// ``` 53 | /// 54 | /// Any [`SeedableRng`] method may be used, but note that `seed_from_u64` is not 55 | /// suitable where security is required. See also [Seeding RNGs] in the book. 56 | /// 57 | /// ## Generation 58 | /// 59 | /// The generators implements [`RngCore`] and thus also [`Rng`][crate::Rng]. 60 | /// See also the [Random Values] chapter in the book. 61 | /// 62 | /// [portable]: https://rust-random.github.io/book/crate-reprod.html 63 | /// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html 64 | /// [unpredictable]: https://rust-random.github.io/book/guide-rngs.html#security 65 | /// [Random Values]: https://rust-random.github.io/book/guide-values.html 66 | /// [CSPRNG]: https://rust-random.github.io/book/guide-gen.html#cryptographically-secure-pseudo-random-number-generator 67 | /// [rand_chacha]: https://crates.io/crates/rand_chacha 68 | /// [rand issue]: https://github.com/rust-random/rand/issues/932 69 | #[derive(Clone, Debug, PartialEq, Eq)] 70 | pub struct StdRng(Rng); 71 | 72 | impl RngCore for StdRng { 73 | #[inline(always)] 74 | fn next_u32(&mut self) -> u32 { 75 | self.0.next_u32() 76 | } 77 | 78 | #[inline(always)] 79 | fn next_u64(&mut self) -> u64 { 80 | self.0.next_u64() 81 | } 82 | 83 | #[inline(always)] 84 | fn fill_bytes(&mut self, dst: &mut [u8]) { 85 | self.0.fill_bytes(dst) 86 | } 87 | } 88 | 89 | impl SeedableRng for StdRng { 90 | // Fix to 256 bits. Changing this is a breaking change! 91 | type Seed = [u8; 32]; 92 | 93 | #[inline(always)] 94 | fn from_seed(seed: Self::Seed) -> Self { 95 | StdRng(Rng::from_seed(seed)) 96 | } 97 | } 98 | 99 | impl CryptoRng for StdRng {} 100 | 101 | #[cfg(test)] 102 | mod test { 103 | use crate::rngs::StdRng; 104 | use crate::{RngCore, SeedableRng}; 105 | 106 | #[test] 107 | fn test_stdrng_construction() { 108 | // Test value-stability of StdRng. This is expected to break any time 109 | // the algorithm is changed. 110 | #[rustfmt::skip] 111 | let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, 112 | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; 113 | 114 | let target = [10719222850664546238, 14064965282130556830]; 115 | 116 | let mut rng0 = StdRng::from_seed(seed); 117 | let x0 = rng0.next_u64(); 118 | 119 | let mut rng1 = StdRng::from_rng(&mut rng0); 120 | let x1 = rng1.next_u64(); 121 | 122 | assert_eq!([x0, x1], target); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/rngs/thread.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Thread-local random number generator 10 | 11 | use core::cell::UnsafeCell; 12 | use std::fmt; 13 | use std::rc::Rc; 14 | use std::thread_local; 15 | 16 | use rand_core::{CryptoRng, RngCore}; 17 | 18 | use super::std::Core; 19 | use crate::rngs::OsRng; 20 | use crate::rngs::ReseedingRng; 21 | 22 | // Rationale for using `UnsafeCell` in `ThreadRng`: 23 | // 24 | // Previously we used a `RefCell`, with an overhead of ~15%. There will only 25 | // ever be one mutable reference to the interior of the `UnsafeCell`, because 26 | // we only have such a reference inside `next_u32`, `next_u64`, etc. Within a 27 | // single thread (which is the definition of `ThreadRng`), there will only ever 28 | // be one of these methods active at a time. 29 | // 30 | // A possible scenario where there could be multiple mutable references is if 31 | // `ThreadRng` is used inside `next_u32` and co. But the implementation is 32 | // completely under our control. We just have to ensure none of them use 33 | // `ThreadRng` internally, which is nonsensical anyway. We should also never run 34 | // `ThreadRng` in destructors of its implementation, which is also nonsensical. 35 | 36 | // Number of generated bytes after which to reseed `ThreadRng`. 37 | // According to benchmarks, reseeding has a noticeable impact with thresholds 38 | // of 32 kB and less. We choose 64 kB to avoid significant overhead. 39 | const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64; 40 | 41 | /// A reference to the thread-local generator 42 | /// 43 | /// This type is a reference to a lazily-initialized thread-local generator. 44 | /// An instance can be obtained via [`rand::rng()`][crate::rng()] or via 45 | /// [`ThreadRng::default()`]. 46 | /// The handle cannot be passed between threads (is not `Send` or `Sync`). 47 | /// 48 | /// # Security 49 | /// 50 | /// Security must be considered relative to a threat model and validation 51 | /// requirements. The Rand project can provide no guarantee of fitness for 52 | /// purpose. The design criteria for `ThreadRng` are as follows: 53 | /// 54 | /// - Automatic seeding via [`OsRng`] and periodically thereafter (see 55 | /// ([`ReseedingRng`] documentation). Limitation: there is no automatic 56 | /// reseeding on process fork (see [below](#fork)). 57 | /// - A rigorusly analyzed, unpredictable (cryptographic) pseudo-random generator 58 | /// (see [the book on security](https://rust-random.github.io/book/guide-rngs.html#security)). 59 | /// The currently selected algorithm is ChaCha (12-rounds). 60 | /// See also [`StdRng`] documentation. 61 | /// - Not to leak internal state through [`Debug`] or serialization 62 | /// implementations. 63 | /// - No further protections exist to in-memory state. In particular, the 64 | /// implementation is not required to zero memory on exit (of the process or 65 | /// thread). (This may change in the future.) 66 | /// - Be fast enough for general-purpose usage. Note in particular that 67 | /// `ThreadRng` is designed to be a "fast, reasonably secure generator" 68 | /// (where "reasonably secure" implies the above criteria). 69 | /// 70 | /// We leave it to the user to determine whether this generator meets their 71 | /// security requirements. For an alternative, see [`OsRng`]. 72 | /// 73 | /// # Fork 74 | /// 75 | /// `ThreadRng` is not automatically reseeded on fork. It is recommended to 76 | /// explicitly call [`ThreadRng::reseed`] immediately after a fork, for example: 77 | /// ```ignore 78 | /// fn do_fork() { 79 | /// let pid = unsafe { libc::fork() }; 80 | /// if pid == 0 { 81 | /// // Reseed ThreadRng in child processes: 82 | /// rand::rng().reseed(); 83 | /// } 84 | /// } 85 | /// ``` 86 | /// 87 | /// Methods on `ThreadRng` are not reentrant-safe and thus should not be called 88 | /// from an interrupt (e.g. a fork handler) unless it can be guaranteed that no 89 | /// other method on the same `ThreadRng` is currently executing. 90 | /// 91 | /// [`ReseedingRng`]: crate::rngs::ReseedingRng 92 | /// [`StdRng`]: crate::rngs::StdRng 93 | #[derive(Clone)] 94 | pub struct ThreadRng { 95 | // Rc is explicitly !Send and !Sync 96 | rng: Rc>>, 97 | } 98 | 99 | impl ThreadRng { 100 | /// Immediately reseed the generator 101 | /// 102 | /// This discards any remaining random data in the cache. 103 | pub fn reseed(&mut self) -> Result<(), rand_core::OsError> { 104 | // SAFETY: We must make sure to stop using `rng` before anyone else 105 | // creates another mutable reference 106 | let rng = unsafe { &mut *self.rng.get() }; 107 | rng.reseed() 108 | } 109 | } 110 | 111 | /// Debug implementation does not leak internal state 112 | impl fmt::Debug for ThreadRng { 113 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 114 | write!(fmt, "ThreadRng {{ .. }}") 115 | } 116 | } 117 | 118 | thread_local!( 119 | // We require Rc<..> to avoid premature freeing when ThreadRng is used 120 | // within thread-local destructors. See #968. 121 | static THREAD_RNG_KEY: Rc>> = { 122 | let rng = ReseedingRng::new(THREAD_RNG_RESEED_THRESHOLD, 123 | OsRng).unwrap_or_else(|err| 124 | panic!("could not initialize ThreadRng: {}", err)); 125 | Rc::new(UnsafeCell::new(rng)) 126 | } 127 | ); 128 | 129 | /// Access a fast, pre-initialized generator 130 | /// 131 | /// This is a handle to the local [`ThreadRng`]. 132 | /// 133 | /// See also [`crate::rngs`] for alternatives. 134 | /// 135 | /// # Example 136 | /// 137 | /// ``` 138 | /// use rand::prelude::*; 139 | /// 140 | /// # fn main() { 141 | /// 142 | /// let mut numbers = [1, 2, 3, 4, 5]; 143 | /// numbers.shuffle(&mut rand::rng()); 144 | /// println!("Numbers: {numbers:?}"); 145 | /// 146 | /// // Using a local binding avoids an initialization-check on each usage: 147 | /// let mut rng = rand::rng(); 148 | /// 149 | /// println!("True or false: {}", rng.random::()); 150 | /// println!("A simulated die roll: {}", rng.random_range(1..=6)); 151 | /// # } 152 | /// ``` 153 | /// 154 | /// # Security 155 | /// 156 | /// Refer to [`ThreadRng#Security`]. 157 | pub fn rng() -> ThreadRng { 158 | let rng = THREAD_RNG_KEY.with(|t| t.clone()); 159 | ThreadRng { rng } 160 | } 161 | 162 | impl Default for ThreadRng { 163 | fn default() -> ThreadRng { 164 | rng() 165 | } 166 | } 167 | 168 | impl RngCore for ThreadRng { 169 | #[inline(always)] 170 | fn next_u32(&mut self) -> u32 { 171 | // SAFETY: We must make sure to stop using `rng` before anyone else 172 | // creates another mutable reference 173 | let rng = unsafe { &mut *self.rng.get() }; 174 | rng.next_u32() 175 | } 176 | 177 | #[inline(always)] 178 | fn next_u64(&mut self) -> u64 { 179 | // SAFETY: We must make sure to stop using `rng` before anyone else 180 | // creates another mutable reference 181 | let rng = unsafe { &mut *self.rng.get() }; 182 | rng.next_u64() 183 | } 184 | 185 | #[inline(always)] 186 | fn fill_bytes(&mut self, dest: &mut [u8]) { 187 | // SAFETY: We must make sure to stop using `rng` before anyone else 188 | // creates another mutable reference 189 | let rng = unsafe { &mut *self.rng.get() }; 190 | rng.fill_bytes(dest) 191 | } 192 | } 193 | 194 | impl CryptoRng for ThreadRng {} 195 | 196 | #[cfg(test)] 197 | mod test { 198 | #[test] 199 | fn test_thread_rng() { 200 | use crate::Rng; 201 | let mut r = crate::rng(); 202 | r.random::(); 203 | assert_eq!(r.random_range(0..1), 0); 204 | } 205 | 206 | #[test] 207 | fn test_debug_output() { 208 | // We don't care about the exact output here, but it must not include 209 | // private CSPRNG state or the cache stored by BlockRng! 210 | assert_eq!(std::format!("{:?}", crate::rng()), "ThreadRng { .. }"); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/rngs/xoshiro128plusplus.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use rand_core::impls::{fill_bytes_via_next, next_u64_via_u32}; 10 | use rand_core::le::read_u32_into; 11 | use rand_core::{RngCore, SeedableRng}; 12 | #[cfg(feature = "serde")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// A xoshiro128++ random number generator. 16 | /// 17 | /// The xoshiro128++ algorithm is not suitable for cryptographic purposes, but 18 | /// is very fast and has excellent statistical properties. 19 | /// 20 | /// The algorithm used here is translated from [the `xoshiro128plusplus.c` 21 | /// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by 22 | /// David Blackman and Sebastiano Vigna. 23 | #[derive(Debug, Clone, PartialEq, Eq)] 24 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 25 | pub struct Xoshiro128PlusPlus { 26 | s: [u32; 4], 27 | } 28 | 29 | impl SeedableRng for Xoshiro128PlusPlus { 30 | type Seed = [u8; 16]; 31 | 32 | /// Create a new `Xoshiro128PlusPlus`. If `seed` is entirely 0, it will be 33 | /// mapped to a different seed. 34 | #[inline] 35 | fn from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus { 36 | let mut state = [0; 4]; 37 | read_u32_into(&seed, &mut state); 38 | // Check for zero on aligned integers for better code generation. 39 | // Furtermore, seed_from_u64(0) will expand to a constant when optimized. 40 | if state.iter().all(|&x| x == 0) { 41 | return Self::seed_from_u64(0); 42 | } 43 | Xoshiro128PlusPlus { s: state } 44 | } 45 | 46 | /// Create a new `Xoshiro128PlusPlus` from a `u64` seed. 47 | /// 48 | /// This uses the SplitMix64 generator internally. 49 | #[inline] 50 | fn seed_from_u64(mut state: u64) -> Self { 51 | const PHI: u64 = 0x9e3779b97f4a7c15; 52 | let mut s = [0; 4]; 53 | for i in s.chunks_exact_mut(2) { 54 | state = state.wrapping_add(PHI); 55 | let mut z = state; 56 | z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9); 57 | z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb); 58 | z = z ^ (z >> 31); 59 | i[0] = z as u32; 60 | i[1] = (z >> 32) as u32; 61 | } 62 | // By using a non-zero PHI we are guaranteed to generate a non-zero state 63 | // Thus preventing a recursion between from_seed and seed_from_u64. 64 | debug_assert_ne!(s, [0; 4]); 65 | Xoshiro128PlusPlus { s } 66 | } 67 | } 68 | 69 | impl RngCore for Xoshiro128PlusPlus { 70 | #[inline] 71 | fn next_u32(&mut self) -> u32 { 72 | let res = self.s[0] 73 | .wrapping_add(self.s[3]) 74 | .rotate_left(7) 75 | .wrapping_add(self.s[0]); 76 | 77 | let t = self.s[1] << 9; 78 | 79 | self.s[2] ^= self.s[0]; 80 | self.s[3] ^= self.s[1]; 81 | self.s[1] ^= self.s[2]; 82 | self.s[0] ^= self.s[3]; 83 | 84 | self.s[2] ^= t; 85 | 86 | self.s[3] = self.s[3].rotate_left(11); 87 | 88 | res 89 | } 90 | 91 | #[inline] 92 | fn next_u64(&mut self) -> u64 { 93 | next_u64_via_u32(self) 94 | } 95 | 96 | #[inline] 97 | fn fill_bytes(&mut self, dst: &mut [u8]) { 98 | fill_bytes_via_next(self, dst) 99 | } 100 | } 101 | 102 | #[cfg(test)] 103 | mod tests { 104 | use super::Xoshiro128PlusPlus; 105 | use rand_core::{RngCore, SeedableRng}; 106 | 107 | #[test] 108 | fn reference() { 109 | let mut rng = 110 | Xoshiro128PlusPlus::from_seed([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]); 111 | // These values were produced with the reference implementation: 112 | // http://xoshiro.di.unimi.it/xoshiro128plusplus.c 113 | let expected = [ 114 | 641, 1573767, 3222811527, 3517856514, 836907274, 4247214768, 3867114732, 1355841295, 115 | 495546011, 621204420, 116 | ]; 117 | for &e in &expected { 118 | assert_eq!(rng.next_u32(), e); 119 | } 120 | } 121 | 122 | #[test] 123 | fn stable_seed_from_u64_and_from_seed() { 124 | // We don't guarantee value-stability for SmallRng but this 125 | // could influence keeping stability whenever possible (e.g. after optimizations). 126 | let mut rng = Xoshiro128PlusPlus::seed_from_u64(0); 127 | // from_seed([0; 16]) should produce the same state as seed_from_u64(0). 128 | let mut rng_from_seed_0 = Xoshiro128PlusPlus::from_seed([0; 16]); 129 | let expected = [ 130 | 1179900579, 1938959192, 3089844957, 3657088315, 1015453891, 479942911, 3433842246, 131 | 669252886, 3985671746, 2737205563, 132 | ]; 133 | for &e in &expected { 134 | assert_eq!(rng.next_u32(), e); 135 | assert_eq!(rng_from_seed_0.next_u32(), e); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/rngs/xoshiro256plusplus.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use rand_core::impls::fill_bytes_via_next; 10 | use rand_core::le::read_u64_into; 11 | use rand_core::{RngCore, SeedableRng}; 12 | #[cfg(feature = "serde")] 13 | use serde::{Deserialize, Serialize}; 14 | 15 | /// A xoshiro256++ random number generator. 16 | /// 17 | /// The xoshiro256++ algorithm is not suitable for cryptographic purposes, but 18 | /// is very fast and has excellent statistical properties. 19 | /// 20 | /// The algorithm used here is translated from [the `xoshiro256plusplus.c` 21 | /// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by 22 | /// David Blackman and Sebastiano Vigna. 23 | #[derive(Debug, Clone, PartialEq, Eq)] 24 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 25 | pub struct Xoshiro256PlusPlus { 26 | s: [u64; 4], 27 | } 28 | 29 | impl SeedableRng for Xoshiro256PlusPlus { 30 | type Seed = [u8; 32]; 31 | 32 | /// Create a new `Xoshiro256PlusPlus`. If `seed` is entirely 0, it will be 33 | /// mapped to a different seed. 34 | #[inline] 35 | fn from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus { 36 | let mut state = [0; 4]; 37 | read_u64_into(&seed, &mut state); 38 | // Check for zero on aligned integers for better code generation. 39 | // Furtermore, seed_from_u64(0) will expand to a constant when optimized. 40 | if state.iter().all(|&x| x == 0) { 41 | return Self::seed_from_u64(0); 42 | } 43 | Xoshiro256PlusPlus { s: state } 44 | } 45 | 46 | /// Create a new `Xoshiro256PlusPlus` from a `u64` seed. 47 | /// 48 | /// This uses the SplitMix64 generator internally. 49 | #[inline] 50 | fn seed_from_u64(mut state: u64) -> Self { 51 | const PHI: u64 = 0x9e3779b97f4a7c15; 52 | let mut s = [0; 4]; 53 | for i in s.iter_mut() { 54 | state = state.wrapping_add(PHI); 55 | let mut z = state; 56 | z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9); 57 | z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb); 58 | z = z ^ (z >> 31); 59 | *i = z; 60 | } 61 | // By using a non-zero PHI we are guaranteed to generate a non-zero state 62 | // Thus preventing a recursion between from_seed and seed_from_u64. 63 | debug_assert_ne!(s, [0; 4]); 64 | Xoshiro256PlusPlus { s } 65 | } 66 | } 67 | 68 | impl RngCore for Xoshiro256PlusPlus { 69 | #[inline] 70 | fn next_u32(&mut self) -> u32 { 71 | // The lowest bits have some linear dependencies, so we use the 72 | // upper bits instead. 73 | let val = self.next_u64(); 74 | (val >> 32) as u32 75 | } 76 | 77 | #[inline] 78 | fn next_u64(&mut self) -> u64 { 79 | let res = self.s[0] 80 | .wrapping_add(self.s[3]) 81 | .rotate_left(23) 82 | .wrapping_add(self.s[0]); 83 | 84 | let t = self.s[1] << 17; 85 | 86 | self.s[2] ^= self.s[0]; 87 | self.s[3] ^= self.s[1]; 88 | self.s[1] ^= self.s[2]; 89 | self.s[0] ^= self.s[3]; 90 | 91 | self.s[2] ^= t; 92 | 93 | self.s[3] = self.s[3].rotate_left(45); 94 | 95 | res 96 | } 97 | 98 | #[inline] 99 | fn fill_bytes(&mut self, dst: &mut [u8]) { 100 | fill_bytes_via_next(self, dst) 101 | } 102 | } 103 | 104 | #[cfg(test)] 105 | mod tests { 106 | use super::Xoshiro256PlusPlus; 107 | use rand_core::{RngCore, SeedableRng}; 108 | 109 | #[test] 110 | fn reference() { 111 | let mut rng = Xoshiro256PlusPlus::from_seed([ 112 | 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 113 | 0, 0, 0, 114 | ]); 115 | // These values were produced with the reference implementation: 116 | // http://xoshiro.di.unimi.it/xoshiro256plusplus.c 117 | let expected = [ 118 | 41943041, 119 | 58720359, 120 | 3588806011781223, 121 | 3591011842654386, 122 | 9228616714210784205, 123 | 9973669472204895162, 124 | 14011001112246962877, 125 | 12406186145184390807, 126 | 15849039046786891736, 127 | 10450023813501588000, 128 | ]; 129 | for &e in &expected { 130 | assert_eq!(rng.next_u64(), e); 131 | } 132 | } 133 | 134 | #[test] 135 | fn stable_seed_from_u64_and_from_seed() { 136 | // We don't guarantee value-stability for SmallRng but this 137 | // could influence keeping stability whenever possible (e.g. after optimizations). 138 | let mut rng = Xoshiro256PlusPlus::seed_from_u64(0); 139 | // from_seed([0; 32]) should produce the same state as seed_from_u64(0). 140 | let mut rng_from_seed_0 = Xoshiro256PlusPlus::from_seed([0; 32]); 141 | let expected = [ 142 | 5987356902031041503, 143 | 7051070477665621255, 144 | 6633766593972829180, 145 | 211316841551650330, 146 | 9136120204379184874, 147 | 379361710973160858, 148 | 15813423377499357806, 149 | 15596884590815070553, 150 | 5439680534584881407, 151 | 1369371744833522710, 152 | ]; 153 | for &e in &expected { 154 | assert_eq!(rng.next_u64(), e); 155 | assert_eq!(rng_from_seed_0.next_u64(), e); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/seq/coin_flipper.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::RngCore; 10 | 11 | pub(crate) struct CoinFlipper { 12 | pub rng: R, 13 | chunk: u32, // TODO(opt): this should depend on RNG word size 14 | chunk_remaining: u32, 15 | } 16 | 17 | impl CoinFlipper { 18 | pub fn new(rng: R) -> Self { 19 | Self { 20 | rng, 21 | chunk: 0, 22 | chunk_remaining: 0, 23 | } 24 | } 25 | 26 | #[inline] 27 | /// Returns true with a probability of 1 / d 28 | /// Uses an expected two bits of randomness 29 | /// Panics if d == 0 30 | pub fn random_ratio_one_over(&mut self, d: usize) -> bool { 31 | debug_assert_ne!(d, 0); 32 | // This uses the same logic as `random_ratio` but is optimized for the case that 33 | // the starting numerator is one (which it always is for `Sequence::Choose()`) 34 | 35 | // In this case (but not `random_ratio`), this way of calculating c is always accurate 36 | let c = (usize::BITS - 1 - d.leading_zeros()).min(32); 37 | 38 | if self.flip_c_heads(c) { 39 | let numerator = 1 << c; 40 | self.random_ratio(numerator, d) 41 | } else { 42 | false 43 | } 44 | } 45 | 46 | #[inline] 47 | /// Returns true with a probability of n / d 48 | /// Uses an expected two bits of randomness 49 | fn random_ratio(&mut self, mut n: usize, d: usize) -> bool { 50 | // Explanation: 51 | // We are trying to return true with a probability of n / d 52 | // If n >= d, we can just return true 53 | // Otherwise there are two possibilities 2n < d and 2n >= d 54 | // In either case we flip a coin. 55 | // If 2n < d 56 | // If it comes up tails, return false 57 | // If it comes up heads, double n and start again 58 | // This is fair because (0.5 * 0) + (0.5 * 2n / d) = n / d and 2n is less than d 59 | // (if 2n was greater than d we would effectively round it down to 1 60 | // by returning true) 61 | // If 2n >= d 62 | // If it comes up tails, set n to 2n - d and start again 63 | // If it comes up heads, return true 64 | // This is fair because (0.5 * 1) + (0.5 * (2n - d) / d) = n / d 65 | // Note that if 2n = d and the coin comes up tails, n will be set to 0 66 | // before restarting which is equivalent to returning false. 67 | 68 | // As a performance optimization we can flip multiple coins at once 69 | // This is efficient because we can use the `lzcnt` intrinsic 70 | // We can check up to 32 flips at once but we only receive one bit of information 71 | // - all heads or at least one tail. 72 | 73 | // Let c be the number of coins to flip. 1 <= c <= 32 74 | // If 2n < d, n * 2^c < d 75 | // If the result is all heads, then set n to n * 2^c 76 | // If there was at least one tail, return false 77 | // If 2n >= d, the order of results matters so we flip one coin at a time so c = 1 78 | // Ideally, c will be as high as possible within these constraints 79 | 80 | while n < d { 81 | // Find a good value for c by counting leading zeros 82 | // This will either give the highest possible c, or 1 less than that 83 | let c = n 84 | .leading_zeros() 85 | .saturating_sub(d.leading_zeros() + 1) 86 | .clamp(1, 32); 87 | 88 | if self.flip_c_heads(c) { 89 | // All heads 90 | // Set n to n * 2^c 91 | // If 2n >= d, the while loop will exit and we will return `true` 92 | // If n * 2^c > `usize::MAX` we always return `true` anyway 93 | n = n.saturating_mul(2_usize.pow(c)); 94 | } else { 95 | // At least one tail 96 | if c == 1 { 97 | // Calculate 2n - d. 98 | // We need to use wrapping as 2n might be greater than `usize::MAX` 99 | let next_n = n.wrapping_add(n).wrapping_sub(d); 100 | if next_n == 0 || next_n > n { 101 | // This will happen if 2n < d 102 | return false; 103 | } 104 | n = next_n; 105 | } else { 106 | // c > 1 so 2n < d so we can return false 107 | return false; 108 | } 109 | } 110 | } 111 | true 112 | } 113 | 114 | /// If the next `c` bits of randomness all represent heads, consume them, return true 115 | /// Otherwise return false and consume the number of heads plus one. 116 | /// Generates new bits of randomness when necessary (in 32 bit chunks) 117 | /// Has a 1 in 2 to the `c` chance of returning true 118 | /// `c` must be less than or equal to 32 119 | fn flip_c_heads(&mut self, mut c: u32) -> bool { 120 | debug_assert!(c <= 32); 121 | // Note that zeros on the left of the chunk represent heads. 122 | // It needs to be this way round because zeros are filled in when left shifting 123 | loop { 124 | let zeros = self.chunk.leading_zeros(); 125 | 126 | if zeros < c { 127 | // The happy path - we found a 1 and can return false 128 | // Note that because a 1 bit was detected, 129 | // We cannot have run out of random bits so we don't need to check 130 | 131 | // First consume all of the bits read 132 | // Using shl seems to give worse performance for size-hinted iterators 133 | self.chunk = self.chunk.wrapping_shl(zeros + 1); 134 | 135 | self.chunk_remaining = self.chunk_remaining.saturating_sub(zeros + 1); 136 | return false; 137 | } else { 138 | // The number of zeros is larger than `c` 139 | // There are two possibilities 140 | if let Some(new_remaining) = self.chunk_remaining.checked_sub(c) { 141 | // Those zeroes were all part of our random chunk, 142 | // throw away `c` bits of randomness and return true 143 | self.chunk_remaining = new_remaining; 144 | self.chunk <<= c; 145 | return true; 146 | } else { 147 | // Some of those zeroes were part of the random chunk 148 | // and some were part of the space behind it 149 | // We need to take into account only the zeroes that were random 150 | c -= self.chunk_remaining; 151 | 152 | // Generate a new chunk 153 | self.chunk = self.rng.next_u32(); 154 | self.chunk_remaining = 32; 155 | // Go back to start of loop 156 | } 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/seq/increasing_uniform.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use crate::{Rng, RngCore}; 10 | 11 | /// Similar to a Uniform distribution, 12 | /// but after returning a number in the range [0,n], n is increased by 1. 13 | pub(crate) struct IncreasingUniform { 14 | pub rng: R, 15 | n: u32, 16 | // Chunk is a random number in [0, (n + 1) * (n + 2) *..* (n + chunk_remaining) ) 17 | chunk: u32, 18 | chunk_remaining: u8, 19 | } 20 | 21 | impl IncreasingUniform { 22 | /// Create a dice roller. 23 | /// The next item returned will be a random number in the range [0,n] 24 | pub fn new(rng: R, n: u32) -> Self { 25 | // If n = 0, the first number returned will always be 0 26 | // so we don't need to generate a random number 27 | let chunk_remaining = if n == 0 { 1 } else { 0 }; 28 | Self { 29 | rng, 30 | n, 31 | chunk: 0, 32 | chunk_remaining, 33 | } 34 | } 35 | 36 | /// Returns a number in [0,n] and increments n by 1. 37 | /// Generates new random bits as needed 38 | /// Panics if `n >= u32::MAX` 39 | #[inline] 40 | pub fn next_index(&mut self) -> usize { 41 | let next_n = self.n + 1; 42 | 43 | // There's room for further optimisation here: 44 | // random_range uses rejection sampling (or other method; see #1196) to avoid bias. 45 | // When the initial sample is biased for range 0..bound 46 | // it may still be viable to use for a smaller bound 47 | // (especially if small biases are considered acceptable). 48 | 49 | let next_chunk_remaining = self.chunk_remaining.checked_sub(1).unwrap_or_else(|| { 50 | // If the chunk is empty, generate a new chunk 51 | let (bound, remaining) = calculate_bound_u32(next_n); 52 | // bound = (n + 1) * (n + 2) *..* (n + remaining) 53 | self.chunk = self.rng.random_range(..bound); 54 | // Chunk is a random number in 55 | // [0, (n + 1) * (n + 2) *..* (n + remaining) ) 56 | 57 | remaining - 1 58 | }); 59 | 60 | let result = if next_chunk_remaining == 0 { 61 | // `chunk` is a random number in the range [0..n+1) 62 | // Because `chunk_remaining` is about to be set to zero 63 | // we do not need to clear the chunk here 64 | self.chunk as usize 65 | } else { 66 | // `chunk` is a random number in a range that is a multiple of n+1 67 | // so r will be a random number in [0..n+1) 68 | let r = self.chunk % next_n; 69 | self.chunk /= next_n; 70 | r as usize 71 | }; 72 | 73 | self.chunk_remaining = next_chunk_remaining; 74 | self.n = next_n; 75 | result 76 | } 77 | } 78 | 79 | #[inline] 80 | /// Calculates `bound`, `count` such that bound (m)*(m+1)*..*(m + remaining - 1) 81 | fn calculate_bound_u32(m: u32) -> (u32, u8) { 82 | debug_assert!(m > 0); 83 | #[inline] 84 | const fn inner(m: u32) -> (u32, u8) { 85 | let mut product = m; 86 | let mut current = m + 1; 87 | 88 | loop { 89 | if let Some(p) = u32::checked_mul(product, current) { 90 | product = p; 91 | current += 1; 92 | } else { 93 | // Count has a maximum value of 13 for when min is 1 or 2 94 | let count = (current - m) as u8; 95 | return (product, count); 96 | } 97 | } 98 | } 99 | 100 | const RESULT2: (u32, u8) = inner(2); 101 | if m == 2 { 102 | // Making this value a constant instead of recalculating it 103 | // gives a significant (~50%) performance boost for small shuffles 104 | return RESULT2; 105 | } 106 | 107 | inner(m) 108 | } 109 | -------------------------------------------------------------------------------- /src/seq/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2023 Developers of the Rand project. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! Sequence-related functionality 10 | //! 11 | //! This module provides: 12 | //! 13 | //! * [`IndexedRandom`] for sampling slices and other indexable lists 14 | //! * [`IndexedMutRandom`] for sampling slices and other mutably indexable lists 15 | //! * [`SliceRandom`] for mutating slices 16 | //! * [`IteratorRandom`] for sampling iterators 17 | //! * [`index::sample`] low-level API to choose multiple indices from 18 | //! `0..length` 19 | //! 20 | //! Also see: 21 | //! 22 | //! * [`crate::distr::weighted::WeightedIndex`] distribution which provides 23 | //! weighted index sampling. 24 | //! 25 | //! In order to make results reproducible across 32-64 bit architectures, all 26 | //! `usize` indices are sampled as a `u32` where possible (also providing a 27 | //! small performance boost in some cases). 28 | 29 | mod coin_flipper; 30 | mod increasing_uniform; 31 | mod iterator; 32 | mod slice; 33 | 34 | #[cfg(feature = "alloc")] 35 | #[path = "index.rs"] 36 | mod index_; 37 | 38 | #[cfg(feature = "alloc")] 39 | #[doc(no_inline)] 40 | pub use crate::distr::weighted::Error as WeightError; 41 | pub use iterator::IteratorRandom; 42 | #[cfg(feature = "alloc")] 43 | pub use slice::SliceChooseIter; 44 | pub use slice::{IndexedMutRandom, IndexedRandom, SliceRandom}; 45 | 46 | /// Low-level API for sampling indices 47 | pub mod index { 48 | use crate::Rng; 49 | 50 | #[cfg(feature = "alloc")] 51 | #[doc(inline)] 52 | pub use super::index_::*; 53 | 54 | /// Randomly sample exactly `N` distinct indices from `0..len`, and 55 | /// return them in random order (fully shuffled). 56 | /// 57 | /// This is implemented via Floyd's algorithm. Time complexity is `O(N^2)` 58 | /// and memory complexity is `O(N)`. 59 | /// 60 | /// Returns `None` if (and only if) `N > len`. 61 | pub fn sample_array(rng: &mut R, len: usize) -> Option<[usize; N]> 62 | where 63 | R: Rng + ?Sized, 64 | { 65 | if N > len { 66 | return None; 67 | } 68 | 69 | // Floyd's algorithm 70 | let mut indices = [0; N]; 71 | for (i, j) in (len - N..len).enumerate() { 72 | let t = rng.random_range(..j + 1); 73 | if let Some(pos) = indices[0..i].iter().position(|&x| x == t) { 74 | indices[pos] = j; 75 | } 76 | indices[i] = t; 77 | } 78 | Some(indices) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /utils/redirect.html: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------