diff --git a/CMakeLists.txt b/CMakeLists.txt index fce8938f..cec6e3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -440,6 +440,8 @@ list ( rand/mwc64x.hpp rand/pcg.cpp rand/pcg.hpp + rand/rdrand.cpp + rand/rdrand.hpp rand/system.hpp random.cpp random.hpp diff --git a/rand/rdrand.cpp b/rand/rdrand.cpp new file mode 100644 index 00000000..6bcb1b0d --- /dev/null +++ b/rand/rdrand.cpp @@ -0,0 +1,44 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019 Danny Robson + */ + +#include "rdrand.hpp" + +using cruft::rand::rdrand; + + +/////////////////////////////////////////////////////////////////////////////// +rdrand::rdrand () +{ ; } + + +//--------------------------------------------------------------------------------------- +rdrand::rdrand (std::string const &) + : rdrand () +{ ; } + + +/////////////////////////////////////////////////////////////////////////////// +rdrand::result_type +rdrand::operator() () +{ + uint64_t res; + char success; + + __asm__ __volatile__ ( + "rdrand %0;" + "setc %1;" + + : "=r" (res) + , "=qm" (success) + ); + + if (!__builtin_expect(success, 1)) + throw std::runtime_error ("no value available for rdrand"); + + return res; +} diff --git a/rand/rdrand.hpp b/rand/rdrand.hpp new file mode 100644 index 00000000..c1d0faf4 --- /dev/null +++ b/rand/rdrand.hpp @@ -0,0 +1,40 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019 Danny Robson + */ + +#pragma once + +#include "../posix/fd.hpp" + + +namespace cruft::rand { + /// Models std::random_device and is suitable as a drop-in replacement. + /// + /// This implementation assumes that the CPU supports the `rdrand` + /// instruction, and does not check that this is the case. + /// + /// It is safe to instantiatate the object even if the instructions are + /// not supported, but it is the users responsibility to prevent calls to + /// the object if this is not the case. + class rdrand { + public: + using result_type = unsigned; + + rdrand (); + rdrand (std::string const&); + rdrand (rdrand const &) = delete; + + rdrand& operator= (rdrand const&) = delete; + + result_type operator() (void); + + double entropy (void) const noexcept; + + static constexpr result_type min (void) { return std::numeric_limits::min (); } + static constexpr result_type max (void) { return std::numeric_limits::max (); } + }; +} diff --git a/test/rand/buckets.cpp b/test/rand/buckets.cpp index 8e359103..9dac1996 100644 --- a/test/rand/buckets.cpp +++ b/test/rand/buckets.cpp @@ -55,6 +55,7 @@ main (int,char**) test_buckets (tap, 0x1234u); test_buckets> (tap, 0x1234u); test_buckets (tap); + test_buckets (tap); return tap.status (); }