[
  {
    "path": ".cargo/config.toml",
    "content": "[target.x86_64-apple-darwin]\nrustflags = [\n\t\"-C\", \"link-arg=-undefined\",\n\t\"-C\", \"link-arg=dynamic_lookup\",\n]\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*]\nindent_style = tab\nindent_size = 4\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.yml]\nindent_style = space\n"
  },
  {
    "path": ".gitattributes",
    "content": "*       text=auto eol=lf\n\n# Guaranteed to be text\n*.rs    text=auto eol=lf\n*.txt   text=auto eol=lf\n*.md    text=auto eol=lf\n*.toml  text=auto eol=lf"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: Absolucy\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: \"Linting\"\non:\n    push:\n        paths:\n            - \"**/*.rs\"\n            - \".github/workflows/*.yml\"\n    pull_request:\n        paths:\n            - \"**/*.rs\"\n            - \".github/workflows/*.yml\"\njobs:\n    lint:\n        name: \"Linting\"\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v2\n            - name: \"Install stable Rust toolchain\"\n              uses: actions-rs/toolchain@v1\n              with:\n                  override: true\n                  profile: minimal\n                  toolchain: \"stable\"\n                  components: rustfmt, clippy\n            - name: Run rustfmt\n              uses: actions-rs/cargo@v1\n              with:\n                  args: \"--all -- --check\"\n                  command: fmt\n            - name: Run 'cargo check'\n              uses: actions-rs/cargo@v1\n              with:\n                  args: \"--workspace\"\n                  command: check\n            - name: Run clippy\n              uses: actions-rs/cargo@v1\n              with:\n                  args: \"--workspace\"\n                  command: clippy\n"
  },
  {
    "path": ".github/workflows/smallcrush.yml",
    "content": "name: \"Run SmallCrush\"\non:\n    push:\n        paths:\n            - \"**/*.rs\"\n            - \"**/*.h\"\n            - \"**/*.c\"\n            - \".github/workflows/*.yml\"\n    pull_request:\n        paths:\n            - \"**/*.rs\"\n            - \"**/*.h\"\n            - \"**/*.c\"\n            - \".github/workflows/*.yml\"\n    workflow_dispatch:\njobs:\n    smallcrush:\n        name: \"Run SmallCrush\"\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v3\n            - name: Install TestU01 and Clang\n              run: sudo apt-get update && sudo apt-get install -y libtestu01-0-dev libtestu01-0-dev-common libtestu01-0 llvm clang\n            - name: \"Install stable Rust toolchain\"\n              uses: actions-rs/toolchain@v1\n              with:\n                  override: true\n                  profile: minimal\n                  toolchain: \"stable\"\n            - name: Build nanorand-abi\n              uses: actions-rs/cargo@v1\n              with:\n                  args: \"--release --package nanorand-abi\"\n                  command: build\n            - name: Build nanorand SmallCrush example\n              run: clang -O3 -pipe -I$GITHUB_WORKSPACE/nanorand-abi nanorand-abi/examples/smallcrush.c target/release/libnanorand_abi.so -o nanorand-smallcrush -ltestu01 -ltestu01probdist -ltestu01mylib -lm\n            - name: Run nanorand SmallCrush\n              run: ./nanorand-smallcrush\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: \"Run Tests\"\non:\n    push:\n        paths:\n            - \"**/*.rs\"\n            - \".github/workflows/*.yml\"\n    pull_request:\n        paths:\n            - \"**/*.rs\"\n            - \".github/workflows/*.yml\"\njobs:\n    version-tests:\n        name: Test on Rust ${{ matrix.toolchain }}\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v2\n            - name: Install stable Rust toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  override: true\n                  profile: minimal\n                  toolchain: ${{ matrix.toolchain }}\n            - name: Run 'cargo check'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --all-features\n            - name: Run 'cargo test'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: test\n                  args: --all-features\n        strategy:\n            matrix:\n                toolchain:\n                    - 1.56.0\n                    - stable\n                    - beta\n                    - nightly\n    linux-tests:\n        name: Test on ${{ matrix.target }}\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/checkout@v2\n            - name: Install stable Rust toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  override: true\n                  profile: minimal\n                  toolchain: stable\n            - name: Run 'cargo check'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --all-features\n            - name: Run 'cargo check --no-default-features'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --no-default-features\n            - name: Run 'cross test'\n              uses: actions-rs/cargo@v1\n              with:\n                  use-cross: true\n                  command: test\n                  args: --all-features --target ${{ matrix.target }}\n        strategy:\n            matrix:\n                target:\n                    - x86_64-unknown-linux-gnu\n                    - aarch64-unknown-linux-gnu\n                    - arm-unknown-linux-gnueabihf\n                    - armv5te-unknown-linux-gnueabi\n                    - armv7-unknown-linux-gnueabihf\n                    - powerpc-unknown-linux-gnu\n                    - powerpc64le-unknown-linux-gnu\n                    - riscv64gc-unknown-linux-gnu\n    windows-tests:\n        name: Test on Windows\n        runs-on: windows-latest\n        steps:\n            - uses: actions/checkout@v2\n            - name: Install stable Rust toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  override: true\n                  profile: minimal\n                  toolchain: stable\n            - name: Run 'cargo check'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --all-features\n            - name: Run 'cargo check --no-default-features'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --no-default-features\n            - name: Run 'cargo test'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: test\n                  args: --all-features\n    macos-tests:\n        name: Test on macOS\n        runs-on: macos-latest\n        steps:\n            - uses: actions/checkout@v2\n            - name: Install stable Rust toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  override: true\n                  profile: minimal\n                  toolchain: stable\n            - name: Run 'cargo check'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --all-features\n            - name: Run 'cargo check --no-default-features'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: check\n                  args: --no-default-features\n            - name: Run 'cargo test'\n              uses: actions-rs/cargo@v1\n              with:\n                  command: test\n                  args: --all-features\n"
  },
  {
    "path": ".gitignore",
    "content": "# RUST gitignore generated by Blindfold\n\n# Generated by Cargo\n# will have compiled files and executables\ntarget/\n\n# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries\n# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html\nCargo.lock\n\n\n# VISUALSTUDIOCODE gitignore generated by Blindfold\n\n.vscode/*\n!.vscode/tasks.json\n!.vscode/launch.json\n*.code-workspace\n\n\n# JETBRAINS gitignore generated by Blindfold\n\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff\n.idea\n\n# Gradle and Maven with auto-import\n# When using Gradle or Maven with auto-import, you should exclude module files,\n# since they will be recreated, and may cause churn.  Uncomment if using\n# auto-import.\n# .idea/artifacts\n# .idea/compiler.xml\n# .idea/jarRepositories.xml\n# .idea/modules.xml\n# .idea/*.iml\n# .idea/modules\n# *.iml\n# *.ipr\n\n# CMake\ncmake-build-*/\n\n# Mongo Explorer plugin\n.idea/**/mongoSettings.xml\n\n# File-based project format\n*.iws\n\n# IntelliJ\nout/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Editor-based Rest Client\n.idea/httpRequests\n\n# Android studio 3.1+ serialized cache file\n.idea/caches/build_file_checksums.ser\n\n\n# WINDOWS gitignore generated by Blindfold\n\n# Windows thumbnail cache files\nThumbs.db\nThumbs.db:encryptable\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder config file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n\n# MACOS gitignore generated by Blindfold\n\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n\n# LINUX gitignore generated by Blindfold\n\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n\n"
  },
  {
    "path": ".rustfmt.toml",
    "content": "hard_tabs = true"
  },
  {
    "path": ".rusty-hook.toml",
    "content": "[hooks]\ncommit-msg = \"python3 enforce-conventional-commits.py \\\"%rh!\\\"\"\npre-commit = \"cargo clippy && cargo test && cargo deny check\"\n\n[logging]\nverbose = true\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"nanorand\"\ndescription = \"A tiny, fast, zero-dep library for random number generation.\"\nrepository = \"https://github.com/Absolucy/nanorand-rs\"\nkeywords = [\"rand\", \"random\", \"no-std\", \"entropy\"]\ncategories = [\"algorithms\", \"no-std\"]\nreadme = \"README.md\"\nversion = \"0.8.0\"\nrust-version = \"1.56\"\nauthors = [\"Lucy <lucy@absolucy.moe>\"]\nedition = \"2021\"\nlicense = \"Zlib\"\n\n[features]\ndefault = [\"entropy\", \"std\", \"tls\", \"wyrand\", \"pcg64\", \"chacha\"]\nentropy = []\nalloc = []\nstd = [\"alloc\"]\ntls = [\"entropy\", \"std\", \"wyrand\"]\nwyrand = []\npcg64 = []\nchacha = []\nrdseed = [\"std\"]\n\n[dependencies]\nzeroize = { version = \"1.5\", optional = true, features = [\"zeroize_derive\"] }\n\n# optional getrandom with 'js' feature for WASM\n[target.'cfg(target_arch = \"wasm32\")'.dependencies]\ngetrandom = { version = \"0.3\", optional = true, features = [\"wasm_js\"] }\n\n# optional getrandom with 'rdrand' feature for x86(-64)\n[target.'cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))'.dependencies]\ngetrandom = { version = \"0.3\", optional = true }\n\n# optional getrandom without any features for non-WASM, non-x86 targets.\n[target.'cfg(not(any(target_arch = \"wasm32\", target_arch = \"x86\", target_arch = \"x86_64\")))'.dependencies]\ngetrandom = { version = \"0.3\", optional = true }\n\n[dev-dependencies]\nhex = \"0.4.3\"\n\n[package.metadata.docs.rs]\nall-features = true\nrustdoc-args = [\"--cfg\", \"docsrs\"]\ndefault-target = \"x86_64-unknown-linux-gnu\"\ntargets = [\"x86_64-pc-windows-msvc\"]\n\n[workspace]\nmembers = [\"nanorand-abi\", \"nanorand-bench\"]\ndefault-members = [\".\"]\n\n[profile.bench]\nlto = \"thin\"\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The zlib/libpng License\n=======================\n\nCopyright (c) 2025 Lucy <lucy@absolucy.moe>\n\nThis software is provided 'as-is', without any express or implied warranty. In\nno event will the authors be held liable for any damages arising from the use of\nthis software.\n\nPermission is granted to anyone to use this software for any purpose, including\ncommercial applications, and to alter it and redistribute it freely, subject to\nthe following restrictions:\n\n1.  The origin of this software must not be misrepresented; you must not claim\n    that you wrote the original software. If you use this software in a product,\n    an acknowledgment in the product documentation would be appreciated but is\n    not required.\n\n2.  Altered source versions must be plainly marked as such, and must not be\n    misrepresented as being the original software.\n\n3.  This notice may not be removed or altered from any source distribution.\n"
  },
  {
    "path": "README.md",
    "content": "[![crates.io](https://img.shields.io/crates/v/nanorand.svg)](https://crates.io/crates/nanorand) [![docs.rs](https://docs.rs/nanorand/badge.svg)](https://docs.rs/nanorand)  [![License: Zlib](https://img.shields.io/badge/License-Zlib-brightgreen.svg)](https://opensource.org/licenses/Zlib) [![Tests](https://github.com/Absolucy/nanorand-rs/workflows/Tests/badge.svg?event=push&branch=master)](https://github.com/Absolucy/nanorand-rs/actions?query=workflow%3A%22Run+Tests%22) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/Absolucy/nanorand-rs.svg)](https://isitmaintained.com/project/Absolucy/nanorand-rs \"Average time to resolve an issue\") [![Percentage of issues still open](https://isitmaintained.com/badge/open/Absolucy/nanorand-rs.svg)](https://isitmaintained.com/project/Absolucy/nanorand-rs \"Percentage of issues still open\") ![Maintenance](https://img.shields.io/badge/maintenance-activly--developed-brightgreen.svg)\n\n# nanorand\n\nCurrent version: **0.8.0**\n\nA library meant for fast, random number generation with quick compile time, and minimal dependencies.\n\n## Examples\n### Generating a number with an initialized RNG\n```rust\nuse nanorand::{Rng, WyRand};\n\nlet mut rng = WyRand::new();\nprintln!(\"Random number: {}\", rng.generate::<u64>());\n```\n### Generating a number with a thread-local RNG\n```rust\nuse nanorand::Rng;\n\nlet mut rng = nanorand::tls_rng();\nprintln!(\"Random number: {}\", rng.generate::<u64>());\n```\n### Generating a number in a range\n```rust\nuse nanorand::{Rng, WyRand};\n\nlet mut rng = WyRand::new();\nprintln!(\"Random number between 1 and 100: {}\", rng.generate_range(1_u64..=100));\nprintln!(\"Random number between -100 and 50: {}\", rng.generate_range(-100_i64..=50));\n```\n#### Buffering random bytes\n```rust\nuse nanorand::{Rng, BufferedRng, WyRand};\n\nlet mut thingy = [0u8; 5];\nlet mut rng = BufferedRng::new(WyRand::new());\nrng.fill(&mut thingy);\n// As WyRand generates 8 bytes of output, and our target is only 5 bytes,\n// 3 bytes will remain in the buffer.\nassert_eq!(rng.buffered(), 3);\n```\n### Shuffling a Vec\n```rust\nuse nanorand::{Rng, WyRand};\n\nlet mut rng = WyRand::new();\nlet mut items = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\nrng.shuffle(&mut items);\n```\n\n### Why should I use this over...\n\n* `rand` - The standard rand crate is a complex beast. It contains unsafe code in the core implementations, and while it has much more options than we do, that's kind of the point. We're straight to the point, while rand is everything and the kitchen sink.\n* `fastrand`, `oorandom`, `random-fast-rng`, or `randomize` - These are all minimal, zero-dep implementations of the PCG family of RNGs (Pcg32 and Pcg64). While these are decent, they are _much_ slower than wyrand (which beats the speed of these Pcg32 implementations while providing 64 random bits), and do not provide CSPRNGs.\n* `getrandom` - The getrandom crate just provides OS entropy sources. It is not meant for random number generation. In fact, we provide it as an optional entropy source.\n\n### RNG Implementations\n\n| **RNG** |                                            **nanorand type**                                            |    **Output Size**     | **Cryptographically Secure** |                    **Speed**<sup>1</sup>                     | **Notes** |                                                     **Original Implementation**                                                      |\n| :-----: | :-----------------------------------------------------------------------------------------------------: | :--------------------: | :--------------------------: | :----------------------------------------------------------: | :-------: | :----------------------------------------------------------------------------------------------------------------------------------: |\n| wyrand  | [`nanorand::WyRand`](rand/wyrand/struct.WyRand.html), [`nanorand::tls::TlsWyRand`](tls/fn.tls_rng.html) |    64 bits (`u64`)     |              🚫               |                           14 GB/s                            |           | [https://github.com/lemire/testingRNG/blob/master/source/wyrand.h](https://github.com/lemire/testingRNG/blob/master/source/wyrand.h) |\n|  Pcg64  |                            [`nanorand::Pcg64`](rand/pcg64/struct.Pcg64.html)                            |    64 bits (`u64`)     |              🚫               |                           1.6 GB/s                           |           |                                   [https://github.com/rkern/pcg64](https://github.com/rkern/pcg64)                                   |\n| ChaCha  |                          [`nanorand::ChaCha`](rand/chacha/struct.ChaCha.html)                           | 512 bits (`[u32; 16]`) |              ✅               | 980 MB/s (ChaCha8), 749 MB/s (ChaCha12), 505 MB/s (ChaCha20) |           |                                     [https://cr.yp.to/chacha.html](https://cr.yp.to/chacha.html)                                     |\n\n<sup>1. Speed benchmarked on an M1 Macbook Air</sup>\n\n### Entropy Sources\n_Listed in order of priority_\n\n* If the `getrandom` feature is enabled, then [`getrandom::getrandom`](https://docs.rs/getrandom/*/getrandom/fn.getrandom.html) will be called, and no other entropy sources will be used.\n* If the `rdseed` feature is enabled, and is running on an x86(-64) system with the [RDSEED](https://en.wikipedia.org/wiki/RDRAND) instruction, then\n  we will attempt to source as much entropy as possible via our [`rdseed_entropy`](entropy::rdseed_entropy) function\n* Linux and Android will attempt to use the [`getrandom`](https://man7.org/linux/man-pages/man2/getrandom.2.html) syscall.\n* macOS and iOS (Darwin-based systems) will use Security.framework's [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes).\n* OpenBSD will attempt to use the [`arc4random_buf`](https://man.openbsd.org/arc4random.3) function.\n* FreeBSD will attempt to use the [`arc4random_buf`](https://man.freebsd.org/cgi/man.cgi?query=arc4random_buf&sektion=3) function.\n* Windows\n  * If we're targeting UWP, then the [`BCryptGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom) is used with system-preferred RNG (`BCRYPT_USE_SYSTEM_PREFERRED_RNG`).\n  * Otherwise, we'll use [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom).\n\n### Feature Flags\n\n* `alloc` (default) - Enables Rust `alloc` lib features, such as a buffering Rng wrapper.\n* `std` (default) - Enables Rust `std` lib features, such as seeding from OS entropy sources. Requires `alloc` to be enabled.\n* `tls` (default) - Enables a thread-local [`WyRand`](rand/wyrand/struct.WyRand.html) RNG (see below). Requires `std` to be enabled.\n* `wyrand` (default) - Enable the [`WyRand`](rand/wyrand/struct.WyRand.html) RNG.\n* `pcg64` (default) - Enable the [`Pcg64`](rand/pcg64/struct.Pcg64.html)  RNG.\n* `chacha` - Enable the [`ChaCha`](rand/chacha/struct.ChaCha.html) RNG. Requires Rust 1.47 or later.\n* `rdseed` - On x86 and x86-64 platforms, the `rdseed` intrinsic will be used when OS entropy isn't available.\n* `zeroize` - Implement the [Zeroize](https://crates.io/crates/zeroize) trait for all RNGs.\n* `getrandom` - Use the [`getrandom`](https://crates.io/crates/getrandom) crate as an entropy source. Works on most systems, optional due to the fact that it brings in more dependencies.\n\n### MSRV\nThe minimum supported Rust version for the latest version of nanorand is **Rust 1.56.0**, released October 21st, 2021.\n\n## License\n\nThe zlib/libpng License\n\nCopyright (c) 2025 Lucy <lucy@absolucy.moe>\n\nThis software is provided 'as-is', without any express or implied warranty. In\nno event will the authors be held liable for any damages arising from the use of\nthis software.\n\nPermission is granted to anyone to use this software for any purpose, including\ncommercial applications, and to alter it and redistribute it freely, subject to\nthe following restrictions:\n\n1.  The origin of this software must not be misrepresented; you must not claim\n    that you wrote the original software. If you use this software in a product,\n    an acknowledgment in the product documentation would be appreciated but is\n    not required.\n\n2.  Altered source versions must be plainly marked as such, and must not be\n    misrepresented as being the original software.\n\n3.  This notice may not be removed or altered from any source distribution.\n"
  },
  {
    "path": "README.tpl",
    "content": "[![crates.io](https://img.shields.io/crates/v/nanorand.svg)](https://crates.io/crates/nanorand) [![docs.rs](https://docs.rs/nanorand/badge.svg)](https://docs.rs/nanorand)  [![License: Zlib](https://img.shields.io/badge/License-Zlib-brightgreen.svg)](https://opensource.org/licenses/Zlib) [![Tests](https://github.com/Absolucy/nanorand-rs/workflows/Tests/badge.svg?event=push&branch=master)](https://github.com/Absolucy/nanorand-rs/actions?query=workflow%3A%22Run+Tests%22) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/Absolucy/nanorand-rs.svg)](https://isitmaintained.com/project/Absolucy/nanorand-rs \"Average time to resolve an issue\") [![Percentage of issues still open](https://isitmaintained.com/badge/open/Absolucy/nanorand-rs.svg)](https://isitmaintained.com/project/Absolucy/nanorand-rs \"Percentage of issues still open\") ![Maintenance](https://img.shields.io/badge/maintenance-activly--developed-brightgreen.svg)\n\n# {{crate}}\n\nCurrent version: **{{version}}**\n\n{{readme}}\n\n## License\n\nThe zlib/libpng License\n\nCopyright (c) 2025 Lucy <lucy@absolucy.moe>\n\nThis software is provided 'as-is', without any express or implied warranty. In\nno event will the authors be held liable for any damages arising from the use of\nthis software.\n\nPermission is granted to anyone to use this software for any purpose, including\ncommercial applications, and to alter it and redistribute it freely, subject to\nthe following restrictions:\n\n1.  The origin of this software must not be misrepresented; you must not claim\n    that you wrote the original software. If you use this software in a product,\n    an acknowledgment in the product documentation would be appreciated but is\n    not required.\n\n2.  Altered source versions must be plainly marked as such, and must not be\n    misrepresented as being the original software.\n\n3.  This notice may not be removed or altered from any source distribution.\n"
  },
  {
    "path": "deny.toml",
    "content": "[advisories]\ndb-path = \"~/.cargo/advisory-db\"\ndb-urls = [\"https://github.com/rustsec/advisory-db\"]\nvulnerability = \"deny\"\nunmaintained = \"warn\"\nyanked = \"warn\"\nnotice = \"warn\"\n\n[licenses]\nunlicensed = \"deny\"\ncopyleft = \"warn\"\nallow-osi-fsf-free = \"neither\"\nconfidence-threshold = 0.8\nallow = [\n\t\"MIT\",\n\t\"Zlib\",\n\t\"Apache-2.0\",\n\t\"Unlicense\",\n\t\"0BSD\",\n\t\"BSL-1.0\",\n\t\"BSD-3-Clause\"\n]\n\n[bans]\nmultiple-versions = \"warn\"\nwildcards = \"allow\"\nhighlight = \"all\"\ndeny = [\n\t{ name = \"CoreFoundation-sys\" },\n\t{ name = \"exif\" },\n\t{ name = \"exif-sys\" },\n\t{ name = \"gphoto\" },\n\t{ name = \"gphoto2-sys\" },\n\t{ name = \"ioctl-rs\" },\n\t{ name = \"IOKit-rs\" },\n\t{ name = \"libraw\" },\n\t{ name = \"libraw-sys\" },\n\t{ name = \"libudev\" },\n\t{ name = \"libudev-sys\" },\n\t{ name = \"libusb\" },\n\t{ name = \"libusb-sys\" },\n\t{ name = \"mach\" },\n\t{ name = \"serial\" },\n\t{ name = \"serial-core\" },\n\t{ name = \"serial-unix\" },\n\t{ name = \"serial-windows\" },\n\t{ name = \"termios\" },\n\t{ name = \"zwave\" },\n]\n\n[sources]\nunknown-registry = \"warn\"\nunknown-git = \"warn\"\nallow-registry = [\"https://github.com/rust-lang/crates.io-index\"]\nallow-git = []\n"
  },
  {
    "path": "enforce-conventional-commits.py",
    "content": "#!/usr/bin/env python\nimport re, sys, os\n\ndef main():\n\t# example:\n\t# feat(apikey): added the ability to add api key to configuration\n\tpattern = r'(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)(\\([\\w\\-]+\\))?:\\s.*'\n\tfilename = sys.argv[1]\n\tss = open(filename, 'r').read()\n\tm = re.match(pattern, ss)\n\tif m == None: raise Exception(\"conventional commit validation failed\")\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "nanorand-abi/.gitignore",
    "content": "# C gitignore generated by Blindfold\n\n# Prerequisites\n*.d\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Linker output\n*.ilk\n*.map\n*.exp\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Debug files\n*.dSYM/\n*.su\n*.idb\n*.pdb\n\n# Kernel Module Compile Results\n*.mod*\n*.cmd\n.tmp_versions/\nmodules.order\nModule.symvers\nMkfile.old\ndkms.conf\n\n\n# C++ gitignore generated by Blindfold\n\n# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Linker files\n*.ilk\n\n# Debugger Files\n*.pdb\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\n\n"
  },
  {
    "path": "nanorand-abi/Cargo.toml",
    "content": "[package]\nname = \"nanorand-abi\"\ndescription = \"A stable C-compatible ABI for nanorand\"\nrepository = \"https://github.com/Absolucy/nanorand-rs\"\nkeywords = [\"rng\", \"wyrand\", \"pcg\", \"chacha\", \"random\", \"pcg64\"]\nversion = \"0.8.0\"\nauthors = [\"Lucy <lucy@absolucy.moe>\"]\nedition = \"2021\"\nlicense = \"Zlib\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\", \"staticlib\"]\n\n[dependencies]\npaste = \"1\"\n\n[dependencies.nanorand]\npath = \"..\"\ndefault-features = false\nfeatures = [\"std\", \"wyrand\", \"pcg64\", \"chacha\", \"getrandom\"]\n"
  },
  {
    "path": "nanorand-abi/examples/smallcrush.c",
    "content": "#include \"nanorand.h\"\n#include <TestU01.h>\n\nstatic BufferedChaCha20 *chacha_rng;\nstatic BufferedWyRand *wyrand_rng;\nstatic BufferedPcg64 *pcg_rng;\n\nunsigned int gen_chacha(void)\n{\n    unsigned int ret;\n    chacha20_buffered_fill(chacha_rng, &ret, sizeof(ret));\n    return ret;\n}\n\nunsigned int gen_wyrand(void)\n{\n    unsigned int ret;\n    wyrand_buffered_fill(wyrand_rng, &ret, sizeof(ret));\n    return ret;\n}\n\nunsigned int gen_pcg(void)\n{\n    unsigned int ret;\n    pcg64_buffered_fill(pcg_rng, &ret, sizeof(ret));\n    return ret;\n}\n\nint main()\n{\n    chacha_rng = chacha20_buffered(new_chacha20());\n    wyrand_rng = wyrand_buffered(new_wyrand());\n    pcg_rng = pcg64_buffered(new_pcg64());\n\n    unif01_Gen *chacha_testu01 = unif01_CreateExternGenBits(\"nanorand chacha20\", gen_chacha);\n    bbattery_SmallCrush(chacha_testu01);\n    unif01_DeleteExternGenBits(chacha_testu01);\n\n    unif01_Gen *wyrand_testu01 = unif01_CreateExternGenBits(\"nanorand wyrand\", gen_wyrand);\n    bbattery_SmallCrush(wyrand_testu01);\n    unif01_DeleteExternGenBits(wyrand_testu01);\n\n    unif01_Gen *pcg_testu01 = unif01_CreateExternGenBits(\"nanorand pcg64\", gen_pcg);\n    bbattery_SmallCrush(pcg_testu01);\n    unif01_DeleteExternGenBits(pcg_testu01);\n}\n"
  },
  {
    "path": "nanorand-abi/examples/test.cpp",
    "content": "#include \"nanorand.h\"\n#include <iostream>\n\nint main()\n{\n\tnanorand::ChaCha rng = nanorand::new_chacha20();\n\tstd::cout << nanorand::chacha_next_u16(&rng) << std::endl;\n}\n"
  },
  {
    "path": "nanorand-abi/nanorand.h",
    "content": "/*\n * Copyright (c) 2022 Lucy <lucy@absolucy.moe>\n * This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held\n * liable for any damages arising from the use of this software.\n * Permission is granted to anyone to use this software for any purpose, including commercial applications, and to\n * alter it and redistribute it freely, subject to the following restrictions:\n *   1. The origin of this software must not be misrepresented; you must not claim that you wrote the original\n *      software. If you use this software in a product, an acknowledgment in the product documentation would be\n *      appreciated but is not required.\n *   2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original\n *      software.\n *   3. This notice may not be removed or altered from any source distribution.\n */\n\n#ifndef NANORAND_H\n#define NANORAND_H\n\n#define DEFINE_NANORAND_BASE(type, buffered_type, name)                                                                \\\n    type *new_##name(void);                                                                                            \\\n    void free_##name(type *rng);                                                                                       \\\n    void name##_fill(type *rng, void *buffer, usize length);                                                           \\\n    buffered_type *name##_buffered(type *rng);                                                                         \\\n    void free_##name##_buffered(buffered_type *rng);                                                                   \\\n    void name##_buffered_fill(buffered_type *rng, void *buffer, usize length);\n\n#define DEFINE_NANORAND_RANGES(type, name)                                                                             \\\n    u8 name##_range_u8(type *rng, u8 lower, u8 upper);                                                                 \\\n    u16 name##_range_u16(type *rng, u16 lower, u16 upper);                                                             \\\n    u32 name##_range_u32(type *rng, u32 lower, u32 upper);                                                             \\\n    u64 name##_range_u64(type *rng, u64 lower, u64 upper);                                                             \\\n    usize name##_range_usize(type *rng, usize lower, usize upper);                                                     \\\n    i8 name##_range_i8(type *rng, i8 lower, i8 upper);                                                                 \\\n    i16 name##_range_i16(type *rng, i16 lower, i16 upper);                                                             \\\n    i32 name##_range_i32(type *rng, i32 lower, i32 upper);                                                             \\\n    i64 name##_range_i64(type *rng, i64 lower, i64 upper);                                                             \\\n    isize name##_range_isize(type *rng, isize lower, isize upper);\n\n#include <stdint.h>\ntypedef uint8_t u8;\ntypedef uint16_t u16;\ntypedef uint32_t u32;\ntypedef uint64_t u64;\ntypedef uintptr_t usize;\ntypedef int8_t i8;\ntypedef int16_t i16;\ntypedef int32_t i32;\ntypedef int64_t i64;\ntypedef intptr_t isize;\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n    typedef struct _WyRand WyRand;\n    typedef struct _BufferedWyRand BufferedWyRand;\n    DEFINE_NANORAND_BASE(WyRand, BufferedWyRand, wyrand);\n    DEFINE_NANORAND_RANGES(WyRand, wyrand);\n\n    typedef struct _Pcg64 Pcg64;\n    typedef struct _BufferedPcg64 BufferedPcg64;\n    DEFINE_NANORAND_BASE(Pcg64, BufferedPcg64, pcg64);\n    DEFINE_NANORAND_RANGES(Pcg64, pcg64);\n\n    typedef struct _ChaCha8 ChaCha8;\n    typedef struct _BufferedChaCha8 BufferedChaCha8;\n    DEFINE_NANORAND_BASE(ChaCha8, BufferedChaCha8, chacha8);\n    DEFINE_NANORAND_RANGES(ChaCha8, chacha8);\n\n    typedef struct _ChaCha12 ChaCha12;\n    typedef struct _BufferedChaCha12 BufferedChaCha12;\n    DEFINE_NANORAND_BASE(ChaCha12, BufferedChaCha12, chacha12);\n    DEFINE_NANORAND_RANGES(ChaCha12, chacha12);\n\n    typedef struct _ChaCha20 ChaCha20;\n    typedef struct _BufferedChaCha20 BufferedChaCha20;\n    DEFINE_NANORAND_BASE(ChaCha20, BufferedChaCha20, chacha20);\n    DEFINE_NANORAND_RANGES(ChaCha20, chacha20);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "nanorand-abi/src/chacha/chacha12.rs",
    "content": "use crate::define_c_api;\n\ndefine_c_api!(chacha12, ChaCha12, 64);\n"
  },
  {
    "path": "nanorand-abi/src/chacha/chacha20.rs",
    "content": "use crate::define_c_api;\n\ndefine_c_api!(chacha20, ChaCha20, 64);\n"
  },
  {
    "path": "nanorand-abi/src/chacha/chacha8.rs",
    "content": "use crate::define_c_api;\n\ndefine_c_api!(chacha8, ChaCha8, 64);\n"
  },
  {
    "path": "nanorand-abi/src/chacha/mod.rs",
    "content": "pub mod chacha12;\npub mod chacha20;\npub mod chacha8;\n"
  },
  {
    "path": "nanorand-abi/src/lib.rs",
    "content": "#![deny(clippy::complexity, clippy::correctness, clippy::perf, clippy::style)]\n#![allow(improper_ctypes_definitions, clippy::missing_safety_doc)]\n\npub mod chacha;\npub mod pcg64;\npub mod wyrand;\n\n#[macro_export]\nmacro_rules! define_c_api {\n\t(range, $rng_name:ident, $rng_type:ty, $num_type:ty) => {\n\t\tpaste::paste! {\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<$rng_name _range_ $num_type>](rng: *mut $rng_type, lower: $num_type, upper: $num_type) -> $num_type {\n\t\t\t\tlet rng = &mut *rng;\n\t\t\t\trng.generate_range(lower..=upper)\n\t\t\t}\n\t\t}\n\t};\n\t($name:ident, $rng_type:ty, $size:expr) => {\n\t\tpaste::paste! {\n\t\t\tuse nanorand::{BufferedRng, $rng_type, Rng};\n\n\t\t\t/// Create a new $type RNG, using system-provided entropy.\n\t\t\t/// This must be freed later with `free_$name(ptr)`!\n\t\t\t#[no_mangle]\n\t\t\tpub extern \"C\" fn [<new_ $name>]() -> *mut $rng_type {\n\t\t\t\tBox::into_raw(Box::new(<$rng_type>::new()))\n\t\t\t}\n\n\t\t\t/// Free a $type RNG.\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<free_ $name>](ptr: *mut $rng_type) {\n\t\t\t\tstd::mem::drop(Box::from_raw(ptr));\n\t\t\t}\n\n\t\t\t/// Get the raw 64-bit output from the provided RNG.\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<$name _next>](rng: *mut $rng_type) -> [u8; $size] {\n\t\t\t\t(*rng).rand()\n\t\t\t}\n\n\t\t\t/// Fill the provided buffer with random bytes.\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<$name _fill>](\n\t\t\t\trng: *mut $rng_type,\n\t\t\t\tbuffer: *mut u8,\n\t\t\t\tbuffer_length: usize,\n\t\t\t) {\n\t\t\t\tlet rng = &mut *rng;\n\t\t\t\tlet buffer = std::slice::from_raw_parts_mut(buffer, buffer_length);\n\t\t\t\trng.fill_bytes(buffer);\n\t\t\t}\n\n\t\t\tdefine_c_api!(range, $name, $rng_type, u8);\n\t\t\tdefine_c_api!(range, $name, $rng_type, u16);\n\t\t\tdefine_c_api!(range, $name, $rng_type, u32);\n\t\t\tdefine_c_api!(range, $name, $rng_type, u64);\n\t\t\tdefine_c_api!(range, $name, $rng_type, usize);\n\t\t\tdefine_c_api!(range, $name, $rng_type, i8);\n\t\t\tdefine_c_api!(range, $name, $rng_type, i16);\n\t\t\tdefine_c_api!(range, $name, $rng_type, i32);\n\t\t\tdefine_c_api!(range, $name, $rng_type, i64);\n\t\t\tdefine_c_api!(range, $name, $rng_type, isize);\n\n\t\t\t/// Wrap a $type RNG in a buffer.\n\t\t\t/// This consumes the RNG, and must be freed later with `free_$name_buffered(ptr)`!\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<$name _buffered>](rng: *mut $rng_type) -> *mut BufferedRng<$rng_type, $size> {\n\t\t\t\tlet rng = *Box::from_raw(rng);\n\t\t\t\tlet buffered = BufferedRng::new(rng);\n\t\t\t\tBox::into_raw(Box::new(buffered))\n\t\t\t}\n\n\t\t\t/// Free a buffer-wrapped $type RNG.\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<free_ $name _buffered>](ptr: *mut BufferedRng<$rng_type, $size>) {\n\t\t\t\tstd::mem::drop(Box::from_raw(ptr));\n\t\t\t}\n\n\t\t\t/// Fill the provided buffer with random bytes.\n\t\t\t#[no_mangle]\n\t\t\tpub unsafe extern \"C\" fn [<$name _buffered_fill>](\n\t\t\t\trng: *mut BufferedRng<$rng_type, $size>,\n\t\t\t\tbuffer: *mut u8,\n\t\t\t\tbuffer_length: usize\n\t\t\t) {\n\t\t\t\tlet rng = &mut *rng;\n\t\t\t\tlet buffer = std::slice::from_raw_parts_mut(buffer, buffer_length);\n\t\t\t\trng.fill_bytes(buffer);\n\t\t\t}\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "nanorand-abi/src/pcg64.rs",
    "content": "use crate::define_c_api;\n\ndefine_c_api!(pcg64, Pcg64, 8);\n"
  },
  {
    "path": "nanorand-abi/src/wyrand.rs",
    "content": "use crate::define_c_api;\n\ndefine_c_api!(wyrand, WyRand, 8);\n"
  },
  {
    "path": "nanorand-bench/Cargo.toml",
    "content": "[package]\nname = \"nanorand-bench\"\nversion = \"0.0.0\"\nauthors = [\"Lucy <lucy@absolucy.moe>\"]\nedition = \"2021\"\npublish = false\n\n[dependencies]\ncriterion = \"0.3\"\nfastrand = \"1\"\nhex = \"0.4\"\nnanorand = { path = \"..\" }\noorandom = \"11\"\nrand_chacha = \"0.3\"\nrand_core = \"0.6\"\nrand_pcg = \"0.3\"\nrandom-fast-rng = \"0.1\"\nrandomize = \"3\"\nwyhash = \"0.5\"\n\n[[bench]]\nname = \"speed\"\nharness = false\n"
  },
  {
    "path": "nanorand-bench/benches/speed.rs",
    "content": "use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};\nuse nanorand::rand::Rng;\nuse rand_core::{block::BlockRngCore, RngCore, SeedableRng};\nuse random_fast_rng::Random;\n\nfn criterion_benchmark(c: &mut Criterion) {\n\tlet mut entropy_group = c.benchmark_group(\"entropy\");\n\tentropy_group.throughput(Throughput::Bytes(std::mem::size_of::<u64>() as u64 * 4096));\n\n\tentropy_group.bench_function(\"system entropy\", |b| {\n\t\tlet mut out = [0u8; std::mem::size_of::<u64>() * 4096];\n\t\tb.iter(|| {\n\t\t\tnanorand::entropy::system(&mut out);\n\t\t})\n\t});\n\n\tentropy_group.finish();\n\n\tlet mut wyrand_group = c.benchmark_group(\"WyRand\");\n\twyrand_group.throughput(Throughput::Bytes(8));\n\n\twyrand_group.bench_function(\"nanorand\", |b| {\n\t\tlet mut rng = nanorand::rand::WyRand::new();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand());\n\t\t})\n\t});\n\n\twyrand_group.bench_function(\"wyhash\", |b| {\n\t\tlet mut seed = 42_u64;\n\t\tb.iter(|| {\n\t\t\tblack_box(wyhash::wyrng(&mut seed));\n\t\t})\n\t});\n\n\twyrand_group.finish();\n\n\tlet mut chacha_group = c.benchmark_group(\"ChaCha\");\n\t// ChaCha has 512-bit output\n\tchacha_group.throughput(Throughput::Bytes(64));\n\n\tchacha_group.bench_function(\"nanorand<8>\", |b| {\n\t\tlet mut rng = nanorand::rand::ChaCha8::new();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand());\n\t\t})\n\t});\n\n\tchacha_group.bench_function(\"nanorand<12>\", |b| {\n\t\tlet mut rng = nanorand::rand::ChaCha12::new();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand());\n\t\t})\n\t});\n\n\tchacha_group.bench_function(\"nanorand<20>\", |b| {\n\t\tlet mut rng = nanorand::rand::ChaCha20::new();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand());\n\t\t})\n\t});\n\n\tchacha_group.bench_function(\"rand_chacha<8>\", |b| {\n\t\tlet mut rng = rand_chacha::ChaCha8Core::from_seed([42; 32]);\n\t\tb.iter(|| {\n\t\t\tlet mut out = Default::default();\n\t\t\trng.generate(&mut out);\n\t\t\tblack_box(out);\n\t\t})\n\t});\n\n\tchacha_group.bench_function(\"rand_chacha<12>\", |b| {\n\t\tlet mut rng = rand_chacha::ChaCha12Core::from_seed([42; 32]);\n\t\tb.iter(|| {\n\t\t\tlet mut out = Default::default();\n\t\t\trng.generate(&mut out);\n\t\t\tblack_box(out);\n\t\t})\n\t});\n\n\tchacha_group.bench_function(\"rand_chacha<20>\", |b| {\n\t\tlet mut rng = rand_chacha::ChaCha20Core::from_seed([42; 32]);\n\t\tb.iter(|| {\n\t\t\tlet mut out = Default::default();\n\t\t\trng.generate(&mut out);\n\t\t\tblack_box(out);\n\t\t})\n\t});\n\n\tchacha_group.finish();\n\n\tlet mut pcg32_group = c.benchmark_group(\"Pcg32\");\n\tpcg32_group.throughput(Throughput::Bytes(4));\n\n\tpcg32_group.bench_function(\"oorandom\", |b| {\n\t\tlet mut rng = oorandom::Rand32::new(42);\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand_u32());\n\t\t})\n\t});\n\n\tpcg32_group.bench_function(\"randomize\", |b| {\n\t\tlet mut rng = randomize::PCG32::seed(42, 0);\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.next_u32());\n\t\t})\n\t});\n\n\tpcg32_group.bench_function(\"rand_pcg\", |b| {\n\t\tlet mut rng = rand_pcg::Pcg32::new(0xcafef00dd15ea5e5, 0xa02bdbf7bb3c0a7);\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.next_u32());\n\t\t})\n\t});\n\n\tpcg32_group.bench_function(\"random_fast_rng\", |b| {\n\t\tlet mut rng = random_fast_rng::FastRng::new();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.get_u32());\n\t\t})\n\t});\n\n\tpcg32_group.finish();\n\n\tlet mut pcg64_group = c.benchmark_group(\"Pcg64\");\n\tpcg64_group.throughput(Throughput::Bytes(8));\n\n\tpcg64_group.bench_function(\"nanorand\", |b| {\n\t\tlet mut rng = nanorand::rand::Pcg64::new();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand());\n\t\t})\n\t});\n\n\tpcg64_group.bench_function(\"oorandom\", |b| {\n\t\tlet mut rng = oorandom::Rand64::new(42);\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.rand_u64());\n\t\t})\n\t});\n\n\tpcg64_group.bench_function(\"randomize\", |b| {\n\t\tlet mut rng = randomize::PCG64::default();\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.next_u64());\n\t\t})\n\t});\n\n\tpcg64_group.bench_function(\"rand_pcg\", |b| {\n\t\tlet mut rng = rand_pcg::Pcg64::new(0xcafef00dd15ea5e5, 0xa02bdbf7bb3c0a7ac28fa16a64abf96);\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.next_u64());\n\t\t})\n\t});\n\n\tpcg64_group.bench_function(\"fastrand\", |b| {\n\t\tlet rng = fastrand::Rng::with_seed(42);\n\t\tb.iter(|| {\n\t\t\tblack_box(rng.u64(..));\n\t\t})\n\t});\n\n\tpcg64_group.finish();\n}\n\ncriterion_group!(benches, criterion_benchmark);\ncriterion_main!(benches);\n"
  },
  {
    "path": "nanorand-bench/src/main.rs",
    "content": "fn main() {\n\tprintln!(\"This is meant to be ran with `cargo bench`!\");\n}\n"
  },
  {
    "path": "nanorand-fuzz/.gitignore",
    "content": "\ntarget\ncorpus\nartifacts\n"
  },
  {
    "path": "nanorand-fuzz/Cargo.toml",
    "content": "\n[package]\nname = \"nanorand-fuzz\"\nversion = \"0.0.0\"\nauthors = [\"Automatically generated\"]\npublish = false\nedition = \"2021\"\n\n[package.metadata]\ncargo-fuzz = true\n\n[dependencies]\nlibfuzzer-sys = \"0.4.1\"\nnanorand = { path = \"..\" }\nc2-chacha = \"0.3.1\"\n\n# Prevent this from interfering with workspaces\n[workspace]\nmembers = [\".\"]\n\n[[bin]]\nname = \"chacha20\"\npath = \"fuzz_targets/chacha20.rs\"\ntest = false\ndoc = false\n\n[[bin]]\nname = \"range\"\npath = \"fuzz_targets/range.rs\"\ntest = false\ndoc = false\n"
  },
  {
    "path": "nanorand-fuzz/fuzz_targets/chacha20.rs",
    "content": "#![no_main]\nuse c2_chacha::{\n\tstream_cipher::{generic_array::GenericArray, NewStreamCipher, SyncStreamCipher},\n\tChaCha20,\n};\nuse libfuzzer_sys::fuzz_target;\nuse nanorand::crypto::chacha;\n\nconst KEY_LEN: usize = 32;\nconst NONCE_LEN: usize = 8;\n\nfuzz_target!(|data: ([u8; KEY_LEN], [u8; NONCE_LEN])| {\n\tlet (key, nonce) = data;\n\n\tlet reference_keystream = {\n\t\tlet mut state = ChaCha20::new(\n\t\t\tGenericArray::from_slice(&key),\n\t\t\tGenericArray::from_slice(&nonce),\n\t\t);\n\t\tlet mut keystream = [0u8; 256];\n\t\tstate.apply_keystream(&mut keystream);\n\t\tkeystream\n\t};\n\n\tlet our_keystream = {\n\t\tlet mut state = chacha::chacha_init(key, nonce);\n\t\tlet mut keystream: Vec<u8> = Vec::with_capacity(reference_keystream.len());\n\n\t\twhile reference_keystream.len() > keystream.len() {\n\t\t\tchacha::chacha_block(20, state)\n\t\t\t\t.iter()\n\t\t\t\t.for_each(|packed| keystream.extend_from_slice(&packed.to_le_bytes()));\n\t\t\tchacha::chacha_increment_counter(&mut state);\n\t\t}\n\t\tkeystream\n\t};\n\n\tassert_eq!(our_keystream, reference_keystream);\n});\n"
  },
  {
    "path": "nanorand-fuzz/fuzz_targets/range.rs",
    "content": "#![no_main]\nuse libfuzzer_sys::fuzz_target;\nuse nanorand::{tls_rng, Rng};\n\nfuzz_target!(|data: (u16, u16, bool)| {\n\tlet (a, b, range_type) = data;\n\tlet (lower, upper) = if a > b { (b, a) } else { (a, b) };\n\tif range_type {\n\t\tlet number = tls_rng().generate_range(lower..=upper);\n\t\tif upper == lower {\n\t\t\tassert_eq!(\n\t\t\t\tnumber, upper,\n\t\t\t\t\"{} was outside of range {}=={}\",\n\t\t\t\tnumber, lower, upper\n\t\t\t);\n\t\t} else {\n\t\t\tassert!(\n\t\t\t\tnumber >= lower,\n\t\t\t\t\"{} was bigger than range {}..={}\",\n\t\t\t\tnumber,\n\t\t\t\tlower,\n\t\t\t\tupper\n\t\t\t);\n\t\t\tassert!(\n\t\t\t\tnumber <= upper,\n\t\t\t\t\"{} was smaller than range {}..={}\",\n\t\t\t\tnumber,\n\t\t\t\tlower,\n\t\t\t\tupper\n\t\t\t);\n\t\t}\n\t} else {\n\t\tlet number = tls_rng().generate_range(lower..upper);\n\t\tif upper == lower {\n\t\t\tassert_eq!(\n\t\t\t\tnumber, upper,\n\t\t\t\t\"{} was outside of range {}=={}\",\n\t\t\t\tnumber, lower, upper\n\t\t\t);\n\t\t} else {\n\t\t\tassert!(\n\t\t\t\tnumber >= lower,\n\t\t\t\t\"{} was bigger than range {}..{}\",\n\t\t\t\tnumber,\n\t\t\t\tlower,\n\t\t\t\tupper\n\t\t\t);\n\t\t\tassert!(\n\t\t\t\tnumber < upper,\n\t\t\t\t\"{} was smaller than range {}..{}\",\n\t\t\t\tnumber,\n\t\t\t\tlower,\n\t\t\t\tupper\n\t\t\t);\n\t\t}\n\t};\n});\n"
  },
  {
    "path": "src/buffer.rs",
    "content": "use crate::rand::{Rng, SeedableRng};\nuse alloc::vec::Vec;\nuse core::default::Default;\n\n/// A buffered wrapper for any [Rng] implementation.\n/// It will keep unused bytes from the last call to [`Rng::rand`], and use them\n/// for subsequent randomness if needed, rather than throwing them away.\n///\n/// ```rust\n/// use nanorand::{Rng, BufferedRng, WyRand};\n///\n/// let mut thingy = [0u8; 5];\n/// let mut rng = BufferedRng::new(WyRand::new());\n/// rng.fill(&mut thingy);\n/// // As WyRand generates 8 bytes of output, and our target is only 5 bytes,\n/// // 3 bytes will remain in the buffer.\n/// assert_eq!(rng.buffered(), 3);\n/// ```\n#[derive(Clone)]\npub struct BufferedRng<InternalGenerator: Rng<OUTPUT>, const OUTPUT: usize> {\n\trng: InternalGenerator,\n\tbuffer: Vec<u8>,\n}\n\nimpl<InternalGenerator: Rng<OUTPUT>, const OUTPUT: usize> BufferedRng<InternalGenerator, OUTPUT> {\n\t/// Wraps a [`Rng`] InternalGenerator in a [`BufferedRng`] instance.\n\tpub const fn new(rng: InternalGenerator) -> Self {\n\t\tSelf {\n\t\t\trng,\n\t\t\tbuffer: Vec::new(),\n\t\t}\n\t}\n\n\t/// Returns the internal RNG, dropping the buffer.\n\t#[allow(clippy::missing_const_for_fn)]\n\tpub fn into_inner(self) -> InternalGenerator {\n\t\tself.rng\n\t}\n\n\t/// Returns how many unused bytes are currently buffered.\n\tpub fn buffered(&self) -> usize {\n\t\tself.buffer.len()\n\t}\n}\n\nimpl<InternalGenerator: Rng<OUTPUT>, const OUTPUT: usize> Rng<OUTPUT>\n\tfor BufferedRng<InternalGenerator, OUTPUT>\n{\n\tfn rand(&mut self) -> [u8; OUTPUT] {\n\t\tlet mut out = [0_u8; OUTPUT];\n\t\tself.fill_bytes(&mut out);\n\t\tout\n\t}\n\n\tfn fill_bytes<Bytes>(&mut self, mut output: Bytes)\n\twhere\n\t\tBytes: AsMut<[u8]>,\n\t{\n\t\tlet output = output.as_mut();\n\t\tlet mut remaining = output.len();\n\t\twhile remaining > 0 {\n\t\t\tif self.buffer.is_empty() {\n\t\t\t\tself.buffer.extend_from_slice(&self.rng.rand());\n\t\t\t}\n\t\t\tlet to_copy = core::cmp::min(remaining, self.buffer.len());\n\t\t\tlet output_len = output.len();\n\t\t\tlet start_idx = output_len - remaining;\n\t\t\toutput[start_idx..start_idx + to_copy].copy_from_slice(&self.buffer[..to_copy]);\n\t\t\tself.buffer.drain(..to_copy);\n\t\t\tremaining = remaining.saturating_sub(to_copy);\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"std\")]\nimpl<InternalGenerator: Rng<OUTPUT>, const OUTPUT: usize> std::io::Read\n\tfor BufferedRng<InternalGenerator, OUTPUT>\n{\n\tfn read(&mut self, output: &mut [u8]) -> std::io::Result<usize> {\n\t\tself.fill_bytes(&mut *output);\n\t\tOk(output.len())\n\t}\n\n\tfn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {\n\t\tbuf.extend_from_slice(&self.buffer);\n\t\tOk(self.buffer.drain(..).count())\n\t}\n\n\tfn read_to_string(&mut self, _buf: &mut String) -> std::io::Result<usize> {\n\t\tpanic!(\"attempted to read an rng into a string\")\n\t}\n}\n\nimpl<\n\t\tInternalGenerator: SeedableRng<SEED_SIZE, OUTPUT>,\n\t\tconst OUTPUT: usize,\n\t\tconst SEED_SIZE: usize,\n\t> SeedableRng<SEED_SIZE, OUTPUT> for BufferedRng<InternalGenerator, OUTPUT>\n{\n\tfn reseed(&mut self, seed: [u8; SEED_SIZE]) {\n\t\tself.rng.reseed(seed);\n\t}\n}\n\nimpl<InternalGenerator: Rng<OUTPUT> + Default, const OUTPUT: usize> Default\n\tfor BufferedRng<InternalGenerator, OUTPUT>\n{\n\tfn default() -> Self {\n\t\tSelf::new(InternalGenerator::default())\n\t}\n}\n"
  },
  {
    "path": "src/crypto/chacha.rs",
    "content": "const CHACHA_TAU: &[u8] = b\"expand 32-byte k\";\n\nfn chacha_quarter_round(state: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize) {\n\tstate[a] = state[a].wrapping_add(state[b]);\n\tstate[d] ^= state[a];\n\tstate[d] = state[d].rotate_left(16);\n\n\tstate[c] = state[c].wrapping_add(state[d]);\n\tstate[b] ^= state[c];\n\tstate[b] = state[b].rotate_left(12);\n\n\tstate[a] = state[a].wrapping_add(state[b]);\n\tstate[d] ^= state[a];\n\tstate[d] = state[d].rotate_left(8);\n\n\tstate[c] = state[c].wrapping_add(state[d]);\n\tstate[b] ^= state[c];\n\tstate[b] = state[b].rotate_left(7);\n}\n\nconst fn chacha_pack(unpacked: &[u8], idx: usize) -> u32 {\n\t(unpacked[idx] as u32)\n\t\t| ((unpacked[idx + 1] as u32) << 8)\n\t\t| ((unpacked[idx + 2] as u32) << 16)\n\t\t| ((unpacked[idx + 3] as u32) << 24)\n}\n\n/// Do one ChaCha round on the input data.\npub fn chacha_block<const ROUNDS: u8>(input: [u32; 16]) -> [u32; 16] {\n\tlet mut x = input;\n\tassert_eq!(ROUNDS % 2, 0, \"ChaCha rounds must be divisble by 2!\");\n\tfor _ in (0..ROUNDS).step_by(2) {\n\t\t// Odd rounds\n\t\tchacha_quarter_round(&mut x, 0, 4, 8, 12);\n\t\tchacha_quarter_round(&mut x, 1, 5, 9, 13);\n\t\tchacha_quarter_round(&mut x, 2, 6, 10, 14);\n\t\tchacha_quarter_round(&mut x, 3, 7, 11, 15);\n\t\t// Even rounds\n\t\tchacha_quarter_round(&mut x, 0, 5, 10, 15);\n\t\tchacha_quarter_round(&mut x, 1, 6, 11, 12);\n\t\tchacha_quarter_round(&mut x, 2, 7, 8, 13);\n\t\tchacha_quarter_round(&mut x, 3, 4, 9, 14);\n\t}\n\tx.iter_mut()\n\t\t.zip(input.iter())\n\t\t.for_each(|(l, r)| *l = l.wrapping_add(*r));\n\tx\n}\n\n/// Initialize the ChaCha internal state, with a 256-bit key and 64-bit nonce.\npub const fn chacha_init(key: [u8; 32], counter: [u8; 8], nonce: [u8; 8]) -> [u32; 16] {\n\tlet mut state = [0u32; 16];\n\tstate[0] = chacha_pack(CHACHA_TAU, 0);\n\tstate[1] = chacha_pack(CHACHA_TAU, 4);\n\tstate[2] = chacha_pack(CHACHA_TAU, 8);\n\tstate[3] = chacha_pack(CHACHA_TAU, 12);\n\n\tstate[4] = chacha_pack(&key, 0);\n\tstate[5] = chacha_pack(&key, 4);\n\tstate[6] = chacha_pack(&key, 8);\n\tstate[7] = chacha_pack(&key, 12);\n\tstate[8] = chacha_pack(&key, 16);\n\tstate[9] = chacha_pack(&key, 20);\n\tstate[10] = chacha_pack(&key, 24);\n\tstate[11] = chacha_pack(&key, 28);\n\n\t// 64-bit counter\n\tstate[12] = chacha_pack(&counter, 0);\n\tstate[13] = chacha_pack(&counter, 4);\n\t// Nonce\n\tstate[14] = chacha_pack(&nonce, 0);\n\tstate[15] = chacha_pack(&nonce, 4);\n\tstate\n}\n\n/// Increment the 64-bit counter of the internal ChaCha20 state by 1.\n/// Returns `false` if it overflows, `true` otherwise.\npub fn chacha_increment_counter(state: &mut [u32; 16]) -> bool {\n\tlet counter = ((state[13] as u64) << 32) | (state[12] as u64);\n\tmatch counter.checked_add(1) {\n\t\tSome(new_counter) => {\n\t\t\tstate[12] = (new_counter & 0xFFFFFFFF) as u32;\n\t\t\tstate[13] = ((counter >> 32) & 0xFFFFFFFF) as u32;\n\t\t\ttrue\n\t\t}\n\t\tNone => false,\n\t}\n}\n\n#[cfg(test)]\nmod tests {\n\tuse super::*;\n\tuse std::convert::TryInto;\n\n\tmacro_rules! ietf_test_vector {\n\t\t($key_hex: tt, $nonce_hex: tt, $keystream_hex: tt) => {\n\t\t\tlet key: [u8; 32] = hex::decode($key_hex).unwrap().try_into().unwrap();\n\t\t\tlet counter = [0u8; 8];\n\t\t\tlet nonce: [u8; 8] = hex::decode($nonce_hex).unwrap().try_into().unwrap();\n\t\t\tlet expected_keystream: Vec<u8> = hex::decode($keystream_hex).unwrap();\n\n\t\t\tlet mut state = chacha_init(key, counter, nonce);\n\t\t\tlet mut keystream: Vec<u8> = Vec::with_capacity(expected_keystream.len());\n\n\t\t\twhile expected_keystream.len() > keystream.len() {\n\t\t\t\tchacha_block::<20>(state)\n\t\t\t\t\t.iter()\n\t\t\t\t\t.for_each(|packed| keystream.extend_from_slice(&packed.to_le_bytes()));\n\t\t\t\tchacha_increment_counter(&mut state);\n\t\t\t}\n\t\t\tkeystream.resize(expected_keystream.len(), 0);\n\n\t\t\tassert_eq!(keystream, expected_keystream);\n\t\t};\n\t}\n\n\t#[test]\n\tfn test_ietf_chacha20_test_vectors() {\n\t\tietf_test_vector!(\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\",\n\t\t\t\"0000000000000000\",\n\t\t\t\"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586\"\n\t\t);\n\n\t\tietf_test_vector!(\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000001\",\n\t\t\t\"0000000000000000\",\n\t\t\t\"4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275ae546963\"\n\t\t);\n\n\t\tietf_test_vector!(\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\",\n\t\t\t\"0000000000000001\",\n\t\t\t\"de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e445f41e3\"\n\t\t);\n\n\t\tietf_test_vector!(\n\t\t\t\"0000000000000000000000000000000000000000000000000000000000000000\",\n\t\t\t\"0100000000000000\",\n\t\t\t\"ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d6bbdb0041b2f586b\"\n\t\t);\n\n\t\tietf_test_vector!(\n\t\t\t\"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\",\n\t\t\t\"0001020304050607\",\n\t\t\t\"f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78fab78c9\"\n\t\t);\n\t}\n}\n"
  },
  {
    "path": "src/crypto.rs",
    "content": "/// Implementation of the ChaCha cryptographic primitives.\n/// More details can be seen at <https://en.wikipedia.org/wiki/Salsa20>\npub mod chacha;\n"
  },
  {
    "path": "src/entropy/bsd.rs",
    "content": "use core::ffi::c_void;\n\nextern \"C\" {\n\tfn arc4random_buf(buf: *mut c_void, nbytes: usize);\n}\n\n/// Obtain a series of random bytes.\npub fn entropy(out: &mut [u8]) -> bool {\n\tunsafe {\n\t\tarc4random_buf(out.as_mut_ptr() as *mut c_void, out.len());\n\t\ttrue\n\t}\n}\n"
  },
  {
    "path": "src/entropy/darwin.rs",
    "content": "use core::ffi::c_void;\n\n#[link(name = \"Security\", kind = \"framework\")]\nextern \"C\" {\n\tfn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> u32;\n}\n\n/// Obtain a series of random bytes.\npub fn entropy(out: &mut [u8]) -> bool {\n\tunsafe { SecRandomCopyBytes(core::ptr::null(), out.len(), out.as_mut_ptr()) == 0 }\n}\n"
  },
  {
    "path": "src/entropy/linux.rs",
    "content": "extern \"C\" {\n\tfn getrandom(buf: *mut u8, buflen: usize, flags: u32) -> isize;\n}\n\n/// Obtain a series of random bytes.\npub fn entropy(out: &mut [u8]) -> bool {\n\tunsafe { getrandom(out.as_mut_ptr(), out.len(), 0x0001) >= 1 }\n}\n"
  },
  {
    "path": "src/entropy/windows.rs",
    "content": "use core::ffi::{c_char, c_ulong, c_void};\n\nextern \"system\" {\n\t#[link_name = \"SystemFunction036\"]\n\tfn RtlGenRandom(pBuffer: *mut c_void, cbBuffer: c_ulong) -> c_char;\n}\n\n/// Obtain a random 64-bit number using WinAPI's `RtlGenRandom` function.\npub fn entropy(out: &mut [u8]) -> bool {\n\tunsafe { RtlGenRandom(out.as_mut_ptr() as *mut c_void, out.len() as u32) == 0 }\n}\n"
  },
  {
    "path": "src/entropy/windows_uwp.rs",
    "content": "use core::{ffi::c_void, ptr};\n\nuse super::backup_entropy;\n\nconst BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;\n\nextern \"system\" {\n\tfn BCryptGenRandom(\n\t\thAlgorithm: *mut c_void,\n\t\tpBuffer: *mut u8,\n\t\tcbBuffer: usize,\n\t\tdwFlags: u32,\n\t) -> u32;\n}\n\n/// Obtain a random 64-bit number using WinAPI's `BCryptGenRandom` function.\npub fn entropy(out: &mut [u8]) -> bool {\n\tunsafe {\n\t\tBCryptGenRandom(\n\t\t\tptr::null_mut(),\n\t\t\tout.as_mut_ptr(),\n\t\t\tout.len(),\n\t\t\tBCRYPT_USE_SYSTEM_PREFERRED_RNG,\n\t\t) == 0\n\t}\n}\n"
  },
  {
    "path": "src/entropy.rs",
    "content": "#[cfg(all(\n\tany(target_os = \"openbsd\", target_os = \"freebsd\"),\n\tnot(feature = \"getrandom\")\n))]\npub use bsd::entropy as system;\n#[cfg(all(target_vendor = \"apple\", not(feature = \"getrandom\")))]\npub use darwin::entropy as system;\n#[cfg(all(\n\tany(target_os = \"linux\", target_os = \"android\"),\n\tnot(feature = \"getrandom\")\n))]\npub use linux::entropy as system;\n#[cfg(all(windows, not(target_vendor = \"uwp\"), not(feature = \"getrandom\")))]\npub use windows::entropy as system;\n#[cfg(all(windows, target_vendor = \"uwp\", not(feature = \"getrandom\")))]\npub use windows_uwp::entropy as system;\n\n#[cfg(all(\n\tany(target_os = \"linux\", target_os = \"android\"),\n\tnot(feature = \"getrandom\")\n))]\n/// An entropy generator for Linux, using libc's `getrandom` function.\npub mod linux;\n\n#[cfg(all(target_vendor = \"apple\", not(feature = \"getrandom\")))]\n/// An entropy generator for macOS/iOS, using libc's `getrandom` function.\npub mod darwin;\n\n#[cfg(all(windows, target_vendor = \"uwp\", not(feature = \"getrandom\")))]\n/// An entropy generator for Windows, using WinAPI's `BCryptGenRandom` function.\npub mod windows_uwp;\n\n#[cfg(all(windows, not(target_vendor = \"uwp\"), not(feature = \"getrandom\")))]\n/// An entropy generator for Windows, using WinAPI's `RtlGenRandom` function.\npub mod windows;\n\n#[cfg(all(\n\tany(target_os = \"openbsd\", target_os = \"freebsd\"),\n\tnot(feature = \"getrandom\")\n))]\n/// An entropy generator for OpenBSD and FreeBSD, using libc's `arc4random_buf` function.\npub mod bsd;\n\n#[cfg(feature = \"getrandom\")]\n/// Pull in system entropy using the [`getrandom`](https://crates.io/crates/getrandom) crate.\n/// Uses backup entropy (rdseed and system time) if it fails.\npub fn system(out: &mut [u8]) {\n\tmatch getrandom::fill(out) {\n\t\tOk(_) => (),\n\t\tErr(_) => backup(out),\n\t}\n}\n\n/// Pull in backup entropy (rdseed and system time).\n#[cfg(not(any(\n\tfeature = \"getrandom\",\n\ttarget_os = \"linux\",\n\ttarget_os = \"android\",\n\ttarget_os = \"openbsd\",\n\ttarget_os = \"freebsd\",\n\ttarget_vendor = \"apple\",\n\twindows\n)))]\npub fn system(out: &mut [u8]) {\n\tbackup(out);\n}\n\n#[cfg(feature = \"rdseed\")]\n#[cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))]\nfn stupid_rdseed_hack() -> Option<u64> {\n\t#[cfg(target_arch = \"x86\")]\n\tuse core::arch::x86::_rdseed64_step as rdseed;\n\t#[cfg(target_arch = \"x86_64\")]\n\tuse core::arch::x86_64::_rdseed64_step as rdseed;\n\tlet mut x = 0;\n\tfor _ in 0..10 {\n\t\tif 0 != unsafe { rdseed(&mut x) } {\n\t\t\treturn Some(x);\n\t\t}\n\t}\n\tNone\n}\n\n#[cfg(all(feature = \"rdseed\", any(target_arch = \"x86\", target_arch = \"x86_64\")))]\n/// An rdseed-based entropy source.\n/// Only works on x86/x86_64 platforms where the `rdseed` instructions are available.\n/// Returns [`None`] if `rdseed` is not available.\n/// Returns [`Some`] if it successfully managed to pull some bytes.\n/// ***VERY unreliable.***\npub fn rdseed(out: &mut [u8]) -> Option<usize> {\n\tif !std::is_x86_feature_detected!(\"rdseed\") {\n\t\treturn None;\n\t}\n\tlet amt = out.len();\n\tlet mut bytes_pulled: usize = 0;\n\n\tlet rdseed_amt = ((amt + core::mem::size_of::<u64>() - 1) / core::mem::size_of::<u64>()).max(0);\n\tfor n in 0..rdseed_amt {\n\t\tlet seed = match stupid_rdseed_hack() {\n\t\t\tSome(s) => s,\n\t\t\tNone => return Some(bytes_pulled),\n\t\t};\n\t\tlet x = seed.to_ne_bytes();\n\t\tbytes_pulled += x.len();\n\t\tx.iter()\n\t\t\t.enumerate()\n\t\t\t.for_each(|(i, val)| out[(core::mem::size_of::<u64>() * n) + i] = *val);\n\t}\n\tSome(bytes_pulled)\n}\n\n/// A wrapper function for non-x86(64) platforms that do not have rdseed.\n#[cfg(any(\n\tnot(feature = \"rdseed\"),\n\tnot(any(target_arch = \"x86\", target_arch = \"x86_64\"))\n))]\npub fn rdseed(_out: &mut [u8]) -> Option<usize> {\n\tNone\n}\n\n#[cfg(feature = \"std\")]\n/// A backup entropy source, trying rdseed first,\n/// and if it fails or does not complete, combining it with or\n/// using system time-based entropy generation.\n///\n/// # Panics\n///\n/// This function panics if sufficient entropy could not be obtained.\npub fn backup(out: &mut [u8]) {\n\tif let Some(amt) = rdseed(out) {\n\t\tif amt >= out.len() {\n\t\t\treturn;\n\t\t}\n\t};\n\n\tpanic!(\"Failed to source sufficient entropy!\")\n}\n\n#[cfg(not(feature = \"std\"))]\n/// This just panics.\npub fn backup(_: &mut [u8]) {\n\tpanic!(\"Failed to source any entropy!\")\n}\n"
  },
  {
    "path": "src/gen.rs",
    "content": "use crate::Rng;\nuse core::ops::{Bound, RangeBounds};\n\nmacro_rules! gen {\n\t($($type:ty),+) => {\n\t\t$(\n\t\t\timpl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for $type {\n\t\t\t\tfn random(rng: &mut Generator) -> Self {\n\t\t\t\t\tlet mut bytes = [0u8; core::mem::size_of::<$type>()];\n\t\t\t\t\trng.fill_bytes(&mut bytes);\n\t\t\t\t\tSelf::from_ne_bytes(bytes)\n\t\t\t\t}\n\t\t\t}\n\t\t)+\n\t};\n}\n\nmacro_rules! range {\n\t($(($type:ty, $bigger:ty, $signed:ty)),+) => {\n\t\t$(\n\t\t\timpl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomRange<Generator, OUTPUT> for $type {\n\t\t\t\tfn random_range<Bounds: RangeBounds<Self>>(rng: &mut Generator, bounds: Bounds) -> Self {\n\t\t\t\t\tconst BITS: $bigger = core::mem::size_of::<$type>() as $bigger * 8;\n\t\t\t\t\tlet lower = match bounds.start_bound() {\n\t\t\t\t\t\tBound::Included(lower) => *lower,\n\t\t\t\t\t\tBound::Excluded(lower) => lower.saturating_add(1),\n\t\t\t\t\t\tBound::Unbounded => <$type>::MIN,\n\t\t\t\t\t};\n\t\t\t\t\tlet upper = match bounds.end_bound() {\n\t\t\t\t\t\tBound::Included(upper) => upper.saturating_add(1),\n\t\t\t\t\t\tBound::Excluded(upper) => *upper,\n\t\t\t\t\t\tBound::Unbounded => <$type>::MAX,\n\t\t\t\t\t};\n\t\t\t\t\tassert!(upper >= lower, \"{} >= {} (lower bound was bigger than upper bound)\", upper, lower);\n\t\t\t\t\tlet upper = upper.saturating_sub(lower);\n\t\t\t\t\tlet mut value = Self::random(rng);\n\t\t\t\t\tlet mut m = (upper as $bigger).wrapping_mul(value as $bigger);\n\t\t\t\t\tif (m as $type) < upper {\n\t\t\t\t\t\tlet t = (!upper + 1) % upper;\n\t\t\t\t\t\twhile (m as $type) < t {\n\t\t\t\t\t\t\tvalue = Self::random(rng);\n\t\t\t\t\t\t\tm = (upper as $bigger).wrapping_mul(value as $bigger);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t(m >> BITS) as $type + lower\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timpl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomRange<Generator, OUTPUT> for $signed {\n\t\t\t\tfn random_range<Bounds: RangeBounds<Self>>(r: &mut Generator, bounds: Bounds) -> Self {\n\t\t\t\t\tlet lower = match bounds.start_bound() {\n\t\t\t\t\t\tBound::Included(lower) => *lower,\n\t\t\t\t\t\tBound::Excluded(lower) => lower.saturating_add(1),\n\t\t\t\t\t\tBound::Unbounded => <$signed>::MIN\n\t\t\t\t\t};\n\t\t\t\t\tlet upper = match bounds.end_bound() {\n\t\t\t\t\t\tBound::Included(upper) => *upper,\n\t\t\t\t\t\tBound::Excluded(upper) => upper.saturating_sub(1),\n\t\t\t\t\t\tBound::Unbounded => <$signed>::MAX,\n\t\t\t\t\t};\n\t\t\t\t\tassert!(upper >= lower, \"{} >= {} (lower bound was bigger than upper bound)\", upper, lower);\n\t\t\t\t\tlet lower = lower.wrapping_sub(<$signed>::MIN) as $type;\n\t\t\t\t\tlet upper = upper.wrapping_sub(<$signed>::MIN) as $type;\n\t\t\t\t\t<$type>::random_range(r, lower..=upper).wrapping_add(<$signed>::MIN as $type) as $signed\n\t\t\t\t}\n\t\t\t}\n\t\t)+\n\t}\n}\n\n/// A trait used for generating a random object with an RNG,\npub trait RandomGen<Generator: Rng<OUTPUT>, const OUTPUT: usize> {\n\t/// Return a random instance of the implementing type, from the specified RNG instance.\n\tfn random(rng: &mut Generator) -> Self;\n}\n\n/// A trait used for generating a random number within a range, with an RNG,\npub trait RandomRange<Generator: Rng<OUTPUT>, const OUTPUT: usize>:\n\tRandomGen<Generator, OUTPUT>\n{\n\t/// Return a ranged number of the implementing type, from the specified RNG instance.\n\t///\n\t/// # Panics\n\t/// This function will panic if the lower bound of the range is greater than the upper bound.\n\tfn random_range<Bounds: RangeBounds<Self>>(nng: &mut Generator, range: Bounds) -> Self;\n}\n\nimpl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for bool {\n\tfn random(rng: &mut Generator) -> Self {\n\t\tu8::random(rng) < 0b10000000\n\t}\n}\n\nimpl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for f32 {\n\tfn random(rng: &mut Generator) -> Self {\n\t\t(u32::random(rng) as f32) / (u32::MAX as f32)\n\t}\n}\n\nimpl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for f64 {\n\tfn random(rng: &mut Generator) -> Self {\n\t\t(u64::random(rng) as f64) / (u64::MAX as f64)\n\t}\n}\n\ngen!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);\nrange!(\n\t(u8, u16, i8),\n\t(u16, u32, i16),\n\t(u32, u64, i32),\n\t(u64, u128, i64)\n);\n#[cfg(target_pointer_width = \"16\")]\nrange!((usize, u32, isize));\n#[cfg(target_pointer_width = \"32\")]\nrange!((usize, u64, isize));\n#[cfg(target_pointer_width = \"64\")]\nrange!((usize, u128, isize));\n\n#[cfg(test)]\nmod tests {\n\tuse crate::{Rng, WyRand};\n\t#[test]\n\tfn ensure_unsigned_in_range() {\n\t\tlet mut rng = WyRand::new();\n\t\tfor _ in 0..1000 {\n\t\t\tlet number = rng.generate_range(10_u64..=20);\n\t\t\tassert!(\n\t\t\t\t(10..=20).contains(&number),\n\t\t\t\t\"{} was outside of 10..=20\",\n\t\t\t\tnumber\n\t\t\t);\n\n\t\t\tlet number = rng.generate_range(10_u64..30);\n\t\t\tassert!(\n\t\t\t\t(10..30).contains(&number),\n\t\t\t\t\"{} was outside of 10..30\",\n\t\t\t\tnumber\n\t\t\t);\n\n\t\t\tlet number = rng.generate_range(512_u64..);\n\t\t\tassert!((512..).contains(&number), \"{} was outside of 512..\", number);\n\n\t\t\tlet number = rng.generate_range(..1024_u64);\n\t\t\tassert!(\n\t\t\t\t(..1024).contains(&number),\n\t\t\t\t\"{} was outside of ..1024\",\n\t\t\t\tnumber\n\t\t\t);\n\n\t\t\tlet number = rng.generate_range(0u64..1);\n\t\t\tassert!(\n\t\t\t\t(0u64..1).contains(&number),\n\t\t\t\t\"{} was outside of 0..1\",\n\t\t\t\tnumber\n\t\t\t);\n\t\t}\n\t}\n\t#[test]\n\tfn ensure_signed_in_range() {\n\t\tlet mut rng = WyRand::new();\n\t\tfor _ in 0..1000 {\n\t\t\tlet number = rng.generate_range(-50..);\n\t\t\tassert!((-50..).contains(&number), \"{} was outside of -50..\", number);\n\n\t\t\tlet number = rng.generate_range(..512);\n\t\t\tassert!((..512).contains(&number), \"{} was outside of ..512\", number);\n\n\t\t\tlet number = rng.generate_range(..-32);\n\t\t\tassert!((..-32).contains(&number), \"{} was outside of ..-32\", number);\n\n\t\t\tlet number = rng.generate_range(1..3);\n\t\t\tassert!((1..3).contains(&number), \"{} was outside of 1..3\", number);\n\n\t\t\tlet number = rng.generate_range(-3..3);\n\t\t\tassert!((-3..3).contains(&number), \"{} was outside of -3..3\", number);\n\n\t\t\tlet number = rng.generate_range(-13..=-12);\n\t\t\tassert!(\n\t\t\t\t(-13..=-12).contains(&number),\n\t\t\t\t\"{} was outside of -13..=-12\",\n\t\t\t\tnumber\n\t\t\t);\n\n\t\t\tlet number = rng.generate_range(0..1);\n\t\t\tassert!((0..1).contains(&number), \"{} was outside of 0..1\", number);\n\t\t}\n\t}\n\n\t#[test]\n\tfn ensure_floats_generate_properly() {\n\t\tlet mut rng = WyRand::new();\n\t\tfor _ in 0..1000 {\n\t\t\tlet number = rng.generate::<f32>();\n\t\t\tassert!(1.0 >= number, \"{} was bigger than 1.0\", number);\n\t\t\tassert!(number >= 0.0, \"0 was bigger than {}\", number);\n\n\t\t\tlet number = rng.generate::<f64>();\n\t\t\tassert!(1.0 >= number, \"{} was bigger than 1.0\", number);\n\t\t\tassert!(number >= 0.0, \"0 was bigger than {}\", number);\n\t\t}\n\t}\n\n\t#[test]\n\t#[should_panic]\n\tfn ensure_invalid_range_panics() {\n\t\tlet mut rng = WyRand::new();\n\t\t#[allow(clippy::reversed_empty_ranges)]\n\t\trng.generate_range(10..=5);\n\t}\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![cfg_attr(not(feature = \"std\"), no_std)]\n#![cfg_attr(docsrs, feature(doc_auto_cfg))]\n#![forbid(missing_docs)]\n#![warn(\n\tclippy::perf,\n\tclippy::complexity,\n\tclippy::style,\n\tclippy::correctness,\n\tclippy::missing_const_for_fn\n)]\n\n//! A library meant for fast, random number generation with quick compile time, and minimal dependencies.\n//!\n//! # Examples\n//! ## Generating a number with an initialized RNG\n//! ```rust\n//! use nanorand::{Rng, WyRand};\n//!\n//! let mut rng = WyRand::new();\n//! println!(\"Random number: {}\", rng.generate::<u64>());\n//! ```\n//! ## Generating a number with a thread-local RNG\n//! ```rust\n//! use nanorand::Rng;\n//!\n//! let mut rng = nanorand::tls_rng();\n//! println!(\"Random number: {}\", rng.generate::<u64>());\n//! ```\n//! ## Generating a number in a range\n//! ```rust\n//! use nanorand::{Rng, WyRand};\n//!\n//! let mut rng = WyRand::new();\n//! println!(\"Random number between 1 and 100: {}\", rng.generate_range(1_u64..=100));\n//! println!(\"Random number between -100 and 50: {}\", rng.generate_range(-100_i64..=50));\n//! ```\n//! ### Buffering random bytes\n//! ```rust\n//! use nanorand::{Rng, BufferedRng, WyRand};\n//!\n//! let mut thingy = [0u8; 5];\n//! let mut rng = BufferedRng::new(WyRand::new());\n//! rng.fill(&mut thingy);\n//! // As WyRand generates 8 bytes of output, and our target is only 5 bytes,\n//! // 3 bytes will remain in the buffer.\n//! assert_eq!(rng.buffered(), 3);\n//! ```\n//! ## Shuffling a Vec\n//! ```rust\n//! use nanorand::{Rng, WyRand};\n//!\n//! let mut rng = WyRand::new();\n//! let mut items = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n//! rng.shuffle(&mut items);\n//! ```\n//!\n//! ## Why should I use this over...\n//!\n//! * `rand` - The standard rand crate is a complex beast. It contains unsafe code in the core implementations, and while it has much more options than we do, that's kind of the point. We're straight to the point, while rand is everything and the kitchen sink.\n//! * `fastrand`, `oorandom`, `random-fast-rng`, or `randomize` - These are all minimal, zero-dep implementations of the PCG family of RNGs (Pcg32 and Pcg64). While these are decent, they are _much_ slower than wyrand (which beats the speed of these Pcg32 implementations while providing 64 random bits), and do not provide CSPRNGs.\n//! * `getrandom` - The getrandom crate just provides OS entropy sources. It is not meant for random number generation. In fact, we provide it as an optional entropy source.\n//!\n//! ## RNG Implementations\n//!\n//! **RNG**|**nanorand type**|**Output Size**|**Cryptographically Secure**|**Speed**<sup>1</sup>|**Notes**|**Original Implementation**\n//! :-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:\n//! wyrand|[`nanorand::WyRand`](rand/wyrand/struct.WyRand.html), [`nanorand::tls::TlsWyRand`](tls/fn.tls_rng.html)|64 bits (`u64`)|🚫|14 GB/s||[https://github.com/lemire/testingRNG/blob/master/source/wyrand.h](https://github.com/lemire/testingRNG/blob/master/source/wyrand.h)\n//! Pcg64|[`nanorand::Pcg64`](rand/pcg64/struct.Pcg64.html)|64 bits (`u64`)|🚫|1.6 GB/s||[https://github.com/rkern/pcg64](https://github.com/rkern/pcg64)\n//! ChaCha|[`nanorand::ChaCha`](rand/chacha/struct.ChaCha.html)|512 bits (`[u32; 16]`)|✅|980 MB/s (ChaCha8), 749 MB/s (ChaCha12), 505 MB/s (ChaCha20)||[https://cr.yp.to/chacha.html](https://cr.yp.to/chacha.html)\n//!\n//! <sup>1. Speed benchmarked on an M1 Macbook Air</sup>\n//!\n//! ## Entropy Sources\n//! _Listed in order of priority_\n//!\n//! * If the `getrandom` feature is enabled, then [`getrandom::getrandom`](https://docs.rs/getrandom/*/getrandom/fn.getrandom.html) will be called, and no other entropy sources will be used.\n//! * If the `rdseed` feature is enabled, and is running on an x86(-64) system with the [RDSEED](https://en.wikipedia.org/wiki/RDRAND) instruction, then\n//!   we will attempt to source as much entropy as possible via our [`rdseed_entropy`](entropy::rdseed_entropy) function\n//! * Linux and Android will attempt to use the [`getrandom`](https://man7.org/linux/man-pages/man2/getrandom.2.html) syscall.\n//! * macOS and iOS (Darwin-based systems) will use Security.framework's [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes).\n//! * OpenBSD will attempt to use the [`arc4random_buf`](https://man.openbsd.org/arc4random.3) function.\n//! * Windows\n//!   * If we're targeting UWP, then the [`BCryptGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom) is used with system-preferred RNG (`BCRYPT_USE_SYSTEM_PREFERRED_RNG`).\n//!   * Otherwise, we'll use [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom).\n//!\n//! ## Feature Flags\n//!\n//! * `alloc` (default) - Enables Rust `alloc` lib features, such as a buffering Rng wrapper.\n//! * `entropy` (default) - Allows sourcing entropy from the system. Implied by `getrandom`, too.\n//! * `std` (default) - Enables Rust `std` lib features, such as seeding from OS entropy sources. Requires `alloc` to be enabled.\n//! * `tls` (default) - Enables a thread-local [`WyRand`](rand/wyrand/struct.WyRand.html) RNG (see below). Requires `std` to be enabled.\n//! * `wyrand` (default) - Enable the [`WyRand`](rand/wyrand/struct.WyRand.html) RNG.\n//! * `pcg64` (default) - Enable the [`Pcg64`](rand/pcg64/struct.Pcg64.html)  RNG.\n//! * `chacha` - Enable the [`ChaCha`](rand/chacha/struct.ChaCha.html) RNG. Requires Rust 1.47 or later.\n//! * `rdseed` - On x86 and x86-64 platforms, the `rdseed` intrinsic will be used when OS entropy isn't available.\n//! * `zeroize` - Implement the [Zeroize](https://crates.io/crates/zeroize) trait for all RNGs.\n//! * `getrandom` - Use the [`getrandom`](https://crates.io/crates/getrandom) crate as an entropy source. Works on most systems, optional due to the fact that it brings in more dependencies.\n//!\n//! ## MSRV\n//! The minimum supported Rust version for the latest version of nanorand is **Rust 1.56.0**, released October 21st, 2021.\n\n#[cfg(feature = \"alloc\")]\nextern crate alloc;\n\n#[cfg(feature = \"alloc\")]\npub use buffer::BufferedRng;\npub use gen::*;\npub use rand::*;\n#[cfg(feature = \"tls\")]\npub use tls::tls_rng;\n\n#[cfg(feature = \"alloc\")]\n/// Provides a buffered wrapper for RNGs, preventing bits from being wasted.\npub mod buffer;\n/// Implementation of cryptography, for CSPRNGs.\npub mod crypto;\n/// Sources for obtaining entropy.\n#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\npub mod entropy;\n/// Traits for generating types from an RNG.\npub mod gen;\n/// RNG algorithms.\npub mod rand;\n#[cfg(feature = \"tls\")]\n/// Provides a thread-local [`WyRand`] RNG.\npub mod tls;\n"
  },
  {
    "path": "src/rand/chacha.rs",
    "content": "use crate::{\n\tcrypto::chacha,\n\trand::{Rng, SeedableRng},\n};\nuse core::fmt::{self, Debug, Display, Formatter};\n#[cfg(feature = \"zeroize\")]\nuse zeroize::Zeroize;\n\n/// The ChaCha CSPRNG, with 8 rounds.\npub type ChaCha8 = ChaCha<8>;\n\n/// The ChaCha CSPRNG, with 12 rounds.\npub type ChaCha12 = ChaCha<12>;\n\n/// The ChaCha CSPRNG, with 20 rounds.\npub type ChaCha20 = ChaCha<20>;\n\n/// An instance of the ChaCha random number generator.\n/// Seeded from the system entropy generator when available.\n/// **This generator _is theoretically_ cryptographically secure.**\n#[cfg_attr(feature = \"zeroize\", derive(Zeroize))]\n#[cfg_attr(feature = \"zeroize\", zeroize(drop))]\npub struct ChaCha<const ROUNDS: u8> {\n\tstate: [u32; 16],\n}\n\nimpl<const ROUNDS: u8> ChaCha<ROUNDS> {\n\t/// Create a new [`ChaCha`] instance, seeding from the system's default source of entropy.\n\t#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\n\t#[must_use]\n\tpub fn new() -> Self {\n\t\tlet mut key: [u8; 32] = Default::default();\n\t\tcrate::entropy::system(&mut key);\n\t\tlet counter = [0u8; 8];\n\t\tlet mut nonce: [u8; 8] = Default::default();\n\t\tcrate::entropy::system(&mut nonce);\n\t\tlet state = chacha::chacha_init(key, counter, nonce);\n\t\tSelf { state }\n\t}\n\n\t/// Create a new [`ChaCha`] instance, using the provided key and nonce.\n\t#[must_use]\n\tpub const fn new_key(key: [u8; 32], counter: [u8; 8], nonce: [u8; 8]) -> Self {\n\t\tlet state = chacha::chacha_init(key, counter, nonce);\n\t\tSelf { state }\n\t}\n}\n\n#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\nimpl<const ROUNDS: u8> Default for ChaCha<ROUNDS> {\n\tfn default() -> Self {\n\t\tlet mut key: [u8; 32] = Default::default();\n\t\tcrate::entropy::system(&mut key);\n\t\tlet counter = [0u8; 8];\n\t\tlet mut nonce: [u8; 8] = Default::default();\n\t\tcrate::entropy::system(&mut nonce);\n\t\tlet state = chacha::chacha_init(key, counter, nonce);\n\t\tSelf { state }\n\t}\n}\n\nimpl<const ROUNDS: u8> Rng<64> for ChaCha<ROUNDS> {\n\tfn rand(&mut self) -> [u8; 64] {\n\t\tlet block = chacha::chacha_block::<ROUNDS>(self.state);\n\t\tlet mut ret = [0_u8; 64];\n\t\tblock.iter().enumerate().for_each(|(idx, num)| {\n\t\t\tlet x = num.to_ne_bytes();\n\t\t\tlet n = idx * 4;\n\t\t\tret[n] = x[0];\n\t\t\tret[n + 1] = x[1];\n\t\t\tret[n + 2] = x[2];\n\t\t\tret[n + 3] = x[3];\n\t\t});\n\t\t// Now, we're going to just increment our counter so we get an entirely new output next time.\n\t\t// If the counter overflows, we just reseed entirely instead.\n\t\tif !chacha::chacha_increment_counter(&mut self.state) {\n\t\t\tlet mut new_seed: [u8; 40] = [42_u8; 40];\n\t\t\tcrate::entropy::system(&mut new_seed);\n\t\t\tself.reseed(new_seed);\n\t\t}\n\t\tret\n\t}\n}\n\nimpl<const ROUNDS: u8> Clone for ChaCha<ROUNDS> {\n\tfn clone(&self) -> Self {\n\t\tSelf { state: self.state }\n\t}\n}\n\nimpl<const ROUNDS: u8> Display for ChaCha<ROUNDS> {\n\tfn fmt(&self, f: &mut Formatter) -> fmt::Result {\n\t\twrite!(f, \"ChaCha ({:p}, {} rounds)\", self, ROUNDS)\n\t}\n}\n\nimpl<const ROUNDS: u8> SeedableRng<40, 64> for ChaCha<ROUNDS> {\n\tfn reseed(&mut self, seed: [u8; 40]) {\n\t\tlet mut key = [0_u8; 32];\n\t\tlet mut nonce = [0_u8; 8];\n\t\tkey.copy_from_slice(&seed[..32]);\n\t\tlet counter = [0u8; 8];\n\t\tnonce.copy_from_slice(&seed[32..]);\n\t\tself.state = chacha::chacha_init(key, counter, nonce);\n\t}\n}\n\nimpl<const ROUNDS: u8> Debug for ChaCha<ROUNDS> {\n\tfn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n\t\tlet counter = ((self.state[13] as u64) << 32) | (self.state[12] as u64);\n\t\tf.debug_struct(\"ChaCha20\")\n\t\t\t.field(\"rounds\", &ROUNDS)\n\t\t\t.field(\"counter\", &counter)\n\t\t\t.finish()\n\t}\n}\n"
  },
  {
    "path": "src/rand/pcg64.rs",
    "content": "// Based off Robert Kern's C implementation at https://github.com/rkern/pcg64/blob/master/pcg64.c\n\nuse crate::rand::{Rng, SeedableRng};\nuse core::fmt::{self, Debug, Display, Formatter};\n#[cfg(feature = \"zeroize\")]\nuse zeroize::Zeroize;\n\nconst PCG_DEFAULT_MULTIPLIER_128: u128 = 47026247687942121848144207491837523525;\n\n/// An instance of the Pcg64 random number generator.\n/// Seeded from the system entropy generator when available.\n/// **This generator is _NOT_ cryptographically secure.**\n#[cfg_attr(feature = \"zeroize\", derive(Zeroize))]\n#[cfg_attr(feature = \"zeroize\", zeroize(drop))]\npub struct Pcg64 {\n\tseed: u128,\n\tstate: u128,\n\tinc: u128,\n}\n\nimpl Pcg64 {\n\t/// Create a new [`Pcg64`] instance, seeding from the system's default source of entropy.\n\t#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\n\t#[must_use]\n\tpub fn new() -> Self {\n\t\tlet mut entropy: [u8; core::mem::size_of::<u128>()] = Default::default();\n\t\tcrate::entropy::system(&mut entropy);\n\t\tSelf {\n\t\t\tseed: u128::from_ne_bytes(entropy),\n\t\t\tinc: 0,\n\t\t\tstate: 0,\n\t\t}\n\t}\n\n\t/// Create a new [`Pcg64`] instance, using a provided seed.\n\t#[must_use]\n\tpub const fn new_seed(seed: u128) -> Self {\n\t\tSelf {\n\t\t\tseed,\n\t\t\tinc: 0,\n\t\t\tstate: 0,\n\t\t}\n\t}\n\n\tfn step(&mut self) {\n\t\tself.state = self\n\t\t\t.state\n\t\t\t.wrapping_mul(PCG_DEFAULT_MULTIPLIER_128)\n\t\t\t.wrapping_add(self.inc);\n\t}\n\n\tfn rand128(&mut self) -> u64 {\n\t\tself.state = 0;\n\t\tself.inc = self.seed.wrapping_shl(1) | 1;\n\t\tself.step();\n\t\tself.state = self.state.wrapping_add(self.seed);\n\t\tself.step();\n\t\tself.step();\n\t\tself.state.wrapping_shr(64) as u64 ^ self.state as u64\n\t}\n}\n\n#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\nimpl Default for Pcg64 {\n\t/// Create a new [`Pcg64`] instance, seeding from the system's default source of entropy.\n\tfn default() -> Self {\n\t\tlet mut entropy: [u8; core::mem::size_of::<u128>()] = Default::default();\n\t\tcrate::entropy::system(&mut entropy);\n\t\tSelf {\n\t\t\tseed: u128::from_ne_bytes(entropy),\n\t\t\tinc: 0,\n\t\t\tstate: 0,\n\t\t}\n\t}\n}\n\nimpl Rng<8> for Pcg64 {\n\tfn rand(&mut self) -> [u8; 8] {\n\t\tlet ret = self.rand128();\n\t\tself.seed = self.state ^ (ret as u128).wrapping_shr(64);\n\t\tret.to_ne_bytes()\n\t}\n}\n\nimpl SeedableRng<16, 8> for Pcg64 {\n\tfn reseed(&mut self, seed: [u8; 16]) {\n\t\tself.seed = u128::from_ne_bytes(seed);\n\t}\n}\n\nimpl Clone for Pcg64 {\n\tfn clone(&self) -> Self {\n\t\tSelf {\n\t\t\tseed: self.seed,\n\t\t\tinc: self.inc,\n\t\t\tstate: self.state,\n\t\t}\n\t}\n}\n\nimpl Display for Pcg64 {\n\tfn fmt(&self, f: &mut Formatter) -> fmt::Result {\n\t\twrite!(f, \"Pcg64 ({:p})\", self)\n\t}\n}\n\nimpl Debug for Pcg64 {\n\tfn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n\t\tf.debug_struct(\"Pcg64\")\n\t\t\t.field(\"seed\", &format_args!(\"0x{:x}\", self.seed))\n\t\t\t.field(\"state\", &format_args!(\"0x{:x}\", self.state))\n\t\t\t.field(\"inc\", &format_args!(\"0x{:x}\", self.inc))\n\t\t\t.finish()\n\t}\n}\n"
  },
  {
    "path": "src/rand/wyrand.rs",
    "content": "// Based off lemire's wyrand C++ code at https://github.com/lemire/testingRNG/blob/master/source/wyrand.h\n\nuse crate::rand::{Rng, SeedableRng};\nuse core::fmt::{self, Debug, Display, Formatter};\n#[cfg(feature = \"zeroize\")]\nuse zeroize::Zeroize;\n\n/// An instance of the WyRand random number generator.\n/// Seeded from the system entropy generator when available.\n/// **This generator is _NOT_ cryptographically secure.**\n#[cfg_attr(feature = \"zeroize\", derive(Zeroize))]\n#[cfg_attr(feature = \"zeroize\", zeroize(drop))]\npub struct WyRand {\n\tseed: u64,\n}\n\nimpl WyRand {\n\t/// Create a new [`WyRand`] instance, seeding from the system's default source of entropy.\n\t#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\n\t#[must_use]\n\tpub fn new() -> Self {\n\t\tSelf::default()\n\t}\n\n\t/// Create a new [`WyRand`] instance, using a provided seed.\n\t#[must_use]\n\tpub const fn new_seed(seed: u64) -> Self {\n\t\tSelf { seed }\n\t}\n}\n\n#[cfg(any(feature = \"entropy\", feature = \"getrandom\"))]\nimpl Default for WyRand {\n\t/// Create a new [`WyRand`] instance, seeding from the system's default source of entropy.\n\tfn default() -> Self {\n\t\tlet mut entropy: [u8; core::mem::size_of::<u64>()] = Default::default();\n\t\tcrate::entropy::system(&mut entropy);\n\t\tSelf {\n\t\t\tseed: u64::from_ne_bytes(entropy),\n\t\t}\n\t}\n}\n\nimpl Rng<8> for WyRand {\n\tfn rand(&mut self) -> [u8; 8] {\n\t\tself.seed = self.seed.wrapping_add(0xa0761d6478bd642f);\n\t\tlet t: u128 = (self.seed as u128).wrapping_mul((self.seed ^ 0xe7037ed1a0b428db) as u128);\n\t\tlet ret = (t.wrapping_shr(64) ^ t) as u64;\n\t\tret.to_ne_bytes()\n\t}\n}\n\nimpl Clone for WyRand {\n\tfn clone(&self) -> Self {\n\t\tSelf { seed: self.seed }\n\t}\n}\n\nimpl Display for WyRand {\n\tfn fmt(&self, f: &mut Formatter) -> fmt::Result {\n\t\twrite!(f, \"WyRand ({:p})\", self)\n\t}\n}\n\nimpl Debug for WyRand {\n\tfn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n\t\tf.debug_struct(\"WyRand\")\n\t\t\t.field(\"seed\", &format_args!(\"0x{:x}\", self.seed))\n\t\t\t.finish()\n\t}\n}\n\nimpl SeedableRng<8, 8> for WyRand {\n\tfn reseed(&mut self, seed: [u8; 8]) {\n\t\tself.seed = u64::from_ne_bytes(seed);\n\t}\n}\n"
  },
  {
    "path": "src/rand.rs",
    "content": "#[cfg(feature = \"chacha\")]\npub use chacha::{ChaCha, ChaCha12, ChaCha20, ChaCha8};\n#[cfg(feature = \"pcg64\")]\npub use pcg64::Pcg64;\n#[cfg(feature = \"wyrand\")]\npub use wyrand::WyRand;\n\nuse crate::gen::{RandomGen, RandomRange};\nuse core::ops::RangeBounds;\n\n/// Implementation of the wyrand PRNG algorithm.\n/// More details can be seen at <https://github.com/wangyi-fudan/wyhash>\n#[cfg(feature = \"wyrand\")]\npub mod wyrand;\n\n/// Implementation of the Pcg64 PRNG algorithm.\n/// More details can be seen at <https://www.pcg-random.org/index.html>\n#[cfg(feature = \"pcg64\")]\npub mod pcg64;\n\n/// Implementation of the ChaCha CSPRNG algorithm.\n/// More details can be seen at <https://en.wikipedia.org/wiki/Salsa20>\n#[cfg(feature = \"chacha\")]\npub mod chacha;\n\n/// A trait that represents a random number generator.\npub trait Rng<const OUTPUT: usize>: Clone {\n\t/// Generates a random sequence of bytes, seeding from the internal state.\n\tfn rand(&mut self) -> [u8; OUTPUT];\n\n\t/// Generates a random of the specified type, seeding from the internal state.\n\tfn generate<Generated>(&mut self) -> Generated\n\twhere\n\t\tGenerated: RandomGen<Self, OUTPUT>,\n\t{\n\t\tGenerated::random(self)\n\t}\n\n\t/// Fill an array of bytes with randomness.\n\tfn fill_bytes<Bytes>(&mut self, mut buffer: Bytes)\n\twhere\n\t\tBytes: AsMut<[u8]>,\n\t{\n\t\tlet mut buffer = buffer.as_mut();\n\t\tlet mut length = buffer.len();\n\t\twhile length > 0 {\n\t\t\tlet chunk = self.rand();\n\t\t\tlet generated = chunk.len().min(length);\n\t\t\tbuffer[..generated].copy_from_slice(&chunk[..generated]);\n\t\t\tbuffer = &mut buffer[generated..];\n\t\t\tlength -= generated;\n\t\t}\n\t}\n\n\t/// Fill an array with the specified type.\n\tfn fill<Contents, Array>(&mut self, mut target: Array)\n\twhere\n\t\tContents: RandomGen<Self, OUTPUT>,\n\t\tArray: AsMut<[Contents]>,\n\t{\n\t\tlet target = target.as_mut();\n\t\ttarget.iter_mut().for_each(|entry| *entry = self.generate());\n\t}\n\n\t/// Generates a random of the specified type, seeding from the internal state.\n\tfn generate_range<Number, Bounds>(&mut self, range: Bounds) -> Number\n\twhere\n\t\tNumber: RandomRange<Self, OUTPUT>,\n\t\tBounds: RangeBounds<Number>,\n\t{\n\t\tNumber::random_range(self, range)\n\t}\n\n\t/// Shuffle a slice, using the RNG.\n\tfn shuffle<Contents, Array>(&mut self, mut target: Array)\n\twhere\n\t\tArray: AsMut<[Contents]>,\n\t{\n\t\tlet target = target.as_mut();\n\t\tlet target_len = target.len();\n\t\tfor idx in (1..target_len).rev() {\n\t\t\tlet random_idx = self.generate_range(0..idx + 1);\n\t\t\ttarget.swap(idx, random_idx);\n\t\t}\n\t}\n}\n\n/// A trait that represents an RNG that can be reseeded from arbitrary bytes.\npub trait SeedableRng<const SEED_SIZE: usize, const OUTPUT: usize>: Rng<OUTPUT> {\n\t/// Re-seed the RNG with the specified bytes.\n\tfn reseed(&mut self, seed: [u8; SEED_SIZE]);\n}\n"
  },
  {
    "path": "src/tls.rs",
    "content": "use crate::rand::{wyrand::WyRand, Rng, SeedableRng};\nuse std::{cell::RefCell, rc::Rc};\n\nthread_local! {\n\tstatic WYRAND: Rc<RefCell<WyRand>> = Rc::new(RefCell::new(WyRand::new()));\n}\n\n#[derive(Clone)]\n#[doc(hidden)]\npub struct TlsWyRand(Rc<RefCell<WyRand>>);\n\nimpl Rng<8> for TlsWyRand {\n\tfn rand(&mut self) -> [u8; 8] {\n\t\tself.0.borrow_mut().rand()\n\t}\n}\n\nimpl SeedableRng<8, 8> for TlsWyRand {\n\tfn reseed(&mut self, seed: [u8; 8]) {\n\t\tself.0.borrow_mut().reseed(seed);\n\t}\n}\n\n/// Fetch a thread-local [`WyRand`]\n/// ```rust\n/// use nanorand::Rng;\n///\n/// let mut rng = nanorand::tls_rng();\n/// println!(\"Random number: {}\", rng.generate::<u64>());\n/// ```\n/// This cannot be passed to another thread, as something like this will fail to compile:\n/// ```compile_fail\n/// use nanorand::Rng;\n///\n/// let mut rng = nanorand::tls_rng();\n/// std::thread::spawn(move || {\n///     println!(\"Random number: {}\", rng.generate::<u64>());\n/// });\n/// ```\npub fn tls_rng() -> TlsWyRand {\n\tWYRAND.with(|tls| TlsWyRand(tls.clone()))\n}\n"
  }
]