diff --git a/Makefile b/Makefile
index 6bf7befb..d5eacb64 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
-SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map
+SOURCES := source source/spl source/spl/smc source/updater source/patcher source/map source/rnd
DATA := data
INCLUDES := include
diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp
index 688d452d..fd478c37 100644
--- a/include/stratosphere.hpp
+++ b/include/stratosphere.hpp
@@ -45,4 +45,4 @@
#include "stratosphere/on_crash.hpp"
-#include "stratosphere/random.hpp"
\ No newline at end of file
+#include "stratosphere/rnd.hpp"
\ No newline at end of file
diff --git a/include/stratosphere/rnd.hpp b/include/stratosphere/rnd.hpp
new file mode 100644
index 00000000..7315f6b9
--- /dev/null
+++ b/include/stratosphere/rnd.hpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+
+#include "rnd/rnd_api.hpp"
diff --git a/include/stratosphere/random.hpp b/include/stratosphere/rnd/rnd_api.hpp
similarity index 72%
rename from include/stratosphere/random.hpp
rename to include/stratosphere/rnd/rnd_api.hpp
index 877f97c4..d7d22789 100644
--- a/include/stratosphere/random.hpp
+++ b/include/stratosphere/rnd/rnd_api.hpp
@@ -17,12 +17,11 @@
#pragma once
#include
-class StratosphereRandomUtils {
- public:
- static u32 GetRandomU32(u32 max);
- static u64 GetRandomU64(u64 max);
- static void GetRandomBytes(void* out, size_t size);
+namespace sts::rnd {
- template
- static T GetRandom(T max);
-};
\ No newline at end of file
+ /* Random utilities. */
+ void GenerateRandomBytes(void* out, size_t size);
+ u32 GenerateRandomU32(u32 max = std::numeric_limits::max());
+ u64 GenerateRandomU64(u64 max = std::numeric_limits::max());
+
+}
diff --git a/source/map/map_api.cpp b/source/map/map_api.cpp
index 0281f940..60fdccd0 100644
--- a/source/map/map_api.cpp
+++ b/source/map/map_api.cpp
@@ -116,7 +116,7 @@ namespace sts::map {
uintptr_t try_address;
for (unsigned int i = 0; i < LocateRetryCount; i++) {
- try_address = address_space.aslr_base + (StratosphereRandomUtils::GetRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12);
+ try_address = address_space.aslr_base + (rnd::GenerateRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12);
MappedCodeMemory tmp_mcm(process_handle, try_address, base_address, size);
R_TRY_CATCH(tmp_mcm.GetResult()) {
@@ -148,7 +148,7 @@ namespace sts::map {
uintptr_t try_address;
for (unsigned int i = 0; i < LocateRetryCount; i++) {
while (true) {
- try_address = address_space.aslr_base + (StratosphereRandomUtils::GetRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12);
+ try_address = address_space.aslr_base + (rnd::GenerateRandomU64(static_cast(address_space.aslr_size - size) >> 12) << 12);
if (address_space.heap_size && (address_space.heap_base <= try_address + size - 1 && try_address <= address_space.heap_end - 1)) {
continue;
}
diff --git a/source/random.cpp b/source/random.cpp
deleted file mode 100644
index 0d442c15..00000000
--- a/source/random.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2018-2019 Atmosphère-NX
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include
-#include
-#include
-
-/* Official HOS uses TinyMT. This is high effort. Let's just use XorShift. */
-/* https://en.wikipedia.org/wiki/Xorshift */
-class XorShiftGenerator {
- public:
- using result_type = uint32_t;
- static constexpr result_type (min)() { return 0; }
- static constexpr result_type (max)() { return UINT32_MAX; }
- static constexpr size_t num_seed_dwords = 4;
- private:
- result_type random_state[num_seed_dwords];
- public:
-
- explicit XorShiftGenerator() {
- /* Seed using process entropy. */
- u64 val = 0;
- for (size_t i = 0; i < num_seed_dwords; i++) {
- R_ASSERT(svcGetInfo(&val, 0xB, 0, i));
- this->random_state[i] = result_type(val);
- }
- }
-
- explicit XorShiftGenerator(std::random_device &rd) {
- for (size_t i = 0; i < num_seed_dwords; i++) {
- this->random_state[i] = result_type(rd());
- }
- }
-
- result_type operator()() {
- result_type s, t = this->random_state[3];
- t ^= t << 11;
- t ^= t >> 8;
- this->random_state[3] = this->random_state[2]; this->random_state[2] = this->random_state[1]; this->random_state[1] = (s = this->random_state[0]);
- t ^= s;
- t ^= s >> 19;
- this->random_state[0] = t;
- return t;
- }
-
- void discard(size_t n) {
- for (size_t i = 0; i < n; i++) {
- operator()();
- }
- }
-};
-
-static XorShiftGenerator g_rnd_generator;
-
-template
-T StratosphereRandomUtils::GetRandom(T max) {
- std::uniform_int_distribution rnd(0, max);
- return rnd(g_rnd_generator);
-}
-
-/* These are slightly biased, but I think that's totally okay. */
-u32 StratosphereRandomUtils::GetRandomU32(u32 max) {
- return GetRandom(max);
-}
-
-u64 StratosphereRandomUtils::GetRandomU64(u64 max) {
- return GetRandom(max);
-}
-
-void StratosphereRandomUtils::GetRandomBytes(void* out, size_t size) {
- std::generate(reinterpret_cast(out), reinterpret_cast(out) + size, std::bind(GetRandom, 0xFF));
-}
-
diff --git a/source/rnd/rnd_api.cpp b/source/rnd/rnd_api.cpp
new file mode 100644
index 00000000..c9c83bb8
--- /dev/null
+++ b/source/rnd/rnd_api.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+namespace sts::rnd {
+
+ namespace {
+
+ /* Generator type. */
+ /* Official HOS uses TinyMT. This is high effort. Let's just use XorShift. */
+ /* https://en.wikipedia.org/wiki/Xorshift */
+ class XorShiftGenerator {
+ public:
+ using ResultType = uint32_t;
+ using result_type = ResultType;
+ static constexpr ResultType (min)() { return std::numeric_limits::min(); }
+ static constexpr ResultType (max)() { return std::numeric_limits::max(); }
+ static constexpr size_t SeedSize = 4;
+ private:
+ ResultType random_state[SeedSize];
+ public:
+
+ explicit XorShiftGenerator() {
+ /* Seed using process entropy. */
+ u64 val = 0;
+ for (size_t i = 0; i < SeedSize; i++) {
+ R_ASSERT(svcGetInfo(&val, InfoType_RandomEntropy, INVALID_HANDLE, i));
+ this->random_state[i] = ResultType(val);
+ }
+ }
+
+ explicit XorShiftGenerator(std::random_device &rd) {
+ for (size_t i = 0; i < SeedSize; i++) {
+ this->random_state[i] = ResultType(rd());
+ }
+ }
+
+ ResultType operator()() {
+ ResultType s, t = this->random_state[3];
+ t ^= t << 11;
+ t ^= t >> 8;
+ this->random_state[3] = this->random_state[2]; this->random_state[2] = this->random_state[1]; this->random_state[1] = (s = this->random_state[0]);
+ t ^= s;
+ t ^= s >> 19;
+ this->random_state[0] = t;
+ return t;
+ }
+
+ void discard(size_t n) {
+ for (size_t i = 0; i < n; i++) {
+ operator()();
+ }
+ }
+ };
+
+ /* Generator global. */
+ XorShiftGenerator g_rnd_generator;
+
+ /* Templated helpers. */
+ template
+ T GenerateRandom(T max = std::numeric_limits::max()) {
+ std::uniform_int_distribution rnd(std::numeric_limits::min(), max);
+ return rnd(g_rnd_generator);
+ }
+
+ }
+
+ void GenerateRandomBytes(void* _out, size_t size) {
+ uintptr_t out = reinterpret_cast(_out);
+ uintptr_t end = out + size;
+
+ /* Force alignment. */
+ if (out % sizeof(u16) && out < end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u8);
+ }
+ if (out % sizeof(u32) && out < end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u16);
+ }
+ if (out % sizeof(u64) && out < end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u32);
+ }
+
+ /* Perform as many aligned writes as possible. */
+ while (out + sizeof(u64) <= end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u64);
+ }
+
+ /* Do remainder writes. */
+ if (out + sizeof(u32) <= end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u32);
+ }
+ if (out + sizeof(u16) <= end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u16);
+ }
+ if (out + sizeof(u8) <= end) {
+ *reinterpret_cast(out) = GenerateRandom();
+ out += sizeof(u8);
+ }
+ }
+
+ u32 GenerateRandomU32(u32 max) {
+ return GenerateRandom(max);
+ }
+
+ u64 GenerateRandomU64(u64 max) {
+ return GenerateRandom(max);
+ }
+
+}