{"id":22128548,"url":"https://github.com/itzmeanjan/randomshake","last_synced_at":"2025-03-24T08:42:50.605Z","repository":{"id":262315641,"uuid":"883102145","full_name":"itzmeanjan/RandomShake","owner":"itzmeanjan","description":"Shake256 Xof -based Portable C++20 Cryptographically Secure Pseudo Random Number Generator (CSPRNG)","archived":false,"fork":false,"pushed_at":"2025-03-04T18:40:24.000Z","size":97,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-04T19:34:24.836Z","etag":null,"topics":["cryptographically-secure-random","csprng","prng","shake256"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itzmeanjan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-04T11:33:19.000Z","updated_at":"2025-03-04T18:40:24.000Z","dependencies_parsed_at":"2024-11-11T19:39:24.120Z","dependency_job_id":"463989e6-7b7a-4702-ad7b-d346d3e748d2","html_url":"https://github.com/itzmeanjan/RandomShake","commit_stats":null,"previous_names":["itzmeanjan/randomshake"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzmeanjan%2FRandomShake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzmeanjan%2FRandomShake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzmeanjan%2FRandomShake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzmeanjan%2FRandomShake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itzmeanjan","download_url":"https://codeload.github.com/itzmeanjan/RandomShake/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245240271,"owners_count":20583099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptographically-secure-random","csprng","prng","shake256"],"created_at":"2024-12-01T17:45:45.156Z","updated_at":"2025-03-24T08:42:50.595Z","avatar_url":"https://github.com/itzmeanjan.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RandomShake\nShake256 Xof -based Portable C++20 Cryptographically Secure Pseudo Random Number Generator (CSPRNG) - plug and play with C++ `\u003crandom\u003e` header's random distributions.\n\n## Why ?\n\nC++11 introduced `\u003crandom\u003e` header to its standard library, which offers multiple pseudo-random number generator engines and distributions. The design of the `\u003crandom\u003e` header is very much modular, it's possible to plug any psuedo-random number generator engine with any distribution and start getting results as per the rules of the statistical distribution. All that is needed is providing the distribution with a source *u*niform *r*andom *n*umber *g*enerator (URNG). One thing that the standard library's `\u003crandom\u003e` header lacks is the psuedo-random number generator engines, which come by default, are not cryptographically secure. Hence using those engines with provided distributions, in cryptographic settings, might be quite catastrophic !\n\nThis is where \"RandomShake\" comes, collecting inspiration from https://seth.rocks/articles/cpprandom.\n\n\"RandomShake\" is a *C*ryptographically *S*ecure *P*seudo-*R*andom *N*umber *G*enerator (CSPRNG) engine, which is backed by Shake256 extendable output function (Xof) with frequent ratcheting of the underlying keccak-1600 permutation state, generating unsigned integer (of all standard bit-widths) stream for all three NIST security levels. It's very easy to plug this CSPRNG engine into any of the C++ standard library's random distributions. Just plug and play. And now you can use those distributions with \"RandomShake\" CSPRNG, in cryptographic settings. It also offers API for generating arbitrary many bytes at a time. \"RandomShake\" offers following two ways for seeding the internal Shake256 state.\n\n- [**Non-deterministic CSPRNG**] Sampling k -bit non-deterministic randomness from `std::random_device` engine.\n- [**Deterministic and re-producible CSPRNG**] Taking k -bit seed as input from function caller.\n\nUsing the non-deterministic CSPRNG is very convenient, but there is a caveat - this CSPRNG samples its seed from `std::random_device` engine, which is supposed to be non-deterministic, but is not guaranteed to be - it's implementation-defined behavior. I strongly advise you to read https://en.cppreference.com/w/cpp/numeric/random/random_device.\n\n```cpp\nusing csprng_256b_t = randomshake::randomshake_t\u003c256\u003e;\n\ncsprng_256b_t csprng; // Automatically seeded using `std::random_device`\n```\n\nWhile for the deterministic CSPRNG, as an user, it's your responsibility to supply a seed of required byte length with sufficient entropy - this CSPRNG is the one to use, if you need reproducible random bytes.\n\n```cpp\nstd::array\u003cuint8_t, csprng_256b_t::seed_byte_len\u003e seed{};\nseed.fill(0xde);            // Please don't do it in any practical scenario !\n\ncsprng_256b_t csprng(seed); // Initialized by the seed we supply\n```\n\nUsing the CSPRNG instance for sampling random value(s), is super easy.\n\n```cpp\n// Sample a single random uint8_t.\nconst auto random_value = csprng();\n\n// or\n// Fill the vector, sampling one byte at a time.\nstd::vector\u003cuint8_t\u003e rand_values(16, 0x00);\nstd::ranges::generate(rand_values, [\u0026]() { return csprng(); });\n\n// or\n// Fill the vector, by squeezing many bytes at a time.\ncsprng.generate(rand_values);\n```\n\n### \"RandomShake\" CSPRNG Performance Overview\n\nCSPRNG Operation for bit-security level `256` | Time taken on AWS EC2 Instance `c7i.large` | Time taken on AWS EC2 Instance `c8g.large`\n--- | --- | ---\nDeterministic seeding of instance | 2.71us | 2.98us\nNon-Deterministic seeding of instance | 7.39us | 5.14us\n\nCSPRNG Operation for bit-security level `256` | Bandwidth on AWS EC2 Instance `c7i.large` (Linux 6.8.0-1021-aws, g++ 13) | Bandwidth on AWS EC2 Instance `c8g.large` (Linux 6.8.0-1021-aws, g++ 13)\n---|---|---\nSampling of `u8` | 379.1 MB/s | 199.9 MB/s\nSampling of `u16` | 428.4 MB/s | 258.0 MB/s\nSampling of `u32` | 459.1 MB/s | 303.8 MB/s\nSampling of `u64` | 470.4 MB/s | 331.2 MB/s\nSampling arbitrary long byte sequence | 483.7 MB/s | 357.5 MB/s\n\n## How to setup ?\n\n- Ensure that you have access to a C++ compiler, which supports compiling C++20 program.\n\n```bash\n# I'm using\n$ c++ --version\nc++ (Ubuntu 14.2.0-4ubuntu2) 14.2.0\n```\n\n- You will also need both `make` and `cmake` for building this project and test framework/ benchmark harness.\n\n```bash\n$ make --version\nGNU Make 4.3\n\n$ cmake --version\ncmake version 3.30.3\n```\n\n- For running tests, you must have `google-test` globally installed. Follow steps described @ https://github.com/google/googletest/blob/main/googletest/README.md.\n- For running benchmarks, you must have `google-benchmark` globally installed. You may find steps described @ https://github.com/google/benchmark/?tab=readme-ov-file#installation helpful.\n\n\u003e [!NOTE]\n\u003e In case you are planning to run benchmarks on a machine which runs GNU/Linux kernel, I suggest you build `google-benchmark` with libPFM, so that you get to know how many CPU cycles does it take for each benchmarked functions to execute. I describe the steps @ https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7.\n\n\u003e [!NOTE]\n\u003e I use the BASH script @ https://gist.github.com/itzmeanjan/84b7df57604708e33f04fc43e55ecb0c to quickly setup a GNU/Linux machine, so that I can run tests and benchmarks. Running this script does the whole setup phase for you on Ubuntu and large family of OS.\n\n## How to test ?\n\nFor running all functional correctness tests, just issue\n\n```bash\nmake test -j\n```\n\n\u003e [!NOTE]\n\u003e There is a help menu, which introduces you to all available commands; just run `make` from the root directory of this project.\n\nYou may want to run tests with AddressSanitizer or UndefinedBehaviorSanitizer enabled, in either debug mode or release mode. You can simply issue\n\n```bash\nmake debug_asan_test -j\nmake debug_ubsan_test -j\n\nmake release_asan_test -j\nmake release_ubsan_test -j\n```\n\nBy default Make will use default c++ compiler of the system to build tests, but you specify your choice, by setting the `CXX` variable, before invoking any of the Make commands.\n\n```bash\nCXX=clang++ make test -j\n```\n\n## How to benchmark ?\n\nFor benchmarking both the creation of a CSPRNG instance and sampling of random unsigned integers from it, just issue.\n\n```bash\nmake benchmark -j\n```\n\nIn case, you decided to build google-benchmark with libPFM, so that you can get access to h/w CPU cycles counter, you have to issue\n\n```bash\nmake perf -j\n```\n\n\u003e [!CAUTION]\n\u003e You must disable CPU frequency scaling during benchmarking. I found guide @ https://github.com/google/benchmark/blob/4931aefb51d1e5872b096a97f43e13fa0fc33c8c/docs/reducing_variance.md helpful.\n\nI've run benchmarks on some platforms and here are the results.\n\nBenchmarking Results on DESKTOP -grade Machine(s)\n---\n\n### On 12th Gen Intel(R) Core(TM) i7-1260P\nI maintain the benchmark results in JSON format @ [bench_result_on_Linux_6.11.0-18-generic_x86_64_with_g++_14](./bench_result_on_Linux_6.11.0-18-generic_x86_64_with_g++_14.json).\n\nBenchmarking Results on SERVER -grade Machine(s)\n---\n\n### On Intel(R) Xeon(R) Platinum 8488C i.e. AWS EC2 Instance `c7i.large`\nFind the benchmark results in JSON format @ [bench_result_on_Linux_6.8.0-1021-aws_x86_64_with_g++_13](./bench_result_on_Linux_6.8.0-1021-aws_x86_64_with_g++_13.json).\n\n### On AWS EC2 Instance `c8g.large` i.e. AWS Graviton4\nFind the benchmark results in JSON format @ [bench_result_on_Linux_6.8.0-1021-aws_aarch64_with_g++_13](./bench_result_on_Linux_6.8.0-1021-aws_aarch64_with_g++_13.json).\n\n## How to use ?\n\nUsing \"RandomShake\" CSPRNG is very easy.\n\n- Clone this repository, whiile importing all git submodule -based dependencies.\n\n```bash\ngit clone https://github.com/itzmeanjan/RandomShake.git --recurse-submodules\n```\n\n- Write a C++ function, using this CSPRNG, while including \"randomshake/randomshake.hpp\" header file.\n\n```cpp\n// csprng_with_binomial_dist.cpp\n\n#include \"randomshake/randomshake.hpp\"\n#include \u003ccstdlib\u003e\n#include \u003crandom\u003e\n#include \u003cranges\u003e\n\n// This example collects inspiration from https://seth.rocks/articles/cpprandom. See the last code-snippet.\nint\nmain()\n{\n  randomshake::randomshake_t\u003c256\u003e csprng;\n  std::binomial_distribution dist{ 1'000, .5 };\n\n  for (auto _ : std::ranges::iota_view{ 1, 10 }) {\n    std::cout \u003c\u003c \"[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: \" \u003c\u003c dist(csprng) \u003c\u003c '\\n';\n  }\n\n  return EXIT_SUCCESS;\n}\n```\n\n\u003e [!NOTE]\n\u003e In above demonstration, I'm showing how to use \"RandomShake\" CSPRNG (at 256 -bit security) with C++ standard library's Binomial Distribution, but it should be fairly easy, plugging this CSPRNG with any other available distribution.\n\n- Compile the C++ translation unit, while including path to both \"RandomShake\" and \"sha3\".\n\n```bash\nc++  -std=c++20 -Wall -Wextra -Wpedantic -O3 -march=native -I ./include -I ./sha3/include examples/csprng_with_binomial_dist.cpp\n```\n\n- And finally run the executable.\n\n```bash\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 515\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 522\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 499\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 500\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 526\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 513\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 509\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 503\n[BINOMIAL dISTRIBUTION] Number of heads in 1,000 flips: 491\n```\n\nIn case you just want to generate arbitrary many random bytes, there is an API `generate` - which can generate arbitrary many random bytes and it should be fine calling this as many times needed.\n\nI maintain a few examples of using \"RandomShake\" API with various C++ STL distributions @ [examples](./examples) directory. You can run them all by `$ make example -j`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitzmeanjan%2Frandomshake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitzmeanjan%2Frandomshake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitzmeanjan%2Frandomshake/lists"}