Modern C++ RandomX Implementation
MIT License
This project aims to provide minimal implementation of RandomX v1 algorithm using modern C++ language.
Current state of this project does not provide sensible performance to use in mining, but you can still use this repository for educational purposes (or whatever that will make sense for you).
1) Out of original scope.
To build this repository you should download the most recent Visual Studio version (at least 17.10) with C++ tools.
Library requires support for AVX512F, AVX512VL, AVX512DQ and AES instructions. In a case of lacking support, exception will be thrown at runtime.
No plans for support multi OSes, platforms or architectures in the nearest future and the only guaranteed environment is the one i develop on, which is:
But it should work with Windows 7 and higher and any 64-bit little-endian CPU with AVX512{F/VL/DQ}/AES support.
This repository is meant to be build as a library that can be linked into other programs, specifically Monero miner programs.
#include "modernRX/hasher.hpp"
/*
* This example counts the number of generated hashes.
*/
// Declare hasher somewhere in your code.
std::unique_ptr<modernRX::Hasher> hasher{ nullptr };
std::atomic<uint64_t> counter{ 0 };
// It is advised to initialize it in a place where exception can be handled.
void initialize() {
try {
hasher = std::make_unique<modernRX::Hasher>();
// This will start VirtualMachine worker threads with a callback function that passes calculated hash.
hasher->run([&counter](const modernRX::RxHash& hash) {
counter.fetch_add(1, std::memory_order_relaxed);
});
} catch (const modernRX::Exception& ex) {
// Handle exception.
}
}
void close() {
// Stop all VirtualMachine worker threads (waits for all of them to finish).
hasher->stop();
std::println("Hashes generated: {}", counter.load());
}
void resetJobParameters() {
// Miner's responsibility to get proper data from blockchain node and setup job parameters.
// For tests these values are hardcoded.
auto [key, input] { miner.getHashingDataFromNode() };
// Update job parameters.
hasher->reset(key); // Resets hasher with new key (it will recalculate dataset if new key provided).
hasher->resetVM(input); // Resets all VirtualMachine worker threads with new input.
}
To run tests open solution, set tests
project with ReleaseAsan
configuration as the startup one and click "run".
Sample output:
[ 0] Blake2b::hash ... Passed (<1ms)
[ 1] Argon2d::Blake2b::hash ... Passed (<1ms)
[ 2] Argon2d::fillMemory ... Passed (3.493s)
[ 3] AesGenerator1R::fill ... Passed (<1ms)
[ 4] AesGenerator4R::fill ... Passed (<1ms)
[ 5] AesHash1R ... Passed (<1ms)
[ 6] Blake2brandom::get ... Passed (<1ms)
[ 7] Reciprocal ... Passed (<1ms)
[ 8] Superscalar::generate ... Passed (0.009s)
[ 9] Dataset::generate ... Passed (6.737s)
[10] VirtualMachine::execute ... Passed (4.582s)
Ideally, tests should be run before every release in Release
and Debug
mode with AddressSanitizer
enabled. ReleaseAsan
and DebugAsan
project configurations are provided for this purpose.
Repository contains fuzzer
project that can be used to fuzz this library with libFuzzer
.
Except of fuzzing to find fatal bugs, it is also used to fuzz against original RandomX implementation to find differences in behavior.
Ideally, fuzzing should be run before every release in Release
mode with AddressSanitizer
enabled.
ReleaseFuzzer
project configuration is provided for this purpose.
Options used for fuzzing:
-max_len=76 -len_control=0 -rss_limit_mb=8192 -max_total_time=14400 -dict=.dict -artifact_prefix=c:/tmp/ -print_pcs=1 -print_final_stats=1 -report_slow_units=120
Be aware that fuzzing is very resource intensive and may take a lot of time to complete. By default it expect up to 8GB of RAM usage and runs for 4 hours.
OpenCppCoverage is used to measure code coverage. To run code coverage download and install latest OpenCppCoverage for Windows, build tests
project with Debug
configuration and finally run it with command:
OpenCppCoverage.exe --sources \path\to\modernRX\ -- \path\to\modernRX\x64\Debug\tests.exe
Ideally, code coverage should be checked before every release in Debug
mode.
For a full report see code coverage report.
Repository contains pgo
project that can be used to generate profile data in Release
mode. ReleasePgo
project configuration is provided for this purpose.
In a case of missing pgort140.dll
just copy it from VisualStudio installation folder to x64/ReleasePGO
folder.
Generated profiles are used for benchmarking (experimental).
Benchmarks were performed on AMD Ryzen 7 7840HS (Radeon 780M Graphics) with 32GB of RAM (4x8GB, dual-channel, 6400 MT/s, DDR5) and Windows 11 Home. Code was compiled with Microsoft Visual Studio 17.10.5 version.
CPU frequency turbo boost was disabled (3.8GHz base frequency).
Hash [H/s] | Efficiency [H/Watt/s] | Blake2b [H/s] | Blake2bLong [H/s] | Argon2d [MB/s] | Superscalar [Prog/s] | Dataset [MB/s] | |
---|---|---|---|---|---|---|---|
RandomX-1.2.1 (102f8acf) | 3753 | ~87.27 | 4.098M | 131.76K | 884.9 | 5921 | ~932.4 |
modernRX 0.9.2 | 3105 | ~77.81 | 6.618M | 211.00K | 1299.0 | 12858 | 2133.0 |
Original RandomX provides benchmark only for calculating final hashes. All other values were estimated (based on information benchmark provides) or some custom benchmarks were written on top of RandomX implementation, thus values may not be 100% accurate.
For details and full benchmark results see BENCHMARKS.md.
Code found in this repository follows guidelines listed below:
[[nodiscard]]
, noexcept
and explicit
wherever possible.[[unlikely]]
and [[likely]]
.Project follows zero-based versioning with several specific versions:
0.0.1
- initial implementation0.1.0
- reference implementation (contains polished documentation and tests + benchmarks; reference point to further tweaks and optimizations)0.1.x
- reference implementation++ (contains bugfixes, documentation corrections, coding standard updates etc.)0.2+.y
- optimized implementation (contains subsequent optimizations)For more details see CHANGELOG.md.
$> gocloc /exclude-ext "xml,json,txt,exp" /not-match-d "3rdparty/*|x64/*|assets/*" .
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C++ 17 664 373 3654
C++ Header 37 589 578 3228
Markdown 3 214 0 630
-------------------------------------------------------------------------------
TOTAL 57 1467 951 7512
-------------------------------------------------------------------------------
If you like this project and would like to support further development you could donate some cryptos to one of those addresses:
bc1qrlw6kdtnwka2ww6j9cvzugs7sk8zk2ewp3mrd6
0x3679B13D96DF9291eB98d1308008Be73F8D05b5B
43hGi1uJDmbGE7RUZJoBLa6BnCDtT3tNdb7v7VMQbheohso81CoUMeJTA7wcHt9Xi27Cw8tPGPex55mpoT3q46MGMa7ca6m
All donations are voluntary and i will be grateful for every single satoshi.