summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Boric <jblbeurope@gmail.com>2021-05-14 17:16:06 +0200
committerAndreas Kling <kling@serenityos.org>2021-05-14 22:24:02 +0200
commit069bf988ed990f68b1f13fb5a63d674f4529cfb4 (patch)
tree3e1c1675c7839bc8e4bd90d426051be3596a1e31
parentad7cd05fc10aab499c4ceb14a546eedf92b49f12 (diff)
downloadserenity-069bf988ed990f68b1f13fb5a63d674f4529cfb4.zip
AK: Introduce get_random_uniform()
This is arc4random_uniform(), but inside AK.
-rw-r--r--AK/Random.cpp31
-rw-r--r--AK/Random.h3
-rw-r--r--Userland/Libraries/LibC/stdlib.cpp18
3 files changed, 36 insertions, 16 deletions
diff --git a/AK/Random.cpp b/AK/Random.cpp
new file mode 100644
index 0000000000..fc5dd268ca
--- /dev/null
+++ b/AK/Random.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, the SerenityOS developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Random.h>
+
+namespace AK {
+
+u32 get_random_uniform(u32 max_bounds)
+{
+ // If we try to divide all 2**32 numbers into groups of "max_bounds" numbers, we may end up
+ // with a group around 2**32-1 that is a bit too small. For this reason, the implementation
+ // `arc4random() % max_bounds` would be insufficient. Here we compute the last number of the
+ // last "full group". Note that if max_bounds is a divisor of UINT32_MAX,
+ // then we end up with UINT32_MAX:
+ const u32 max_usable = UINT32_MAX - (static_cast<u64>(UINT32_MAX) + 1) % max_bounds;
+ auto random_value = get_random<u32>();
+ for (int i = 0; i < 20 && random_value > max_usable; ++i) {
+ // By chance we picked a value from the incomplete group. Note that this group has size at
+ // most 2**31-1, so picking this group has a chance of less than 50%.
+ // In practice, this means that for the worst possible input, there is still only a
+ // once-in-a-million chance to get to iteration 20. In theory we should be able to loop
+ // forever. Here we prefer marginally imperfect random numbers over weird runtime behavior.
+ random_value = get_random<u32>();
+ }
+ return random_value % max_bounds;
+}
+
+}
diff --git a/AK/Random.h b/AK/Random.h
index 69319a5bf2..b4fe621d8b 100644
--- a/AK/Random.h
+++ b/AK/Random.h
@@ -41,7 +41,10 @@ inline T get_random()
return t;
}
+u32 get_random_uniform(u32 max_bounds);
+
}
using AK::fill_with_random;
using AK::get_random;
+using AK::get_random_uniform;
diff --git a/Userland/Libraries/LibC/stdlib.cpp b/Userland/Libraries/LibC/stdlib.cpp
index 6811c5f537..1e66630927 100644
--- a/Userland/Libraries/LibC/stdlib.cpp
+++ b/Userland/Libraries/LibC/stdlib.cpp
@@ -7,6 +7,7 @@
#include <AK/Assertions.h>
#include <AK/HashMap.h>
#include <AK/Noncopyable.h>
+#include <AK/Random.h>
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <AK/Utf8View.h>
@@ -1093,22 +1094,7 @@ void arc4random_buf(void* buffer, size_t buffer_size)
uint32_t arc4random_uniform(uint32_t max_bounds)
{
- // If we try to divide all 2**32 numbers into groups of "max_bounds" numbers, we may end up
- // with a group around 2**32-1 that is a bit too small. For this reason, the implementation
- // `arc4random() % max_bounds` would be insufficient. Here we compute the last number of the
- // last "full group". Note that if max_bounds is a divisor of UINT32_MAX,
- // then we end up with UINT32_MAX:
- const uint32_t max_usable = UINT32_MAX - (static_cast<uint64_t>(UINT32_MAX) + 1) % max_bounds;
- uint32_t random_value = arc4random();
- for (int i = 0; i < 20 && random_value > max_usable; ++i) {
- // By chance we picked a value from the incomplete group. Note that this group has size at
- // most 2**31-1, so picking this group has a chance of less than 50%.
- // In practice, this means that for the worst possible input, there is still only a
- // once-in-a-million chance to get to iteration 20. In theory we should be able to loop
- // forever. Here we prefer marginally imperfect random numbers over weird runtime behavior.
- random_value = arc4random();
- }
- return random_value % max_bounds;
+ return AK::get_random_uniform(max_bounds);
}
char* realpath(const char* pathname, char* buffer)