From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 6B1993858D39 for ; Tue, 19 Oct 2021 16:31:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 6B1993858D39 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-350-ffHDNf2GP6-Jx_RW3bpTnw-1; Tue, 19 Oct 2021 12:31:48 -0400 X-MC-Unique: ffHDNf2GP6-Jx_RW3bpTnw-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 3887C100CCC2; Tue, 19 Oct 2021 16:31:47 +0000 (UTC) Received: from localhost (unknown [10.33.36.194]) by smtp.corp.redhat.com (Postfix) with ESMTP id D5A125FC13; Tue, 19 Oct 2021 16:31:46 +0000 (UTC) Date: Tue, 19 Oct 2021 17:31:45 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Implement std::random_device::entropy() for other sources Message-ID: MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: multipart/mixed; boundary="QMmmLvgkU9Kx8qYJ" Content-Disposition: inline X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Oct 2021 16:31:53 -0000 --QMmmLvgkU9Kx8qYJ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Currently this function only returns a non-zero value for /dev/random and /dev/urandom. When a hardware instruction such as RDRAND is in use it should (in theory) be perfectly random and produce 32 bits of entropy in each 32-bit result. Add a helper function to identify the source of randomness from the _M_func and _M_file data members, and return a suitable value when RDRAND or RDSEED is being used. libstdc++-v3/ChangeLog: * src/c++11/random.cc (which_source): New helper function. (random_device::_M_getentropy()): Use which_source and return suitable values for sources other than device files. * testsuite/26_numerics/random/random_device/entropy.cc: New test. Tested powerpc64le-linux. Committed to trunk. --QMmmLvgkU9Kx8qYJ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" commit 58f339fc5eaae7db9526f81ab91f282ad4a9b8cc Author: Jonathan Wakely Date: Tue Oct 19 12:31:06 2021 libstdc++: Implement std::random_device::entropy() for other sources Currently this function only returns a non-zero value for /dev/random and /dev/urandom. When a hardware instruction such as RDRAND is in use it should (in theory) be perfectly random and produce 32 bits of entropy in each 32-bit result. Add a helper function to identify the source of randomness from the _M_func and _M_file data members, and return a suitable value when RDRAND or RDSEED is being used. libstdc++-v3/ChangeLog: * src/c++11/random.cc (which_source): New helper function. (random_device::_M_getentropy()): Use which_source and return suitable values for sources other than device files. * testsuite/26_numerics/random/random_device/entropy.cc: New test. diff --git a/libstdc++-v3/src/c++11/random.cc b/libstdc++-v3/src/c++11/random.cc index 44b9f30e4a9..4b64bde00ea 100644 --- a/libstdc++-v3/src/c++11/random.cc +++ b/libstdc++-v3/src/c++11/random.cc @@ -192,6 +192,51 @@ namespace std _GLIBCXX_VISIBILITY(default) return lcg(); } #endif + + enum Which { + rand_s = 1, rdseed = 2, rdrand = 4, device_file = 8, prng = 16, + any = 0xffff + }; + + inline Which + which_source(random_device::result_type (*func [[maybe_unused]])(void*), + void* file [[maybe_unused]]) + { +#ifdef _GLIBCXX_USE_CRT_RAND_S + if (func == &__winxp_rand_s) + return rand_s; +#endif + +#ifdef USE_RDSEED +#ifdef USE_RDRAND + if (func == &__x86_rdseed_rdrand) + return rdseed; +#endif + if (func == &__x86_rdseed) + return rdseed; +#endif + +#ifdef USE_RDRAND + if (func == &__x86_rdrand) + return rdrand; +#endif + +#ifdef _GLIBCXX_USE_DEV_RANDOM + if (file != nullptr) + return device_file; +#endif + +#ifdef USE_LCG + if (func == &__lcg) + return prng; +#endif + +#ifdef USE_MT19937 + return prng; +#endif + + return any; // should be unreachable + } } void @@ -209,10 +254,7 @@ namespace std _GLIBCXX_VISIBILITY(default) const char* fname [[gnu::unused]] = nullptr; - enum { - rand_s = 1, rdseed = 2, rdrand = 4, device_file = 8, prng = 16, - any = 0xffff - } which; + Which which; if (token == "default") { @@ -449,10 +491,25 @@ namespace std _GLIBCXX_VISIBILITY(default) double random_device::_M_getentropy() const noexcept { + const int max = sizeof(result_type) * __CHAR_BIT__; + + switch(which_source(_M_func, _M_file)) + { + case rdrand: + case rdseed: + return (double) max; + case rand_s: + case prng: + return 0.0; + case device_file: + // handled below + break; + default: + return 0.0; + } + #if defined _GLIBCXX_USE_DEV_RANDOM \ && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT - if (!_M_file) - return 0.0; #ifdef USE_POSIX_FILE_IO const int fd = _M_fd; @@ -469,7 +526,6 @@ namespace std _GLIBCXX_VISIBILITY(default) if (ent < 0) return 0.0; - const int max = sizeof(result_type) * __CHAR_BIT__; if (ent > max) ent = max; diff --git a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc new file mode 100644 index 00000000000..9ef1538d2bb --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc @@ -0,0 +1,37 @@ +// { dg-do run { target c++11 } } + +#include +#include +#include + +void +test01() +{ + for (auto token : { "mt19937", "prng", "rand_s" }) + if (__gnu_test::random_device_available(token)) + VERIFY( std::random_device(token).entropy() == 0.0 ); + + using result_type = std::random_device::result_type; + const double max = std::log2(std::numeric_limits::max() + 1.0); + + for (auto token : { "/dev/random", "/dev/urandom" }) + if (__gnu_test::random_device_available(token)) + { + const double entropy = std::random_device(token).entropy(); + VERIFY( entropy >= 0.0 ); + VERIFY( entropy <= max ); + } + + for (auto token : { "rdrand", "rdseed" }) + if (__gnu_test::random_device_available(token)) + { + const double entropy = std::random_device(token).entropy(); + VERIFY( entropy == max ); + } +} + +int +main() +{ + test01(); +} --QMmmLvgkU9Kx8qYJ--