1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #if defined(_LIBCPP_USING_WIN32_RANDOM)
12 // Must be defined before including stdlib.h to enable rand_s().
14 #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
16 #include <__system_error/throw_system_error.h>
24 #if defined(_LIBCPP_USING_GETENTROPY)
25 # include <sys/random.h>
26 #elif defined(_LIBCPP_USING_DEV_RANDOM)
29 # if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)
30 # include <linux/random.h>
31 # include <sys/ioctl.h>
33 #elif defined(_LIBCPP_USING_NACL_RANDOM)
34 # include <nacl/nacl_random.h>
35 #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
36 # include <zircon/syscalls.h>
39 _LIBCPP_BEGIN_NAMESPACE_STD
41 #if defined(_LIBCPP_USING_GETENTROPY)
43 random_device::random_device(const string
& __token
) {
44 if (__token
!= "/dev/urandom")
45 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
48 random_device::~random_device() {}
50 unsigned random_device::operator()() {
53 int err
= getentropy(&r
, n
);
55 __throw_system_error(errno
, "random_device getentropy failed");
59 #elif defined(_LIBCPP_USING_ARC4_RANDOM)
61 random_device::random_device(const string
&) {}
63 random_device::~random_device() {}
65 unsigned random_device::operator()() { return arc4random(); }
67 #elif defined(_LIBCPP_USING_DEV_RANDOM)
69 random_device::random_device(const string
& __token
) : __f_(open(__token
.c_str(), O_RDONLY
)) {
71 __throw_system_error(errno
, ("random_device failed to open " + __token
).c_str());
74 random_device::~random_device() { close(__f_
); }
76 unsigned random_device::operator()() {
79 char* p
= reinterpret_cast<char*>(&r
);
81 ssize_t s
= read(__f_
, p
, n
);
83 __throw_system_error(ENOMSG
, "random_device got EOF");
86 __throw_system_error(errno
, "random_device got an unexpected error");
89 n
-= static_cast<size_t>(s
);
90 p
+= static_cast<size_t>(s
);
95 #elif defined(_LIBCPP_USING_NACL_RANDOM)
97 random_device::random_device(const string
& __token
) {
98 if (__token
!= "/dev/urandom")
99 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
100 int error
= nacl_secure_random_init();
102 __throw_system_error(error
, ("random device failed to open " + __token
).c_str());
105 random_device::~random_device() {}
107 unsigned random_device::operator()() {
109 size_t n
= sizeof(r
);
110 size_t bytes_written
;
111 int error
= nacl_secure_random(&r
, n
, &bytes_written
);
113 __throw_system_error(error
, "random_device failed getting bytes");
114 else if (bytes_written
!= n
)
115 __throw_runtime_error("random_device failed to obtain enough bytes");
119 #elif defined(_LIBCPP_USING_WIN32_RANDOM)
121 random_device::random_device(const string
& __token
) {
122 if (__token
!= "/dev/urandom")
123 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
126 random_device::~random_device() {}
128 unsigned random_device::operator()() {
130 errno_t err
= rand_s(&r
);
132 __throw_system_error(err
, "random_device rand_s failed.");
136 #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)
138 random_device::random_device(const string
& __token
) {
139 if (__token
!= "/dev/urandom")
140 __throw_system_error(ENOENT
, ("random device not supported " + __token
).c_str());
143 random_device::~random_device() {}
145 unsigned random_device::operator()() {
146 // Implicitly link against the vDSO system call ABI without
147 // requiring the final link to specify -lzircon explicitly when
148 // statically linking libc++.
149 # pragma comment(lib, "zircon")
151 // The system call cannot fail. It returns only when the bits are ready.
153 _zx_cprng_draw(&r
, sizeof(r
));
158 # error "Random device not implemented for this architecture"
161 double random_device::entropy() const noexcept
{
162 #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)
164 if (::ioctl(__f_
, RNDGETENTCNT
, &ent
) < 0)
170 if (ent
> std::numeric_limits
<result_type
>::digits
)
171 return std::numeric_limits
<result_type
>::digits
;
174 #elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)
175 return std::numeric_limits
<result_type
>::digits
;
181 _LIBCPP_END_NAMESPACE_STD