From 3922dff2503bfca1d3a08ad148fe4e15a96417d7 Mon Sep 17 00:00:00 2001
From: iphydf <iphydf@users.noreply.github.com>
Date: Tue, 29 Aug 2023 21:26:57 +0000
Subject: [PATCH] refactor: Move some OS-specifics into tox_system.

---
 .dockerignore                               |   2 +
 .github/scripts/flags.sh                    |   2 +-
 BUILD.bazel                                 |  36 ++-
 CMakeLists.txt                              |  42 ++-
 auto_tests/BUILD.bazel                      |   5 +
 auto_tests/TCP_test.c                       |  79 ++---
 auto_tests/announce_test.c                  |  17 +-
 auto_tests/auto_test_support.c              |  18 +-
 auto_tests/auto_test_support.h              |   1 +
 auto_tests/conference_av_test.c             |   3 +-
 auto_tests/conference_test.c                |   3 +-
 auto_tests/crypto_test.c                    |  57 ++--
 auto_tests/encryptsave_test.c               |   3 +-
 auto_tests/forwarding_test.c                |  19 +-
 auto_tests/group_message_test.c             |   3 +-
 auto_tests/group_sync_test.c                |   3 +-
 auto_tests/group_topic_test.c               |   5 +-
 auto_tests/lan_discovery_test.c             |  16 +-
 auto_tests/network_test.c                   |   3 +-
 auto_tests/onion_test.c                     |  49 +--
 auto_tests/reconnect_test.c                 |   3 +-
 auto_tests/save_friend_test.c               |   3 +-
 auto_tests/save_load_test.c                 |  21 +-
 auto_tests/tox_dispatch_test.c              |   6 +-
 auto_tests/tox_events_test.c                |  15 +-
 auto_tests/tox_many_tcp_test.c              |   5 +-
 auto_tests/tox_many_test.c                  |   3 +-
 auto_tests/toxav_many_test.c                |  26 +-
 cmake/ModulePackage.cmake                   |   6 +-
 cmake/StrictAbi.cmake                       |   2 +-
 other/BUILD.bazel                           |   3 +
 other/DHT_bootstrap.c                       |  21 +-
 other/analysis/run-clang                    |   2 +-
 other/analysis/run-clang-analyze            |   2 +-
 other/analysis/run-gcc                      |   2 +-
 other/bootstrap_daemon/BUILD.bazel          |   3 +
 other/bootstrap_daemon/src/tox-bootstrapd.c |  20 +-
 testing/BUILD.bazel                         |   3 +
 testing/Messenger_test.c                    |   9 +-
 testing/fuzzing/BUILD.bazel                 |   6 +
 testing/fuzzing/bootstrap_harness.cc        |  12 +-
 testing/fuzzing/e2e_fuzz_test.cc            |   7 +-
 testing/fuzzing/fuzz_support.cc             | 109 +++----
 testing/fuzzing/fuzz_support.h              |  14 +-
 testing/fuzzing/fuzz_tox.h                  |   3 +-
 tox.h                                       |   5 +
 toxav.h                                     |   5 +
 toxav/BUILD.bazel                           |   1 +
 toxav/Makefile.inc                          |   5 +-
 toxav/rtp_test.cc                           |   3 +-
 toxav/toxav.c                               |   2 +-
 toxcore/BUILD.bazel                         | 236 +++++++++++++-
 toxcore/DHT.c                               |  28 +-
 toxcore/DHT.h                               |  12 +-
 toxcore/DHT_fuzz_test.cc                    |   7 +-
 toxcore/DHT_test.cc                         |  31 +-
 toxcore/LAN_discovery.c                     |  52 ++--
 toxcore/LAN_discovery.h                     |   2 +-
 toxcore/Makefile.inc                        | 180 ++++++-----
 toxcore/Messenger.c                         |  14 +-
 toxcore/Messenger.h                         |   4 +-
 toxcore/TCP_client.c                        |   6 +-
 toxcore/TCP_client.h                        |   2 +-
 toxcore/TCP_common.c                        |   4 +-
 toxcore/TCP_common.h                        |   2 +-
 toxcore/TCP_connection.c                    |   4 +-
 toxcore/TCP_connection.h                    |   2 +-
 toxcore/TCP_server.c                        |  17 +-
 toxcore/TCP_server.h                        |   2 +-
 toxcore/announce.c                          |  31 +-
 toxcore/announce.h                          |   2 +-
 toxcore/bin_pack.c                          |  14 +-
 toxcore/bin_pack.h                          |   5 +-
 toxcore/bin_pack_test.cc                    |  37 ++-
 toxcore/bin_unpack.c                        |  21 +-
 toxcore/bin_unpack.h                        |   5 +-
 toxcore/ccompat.h                           |   2 +-
 toxcore/crypto_core.c                       | 108 ++-----
 toxcore/crypto_core.h                       |  29 +-
 toxcore/crypto_core_test.cc                 |   5 +-
 toxcore/events/events_alloc.h               |   2 +-
 toxcore/forwarding.c                        |   8 +-
 toxcore/forwarding.h                        |   2 +-
 toxcore/forwarding_fuzz_test.cc             |  10 +-
 toxcore/friend_connection.c                 |  16 +-
 toxcore/friend_connection.h                 |   2 +-
 toxcore/friend_requests.c                   |  16 +-
 toxcore/friend_requests.h                   |   3 +-
 toxcore/group.c                             |  66 ++--
 toxcore/group.h                             |   6 +-
 toxcore/group_announce.c                    |  20 +-
 toxcore/group_announce.h                    |   5 +-
 toxcore/group_announce_fuzz_test.cc         |  25 +-
 toxcore/group_announce_test.cc              |  23 +-
 toxcore/group_chats.c                       | 295 +++++++++---------
 toxcore/group_chats.h                       |   5 +-
 toxcore/group_common.h                      |   2 +-
 toxcore/group_connection.c                  |  95 +++---
 toxcore/group_connection.h                  |  12 +-
 toxcore/group_moderation.c                  |  50 +--
 toxcore/group_moderation_fuzz_test.cc       |   3 +-
 toxcore/group_moderation_test.cc            |  43 +--
 toxcore/group_onion_announce.c              |  11 +-
 toxcore/group_onion_announce.h              |   8 +-
 toxcore/group_pack.c                        |  24 +-
 toxcore/list.c                              |  12 +-
 toxcore/list.h                              |   7 +-
 toxcore/list_test.cc                        |  19 +-
 toxcore/logger.c                            |  22 +-
 toxcore/logger.h                            |   6 +-
 toxcore/mem.c                               |  61 ++--
 toxcore/mem.h                               |  31 +-
 toxcore/mem_test.cc                         |  12 +-
 toxcore/mono_time.c                         |  31 +-
 toxcore/mono_time.h                         |  14 +-
 toxcore/mono_time_test.cc                   |  27 +-
 toxcore/net_crypto.c                        |  40 +--
 toxcore/net_crypto.h                        |   2 +-
 toxcore/network.c                           | 323 ++++++--------------
 toxcore/network.h                           |  56 +---
 toxcore/onion.c                             |  38 +--
 toxcore/onion.h                             |  10 +-
 toxcore/onion_announce.c                    |  32 +-
 toxcore/onion_announce.h                    |  19 +-
 toxcore/onion_client.c                      |  45 +--
 toxcore/onion_client.h                      |   2 +-
 toxcore/os_logger.c                         |  28 ++
 toxcore/os_logger.h                         |  20 ++
 toxcore/os_memory.c                         |  39 +++
 toxcore/os_memory.h                         |  20 ++
 toxcore/os_network.c                        | 288 +++++++++++++++++
 toxcore/os_network.h                        |  20 ++
 toxcore/os_network_impl.h                   |  34 +++
 toxcore/os_random.c                         |  60 ++++
 toxcore/os_random.h                         |  20 ++
 toxcore/os_system.c                         |  24 ++
 toxcore/os_system.h                         |  31 ++
 toxcore/ping.c                              |  17 +-
 toxcore/ping.h                              |   2 +-
 toxcore/ping_array.c                        |   2 +-
 toxcore/ping_array.h                        |   2 +-
 toxcore/ping_array_test.cc                  |  42 +--
 toxcore/tox.c                               |   7 +-
 toxcore/tox.h                               |  49 +--
 toxcore/tox_attributes.h                    |  31 ++
 toxcore/tox_events.c                        |   4 +-
 toxcore/tox_events.h                        |   4 +-
 toxcore/tox_events_test.cc                  |  12 +-
 toxcore/tox_logger.c                        |  39 +++
 toxcore/tox_logger.h                        |  65 ++++
 toxcore/tox_logger_impl.h                   |  53 ++++
 toxcore/tox_memory.c                        |  60 ++++
 toxcore/tox_memory.h                        |  76 +++++
 toxcore/tox_memory_impl.h                   |  49 +++
 toxcore/tox_network.c                       | 106 +++++++
 toxcore/tox_network.h                       |  51 ++++
 toxcore/tox_network_impl.h                  |  64 ++++
 toxcore/tox_private.c                       |  12 -
 toxcore/tox_private.h                       |  12 -
 toxcore/tox_random.c                        |  41 +++
 toxcore/tox_random.h                        |  33 ++
 toxcore/tox_random_impl.h                   |  33 ++
 toxcore/tox_struct.h                        |   1 +
 toxcore/tox_system.c                        |  32 ++
 toxcore/tox_system.h                        |  34 +++
 toxcore/tox_system_impl.h                   |  26 ++
 toxcore/tox_test.cc                         |   3 +-
 toxcore/tox_time.c                          |  36 +++
 toxcore/tox_time.h                          |  33 ++
 toxcore/tox_time_impl.h                     |  31 ++
 toxcore/tox_unpack.h                        |   2 +-
 toxcore/util.h                              |   2 +-
 toxcore/util_test.cc                        |   5 +-
 toxencryptsave.h                            |   5 +
 toxencryptsave/BUILD.bazel                  |   4 +
 toxencryptsave/Makefile.inc                 |   2 +-
 toxencryptsave/toxencryptsave.c             |  20 +-
 177 files changed, 3299 insertions(+), 1505 deletions(-)
 create mode 100644 .dockerignore
 create mode 100644 tox.h
 create mode 100644 toxav.h
 create mode 100644 toxcore/os_logger.c
 create mode 100644 toxcore/os_logger.h
 create mode 100644 toxcore/os_memory.c
 create mode 100644 toxcore/os_memory.h
 create mode 100644 toxcore/os_network.c
 create mode 100644 toxcore/os_network.h
 create mode 100644 toxcore/os_network_impl.h
 create mode 100644 toxcore/os_random.c
 create mode 100644 toxcore/os_random.h
 create mode 100644 toxcore/os_system.c
 create mode 100644 toxcore/os_system.h
 create mode 100644 toxcore/tox_attributes.h
 create mode 100644 toxcore/tox_logger.c
 create mode 100644 toxcore/tox_logger.h
 create mode 100644 toxcore/tox_logger_impl.h
 create mode 100644 toxcore/tox_memory.c
 create mode 100644 toxcore/tox_memory.h
 create mode 100644 toxcore/tox_memory_impl.h
 create mode 100644 toxcore/tox_network.c
 create mode 100644 toxcore/tox_network.h
 create mode 100644 toxcore/tox_network_impl.h
 create mode 100644 toxcore/tox_random.c
 create mode 100644 toxcore/tox_random.h
 create mode 100644 toxcore/tox_random_impl.h
 create mode 100644 toxcore/tox_system.c
 create mode 100644 toxcore/tox_system.h
 create mode 100644 toxcore/tox_system_impl.h
 create mode 100644 toxcore/tox_time.c
 create mode 100644 toxcore/tox_time.h
 create mode 100644 toxcore/tox_time_impl.h
 create mode 100644 toxencryptsave.h

diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000000..3ad05109d47
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+_build
+_install
diff --git a/.github/scripts/flags.sh b/.github/scripts/flags.sh
index 80a56c017df..d2af1292c48 100644
--- a/.github/scripts/flags.sh
+++ b/.github/scripts/flags.sh
@@ -29,7 +29,7 @@ add_flag -O3 -march=native
 # Warn on non-ISO C.
 add_c_flag -pedantic
 add_c_flag -std=c99
-add_cxx_flag -std=c++11
+add_cxx_flag -std=c++17
 
 add_flag -g3
 add_flag -ftrapv
diff --git a/BUILD.bazel b/BUILD.bazel
index 4d39dab3332..472347b04b7 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -8,19 +8,49 @@ project()
 genrule(
     name = "public_headers",
     srcs = [
+        "toxav.h",
+        "tox.h",
+        "toxencryptsave.h",
         "//c-toxcore/toxav:toxav.h",
         "//c-toxcore/toxcore:tox.h",
+        "//c-toxcore/toxcore:tox_attributes.h",
+        "//c-toxcore/toxcore:tox_logger.h",
+        "//c-toxcore/toxcore:tox_memory.h",
+        "//c-toxcore/toxcore:tox_network.h",
+        "//c-toxcore/toxcore:tox_random.h",
+        "//c-toxcore/toxcore:tox_system.h",
+        "//c-toxcore/toxcore:tox_time.h",
         "//c-toxcore/toxencryptsave:toxencryptsave.h",
     ],
     outs = [
         "tox/toxav.h",
         "tox/tox.h",
         "tox/toxencryptsave.h",
+        "tox/toxav/toxav.h",
+        "tox/toxcore/tox.h",
+        "tox/toxcore/tox_attributes.h",
+        "tox/toxcore/tox_logger.h",
+        "tox/toxcore/tox_memory.h",
+        "tox/toxcore/tox_network.h",
+        "tox/toxcore/tox_random.h",
+        "tox/toxcore/tox_system.h",
+        "tox/toxcore/tox_time.h",
+        "tox/toxencryptsave/toxencryptsave.h",
     ],
     cmd = """
-        cp $(location //c-toxcore/toxav:toxav.h) $(GENDIR)/c-toxcore/tox/toxav.h
-        cp $(location //c-toxcore/toxcore:tox.h) $(GENDIR)/c-toxcore/tox/tox.h
-        cp $(location //c-toxcore/toxencryptsave:toxencryptsave.h) $(GENDIR)/c-toxcore/tox/toxencryptsave.h
+        cp $(location toxav.h) $(GENDIR)/c-toxcore/tox/toxav.h
+        cp $(location tox.h) $(GENDIR)/c-toxcore/tox/tox.h
+        cp $(location toxencryptsave.h) $(GENDIR)/c-toxcore/tox/toxencryptsave.h
+        cp $(location //c-toxcore/toxav:toxav.h) $(GENDIR)/c-toxcore/tox/toxav/toxav.h
+        cp $(location //c-toxcore/toxcore:tox.h) $(GENDIR)/c-toxcore/tox/toxcore/tox.h
+        cp $(location //c-toxcore/toxcore:tox_attributes.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_attributes.h
+        cp $(location //c-toxcore/toxcore:tox_logger.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_logger.h
+        cp $(location //c-toxcore/toxcore:tox_memory.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_memory.h
+        cp $(location //c-toxcore/toxcore:tox_network.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_network.h
+        cp $(location //c-toxcore/toxcore:tox_random.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_random.h
+        cp $(location //c-toxcore/toxcore:tox_system.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_system.h
+        cp $(location //c-toxcore/toxcore:tox_time.h) $(GENDIR)/c-toxcore/tox/toxcore/tox_time.h
+        cp $(location //c-toxcore/toxencryptsave:toxencryptsave.h) $(GENDIR)/c-toxcore/tox/toxencryptsave/toxencryptsave.h
     """,
     visibility = ["//visibility:public"],
 )
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d3cabf06c66..16c6ba802a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -282,6 +282,17 @@ set(toxcore_SOURCES
   toxcore/onion_client.c
   toxcore/onion_client.h
   toxcore/onion.h
+  toxcore/os_logger.c
+  toxcore/os_logger.h
+  toxcore/os_memory.c
+  toxcore/os_memory.h
+  toxcore/os_network.c
+  toxcore/os_network.h
+  toxcore/os_network_impl.h
+  toxcore/os_random.c
+  toxcore/os_random.h
+  toxcore/os_system.c
+  toxcore/os_system.h
   toxcore/ping_array.c
   toxcore/ping_array.h
   toxcore/ping.c
@@ -302,11 +313,29 @@ set(toxcore_SOURCES
   toxcore/timed_auth.h
   toxcore/tox_api.c
   toxcore/tox.c
+  toxcore/tox.h
   toxcore/tox_dispatch.c
   toxcore/tox_dispatch.h
   toxcore/tox_events.c
   toxcore/tox_events.h
-  toxcore/tox.h
+  toxcore/tox_logger.c
+  toxcore/tox_logger.h
+  toxcore/tox_logger_impl.h
+  toxcore/tox_memory.c
+  toxcore/tox_memory.h
+  toxcore/tox_memory_impl.h
+  toxcore/tox_network.c
+  toxcore/tox_network.h
+  toxcore/tox_network_impl.h
+  toxcore/tox_random.c
+  toxcore/tox_random.h
+  toxcore/tox_random_impl.h
+  toxcore/tox_system.c
+  toxcore/tox_system.h
+  toxcore/tox_system_impl.h
+  toxcore/tox_time.c
+  toxcore/tox_time.h
+  toxcore/tox_time_impl.h
   toxcore/tox_private.c
   toxcore/tox_private.h
   toxcore/tox_unpack.c
@@ -316,9 +345,16 @@ set(toxcore_SOURCES
 set(toxcore_LINK_MODULES ${toxcore_LINK_MODULES} ${LIBSODIUM_LIBRARIES})
 set(toxcore_PKGCONFIG_REQUIRES ${toxcore_PKGCONFIG_REQUIRES} libsodium)
 set(toxcore_API_HEADERS
+  ${toxcore_SOURCE_DIR}/tox.h^tox
   ${toxcore_SOURCE_DIR}/toxcore/tox.h^tox
+  ${toxcore_SOURCE_DIR}/toxcore/tox_dispatch.h^tox
   ${toxcore_SOURCE_DIR}/toxcore/tox_events.h^tox
-  ${toxcore_SOURCE_DIR}/toxcore/tox_dispatch.h^tox)
+  ${toxcore_SOURCE_DIR}/toxcore/tox_logger.h^tox
+  ${toxcore_SOURCE_DIR}/toxcore/tox_memory.h^tox
+  ${toxcore_SOURCE_DIR}/toxcore/tox_network.h^tox
+  ${toxcore_SOURCE_DIR}/toxcore/tox_random.h^tox
+  ${toxcore_SOURCE_DIR}/toxcore/tox_system.h^tox
+  ${toxcore_SOURCE_DIR}/toxcore/tox_time.h^tox)
 
 ################################################################################
 #
@@ -346,6 +382,7 @@ if(BUILD_TOXAV)
     toxav/video.c
     toxav/video.h)
   set(toxcore_API_HEADERS ${toxcore_API_HEADERS}
+    ${toxcore_SOURCE_DIR}/toxav.h^toxav
     ${toxcore_SOURCE_DIR}/toxav/toxav.h^toxav)
 
   set(toxcore_LINK_MODULES ${toxcore_LINK_MODULES} ${OPUS_LIBRARIES} ${VPX_LIBRARIES})
@@ -362,6 +399,7 @@ set(toxcore_SOURCES ${toxcore_SOURCES}
   toxencryptsave/toxencryptsave.c
   toxencryptsave/toxencryptsave.h)
 set(toxcore_API_HEADERS ${toxcore_API_HEADERS}
+  ${toxcore_SOURCE_DIR}/toxencryptsave.h^tox
   ${toxcore_SOURCE_DIR}/toxencryptsave/toxencryptsave.h^tox)
 
 ################################################################################
diff --git a/auto_tests/BUILD.bazel b/auto_tests/BUILD.bazel
index babd3aca845..d5731890e78 100644
--- a/auto_tests/BUILD.bazel
+++ b/auto_tests/BUILD.bazel
@@ -19,6 +19,7 @@ cc_library(
         "//c-toxcore/toxcore:Messenger",
         "//c-toxcore/toxcore:mono_time",
         "//c-toxcore/toxcore:tox",
+        "//c-toxcore/toxcore:tox_time",
     ],
 )
 
@@ -61,9 +62,13 @@ flaky_tests = {
         "//c-toxcore/toxcore:onion",
         "//c-toxcore/toxcore:onion_announce",
         "//c-toxcore/toxcore:onion_client",
+        "//c-toxcore/toxcore:os_memory",
+        "//c-toxcore/toxcore:os_network",
+        "//c-toxcore/toxcore:os_random",
         "//c-toxcore/toxcore:tox",
         "//c-toxcore/toxcore:tox_dispatch",
         "//c-toxcore/toxcore:tox_events",
+        "//c-toxcore/toxcore:tox_time",
         "//c-toxcore/toxcore:util",
         "//c-toxcore/toxencryptsave",
         "@libsodium",
diff --git a/auto_tests/TCP_test.c b/auto_tests/TCP_test.c
index d5455cf0e83..f056082272a 100644
--- a/auto_tests/TCP_test.c
+++ b/auto_tests/TCP_test.c
@@ -8,6 +8,9 @@
 #include "../toxcore/TCP_server.h"
 #include "../toxcore/crypto_core.h"
 #include "../toxcore/mono_time.h"
+#include "../toxcore/os_random.h"
+#include "../toxcore/os_network.h"
+#include "../toxcore/os_memory.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
 
@@ -45,15 +48,15 @@ static uint16_t ports[NUM_PORTS] = {13215, 33445, 25643};
 
 static void test_basic(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
-    Logger *logger = logger_new();
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
+    Logger *logger = logger_new(mem);
     logger_callback_log(logger, print_debug_logger, nullptr, nullptr);
 
     // Attempt to create a new TCP_Server instance.
@@ -103,7 +106,7 @@ static void test_basic(void)
 
     // Encrypting handshake
     int ret = encrypt_data(self_public_key, f_secret_key, handshake + CRYPTO_PUBLIC_KEY_SIZE, handshake_plain,
-                           TCP_HANDSHAKE_PLAIN_SIZE, handshake + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                           TCP_HANDSHAKE_PLAIN_SIZE, handshake + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, mem);
     ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE),
                   "encrypt_data() call failed.");
 
@@ -129,7 +132,7 @@ static void test_basic(void)
     ck_assert_msg(net_recv(ns, logger, sock, response, TCP_SERVER_HANDSHAKE_SIZE, &localhost) == TCP_SERVER_HANDSHAKE_SIZE,
                   "Could/did not receive a server response to the initial handshake.");
     ret = decrypt_data(self_public_key, f_secret_key, response, response + CRYPTO_NONCE_SIZE,
-                       TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, response_plain);
+                       TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, response_plain, mem);
     ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, "Failed to decrypt handshake response.");
     uint8_t f_nonce_r[CRYPTO_NONCE_SIZE];
     uint8_t f_shared_key[CRYPTO_SHARED_KEY_SIZE];
@@ -143,7 +146,7 @@ static void test_basic(void)
     uint8_t r_req[2 + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE];
     uint16_t size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE;
     size = net_htons(size);
-    encrypt_data_symmetric(f_shared_key, f_nonce, r_req_p, 1 + CRYPTO_PUBLIC_KEY_SIZE, r_req + 2);
+    encrypt_data_symmetric(f_shared_key, f_nonce, r_req_p, 1 + CRYPTO_PUBLIC_KEY_SIZE, r_req + 2, mem);
     increment_nonce(f_nonce);
     memcpy(r_req, &size, 2);
 
@@ -174,7 +177,7 @@ static void test_basic(void)
                   "Wrong packet size for request response.");
 
     uint8_t packet_resp_plain[4096];
-    ret = decrypt_data_symmetric(f_shared_key, f_nonce_r, packet_resp + 2, recv_data_len - 2, packet_resp_plain);
+    ret = decrypt_data_symmetric(f_shared_key, f_nonce_r, packet_resp + 2, recv_data_len - 2, packet_resp_plain, mem);
     ck_assert_msg(ret != -1, "Failed to decrypt the TCP server's response.");
     increment_nonce(f_nonce_r);
 
@@ -229,7 +232,7 @@ static struct sec_TCP_con *new_TCP_con(const Logger *logger, const Memory *mem,
     random_nonce(rng, handshake + CRYPTO_PUBLIC_KEY_SIZE);
 
     int ret = encrypt_data(tcp_server_public_key(tcp_s), f_secret_key, handshake + CRYPTO_PUBLIC_KEY_SIZE, handshake_plain,
-                           TCP_HANDSHAKE_PLAIN_SIZE, handshake + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                           TCP_HANDSHAKE_PLAIN_SIZE, handshake + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, mem);
     ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE),
                   "Failed to encrypt the outgoing handshake.");
 
@@ -249,7 +252,7 @@ static struct sec_TCP_con *new_TCP_con(const Logger *logger, const Memory *mem,
     ck_assert_msg(net_recv(sec_c->ns, logger, sock, response, TCP_SERVER_HANDSHAKE_SIZE, &localhost) == TCP_SERVER_HANDSHAKE_SIZE,
                   "Failed to receive server handshake response.");
     ret = decrypt_data(tcp_server_public_key(tcp_s), f_secret_key, response, response + CRYPTO_NONCE_SIZE,
-                       TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, response_plain);
+                       TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, response_plain, mem);
     ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, "Failed to decrypt server handshake response.");
     encrypt_precompute(response_plain, t_secret_key, sec_c->shared_key);
     memcpy(sec_c->recv_nonce, response_plain + CRYPTO_SHARED_KEY_SIZE, CRYPTO_NONCE_SIZE);
@@ -270,7 +273,7 @@ static int write_packet_TCP_test_connection(const Logger *logger, struct sec_TCP
 
     uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
     memcpy(packet, &c_length, sizeof(uint16_t));
-    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
+    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t), con->mem);
 
     if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) {
         return -1;
@@ -295,7 +298,7 @@ static int read_packet_sec_TCP(const Logger *logger, struct sec_TCP_con *con, ui
 
     int rlen = net_recv(con->ns, logger, con->sock, data, length, &localhost);
     ck_assert_msg(rlen == length, "Did not receive packet of correct length. Wanted %i, instead got %i", length, rlen);
-    rlen = decrypt_data_symmetric(con->shared_key, con->recv_nonce, data + 2, length - 2, data);
+    rlen = decrypt_data_symmetric(con->shared_key, con->recv_nonce, data + 2, length - 2, data, con->mem);
     ck_assert_msg(rlen != -1, "Failed to decrypt a received packet from the Relay server.");
     increment_nonce(con->recv_nonce);
     return rlen;
@@ -303,15 +306,15 @@ static int read_packet_sec_TCP(const Logger *logger, struct sec_TCP_con *con, ui
 
 static void test_some(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
-    Logger *logger = logger_new();
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
+    Logger *logger = logger_new(mem);
 
     uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
     uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
@@ -498,15 +501,15 @@ static int oob_data_callback(void *object, const uint8_t *public_key, const uint
 
 static void test_client(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Logger *logger = logger_new();
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    Logger *logger = logger_new(mem);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
 
     uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
     uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
@@ -632,15 +635,15 @@ static void test_client(void)
 // Test how the client handles servers that don't respond.
 static void test_client_invalid(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
-    Logger *logger = logger_new();
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
+    Logger *logger = logger_new(mem);
 
     uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
     uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
@@ -711,15 +714,15 @@ static int tcp_data_callback(void *object, int id, const uint8_t *data, uint16_t
 
 static void test_tcp_connection(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
-    Logger *logger = logger_new();
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
+    Logger *logger = logger_new(mem);
 
     tcp_data_callback_called = 0;
     uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
@@ -824,15 +827,15 @@ static int tcp_oobdata_callback(void *object, const uint8_t *public_key, unsigne
 
 static void test_tcp_connection2(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
-    Logger *logger = logger_new();
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
+    Logger *logger = logger_new(mem);
 
     tcp_oobdata_callback_called = 0;
     tcp_data_callback_called = 0;
diff --git a/auto_tests/announce_test.c b/auto_tests/announce_test.c
index f0929c757c6..78d91895ed1 100644
--- a/auto_tests/announce_test.c
+++ b/auto_tests/announce_test.c
@@ -7,13 +7,16 @@
 #include "../toxcore/mono_time.h"
 #include "../toxcore/forwarding.h"
 #include "../toxcore/net_crypto.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_network.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
 
 static void test_bucketnum(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     uint8_t key1[CRYPTO_PUBLIC_KEY_SIZE], key2[CRYPTO_PUBLIC_KEY_SIZE];
     random_bytes(rng, key1, sizeof(key1));
@@ -50,20 +53,20 @@ static void test_announce_data(void *object, const uint8_t *data, uint16_t lengt
 
 static void test_store_data(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
-    Logger *log = logger_new();
+    Logger *log = logger_new(mem);
     ck_assert(log != nullptr);
     logger_callback_log(log, print_debug_logger, nullptr, nullptr);
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
     Networking_Core *net = new_networking_no_udp(log, mem, ns);
     DHT *dht = new_dht(log, mem, rng, ns, mono_time, net, true, true);
-    Forwarding *forwarding = new_forwarding(log, rng, mono_time, dht);
+    Forwarding *forwarding = new_forwarding(log, mem, rng, mono_time, dht);
     Announcements *announce = new_announcements(log, mem, rng, mono_time, forwarding);
     ck_assert(announce != nullptr);
 
diff --git a/auto_tests/auto_test_support.c b/auto_tests/auto_test_support.c
index cb409738ef4..b7d52b9c089 100644
--- a/auto_tests/auto_test_support.c
+++ b/auto_tests/auto_test_support.c
@@ -6,6 +6,7 @@
 #include "../toxcore/Messenger.h"
 #include "../toxcore/mono_time.h"
 #include "../toxcore/tox_struct.h"
+#include "../toxcore/tox_time_impl.h"
 
 #include "auto_test_support.h"
 
@@ -13,7 +14,7 @@
 #define ABORT_ON_LOG_ERROR true
 #endif
 
-Run_Auto_Options default_run_auto_options()
+Run_Auto_Options default_run_auto_options(void)
 {
     return (Run_Auto_Options) {
         .graph = GRAPH_COMPLETE,
@@ -159,15 +160,23 @@ static uint64_t get_state_clock_callback(void *user_data)
     return *clock;
 }
 
+static const Tox_Time_Funcs autotox_time_funcs = {
+    get_state_clock_callback,
+};
+
 void set_mono_time_callback(AutoTox *autotox)
 {
     ck_assert(autotox != nullptr);
 
+    if (autotox->tm == nullptr) {
+        autotox->tm = tox_time_new(&autotox_time_funcs, &autotox->clock, autotox->tox->sys.mem);
+    }
+
     Mono_Time *mono_time = autotox->tox->mono_time;
 
     autotox->clock = current_time_monotonic(mono_time);
-    mono_time_set_current_time_callback(mono_time, nullptr, nullptr);  // set to default first
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &autotox->clock);
+    mono_time_set_current_time_callback(mono_time, nullptr);  // set to default first
+    mono_time_set_current_time_callback(mono_time, autotox->tm);
 }
 
 void save_autotox(AutoTox *autotox)
@@ -193,6 +202,8 @@ void kill_autotox(AutoTox *autotox)
     fprintf(stderr, "Killing #%u\n", autotox->index);
     autotox->alive = false;
     tox_kill(autotox->tox);
+    tox_time_free(autotox->tm);
+    autotox->tm = nullptr;
 }
 
 void reload(AutoTox *autotox)
@@ -380,6 +391,7 @@ void run_auto_test(struct Tox_Options *options, uint32_t tox_count, void test(Au
 
     for (uint32_t i = 0; i < tox_count; ++i) {
         tox_kill(autotoxes[i].tox);
+        tox_time_free(autotoxes[i].tm);
         free(autotoxes[i].state);
         free(autotoxes[i].save_state);
     }
diff --git a/auto_tests/auto_test_support.h b/auto_tests/auto_test_support.h
index eab121aa367..10a250a0ffa 100644
--- a/auto_tests/auto_test_support.h
+++ b/auto_tests/auto_test_support.h
@@ -10,6 +10,7 @@
 
 typedef struct AutoTox {
     Tox *tox;
+    Tox_Time *tm;
 
     uint32_t index;
     uint64_t clock;
diff --git a/auto_tests/conference_av_test.c b/auto_tests/conference_av_test.c
index 9bbc4182699..2fbcd5e7f21 100644
--- a/auto_tests/conference_av_test.c
+++ b/auto_tests/conference_av_test.c
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "../toxav/toxav.h"
+#include "../toxcore/os_random.h"
 #include "check_compat.h"
 
 #define NUM_AV_GROUP_TOX 16
@@ -287,7 +288,7 @@ static void do_audio(AutoTox *autotoxes, uint32_t iterations)
 
 static void run_conference_tests(AutoTox *autotoxes)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     bool disabled[NUM_AV_GROUP_TOX] = {0};
 
diff --git a/auto_tests/conference_test.c b/auto_tests/conference_test.c
index 66edddd85c7..d7e3fe6283c 100644
--- a/auto_tests/conference_test.c
+++ b/auto_tests/conference_test.c
@@ -6,6 +6,7 @@
 #include <time.h>
 #include <stdint.h>
 
+#include "../toxcore/os_random.h"
 #include "../toxcore/util.h"
 
 #include "check_compat.h"
@@ -192,7 +193,7 @@ static uint32_t random_false_index(const Random *rng, bool *list, const uint32_t
 
 static void run_conference_tests(AutoTox *autotoxes)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     /* disabling name change propagation check for now, as it occasionally
      * fails due to disconnections too short to trigger freezing */
diff --git a/auto_tests/crypto_test.c b/auto_tests/crypto_test.c
index f4fdf3e22de..7d28fa0d832 100644
--- a/auto_tests/crypto_test.c
+++ b/auto_tests/crypto_test.c
@@ -4,6 +4,8 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/net_crypto.h"
 #include "check_compat.h"
 
@@ -82,6 +84,9 @@ static const uint8_t test_c[147] = {
 
 static void test_known(void)
 {
+    const Memory *mem = os_memory();
+    ck_assert(mem != nullptr);
+
     uint8_t c[147];
     uint8_t m[131];
     uint16_t clen, mlen;
@@ -91,12 +96,12 @@ static void test_known(void)
     ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed");
     ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed");
 
-    clen = encrypt_data(bobpk, alicesk, test_nonce, test_m, sizeof(test_m) / sizeof(uint8_t), c);
+    clen = encrypt_data(bobpk, alicesk, test_nonce, test_m, sizeof(test_m) / sizeof(uint8_t), c, mem);
 
     ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector");
     ck_assert_msg(clen == sizeof(c) / sizeof(uint8_t), "wrong ciphertext length");
 
-    mlen = decrypt_data(bobpk, alicesk, test_nonce, test_c, sizeof(test_c) / sizeof(uint8_t), m);
+    mlen = decrypt_data(bobpk, alicesk, test_nonce, test_c, sizeof(test_c) / sizeof(uint8_t), m, mem);
 
     ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector");
     ck_assert_msg(mlen == sizeof(m) / sizeof(uint8_t), "wrong plaintext length");
@@ -104,6 +109,9 @@ static void test_known(void)
 
 static void test_fast_known(void)
 {
+    const Memory *mem = os_memory();
+    ck_assert(mem != nullptr);
+
     uint8_t k[CRYPTO_SHARED_KEY_SIZE];
     uint8_t c[147];
     uint8_t m[131];
@@ -116,12 +124,12 @@ static void test_fast_known(void)
     ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed");
     ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed");
 
-    clen = encrypt_data_symmetric(k, test_nonce, test_m, sizeof(test_m) / sizeof(uint8_t), c);
+    clen = encrypt_data_symmetric(k, test_nonce, test_m, sizeof(test_m) / sizeof(uint8_t), c, mem);
 
     ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector");
     ck_assert_msg(clen == sizeof(c) / sizeof(uint8_t), "wrong ciphertext length");
 
-    mlen = decrypt_data_symmetric(k, test_nonce, test_c, sizeof(test_c) / sizeof(uint8_t), m);
+    mlen = decrypt_data_symmetric(k, test_nonce, test_c, sizeof(test_c) / sizeof(uint8_t), m, mem);
 
     ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector");
     ck_assert_msg(mlen == sizeof(m) / sizeof(uint8_t), "wrong plaintext length");
@@ -129,7 +137,9 @@ static void test_fast_known(void)
 
 static void test_endtoend(void)
 {
-    const Random *rng = system_random();
+    const Memory *mem = os_memory();
+    ck_assert(mem != nullptr);
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
 
     // Test 100 random messages and keypairs
@@ -170,10 +180,10 @@ static void test_endtoend(void)
         ck_assert_msg(memcmp(k1, k2, CRYPTO_SHARED_KEY_SIZE) == 0, "encrypt_precompute: bad");
 
         //Encrypt all four ways
-        const uint16_t c1len = encrypt_data(pk2, sk1, n, m, mlen, c1);
-        const uint16_t c2len = encrypt_data(pk1, sk2, n, m, mlen, c2);
-        const uint16_t c3len = encrypt_data_symmetric(k1, n, m, mlen, c3);
-        const uint16_t c4len = encrypt_data_symmetric(k2, n, m, mlen, c4);
+        const uint16_t c1len = encrypt_data(pk2, sk1, n, m, mlen, c1, mem);
+        const uint16_t c2len = encrypt_data(pk1, sk2, n, m, mlen, c2, mem);
+        const uint16_t c3len = encrypt_data_symmetric(k1, n, m, mlen, c3, mem);
+        const uint16_t c4len = encrypt_data_symmetric(k2, n, m, mlen, c4, mem);
 
         ck_assert_msg(c1len == c2len && c1len == c3len && c1len == c4len, "cyphertext lengths differ");
         ck_assert_msg(c1len == mlen + (uint16_t)CRYPTO_MAC_SIZE, "wrong cyphertext length");
@@ -181,10 +191,10 @@ static void test_endtoend(void)
                       && memcmp(c1, c4, c1len) == 0, "crypertexts differ");
 
         //Decrypt all four ways
-        const uint16_t m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1);
-        const uint16_t m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2);
-        const uint16_t m3len = decrypt_data_symmetric(k1, n, c1, c1len, m3);
-        const uint16_t m4len = decrypt_data_symmetric(k2, n, c1, c1len, m4);
+        const uint16_t m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1, mem);
+        const uint16_t m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2, mem);
+        const uint16_t m3len = decrypt_data_symmetric(k1, n, c1, c1len, m3, mem);
+        const uint16_t m4len = decrypt_data_symmetric(k2, n, c1, c1len, m4, mem);
 
         ck_assert_msg(m1len == m2len && m1len == m3len && m1len == m4len, "decrypted text lengths differ");
         ck_assert_msg(m1len == mlen, "wrong decrypted text length");
@@ -196,7 +206,9 @@ static void test_endtoend(void)
 
 static void test_large_data(void)
 {
-    const Random *rng = system_random();
+    const Memory *mem = os_memory();
+    ck_assert(mem != nullptr);
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     uint8_t k[CRYPTO_SHARED_KEY_SIZE];
     uint8_t n[CRYPTO_NONCE_SIZE];
@@ -220,13 +232,13 @@ static void test_large_data(void)
     //Generate key
     rand_bytes(rng, k, CRYPTO_SHARED_KEY_SIZE);
 
-    const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1);
-    const uint16_t c2len = encrypt_data_symmetric(k, n, m2, m2_size, c2);
+    const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1, mem);
+    const uint16_t c2len = encrypt_data_symmetric(k, n, m2, m2_size, c2, mem);
 
     ck_assert_msg(c1len == m1_size + CRYPTO_MAC_SIZE, "could not encrypt");
     ck_assert_msg(c2len == m2_size + CRYPTO_MAC_SIZE, "could not encrypt");
 
-    const uint16_t m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime);
+    const uint16_t m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime, mem);
 
     ck_assert_msg(m1plen == m1_size, "decrypted text lengths differ");
     ck_assert_msg(memcmp(m1prime, m1, m1_size) == 0, "decrypted texts differ");
@@ -240,8 +252,11 @@ static void test_large_data(void)
 
 static void test_large_data_symmetric(void)
 {
-    const Random *rng = system_random();
+    const Memory *mem = os_memory();
+    ck_assert(mem != nullptr);
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
+
     uint8_t k[CRYPTO_SYMMETRIC_KEY_SIZE];
 
     uint8_t n[CRYPTO_NONCE_SIZE];
@@ -260,10 +275,10 @@ static void test_large_data_symmetric(void)
     //Generate key
     new_symmetric_key(rng, k);
 
-    const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1);
+    const uint16_t c1len = encrypt_data_symmetric(k, n, m1, m1_size, c1, mem);
     ck_assert_msg(c1len == m1_size + CRYPTO_MAC_SIZE, "could not encrypt data");
 
-    const uint16_t m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime);
+    const uint16_t m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime, mem);
 
     ck_assert_msg(m1plen == m1_size, "decrypted text lengths differ");
     ck_assert_msg(memcmp(m1prime, m1, m1_size) == 0, "decrypted texts differ");
@@ -296,7 +311,7 @@ static void increment_nonce_number_cmp(uint8_t *nonce, uint32_t num)
 
 static void test_increment_nonce(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
 
     uint32_t i;
diff --git a/auto_tests/encryptsave_test.c b/auto_tests/encryptsave_test.c
index fb49c4e2af2..cd56f65710b 100644
--- a/auto_tests/encryptsave_test.c
+++ b/auto_tests/encryptsave_test.c
@@ -9,6 +9,7 @@
 #include "../testing/misc_tools.h"
 #include "../toxcore/ccompat.h"
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "../toxencryptsave/toxencryptsave.h"
 #include "auto_test_support.h"
@@ -169,7 +170,7 @@ static void test_keys(void)
     ck_assert(encrypted2a != nullptr);
     uint8_t *in_plaintext2a = (uint8_t *)malloc(plaintext_length2a);
     ck_assert(in_plaintext2a != nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     random_bytes(rng, in_plaintext2a, plaintext_length2a);
     ret = tox_pass_encrypt(in_plaintext2a, plaintext_length2a, key_char, 12, encrypted2a, &encerr);
diff --git a/auto_tests/forwarding_test.c b/auto_tests/forwarding_test.c
index f9c82784f20..f7e9336e215 100644
--- a/auto_tests/forwarding_test.c
+++ b/auto_tests/forwarding_test.c
@@ -8,6 +8,9 @@
 #include "../toxcore/mono_time.h"
 #include "../toxcore/forwarding.h"
 #include "../toxcore/net_crypto.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_network.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
@@ -104,18 +107,18 @@ typedef struct Forwarding_Subtox {
 
 static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp, uint32_t *index, uint16_t port)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
 
     Forwarding_Subtox *subtox = (Forwarding_Subtox *)calloc(1, sizeof(Forwarding_Subtox));
     ck_assert(subtox != nullptr);
 
-    subtox->log = logger_new();
+    subtox->log = logger_new(mem);
     ck_assert(subtox->log != nullptr);
     logger_callback_log(subtox->log, print_debug_logger, nullptr, index);
-    subtox->mono_time = mono_time_new(mem, nullptr, nullptr);
+    subtox->mono_time = mono_time_new(mem, nullptr);
 
     if (no_udp) {
         subtox->net = new_networking_no_udp(subtox->log, mem, ns);
@@ -129,7 +132,7 @@ static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp,
     const TCP_Proxy_Info inf = {{{{0}}}};
     subtox->c = new_net_crypto(subtox->log, mem, rng, ns, subtox->mono_time, subtox->dht, &inf);
 
-    subtox->forwarding = new_forwarding(subtox->log, rng, subtox->mono_time, subtox->dht);
+    subtox->forwarding = new_forwarding(subtox->log, mem, rng, subtox->mono_time, subtox->dht);
     ck_assert(subtox->forwarding != nullptr);
 
     subtox->announce = new_announcements(subtox->log, mem, rng, subtox->mono_time, subtox->forwarding);
@@ -152,11 +155,11 @@ static void kill_forwarding_subtox(const Memory *mem, Forwarding_Subtox *subtox)
 
 static void test_forwarding(void)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
 
     uint32_t index[NUM_FORWARDER];
diff --git a/auto_tests/group_message_test.c b/auto_tests/group_message_test.c
index d7a00a9fee0..8d5d7cc64d3 100644
--- a/auto_tests/group_message_test.c
+++ b/auto_tests/group_message_test.c
@@ -12,6 +12,7 @@
 
 #include "auto_test_support.h"
 #include "check_compat.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/util.h"
 
 typedef struct State {
@@ -334,7 +335,7 @@ static void group_message_test(AutoTox *autotoxes)
 #ifndef VANILLA_NACL
     ck_assert_msg(NUM_GROUP_TOXES >= 2, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES);
 
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
 
     Tox *tox0 = autotoxes[0].tox;
diff --git a/auto_tests/group_sync_test.c b/auto_tests/group_sync_test.c
index 4d2bc1866dc..fdd895ed344 100644
--- a/auto_tests/group_sync_test.c
+++ b/auto_tests/group_sync_test.c
@@ -10,6 +10,7 @@
 
 #include "auto_test_support.h"
 
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/util.h"
 
@@ -332,7 +333,7 @@ static void group_sync_test(AutoTox *autotoxes)
 {
 #ifndef VANILLA_NACL
     ck_assert(NUM_GROUP_TOXES >= 5);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
 
     for (size_t i = 0; i < NUM_GROUP_TOXES; ++i) {
diff --git a/auto_tests/group_topic_test.c b/auto_tests/group_topic_test.c
index 26dafcb459a..00fff8555d8 100644
--- a/auto_tests/group_topic_test.c
+++ b/auto_tests/group_topic_test.c
@@ -11,8 +11,9 @@
 #include "auto_test_support.h"
 #include "check_compat.h"
 
-#include "../toxcore/tox.h"
 #include "../toxcore/group_chats.h"
+#include "../toxcore/os_random.h"
+#include "../toxcore/tox.h"
 
 #define NUM_GROUP_TOXES 3
 
@@ -206,7 +207,7 @@ static void group_topic_test(AutoTox *autotoxes)
 #ifndef VANILLA_NACL
     ck_assert_msg(NUM_GROUP_TOXES >= 3, "NUM_GROUP_TOXES is too small: %d", NUM_GROUP_TOXES);
 
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
 
     Tox *tox0 = autotoxes[0].tox;
diff --git a/auto_tests/lan_discovery_test.c b/auto_tests/lan_discovery_test.c
index d7bf594b2bf..8ea4e39764c 100644
--- a/auto_tests/lan_discovery_test.c
+++ b/auto_tests/lan_discovery_test.c
@@ -3,6 +3,8 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/ccompat.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/tox_time_impl.h"
 #include "../toxcore/tox_struct.h"
 #include "auto_test_support.h"
 
@@ -12,6 +14,10 @@ static uint64_t get_state_clock_callback(void *user_data)
     return *clock;
 }
 
+static const Tox_Time_Funcs mock_time_funcs = {
+    get_state_clock_callback,
+};
+
 int main(void)
 {
     setvbuf(stdout, nullptr, _IONBF, 0);
@@ -21,14 +27,18 @@ int main(void)
     ck_assert(tox1 != nullptr);
     ck_assert(tox2 != nullptr);
 
+    const Memory *mem = os_memory();
+
     uint64_t clock = current_time_monotonic(tox1->mono_time);
+    Tox_Time *tm = tox_time_new(&mock_time_funcs, &clock, mem);
+
     Mono_Time *mono_time;
 
     mono_time = tox1->mono_time;
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock);
+    mono_time_set_current_time_callback(mono_time, tm);
 
     mono_time = tox2->mono_time;
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock);
+    mono_time_set_current_time_callback(mono_time, tm);
 
     printf("Waiting for LAN discovery. This loop will attempt to run until successful.");
 
@@ -49,5 +59,7 @@ int main(void)
 
     tox_kill(tox2);
     tox_kill(tox1);
+
+    tox_time_free(tm);
     return 0;
 }
diff --git a/auto_tests/network_test.c b/auto_tests/network_test.c
index df3b625a9e1..f96618385e2 100644
--- a/auto_tests/network_test.c
+++ b/auto_tests/network_test.c
@@ -3,6 +3,7 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/network.h"
+#include "../toxcore/os_network.h"
 #include "check_compat.h"
 
 #ifndef USE_IPV6
@@ -20,7 +21,7 @@ static void test_addr_resolv_localhost(void)
     errno = 0;
 #endif
 
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
 
     const char localhost[] = "localhost";
diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c
index 282b99637e6..c2874c2e8da 100644
--- a/auto_tests/onion_test.c
+++ b/auto_tests/onion_test.c
@@ -6,6 +6,9 @@
 #include "../toxcore/onion.h"
 #include "../toxcore/onion_announce.h"
 #include "../toxcore/onion_client.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_network.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
@@ -112,7 +115,7 @@ static int handle_test_3(void *object, const IP_Port *source, const uint8_t *pac
     int len = decrypt_data(test_3_pub_key, dht_get_self_secret_key(onion->dht),
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
-                           2 + CRYPTO_SHA256_SIZE + CRYPTO_MAC_SIZE, plain);
+                           2 + CRYPTO_SHA256_SIZE + CRYPTO_MAC_SIZE, plain, onion->mem);
 
     if (len == -1) {
         return 1;
@@ -148,7 +151,7 @@ static int handle_test_3_old(void *object, const IP_Port *source, const uint8_t
     int len = decrypt_data(test_3_pub_key, dht_get_self_secret_key(onion->dht),
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
-                           1 + CRYPTO_SHA256_SIZE + CRYPTO_MAC_SIZE, plain);
+                           1 + CRYPTO_SHA256_SIZE + CRYPTO_MAC_SIZE, plain, onion->mem);
 
     if (len == -1) {
         return 1;
@@ -185,7 +188,7 @@ static int handle_test_4(void *object, const IP_Port *source, const uint8_t *pac
     }
 
     int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, dht_get_self_secret_key(onion->dht), packet + 1,
-                           packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, sizeof("Install gentoo") + CRYPTO_MAC_SIZE, plain);
+                           packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, sizeof("Install gentoo") + CRYPTO_MAC_SIZE, plain, onion->mem);
 
     if (len == -1) {
         return 1;
@@ -204,10 +207,10 @@ static int handle_test_4(void *object, const IP_Port *source, const uint8_t *pac
  * Use Onion_Path path to send data of length to dest.
  * Maximum length of data is ONION_MAX_DATA_SIZE.
  */
-static void send_onion_packet(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length)
+static void send_onion_packet(const Networking_Core *net, const Memory *mem, const Random *rng, const Onion_Path *path, const IP_Port *dest, const uint8_t *data, uint16_t length)
 {
     uint8_t packet[ONION_MAX_PACKET_SIZE];
-    const int len = create_onion_packet(rng, packet, sizeof(packet), path, dest, data, length);
+    const int len = create_onion_packet(rng, packet, sizeof(packet), path, dest, data, length, mem);
     ck_assert_msg(len != -1, "failed to create onion packet");
     ck_assert_msg(sendpacket(net, &path->ip_port1, packet, len) == len, "failed to send onion packet");
 }
@@ -223,20 +226,20 @@ static Networking_Core *new_networking(const Logger *log, const Memory *mem, con
 static void test_basic(void)
 {
     uint32_t index[] = { 1, 2, 3 };
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     ck_assert(ns != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
 
-    Logger *log1 = logger_new();
+    Logger *log1 = logger_new(mem);
     logger_callback_log(log1, print_debug_logger, nullptr, &index[0]);
-    Logger *log2 = logger_new();
+    Logger *log2 = logger_new(mem);
     logger_callback_log(log2, print_debug_logger, nullptr, &index[1]);
 
-    Mono_Time *mono_time1 = mono_time_new(mem, nullptr, nullptr);
-    Mono_Time *mono_time2 = mono_time_new(mem, nullptr, nullptr);
+    Mono_Time *mono_time1 = mono_time_new(mem, nullptr);
+    Mono_Time *mono_time2 = mono_time_new(mem, nullptr);
 
     IP ip = get_loopback();
     Onion *onion1 = new_onion(log1, mem, mono_time1, rng, new_dht(log1, mem, rng, ns, mono_time1, new_networking(log1, mem, ns, &ip, 36567), true, false));
@@ -266,7 +269,7 @@ static void test_basic(void)
     nodes[3] = n2;
     Onion_Path path;
     create_onion_path(rng, onion1->dht, &path, nodes);
-    send_onion_packet(onion1->net, rng, &path, &nodes[3].ip_port, req_packet, sizeof(req_packet));
+    send_onion_packet(onion1->net, mem, rng, &path, &nodes[3].ip_port, req_packet, sizeof(req_packet));
 
     handled_test_1 = 0;
 
@@ -293,7 +296,7 @@ static void test_basic(void)
     uint64_t s;
     memcpy(&s, sb_data, sizeof(uint64_t));
     memcpy(test_3_pub_key, nodes[3].public_key, CRYPTO_PUBLIC_KEY_SIZE);
-    int ret = send_announce_request(onion1->net, rng, &path, &nodes[3],
+    int ret = send_announce_request(onion1->net, rng, mem, &path, &nodes[3],
                                     dht_get_self_public_key(onion1->dht),
                                     dht_get_self_secret_key(onion1->dht),
                                     zeroes,
@@ -315,7 +318,7 @@ static void test_basic(void)
     memcpy(onion_announce_entry_public_key(onion2_a, 1), dht_get_self_public_key(onion2->dht), CRYPTO_PUBLIC_KEY_SIZE);
     onion_announce_entry_set_time(onion2_a, 1, mono_time_get(mono_time2));
     networking_registerhandler(onion1->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_test_4, onion1);
-    send_announce_request(onion1->net, rng, &path, &nodes[3],
+    send_announce_request(onion1->net, rng, mem, &path, &nodes[3],
                           dht_get_self_public_key(onion1->dht),
                           dht_get_self_secret_key(onion1->dht),
                           test_3_ping_id,
@@ -331,16 +334,16 @@ static void test_basic(void)
                     CRYPTO_PUBLIC_KEY_SIZE) != 0);
 
     c_sleep(1000);
-    Logger *log3 = logger_new();
+    Logger *log3 = logger_new(mem);
     logger_callback_log(log3, print_debug_logger, nullptr, &index[2]);
 
-    Mono_Time *mono_time3 = mono_time_new(mem, nullptr, nullptr);
+    Mono_Time *mono_time3 = mono_time_new(mem, nullptr);
 
     Onion *onion3 = new_onion(log3, mem, mono_time3, rng, new_dht(log3, mem, rng, ns, mono_time3, new_networking(log3, mem, ns, &ip, 36569), true, false));
     ck_assert_msg((onion3 != nullptr), "Onion failed initializing.");
 
     random_nonce(rng, nonce);
-    ret = send_data_request(onion3->net, rng, &path, &nodes[3].ip_port,
+    ret = send_data_request(onion3->net, rng, mem, &path, &nodes[3].ip_port,
                             dht_get_self_public_key(onion1->dht),
                             dht_get_self_public_key(onion1->dht),
                             nonce, (const uint8_t *)"Install gentoo", sizeof("Install gentoo"));
@@ -407,14 +410,14 @@ static Onions *new_onions(const Memory *mem, const Random *rng, uint16_t port, u
 {
     IP ip = get_loopback();
     ip.ip.v6.uint8[15] = 1;
-    const Network *ns = system_network();
+    const Network *ns = os_network();
     Onions *on = (Onions *)malloc(sizeof(Onions));
 
     if (!on) {
         return nullptr;
     }
 
-    on->log = logger_new();
+    on->log = logger_new(mem);
 
     if (!on->log) {
         free(on);
@@ -423,7 +426,7 @@ static Onions *new_onions(const Memory *mem, const Random *rng, uint16_t port, u
 
     logger_callback_log(on->log, print_debug_logger, nullptr, index);
 
-    on->mono_time = mono_time_new(mem, nullptr, nullptr);
+    on->mono_time = mono_time_new(mem, nullptr);
 
     if (!on->mono_time) {
         logger_kill(on->log);
@@ -577,9 +580,9 @@ static void test_announce(void)
     uint32_t i, j;
     uint32_t index[NUM_ONIONS];
     Onions *onions[NUM_ONIONS];
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     ck_assert(mem != nullptr);
 
     for (i = 0; i < NUM_ONIONS; ++i) {
diff --git a/auto_tests/reconnect_test.c b/auto_tests/reconnect_test.c
index 253f66b0c5c..ad6a021f227 100644
--- a/auto_tests/reconnect_test.c
+++ b/auto_tests/reconnect_test.c
@@ -11,6 +11,7 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/friend_connection.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/util.h"
 #include "check_compat.h"
@@ -51,7 +52,7 @@ static bool all_disconnected_from(uint32_t tox_count, AutoTox *autotoxes, uint32
 
 static void test_reconnect(AutoTox *autotoxes)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     const time_t test_start_time = time(nullptr);
 
diff --git a/auto_tests/save_friend_test.c b/auto_tests/save_friend_test.c
index 80a6ed037e8..4a546cc53c6 100644
--- a/auto_tests/save_friend_test.c
+++ b/auto_tests/save_friend_test.c
@@ -8,6 +8,7 @@
 #include "../testing/misc_tools.h"
 #include "../toxcore/ccompat.h"
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
@@ -86,7 +87,7 @@ int main(void)
     ck_assert(reference_name != nullptr);
     ck_assert(reference_status != nullptr);
 
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     set_random(tox1, rng, tox_self_set_name, tox_max_name_length());
     set_random(tox2, rng, tox_self_set_name, tox_max_name_length());
diff --git a/auto_tests/save_load_test.c b/auto_tests/save_load_test.c
index 97077735633..41ac2bb48bf 100644
--- a/auto_tests/save_load_test.c
+++ b/auto_tests/save_load_test.c
@@ -8,8 +8,10 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/ccompat.h"
+#include "../toxcore/os_memory.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/tox_struct.h"
+#include "../toxcore/tox_time_impl.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
@@ -119,6 +121,10 @@ static uint64_t get_state_clock_callback(void *user_data)
     return clock;
 }
 
+static const Tox_Time_Funcs mock_time_funcs = {
+    get_state_clock_callback,
+};
+
 static void increment_clock(Time_Data *time_data, uint64_t count)
 {
     pthread_mutex_lock(&time_data->lock);
@@ -126,10 +132,10 @@ static void increment_clock(Time_Data *time_data, uint64_t count)
     pthread_mutex_unlock(&time_data->lock);
 }
 
-static void set_current_time_callback(Tox *tox, Time_Data *time_data)
+static void set_current_time_callback(Tox *tox, Tox_Time *tm)
 {
     Mono_Time *mono_time = tox->mono_time;
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, time_data);
+    mono_time_set_current_time_callback(mono_time, tm);
 }
 
 static void test_few_clients(void)
@@ -161,9 +167,12 @@ static void test_few_clients(void)
     Time_Data time_data;
     ck_assert_msg(pthread_mutex_init(&time_data.lock, nullptr) == 0, "Failed to init time_data mutex");
     time_data.clock = current_time_monotonic(tox1->mono_time);
-    set_current_time_callback(tox1, &time_data);
-    set_current_time_callback(tox2, &time_data);
-    set_current_time_callback(tox3, &time_data);
+
+    const Memory *mem = os_memory();
+    Tox_Time *tm = tox_time_new(&mock_time_funcs, &time_data, mem);
+    set_current_time_callback(tox1, tm);
+    set_current_time_callback(tox2, tm);
+    set_current_time_callback(tox3, tm);
 
     uint8_t dht_key[TOX_PUBLIC_KEY_SIZE];
     tox_self_get_dht_id(tox1, dht_key);
@@ -257,6 +266,8 @@ static void test_few_clients(void)
 
     tox_options_free(opts2);
     tox_options_free(opts3);
+
+    tox_time_free(tm);
 }
 
 int main(void)
diff --git a/auto_tests/tox_dispatch_test.c b/auto_tests/tox_dispatch_test.c
index 209e13788f2..c887176717b 100644
--- a/auto_tests/tox_dispatch_test.c
+++ b/auto_tests/tox_dispatch_test.c
@@ -43,7 +43,7 @@ static void dump_events(const char *path, const Tox_Events *events)
     }
 }
 
-static void print_events(const Tox_System *sys, Tox_Events *events)
+static void print_events(const struct Tox_System *sys, Tox_Events *events)
 {
     const uint32_t size = tox_events_bytes_size(events);
 
@@ -64,7 +64,7 @@ static void print_events(const Tox_System *sys, Tox_Events *events)
 
 static bool await_message(Tox **toxes, const Tox_Dispatch *dispatch)
 {
-    const Tox_System *sys = tox_get_system(toxes[0]);
+    const struct Tox_System *sys = tox_get_system(toxes[0]);
 
     for (uint32_t i = 0; i < 100; ++i) {
         // Ignore events on tox 1.
@@ -103,7 +103,7 @@ static void test_tox_events(void)
         ck_assert_msg(toxes[i] != nullptr, "failed to create tox instances %u", i);
     }
 
-    const Tox_System *sys = tox_get_system(toxes[0]);
+    const struct Tox_System *sys = tox_get_system(toxes[0]);
 
     Tox_Err_Dispatch_New err_new;
     Tox_Dispatch *dispatch = tox_dispatch_new(&err_new);
diff --git a/auto_tests/tox_events_test.c b/auto_tests/tox_events_test.c
index 04549b2179c..9bc211fd33d 100644
--- a/auto_tests/tox_events_test.c
+++ b/auto_tests/tox_events_test.c
@@ -7,9 +7,11 @@
 #include <time.h>
 
 #include "../testing/misc_tools.h"
+#include "../toxcore/os_memory.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/tox_events.h"
 #include "../toxcore/tox_struct.h"
+#include "../toxcore/tox_time_impl.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
 
@@ -43,6 +45,9 @@ static uint64_t get_state_clock_callback(void *user_data)
     const uint64_t *clock = (const uint64_t *)user_data;
     return *clock;
 }
+static const Tox_Time_Funcs mock_time_funcs = {
+    get_state_clock_callback,
+};
 
 static void test_tox_events(void)
 {
@@ -59,13 +64,17 @@ static void test_tox_events(void)
         ck_assert_msg(toxes[i] != nullptr, "failed to create tox instances %u", i);
     }
 
+    const Memory *mem = os_memory();
+
     uint64_t clock = current_time_monotonic(toxes[0]->mono_time);
+    Tox_Time *tm = tox_time_new(&mock_time_funcs, &clock, mem);
+
     Mono_Time *mono_time;
 
     mono_time = toxes[0]->mono_time;
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock);
+    mono_time_set_current_time_callback(mono_time, tm);
     mono_time = toxes[1]->mono_time;
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, &clock);
+    mono_time_set_current_time_callback(mono_time, tm);
 
     uint8_t pk[TOX_PUBLIC_KEY_SIZE];
     tox_self_get_dht_id(toxes[0], pk);
@@ -113,6 +122,8 @@ static void test_tox_events(void)
     for (uint32_t i = 0; i < 2; ++i) {
         tox_kill(toxes[i]);
     }
+
+    tox_time_free(tm);
 }
 
 int main(void)
diff --git a/auto_tests/tox_many_tcp_test.c b/auto_tests/tox_many_tcp_test.c
index f466e3e1711..816707cb13b 100644
--- a/auto_tests/tox_many_tcp_test.c
+++ b/auto_tests/tox_many_tcp_test.c
@@ -8,6 +8,7 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
@@ -41,7 +42,7 @@ static uint16_t tcp_relay_port = 33448;
 
 static void test_many_clients_tcp(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     long long unsigned int cur_time = time(nullptr);
     Tox *toxes[NUM_TOXES_TCP];
@@ -144,7 +145,7 @@ static void test_many_clients_tcp(void)
 
 static void test_many_clients_tcp_b(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     long long unsigned int cur_time = time(nullptr);
     Tox *toxes[NUM_TOXES_TCP];
diff --git a/auto_tests/tox_many_test.c b/auto_tests/tox_many_test.c
index 8501b5c172a..da44f23c4e2 100644
--- a/auto_tests/tox_many_test.c
+++ b/auto_tests/tox_many_test.c
@@ -8,6 +8,7 @@
 
 #include "../testing/misc_tools.h"
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
@@ -26,7 +27,7 @@ static void accept_friend_request(Tox *m, const uint8_t *public_key, const uint8
 
 static void test_many_clients(void)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ck_assert(rng != nullptr);
     time_t cur_time = time(nullptr);
     Tox *toxes[TCP_TEST_NUM_TOXES];
diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c
index 725fe61317f..30d36df5943 100644
--- a/auto_tests/toxav_many_test.c
+++ b/auto_tests/toxav_many_test.c
@@ -15,8 +15,10 @@
 #include "../toxav/toxav.h"
 #include "../toxcore/crypto_core.h"
 #include "../toxcore/logger.h"
+#include "../toxcore/os_memory.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/tox_struct.h"
+#include "../toxcore/tox_time_impl.h"
 #include "../toxcore/util.h"
 #include "auto_test_support.h"
 #include "check_compat.h"
@@ -144,6 +146,10 @@ static uint64_t get_state_clock_callback(void *user_data)
     return clock;
 }
 
+static const Tox_Time_Funcs mock_time_funcs = {
+    get_state_clock_callback,
+};
+
 static void increment_clock(Time_Data *time_data, uint64_t count)
 {
     pthread_mutex_lock(&time_data->lock);
@@ -151,10 +157,10 @@ static void increment_clock(Time_Data *time_data, uint64_t count)
     pthread_mutex_unlock(&time_data->lock);
 }
 
-static void set_current_time_callback(Tox *tox, Time_Data *time_data)
+static void set_current_time_callback(Tox *tox, Tox_Time *tm)
 {
     Mono_Time *mono_time = tox->mono_time;
-    mono_time_set_current_time_callback(mono_time, get_state_clock_callback, time_data);
+    mono_time_set_current_time_callback(mono_time, tm);
 }
 
 static void test_av_three_calls(void)
@@ -168,6 +174,10 @@ static void test_av_three_calls(void)
 
     Time_Data time_data;
     pthread_mutex_init(&time_data.lock, nullptr);
+
+    const Memory *mem = os_memory();
+    Tox_Time *tm = tox_time_new(&mock_time_funcs, &time_data, mem);
+
     {
         Tox_Err_New error;
 
@@ -175,23 +185,23 @@ static void test_av_three_calls(void)
         ck_assert(error == TOX_ERR_NEW_OK);
 
         time_data.clock = current_time_monotonic(bootstrap->mono_time);
-        set_current_time_callback(bootstrap, &time_data);
+        set_current_time_callback(bootstrap, tm);
 
         Alice = tox_new_log(nullptr, &error, &index[1]);
         ck_assert(error == TOX_ERR_NEW_OK);
-        set_current_time_callback(Alice, &time_data);
+        set_current_time_callback(Alice, tm);
 
         Bobs[0] = tox_new_log(nullptr, &error, &index[2]);
         ck_assert(error == TOX_ERR_NEW_OK);
-        set_current_time_callback(Bobs[0], &time_data);
+        set_current_time_callback(Bobs[0], tm);
 
         Bobs[1] = tox_new_log(nullptr, &error, &index[3]);
         ck_assert(error == TOX_ERR_NEW_OK);
-        set_current_time_callback(Bobs[1], &time_data);
+        set_current_time_callback(Bobs[1], tm);
 
         Bobs[2] = tox_new_log(nullptr, &error, &index[4]);
         ck_assert(error == TOX_ERR_NEW_OK);
-        set_current_time_callback(Bobs[2], &time_data);
+        set_current_time_callback(Bobs[2], tm);
     }
 
     printf("Created 5 instances of Tox\n");
@@ -367,6 +377,8 @@ static void test_av_three_calls(void)
     tox_kill(Alice);
     tox_kill(bootstrap);
 
+    tox_time_free(tm);
+
     pthread_mutex_destroy(&time_data.lock);
 
     printf("\nTest successful!\n");
diff --git a/cmake/ModulePackage.cmake b/cmake/ModulePackage.cmake
index 04dbf16d7a5..a5acbf34667 100644
--- a/cmake/ModulePackage.cmake
+++ b/cmake/ModulePackage.cmake
@@ -70,6 +70,7 @@ function(add_module lib)
 endfunction()
 
 function(install_module lib)
+  cmake_parse_arguments(INSTALL_MODULE "" "DESTINATION" "" ${ARGN})
   if(ENABLE_SHARED)
     set_target_properties(${lib}_shared PROPERTIES
       VERSION ${SOVERSION}
@@ -109,8 +110,11 @@ function(install_module lib)
   foreach(sublib ${${lib}_API_HEADERS})
     string(REPLACE "^" ";" sublib ${sublib})
     list(GET sublib 0 header)
+    string(REPLACE "${${lib}_SOURCE_DIR}/" "" target_header ${header})
+    get_filename_component(target_path ${target_header} DIRECTORY)
 
-    install(FILES ${header} ${ARGN})
+    install(FILES ${header} DESTINATION
+            "${INSTALL_MODULE_DESTINATION}/${target_path}")
   endforeach()
 endfunction()
 
diff --git a/cmake/StrictAbi.cmake b/cmake/StrictAbi.cmake
index 22b1ca447af..0a17f561ded 100644
--- a/cmake/StrictAbi.cmake
+++ b/cmake/StrictAbi.cmake
@@ -32,7 +32,7 @@ function(_make_version_script target)
       COMMAND ${SHELL} -c "egrep '^\\w' ${header} | grep '${ns}_[a-z0-9_]*(' | grep -v '^typedef' | grep -o '${ns}_[a-z0-9_]*(' | egrep -o '\\w+' | sort -u"
       OUTPUT_VARIABLE sublib_SYMS
       OUTPUT_STRIP_TRAILING_WHITESPACE)
-    string(REPLACE "\n" ";" sublib_SYMS ${sublib_SYMS})
+    string(REPLACE "\n" ";" sublib_SYMS "${sublib_SYMS}")
 
     foreach(sym ${sublib_SYMS})
       file(APPEND ${${target}_VERSION_SCRIPT}
diff --git a/other/BUILD.bazel b/other/BUILD.bazel
index 1a8929a3758..4ed80ec49c4 100644
--- a/other/BUILD.bazel
+++ b/other/BUILD.bazel
@@ -28,6 +28,9 @@ cc_binary(
         "//c-toxcore/toxcore:mono_time",
         "//c-toxcore/toxcore:network",
         "//c-toxcore/toxcore:onion_announce",
+        "//c-toxcore/toxcore:os_memory",
+        "//c-toxcore/toxcore:os_network",
+        "//c-toxcore/toxcore:os_random",
         "//c-toxcore/toxcore:tox",
         "//c-toxcore/toxcore:util",
     ],
diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c
index e59f9eedea2..4274c50d460 100644
--- a/other/DHT_bootstrap.c
+++ b/other/DHT_bootstrap.c
@@ -20,6 +20,9 @@
 #include "../toxcore/group_onion_announce.h"
 #include "../toxcore/logger.h"
 #include "../toxcore/mono_time.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_network.h"
+#include "../toxcore/os_random.h"
 #include "../toxcore/tox.h"
 #include "../toxcore/util.h"
 
@@ -137,23 +140,23 @@ int main(int argc, char *argv[])
     IP ip;
     ip_init(&ip, ipv6enabled);
 
-    Logger *logger = logger_new();
+    const Random *rng = os_random();
+    const Network *ns = os_network();
+    const Memory *mem = os_memory();
+
+    Logger *logger = logger_new(mem);
 
     if (MIN_LOGGER_LEVEL == LOGGER_LEVEL_TRACE || MIN_LOGGER_LEVEL == LOGGER_LEVEL_DEBUG) {
         logger_callback_log(logger, print_log, nullptr, nullptr);
     }
 
-    const Random *rng = system_random();
-    const Network *ns = system_network();
-    const Memory *mem = system_memory();
-
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
     const uint16_t start_port = PORT;
     const uint16_t end_port = start_port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM);
     DHT *dht = new_dht(logger, mem, rng, ns, mono_time, new_networking_ex(logger, mem, ns, &ip, start_port, end_port, nullptr), true, true);
     Onion *onion = new_onion(logger, mem, mono_time, rng, dht);
-    Forwarding *forwarding = new_forwarding(logger, rng, mono_time, dht);
-    GC_Announces_List *gc_announces_list = new_gca_list();
+    Forwarding *forwarding = new_forwarding(logger, mem, rng, mono_time, dht);
+    GC_Announces_List *gc_announces_list = new_gca_list(mem);
     Onion_Announce *onion_a = new_onion_announce(logger, mem, rng, mono_time, dht);
 
 #ifdef DHT_NODE_EXTRA_PACKETS
@@ -229,7 +232,7 @@ int main(int argc, char *argv[])
     int is_waiting_for_dht_connection = 1;
 
     uint64_t last_LANdiscovery = 0;
-    const Broadcast_Info *broadcast = lan_discovery_init(ns);
+    const Broadcast_Info *broadcast = lan_discovery_init(mem, ns);
 
     while (1) {
         mono_time_update(mono_time);
diff --git a/other/analysis/run-clang b/other/analysis/run-clang
index c18464071e6..f5ec50f4a23 100755
--- a/other/analysis/run-clang
+++ b/other/analysis/run-clang
@@ -10,7 +10,7 @@ run() {
     "${CPPFLAGS[@]}" \
     "${LDFLAGS[@]}" \
     "$@" \
-    -std=c++11 \
+    -std=c++17 \
     -Werror \
     -Weverything \
     -Wno-alloca \
diff --git a/other/analysis/run-clang-analyze b/other/analysis/run-clang-analyze
index 05e94e78bd8..5ed9ff3041f 100755
--- a/other/analysis/run-clang-analyze
+++ b/other/analysis/run-clang-analyze
@@ -9,7 +9,7 @@ run() {
   clang++ --analyze amalgamation.cc \
     "${CPPFLAGS[@]}" \
     "$@" \
-    -std=c++11
+    -std=c++17
 }
 
 . other/analysis/variants.sh
diff --git a/other/analysis/run-gcc b/other/analysis/run-gcc
index ce3338c5567..8a49b32585c 100755
--- a/other/analysis/run-gcc
+++ b/other/analysis/run-gcc
@@ -11,7 +11,7 @@ run() {
     "${CPPFLAGS[@]}" \
     "${LDFLAGS[@]}" \
     "$@" \
-    -std=c++11 \
+    -std=c++17 \
     -fdiagnostics-color=always \
     -Wall \
     -Wextra \
diff --git a/other/bootstrap_daemon/BUILD.bazel b/other/bootstrap_daemon/BUILD.bazel
index e1a2e41f449..8e083558b77 100644
--- a/other/bootstrap_daemon/BUILD.bazel
+++ b/other/bootstrap_daemon/BUILD.bazel
@@ -19,6 +19,9 @@ cc_binary(
         "//c-toxcore/toxcore:logger",
         "//c-toxcore/toxcore:mono_time",
         "//c-toxcore/toxcore:onion_announce",
+        "//c-toxcore/toxcore:os_memory",
+        "//c-toxcore/toxcore:os_network",
+        "//c-toxcore/toxcore:os_random",
         "//c-toxcore/toxcore:tox",
         "//c-toxcore/toxcore:util",
         "@libconfig",
diff --git a/other/bootstrap_daemon/src/tox-bootstrapd.c b/other/bootstrap_daemon/src/tox-bootstrapd.c
index 7efd2c889d3..eba64971fc0 100644
--- a/other/bootstrap_daemon/src/tox-bootstrapd.c
+++ b/other/bootstrap_daemon/src/tox-bootstrapd.c
@@ -33,6 +33,9 @@
 #include "../../../toxcore/logger.h"
 #include "../../../toxcore/mono_time.h"
 #include "../../../toxcore/onion_announce.h"
+#include "../../../toxcore/os_memory.h"
+#include "../../../toxcore/os_network.h"
+#include "../../../toxcore/os_random.h"
 #include "../../../toxcore/util.h"
 
 // misc
@@ -273,16 +276,17 @@ int main(int argc, char *argv[])
     IP ip;
     ip_init(&ip, enable_ipv6);
 
-    Logger *logger = logger_new();
+    const Memory *mem = os_memory();
+    const Random *rng = os_random();
+    const Network *ns = os_network();
+
+    Logger *logger = logger_new(mem);
 
     if (MIN_LOGGER_LEVEL == LOGGER_LEVEL_TRACE || MIN_LOGGER_LEVEL == LOGGER_LEVEL_DEBUG) {
         logger_callback_log(logger, toxcore_logger_callback, nullptr, nullptr);
     }
 
     const uint16_t end_port = start_port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM);
-    const Memory *mem = system_memory();
-    const Random *rng = system_random();
-    const Network *ns = system_network();
     Networking_Core *net = new_networking_ex(logger, mem, ns, &ip, start_port, end_port, nullptr);
 
     if (net == nullptr) {
@@ -310,7 +314,7 @@ int main(int argc, char *argv[])
         }
     }
 
-    Mono_Time *const mono_time = mono_time_new(mem, nullptr, nullptr);
+    Mono_Time *const mono_time = mono_time_new(mem, nullptr);
 
     if (mono_time == nullptr) {
         log_write(LOG_LEVEL_ERROR, "Couldn't initialize monotonic timer. Exiting.\n");
@@ -337,7 +341,7 @@ int main(int argc, char *argv[])
         return 1;
     }
 
-    Forwarding *forwarding = new_forwarding(logger, rng, mono_time, dht);
+    Forwarding *forwarding = new_forwarding(logger, mem, rng, mono_time, dht);
 
     if (forwarding == nullptr) {
         log_write(LOG_LEVEL_ERROR, "Couldn't initialize forwarding. Exiting.\n");
@@ -366,7 +370,7 @@ int main(int argc, char *argv[])
         return 1;
     }
 
-    GC_Announces_List *group_announce = new_gca_list();
+    GC_Announces_List *group_announce = new_gca_list(mem);
 
     if (group_announce == nullptr) {
         log_write(LOG_LEVEL_ERROR, "Couldn't initialize group announces. Exiting.\n");
@@ -551,7 +555,7 @@ int main(int argc, char *argv[])
     Broadcast_Info *broadcast = nullptr;
 
     if (enable_lan_discovery) {
-        broadcast = lan_discovery_init(ns);
+        broadcast = lan_discovery_init(mem, ns);
         log_write(LOG_LEVEL_INFO, "Initialized LAN discovery successfully.\n");
     }
 
diff --git a/testing/BUILD.bazel b/testing/BUILD.bazel
index 68e89a15918..b9c0f63f31d 100644
--- a/testing/BUILD.bazel
+++ b/testing/BUILD.bazel
@@ -57,5 +57,8 @@ cc_binary(
         "//c-toxcore/toxcore:Messenger",
         "//c-toxcore/toxcore:ccompat",
         "//c-toxcore/toxcore:mono_time",
+        "//c-toxcore/toxcore:os_memory",
+        "//c-toxcore/toxcore:os_network",
+        "//c-toxcore/toxcore:os_random",
     ],
 )
diff --git a/testing/Messenger_test.c b/testing/Messenger_test.c
index 4c2c8f85ffb..a5548c86810 100644
--- a/testing/Messenger_test.c
+++ b/testing/Messenger_test.c
@@ -35,6 +35,9 @@
 #include "../toxcore/Messenger.h"
 #include "../toxcore/ccompat.h"
 #include "../toxcore/mono_time.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_network.h"
+#include "../toxcore/os_random.h"
 #include "misc_tools.h"
 
 static void print_message(Messenger *m, uint32_t friendnumber, unsigned int type, const uint8_t *string, size_t length,
@@ -92,8 +95,8 @@ int main(int argc, char *argv[])
         exit(0);
     }
 
-    const Memory *mem = system_memory();
-    Mono_Time *const mono_time = mono_time_new(mem, nullptr, nullptr);
+    const Memory *mem = os_memory();
+    Mono_Time *const mono_time = mono_time_new(mem, nullptr);
 
     if (mono_time == nullptr) {
         fputs("Failed to allocate monotonic timer datastructure\n", stderr);
@@ -103,7 +106,7 @@ int main(int argc, char *argv[])
     Messenger_Options options = {0};
     options.ipv6enabled = ipv6enabled;
     Messenger_Error err;
-    m = new_messenger(mono_time, mem, system_random(), system_network(), &options, &err);
+    m = new_messenger(mono_time, mem, os_random(), os_network(), &options, &err);
 
     if (!m) {
         fprintf(stderr, "Failed to allocate messenger datastructure: %d\n", err);
diff --git a/testing/fuzzing/BUILD.bazel b/testing/fuzzing/BUILD.bazel
index 386516d72bf..68696f7ef09 100644
--- a/testing/fuzzing/BUILD.bazel
+++ b/testing/fuzzing/BUILD.bazel
@@ -15,7 +15,13 @@ cc_library(
     deps = [
         "//c-toxcore/toxcore:crypto_core",
         "//c-toxcore/toxcore:network",
+        "//c-toxcore/toxcore:os_network",
         "//c-toxcore/toxcore:tox",
+        "//c-toxcore/toxcore:tox_memory",
+        "//c-toxcore/toxcore:tox_network",
+        "//c-toxcore/toxcore:tox_random",
+        "//c-toxcore/toxcore:tox_system",
+        "//c-toxcore/toxcore:tox_time",
     ],
 )
 
diff --git a/testing/fuzzing/bootstrap_harness.cc b/testing/fuzzing/bootstrap_harness.cc
index 9ffb69d1f1b..ee98f84608b 100644
--- a/testing/fuzzing/bootstrap_harness.cc
+++ b/testing/fuzzing/bootstrap_harness.cc
@@ -107,6 +107,9 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 
 void TestBootstrap(Fuzz_Data &input)
 {
+    // Null system for regularly working memory allocations needed in
+    // tox_events_equal.
+    Null_System null_sys;
     Fuzz_System sys(input);
 
     Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
@@ -154,11 +157,8 @@ void TestBootstrap(Fuzz_Data &input)
 
     uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0};
 
-    const bool udp_success = tox_bootstrap(tox, "127.0.0.2", 33446, pub_key, nullptr);
-    assert(udp_success);
-
-    const bool tcp_success = tox_add_tcp_relay(tox, "127.0.0.2", 33446, pub_key, nullptr);
-    assert(tcp_success);
+    tox_bootstrap(tox, "127.0.0.2", 33446, pub_key, nullptr);
+    tox_add_tcp_relay(tox, "127.0.0.2", 33446, pub_key, nullptr);
 
     tox_events_init(tox);
 
@@ -169,7 +169,7 @@ void TestBootstrap(Fuzz_Data &input)
     while (input.size > 0) {
         Tox_Err_Events_Iterate error_iterate;
         Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
-        assert(tox_events_equal(sys.sys.get(), events, events));
+        assert(tox_events_equal(null_sys.sys.get(), events, events));
         tox_dispatch_invoke(dispatch, events, tox, nullptr);
         tox_events_free(events);
         // Move the clock forward a decent amount so all the time-based checks
diff --git a/testing/fuzzing/e2e_fuzz_test.cc b/testing/fuzzing/e2e_fuzz_test.cc
index f5258853e5c..868db2165db 100644
--- a/testing/fuzzing/e2e_fuzz_test.cc
+++ b/testing/fuzzing/e2e_fuzz_test.cc
@@ -155,12 +155,7 @@ void TestEndToEnd(Fuzz_Data &input)
     Tox_Err_New error_new;
     Tox *tox = tox_new(opts.get(), &error_new);
 
-    if (tox == nullptr) {
-        // It might fail, because some I/O happens in tox_new, and the fuzzer
-        // might do things that make that I/O fail.
-        return;
-    }
-
+    // tox_new never fails, because we execute a recorded successful trace.
     assert(error_new == TOX_ERR_NEW_OK);
 
     tox_events_init(tox);
diff --git a/testing/fuzzing/fuzz_support.cc b/testing/fuzzing/fuzz_support.cc
index 510a6563f33..6c9b14165ff 100644
--- a/testing/fuzzing/fuzz_support.cc
+++ b/testing/fuzzing/fuzz_support.cc
@@ -17,17 +17,16 @@
 
 #include "../../toxcore/crypto_core.h"
 #include "../../toxcore/network.h"
-#include "../../toxcore/tox_private.h"
+#include "../../toxcore/os_network_impl.h"
+#include "../../toxcore/tox_memory_impl.h"
+#include "../../toxcore/tox_network_impl.h"
+#include "../../toxcore/tox_random_impl.h"
+#include "../../toxcore/tox_system_impl.h"
+#include "../../toxcore/tox_time_impl.h"
 #include "func_conversion.h"
 
 const bool DEBUG = false;
 
-// TODO(iphydf): Put this somewhere shared.
-struct Network_Addr {
-    struct sockaddr_storage addr;
-    size_t size;
-};
-
 System::~System() { }
 
 static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
@@ -72,15 +71,11 @@ static void *alloc_common(Fuzz_Data &data, F func)
     return func();
 }
 
-static constexpr Memory_Funcs fuzz_memory_funcs = {
+static constexpr Tox_Memory_Funcs fuzz_memory_funcs = {
     /* .malloc = */
     ![](Fuzz_System *self, uint32_t size) {
         return alloc_common(self->data, [=]() { return std::malloc(size); });
     },
-    /* .calloc = */
-    ![](Fuzz_System *self, uint32_t nmemb, uint32_t size) {
-        return alloc_common(self->data, [=]() { return std::calloc(nmemb, size); });
-    },
     /* .realloc = */
     ![](Fuzz_System *self, void *ptr, uint32_t size) {
         return alloc_common(self->data, [=]() { return std::realloc(ptr, size); });
@@ -89,7 +84,7 @@ static constexpr Memory_Funcs fuzz_memory_funcs = {
     ![](Fuzz_System *self, void *ptr) { std::free(ptr); },
 };
 
-static constexpr Network_Funcs fuzz_network_funcs = {
+static constexpr Tox_Network_Funcs fuzz_network_funcs = {
     /* .close = */ ![](Fuzz_System *self, int sock) { return 0; },
     /* .accept = */ ![](Fuzz_System *self, int sock) { return 1337; },
     /* .bind = */ ![](Fuzz_System *self, int sock, const Network_Addr *addr) { return 0; },
@@ -109,16 +104,14 @@ static constexpr Network_Funcs fuzz_network_funcs = {
     /* .recvfrom = */
     ![](Fuzz_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
         assert(sock == 42 || sock == 1337);
-
-        addr->addr = sockaddr_storage{};
-        // Dummy Addr
-        addr->addr.ss_family = AF_INET;
+        assert(addr != nullptr);
 
         // We want an AF_INET address with dummy values
-        sockaddr_in *addr_in = reinterpret_cast<sockaddr_in *>(&addr->addr);
-        addr_in->sin_port = htons(33446);
-        addr_in->sin_addr.s_addr = htonl(0x7f000002);  // 127.0.0.2
-        addr->size = sizeof(struct sockaddr);
+        sockaddr_in addr_in{};
+        addr_in.sin_port = htons(33446);
+        addr_in.sin_addr.s_addr = htonl(0x7f000002);  // 127.0.0.2
+
+        net_addr_set(addr, &addr_in, sizeof(addr_in));
 
         return recv_common(self->data, buf, len);
     },
@@ -147,7 +140,7 @@ static constexpr Network_Funcs fuzz_network_funcs = {
     },
 };
 
-static constexpr Random_Funcs fuzz_random_funcs = {
+static constexpr Tox_Random_Funcs fuzz_random_funcs = {
     /* .random_bytes = */
     ![](Fuzz_System *self, uint8_t *bytes, size_t length) {
         // Amount of data is limited
@@ -165,7 +158,7 @@ static constexpr Random_Funcs fuzz_random_funcs = {
     ![](Fuzz_System *self, uint32_t upper_bound) {
         uint32_t randnum = 0;
         if (upper_bound > 0) {
-            self->rng->funcs->random_bytes(
+            self->rng->funcs->bytes_callback(
                 self, reinterpret_cast<uint8_t *>(&randnum), sizeof(randnum));
             randnum %= upper_bound;
         }
@@ -173,34 +166,37 @@ static constexpr Random_Funcs fuzz_random_funcs = {
     },
 };
 
+static constexpr Tox_Time_Funcs fuzz_time_funcs = {
+    /* .monotonic = */
+    ![](Fuzz_System *self) { return self->clock; },
+};
+
 Fuzz_System::Fuzz_System(Fuzz_Data &input)
     : System{
         std::make_unique<Tox_System>(),
         std::make_unique<Memory>(Memory{&fuzz_memory_funcs, this}),
         std::make_unique<Network>(Network{&fuzz_network_funcs, this}),
         std::make_unique<Random>(Random{&fuzz_random_funcs, this}),
+        std::make_unique<Tox_Time>(Tox_Time{&fuzz_time_funcs, this}),
     }
     , data(input)
 {
-    sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; };
-    sys->mono_time_user_data = this;
     sys->mem = mem.get();
     sys->ns = ns.get();
     sys->rng = rng.get();
+    sys->tm = tm.get();
 }
 
-static constexpr Memory_Funcs null_memory_funcs = {
+static constexpr Tox_Memory_Funcs null_memory_funcs = {
     /* .malloc = */
     ![](Null_System *self, uint32_t size) { return std::malloc(size); },
-    /* .calloc = */
-    ![](Null_System *self, uint32_t nmemb, uint32_t size) { return std::calloc(nmemb, size); },
     /* .realloc = */
     ![](Null_System *self, void *ptr, uint32_t size) { return std::realloc(ptr, size); },
     /* .free = */
     ![](Null_System *self, void *ptr) { std::free(ptr); },
 };
 
-static constexpr Network_Funcs null_network_funcs = {
+static constexpr Tox_Network_Funcs null_network_funcs = {
     /* .close = */ ![](Null_System *self, int sock) { return 0; },
     /* .accept = */ ![](Null_System *self, int sock) { return 1337; },
     /* .bind = */ ![](Null_System *self, int sock, const Network_Addr *addr) { return 0; },
@@ -248,7 +244,7 @@ static uint64_t simple_rng(uint64_t &seed)
     return seed;
 }
 
-static constexpr Random_Funcs null_random_funcs = {
+static constexpr Tox_Random_Funcs null_random_funcs = {
     /* .random_bytes = */
     ![](Null_System *self, uint8_t *bytes, size_t length) {
         for (size_t i = 0; i < length; ++i) {
@@ -264,36 +260,27 @@ static constexpr Random_Funcs null_random_funcs = {
 Null_System::Null_System()
     : System{
         std::make_unique<Tox_System>(),
-        std::make_unique<Memory>(Memory{&null_memory_funcs, this}),
-        std::make_unique<Network>(Network{&null_network_funcs, this}),
-        std::make_unique<Random>(Random{&null_random_funcs, this}),
+        std::make_unique<Tox_Memory>(Tox_Memory{&null_memory_funcs, this}),
+        std::make_unique<Tox_Network>(Tox_Network{&null_network_funcs, this}),
+        std::make_unique<Tox_Random>(Tox_Random{&null_random_funcs, this}),
+        std::make_unique<Tox_Time>(Tox_Time{&fuzz_time_funcs, this}),
     }
 {
-    sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; };
-    sys->mono_time_user_data = this;
     sys->mem = mem.get();
     sys->ns = ns.get();
     sys->rng = rng.get();
+    sys->tm = tm.get();
 }
 
-static uint16_t get_port(const Network_Addr *addr)
-{
-    if (addr->addr.ss_family == AF_INET6) {
-        return reinterpret_cast<const sockaddr_in6 *>(&addr->addr)->sin6_port;
-    } else {
-        assert(addr->addr.ss_family == AF_INET);
-        return reinterpret_cast<const sockaddr_in *>(&addr->addr)->sin_port;
-    }
-}
+static constexpr Tox_Memory_Funcs record_memory_funcs = null_memory_funcs;
 
-static constexpr Memory_Funcs record_memory_funcs = null_memory_funcs;
-
-static constexpr Network_Funcs record_network_funcs = {
+static constexpr Tox_Network_Funcs record_network_funcs = {
     /* .close = */ ![](Record_System *self, int sock) { return 0; },
     /* .accept = */ ![](Record_System *self, int sock) { return 2; },
     /* .bind = */
     ![](Record_System *self, int sock, const Network_Addr *addr) {
-        const uint16_t port = get_port(addr);
+        assert(addr != nullptr);
+        const uint16_t port = net_addr_get_port(addr);
         if (self->global_.bound.find(port) != self->global_.bound.end()) {
             errno = EADDRINUSE;
             return -1;
@@ -313,6 +300,7 @@ static constexpr Network_Funcs record_network_funcs = {
     /* .recvfrom = */
     ![](Record_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
         assert(sock == 42);
+        assert(addr != nullptr);
         if (self->recvq.empty()) {
             self->recording.push_back(0xff);
             self->recording.push_back(0xff);
@@ -327,15 +315,13 @@ static constexpr Network_Funcs record_network_funcs = {
         const size_t recvlen = std::min(len, packet.size());
         std::copy(packet.begin(), packet.end(), buf);
 
-        addr->addr = sockaddr_storage{};
-        // Dummy Addr
-        addr->addr.ss_family = AF_INET;
-
         // We want an AF_INET address with dummy values
-        sockaddr_in *addr_in = reinterpret_cast<sockaddr_in *>(&addr->addr);
-        addr_in->sin_port = from;
-        addr_in->sin_addr.s_addr = htonl(0x7f000002);  // 127.0.0.2
-        addr->size = sizeof(struct sockaddr);
+        sockaddr_in addr_in{};
+        addr_in.sin_family = AF_INET;
+        addr_in.sin_port = from;
+        addr_in.sin_addr.s_addr = htonl(0x7f000002);  // 127.0.0.2
+
+        net_addr_set(addr, &addr_in, sizeof(addr_in));
 
         assert(recvlen > 0 && recvlen <= INT_MAX);
         self->recording.push_back(recvlen >> 8);
@@ -355,7 +341,8 @@ static constexpr Network_Funcs record_network_funcs = {
     /* .sendto = */
     ![](Record_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
         assert(sock == 42);
-        auto backend = self->global_.bound.find(get_port(addr));
+        assert(addr != nullptr);
+        auto backend = self->global_.bound.find(net_addr_get_port(addr));
         assert(backend != self->global_.bound.end());
         backend->second->receive(self->port, buf, len);
         return static_cast<int>(len);
@@ -373,7 +360,7 @@ static constexpr Network_Funcs record_network_funcs = {
     },
 };
 
-static constexpr Random_Funcs record_random_funcs = {
+static constexpr Tox_Random_Funcs record_random_funcs = {
     /* .random_bytes = */
     ![](Record_System *self, uint8_t *bytes, size_t length) {
         for (size_t i = 0; i < length; ++i) {
@@ -386,7 +373,7 @@ static constexpr Random_Funcs record_random_funcs = {
         }
     },
     /* .random_uniform = */
-    fuzz_random_funcs.random_uniform,
+    fuzz_random_funcs.uniform_callback,
 };
 
 Record_System::Record_System(Global &global, uint64_t seed, const char *name)
@@ -395,16 +382,16 @@ Record_System::Record_System(Global &global, uint64_t seed, const char *name)
         std::make_unique<Memory>(Memory{&record_memory_funcs, this}),
         std::make_unique<Network>(Network{&record_network_funcs, this}),
         std::make_unique<Random>(Random{&record_random_funcs, this}),
+        std::make_unique<Tox_Time>(Tox_Time{&fuzz_time_funcs, this}),
     }
     , global_(global)
     , seed_(seed)
     , name_(name)
 {
-    sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; };
-    sys->mono_time_user_data = this;
     sys->mem = mem.get();
     sys->ns = ns.get();
     sys->rng = rng.get();
+    sys->tm = tm.get();
 }
 
 void Record_System::receive(uint16_t send_port, const uint8_t *buf, size_t len)
diff --git a/testing/fuzzing/fuzz_support.h b/testing/fuzzing/fuzz_support.h
index a20d85b4f2e..e52e4cc7828 100644
--- a/testing/fuzzing/fuzz_support.h
+++ b/testing/fuzzing/fuzz_support.h
@@ -117,15 +117,17 @@ void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&... args)
     return fuzz_select_target(selector, input, std::forward<Args>(args)...);
 }
 
-struct Memory;
-struct Network;
-struct Random;
+struct Tox_Memory;
+struct Tox_Network;
+struct Tox_Random;
+struct Tox_Time;
 
 struct System {
     std::unique_ptr<Tox_System> sys;
-    std::unique_ptr<Memory> mem;
-    std::unique_ptr<Network> ns;
-    std::unique_ptr<Random> rng;
+    std::unique_ptr<Tox_Memory> mem;
+    std::unique_ptr<Tox_Network> ns;
+    std::unique_ptr<Tox_Random> rng;
+    std::unique_ptr<Tox_Time> tm;
 
     // Not inline because sizeof of the above 2 structs is not known everywhere.
     ~System();
diff --git a/testing/fuzzing/fuzz_tox.h b/testing/fuzzing/fuzz_tox.h
index b5864e78d3a..8ca359b18b1 100644
--- a/testing/fuzzing/fuzz_tox.h
+++ b/testing/fuzzing/fuzz_tox.h
@@ -11,6 +11,7 @@
 #include "../../toxcore/DHT.h"
 #include "../../toxcore/logger.h"
 #include "../../toxcore/network.h"
+#include "../../toxcore/os_memory.h"
 #include "fuzz_support.h"
 
 constexpr uint16_t SIZE_IP_PORT = SIZE_IP6 + sizeof(uint16_t);
@@ -37,7 +38,7 @@ struct with<Logger> {
     template <typename F>
     void operator>>(F &&f)
     {
-        Ptr<Logger> logger(logger_new(), logger_kill);
+        Ptr<Logger> logger(logger_new(os_memory()), logger_kill);
         assert(logger != nullptr);
         f(std::move(logger));
     }
diff --git a/tox.h b/tox.h
new file mode 100644
index 00000000000..4209883cf60
--- /dev/null
+++ b/tox.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#include "toxcore/tox.h"
diff --git a/toxav.h b/toxav.h
new file mode 100644
index 00000000000..83e5daa8e64
--- /dev/null
+++ b/toxav.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#include "toxav/toxav.h"
diff --git a/toxav/BUILD.bazel b/toxav/BUILD.bazel
index ca88f1334aa..c3f3423a89a 100644
--- a/toxav/BUILD.bazel
+++ b/toxav/BUILD.bazel
@@ -81,6 +81,7 @@ cc_test(
     deps = [
         ":rtp",
         "//c-toxcore/toxcore:crypto_core",
+        "//c-toxcore/toxcore:os_random",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc
index 7b7881985c4..931d6445941 100644
--- a/toxav/Makefile.inc
+++ b/toxav/Makefile.inc
@@ -1,8 +1,9 @@
 if BUILD_AV
 
 lib_LTLIBRARIES +=  libtoxav.la
-                    libtoxav_la_include_HEADERS = ../toxav/toxav.h
-                    libtoxav_la_includedir = $(includedir)/tox
+
+libtoxav_la_include_HEADERS = ../toxav/toxav.h
+libtoxav_la_includedir = $(includedir)/tox/toxav
 
 libtoxav_la_SOURCES = ../toxav/rtp.h \
                     ../toxav/rtp.c \
diff --git a/toxav/rtp_test.cc b/toxav/rtp_test.cc
index b29c937ac91..24e5244804d 100644
--- a/toxav/rtp_test.cc
+++ b/toxav/rtp_test.cc
@@ -3,6 +3,7 @@
 #include <gtest/gtest.h>
 
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_random.h"
 
 namespace {
 
@@ -29,7 +30,7 @@ RTPHeader random_header(const Random *rng)
 
 TEST(Rtp, Deserialisation)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
     RTPHeader const header = random_header(rng);
 
diff --git a/toxav/toxav.c b/toxav/toxav.c
index bdec43b504a..c9a3d1db70a 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -181,7 +181,7 @@ ToxAV *toxav_new(Tox *tox, Toxav_Err_New *error)
 
     av->tox = tox;
     av->m = m;
-    av->toxav_mono_time = mono_time_new(tox->sys.mem, nullptr, nullptr);
+    av->toxav_mono_time = mono_time_new(tox->sys.mem, nullptr);
     av->msi = msi_new(av->m);
 
     if (av->msi == nullptr) {
diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel
index 4701cf437d3..5f5771b6a34 100644
--- a/toxcore/BUILD.bazel
+++ b/toxcore/BUILD.bazel
@@ -5,13 +5,22 @@ load("//tools:no_undefined.bzl", "cc_library")
 package(features = ["layering_check"])
 
 exports_files(
-    srcs = ["tox.h"],
+    srcs = [
+        "tox.h",
+        "tox_attributes.h",
+        "tox_logger.h",
+        "tox_memory.h",
+        "tox_network.h",
+        "tox_random.h",
+        "tox_system.h",
+        "tox_time.h",
+    ],
     visibility = ["//c-toxcore:__pkg__"],
 )
 
 cc_library(
-    name = "attributes",
-    hdrs = ["attributes.h"],
+    name = "tox_attributes",
+    hdrs = ["tox_attributes.h"],
     visibility = ["//c-toxcore:__subpackages__"],
 )
 
@@ -20,7 +29,163 @@ cc_library(
     srcs = ["ccompat.c"],
     hdrs = ["ccompat.h"],
     visibility = ["//c-toxcore:__subpackages__"],
-    deps = [":attributes"],
+    deps = [":tox_attributes"],
+)
+
+cc_library(
+    name = "tox_memory",
+    srcs = ["tox_memory.c"],
+    hdrs = [
+        "tox_memory.h",
+        "tox_memory_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_attributes",
+    ],
+)
+
+cc_library(
+    name = "tox_logger",
+    srcs = ["tox_logger.c"],
+    hdrs = [
+        "tox_logger.h",
+        "tox_logger_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_attributes",
+        ":tox_memory",
+    ],
+)
+
+cc_library(
+    name = "tox_network",
+    srcs = ["tox_network.c"],
+    hdrs = [
+        "tox_network.h",
+        "tox_network_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_attributes",
+        ":tox_memory",
+    ],
+)
+
+cc_library(
+    name = "tox_random",
+    srcs = ["tox_random.c"],
+    hdrs = [
+        "tox_random.h",
+        "tox_random_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_attributes",
+        ":tox_memory",
+    ],
+)
+
+cc_library(
+    name = "tox_time",
+    srcs = ["tox_time.c"],
+    hdrs = [
+        "tox_time.h",
+        "tox_time_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_attributes",
+        ":tox_memory",
+    ],
+)
+
+cc_library(
+    name = "tox_system",
+    srcs = ["tox_system.c"],
+    hdrs = [
+        "tox_system.h",
+        "tox_system_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_attributes",
+        ":tox_logger",
+        ":tox_memory",
+        ":tox_network",
+        ":tox_random",
+        ":tox_time",
+    ],
+)
+
+cc_library(
+    name = "os_logger",
+    srcs = ["os_logger.c"],
+    hdrs = ["os_logger.h"],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_logger",
+    ],
+)
+
+cc_library(
+    name = "os_memory",
+    srcs = ["os_memory.c"],
+    hdrs = ["os_memory.h"],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_memory",
+    ],
+)
+
+cc_library(
+    name = "os_network",
+    srcs = ["os_network.c"],
+    hdrs = [
+        "os_network.h",
+        "os_network_impl.h",
+    ],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_network",
+    ],
+)
+
+cc_library(
+    name = "os_random",
+    srcs = ["os_random.c"],
+    hdrs = ["os_random.h"],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":tox_random",
+        "@libsodium",
+    ],
+)
+
+cc_library(
+    name = "os_system",
+    srcs = ["os_system.c"],
+    hdrs = ["os_system.h"],
+    visibility = ["//c-toxcore:__subpackages__"],
+    deps = [
+        ":ccompat",
+        ":os_logger",
+        ":os_memory",
+        ":os_network",
+        ":os_random",
+        ":tox_system",
+    ],
 )
 
 cc_library(
@@ -29,8 +194,9 @@ cc_library(
     hdrs = ["mem.h"],
     visibility = ["//c-toxcore:__subpackages__"],
     deps = [
-        ":attributes",
         ":ccompat",
+        ":tox_attributes",
+        ":tox_memory",
     ],
 )
 
@@ -40,6 +206,7 @@ cc_test(
     srcs = ["mem_test.cc"],
     deps = [
         ":mem",
+        ":os_memory",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
@@ -57,9 +224,9 @@ cc_library(
         "//c-toxcore/toxav:__pkg__",
     ],
     deps = [
-        ":attributes",
         ":ccompat",
         ":mem",
+        ":tox_attributes",
         "@pthread",
     ],
 )
@@ -70,6 +237,7 @@ cc_test(
     srcs = ["util_test.cc"],
     deps = [
         ":crypto_core",
+        ":os_random",
         ":util",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
@@ -82,8 +250,9 @@ cc_library(
     hdrs = ["bin_pack.h"],
     visibility = ["//c-toxcore:__subpackages__"],
     deps = [
-        ":attributes",
         ":ccompat",
+        ":mem",
+        ":tox_attributes",
         "//c-toxcore/third_party:cmp",
     ],
 )
@@ -94,8 +263,9 @@ cc_library(
     hdrs = ["bin_unpack.h"],
     visibility = ["//c-toxcore:__subpackages__"],
     deps = [
-        ":attributes",
         ":ccompat",
+        ":mem",
+        ":tox_attributes",
         "//c-toxcore/third_party:cmp",
     ],
 )
@@ -107,6 +277,7 @@ cc_test(
     deps = [
         ":bin_pack",
         ":bin_unpack",
+        ":os_memory",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
@@ -118,8 +289,10 @@ cc_library(
     hdrs = ["crypto_core.h"],
     visibility = ["//c-toxcore:__subpackages__"],
     deps = [
-        ":attributes",
         ":ccompat",
+        ":mem",
+        ":tox_attributes",
+        ":tox_random",
         "@libsodium",
     ],
 )
@@ -131,6 +304,7 @@ cc_test(
     flaky = True,
     deps = [
         ":crypto_core",
+        ":os_random",
         ":util",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
@@ -142,8 +316,9 @@ cc_library(
     srcs = ["list.c"],
     hdrs = ["list.h"],
     deps = [
-        ":attributes",
         ":ccompat",
+        ":mem",
+        ":tox_attributes",
     ],
 )
 
@@ -153,6 +328,7 @@ cc_test(
     srcs = ["list_test.cc"],
     deps = [
         ":list",
+        ":os_memory",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
@@ -169,8 +345,9 @@ cc_library(
         "//c-toxcore/toxav:__pkg__",
     ],
     deps = [
-        ":attributes",
         ":ccompat",
+        ":mem",
+        ":tox_attributes",
     ],
 )
 
@@ -196,9 +373,10 @@ cc_library(
         "//c-toxcore/toxav:__pkg__",
     ],
     deps = [
-        ":attributes",
         ":ccompat",
         ":mem",
+        ":tox_attributes",
+        ":tox_time",
         "@pthread",
     ],
 )
@@ -209,6 +387,8 @@ cc_test(
     srcs = ["mono_time_test.cc"],
     deps = [
         ":mono_time",
+        ":os_memory",
+        ":tox_time",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
@@ -250,6 +430,8 @@ cc_library(
         ":logger",
         ":mem",
         ":mono_time",
+        ":os_network",
+        ":tox_network",
         ":util",
         "@libsodium",
         "@psocket",
@@ -298,6 +480,8 @@ cc_test(
     srcs = ["ping_array_test.cc"],
     deps = [
         ":mono_time",
+        ":os_memory",
+        ":os_random",
         ":ping_array",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
@@ -338,7 +522,6 @@ cc_library(
     ],
     deps = [
         ":LAN_discovery",
-        ":attributes",
         ":ccompat",
         ":crypto_core",
         ":logger",
@@ -348,6 +531,7 @@ cc_library(
         ":ping_array",
         ":shared_key_cache",
         ":state",
+        ":tox_attributes",
         ":util",
     ],
 )
@@ -359,6 +543,9 @@ cc_test(
     deps = [
         ":DHT",
         ":crypto_core",
+        ":os_memory",
+        ":os_network",
+        ":os_random",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
@@ -370,6 +557,7 @@ cc_fuzz_test(
     corpus = ["//tools/toktok-fuzzer/corpus:DHT_fuzz_test"],
     deps = [
         ":DHT",
+        ":os_memory",
         "//c-toxcore/testing/fuzzing:fuzz_support",
     ],
 )
@@ -409,6 +597,8 @@ cc_fuzz_test(
     #corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
     deps = [
         ":forwarding",
+        ":os_memory",
+        ":os_network",
         "//c-toxcore/testing/fuzzing:fuzz_support",
         "//c-toxcore/testing/fuzzing:fuzz_tox",
     ],
@@ -438,11 +628,11 @@ cc_library(
     hdrs = ["TCP_common.h"],
     visibility = ["//c-toxcore/auto_tests:__pkg__"],
     deps = [
-        ":attributes",
         ":ccompat",
         ":crypto_core",
         ":mem",
         ":network",
+        ":tox_attributes",
     ],
 )
 
@@ -580,6 +770,8 @@ cc_test(
     deps = [
         ":group_announce",
         ":mono_time",
+        ":os_memory",
+        ":tox_time",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
@@ -607,6 +799,8 @@ cc_fuzz_test(
     #corpus = ["//tools/toktok-fuzzer/corpus:group_announce_fuzz_test"],
     deps = [
         ":group_announce",
+        ":os_memory",
+        ":tox_time",
         "//c-toxcore/testing/fuzzing:fuzz_support",
     ],
 )
@@ -698,6 +892,8 @@ cc_test(
         ":crypto_core",
         ":group_moderation",
         ":logger",
+        ":os_memory",
+        ":os_random",
         ":util",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
@@ -710,6 +906,7 @@ cc_fuzz_test(
     corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"],
     deps = [
         ":group_moderation",
+        ":os_memory",
         "//c-toxcore/testing/fuzzing:fuzz_support",
     ],
 )
@@ -798,6 +995,9 @@ cc_library(
         ":mem",
         ":mono_time",
         ":network",
+        ":os_system",
+        ":tox_logger",
+        ":tox_system",
         "//c-toxcore/toxencryptsave:defines",
     ],
 )
@@ -808,6 +1008,7 @@ cc_test(
     srcs = ["tox_test.cc"],
     deps = [
         ":crypto_core",
+        ":os_random",
         ":tox",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
@@ -820,10 +1021,10 @@ cc_library(
     hdrs = ["tox_unpack.h"],
     visibility = ["//c-toxcore:__subpackages__"],
     deps = [
-        ":attributes",
         ":bin_unpack",
         ":ccompat",
         ":tox",
+        ":tox_attributes",
     ],
 )
 
@@ -836,12 +1037,13 @@ cc_library(
     hdrs = ["tox_events.h"],
     visibility = ["//c-toxcore:__subpackages__"],
     deps = [
-        ":attributes",
         ":bin_pack",
         ":bin_unpack",
         ":ccompat",
         ":mem",
         ":tox",
+        ":tox_attributes",
+        ":tox_system",
         ":tox_unpack",
         "//c-toxcore/third_party:cmp",
     ],
@@ -853,8 +1055,10 @@ cc_test(
     srcs = ["tox_events_test.cc"],
     deps = [
         ":crypto_core",
+        ":os_system",
         ":tox",
         ":tox_events",
+        ":tox_system",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index 1b4062cbbe4..0e76a3958d6 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -92,7 +92,7 @@ struct DHT {
     const Network *ns;
     Mono_Time *mono_time;
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     Networking_Core *net;
 
     bool hole_punching_enabled;
@@ -277,7 +277,7 @@ const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key)
 
 int create_request(const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key,
                    uint8_t *packet, const uint8_t *recv_public_key,
-                   const uint8_t *data, uint32_t data_length, uint8_t request_id)
+                   const uint8_t *data, uint32_t data_length, uint8_t request_id, const Memory *mem)
 {
     if (send_public_key == nullptr || packet == nullptr || recv_public_key == nullptr || data == nullptr) {
         return -1;
@@ -293,7 +293,7 @@ int create_request(const Random *rng, const uint8_t *send_public_key, const uint
     temp[0] = request_id;
     memcpy(temp + 1, data, data_length);
     const int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, data_length + 1,
-                                 packet + CRYPTO_SIZE);
+                                 packet + CRYPTO_SIZE, mem);
 
     if (len == -1) {
         crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE);
@@ -309,7 +309,7 @@ int create_request(const Random *rng, const uint8_t *send_public_key, const uint
 }
 
 int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
-                   uint8_t *request_id, const uint8_t *packet, uint16_t packet_length)
+                   uint8_t *request_id, const uint8_t *packet, uint16_t packet_length, const Memory *mem)
 {
     if (self_public_key == nullptr || public_key == nullptr || data == nullptr || request_id == nullptr
             || packet == nullptr) {
@@ -328,7 +328,7 @@ int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_ke
     const uint8_t *const nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2;
     uint8_t temp[MAX_CRYPTO_REQUEST_SIZE];
     int32_t len1 = decrypt_data(public_key, self_secret_key, nonce,
-                                packet + CRYPTO_SIZE, packet_length - CRYPTO_SIZE, temp);
+                                packet + CRYPTO_SIZE, packet_length - CRYPTO_SIZE, temp, mem);
 
     if (len1 == -1 || len1 == 0) {
         crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE);
@@ -415,7 +415,7 @@ int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_
     }
 }
 
-int dht_create_packet(const Memory *mem, const Random *rng,
+int dht_create_packet(const Memory *mem, const Tox_Random *rng,
                       const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
                       const uint8_t *shared_key, const uint8_t type,
                       const uint8_t *plain, size_t plain_length,
@@ -430,7 +430,7 @@ int dht_create_packet(const Memory *mem, const Random *rng,
 
     random_nonce(rng, nonce);
 
-    const int encrypted_length = encrypt_data_symmetric(shared_key, nonce, plain, plain_length, encrypted);
+    const int encrypted_length = encrypt_data_symmetric(shared_key, nonce, plain, plain_length, encrypted, mem);
 
     if (encrypted_length == -1) {
         mem_delete(mem, encrypted);
@@ -970,7 +970,7 @@ static int handle_data_search_response(void *object, const IP_Port *source,
                                packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                                plain_len + CRYPTO_MAC_SIZE,
-                               plain) != plain_len) {
+                               plain, dht->mem) != plain_len) {
         return 1;
     }
 
@@ -1479,7 +1479,7 @@ static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *p
                         packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                         packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                         CRYPTO_NODE_SIZE + CRYPTO_MAC_SIZE,
-                        plain);
+                        plain, dht->mem);
 
     if (len != CRYPTO_NODE_SIZE) {
         return 1;
@@ -1539,7 +1539,7 @@ static bool handle_sendnodes_core(void *object, const IP_Port *source, const uin
                         packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                         packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                         1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE,
-                        plain);
+                        plain, dht->mem);
 
     if ((unsigned int)len != SIZEOF_VLA(plain)) {
         return false;
@@ -2219,7 +2219,7 @@ static int send_NATping(const DHT *dht, const uint8_t *public_key, uint64_t ping
     /* 254 is NAT ping request packet id */
     const int len = create_request(
                         dht->rng, dht->self_public_key, dht->self_secret_key, packet_data, public_key,
-                        data, sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING);
+                        data, sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING, dht->mem);
 
     if (len == -1) {
         return -1;
@@ -2449,7 +2449,7 @@ static void do_NAT(DHT *dht)
  * @return the number of nodes.
  */
 non_null()
-static uint16_t list_nodes(const Random *rng, const Client_data *list, size_t length,
+static uint16_t list_nodes(const Tox_Random *rng, const Client_data *list, size_t length,
                            uint64_t cur_time, Node_format *nodes, uint16_t max_num)
 {
     if (max_num == 0) {
@@ -2555,7 +2555,7 @@ static int cryptopacket_handle(void *object, const IP_Port *source, const uint8_
         uint8_t data[MAX_CRYPTO_REQUEST_SIZE];
         uint8_t number;
         const int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key,
-                                       data, &number, packet, length);
+                                       data, &number, packet, length, dht->mem);
 
         if (len == -1 || len == 0) {
             return 1;
@@ -2609,7 +2609,7 @@ static int handle_LANdiscovery(void *object, const IP_Port *source, const uint8_
 
 /*----------------------------------------------------------------------------------*/
 
-DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
+DHT *new_dht(const Logger *log, const Memory *mem, const Tox_Random *rng, const Network *ns,
              Mono_Time *mono_time, Networking_Core *net,
              bool hole_punching_enabled, bool lan_discovery_enabled)
 {
diff --git a/toxcore/DHT.h b/toxcore/DHT.h
index 95f442e79fa..f5210e675fd 100644
--- a/toxcore/DHT.h
+++ b/toxcore/DHT.h
@@ -11,7 +11,7 @@
 
 #include <stdbool.h>
 
-#include "attributes.h"
+#include "tox_attributes.h"
 #include "crypto_core.h"
 #include "logger.h"
 #include "mem.h"
@@ -113,9 +113,9 @@ extern "C" {
  * @return the length of the created packet on success.
  */
 non_null()
-int create_request(const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key,
+int create_request(const Tox_Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key,
                    uint8_t *packet, const uint8_t *recv_public_key,
-                   const uint8_t *data, uint32_t data_length, uint8_t request_id);
+                   const uint8_t *data, uint32_t data_length, uint8_t request_id, const Memory *mem);
 
 /**
  * @brief Decrypts and unpacks a DHT request packet.
@@ -142,7 +142,7 @@ int create_request(const Random *rng, const uint8_t *send_public_key, const uint
 non_null()
 int handle_request(
     const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
-    uint8_t *request_id, const uint8_t *packet, uint16_t packet_length);
+    uint8_t *request_id, const uint8_t *packet, uint16_t packet_length, const Memory *mem);
 
 typedef struct IPPTs {
     IP_Port     ip_port;
@@ -220,7 +220,7 @@ int pack_ip_port(const Logger *logger, uint8_t *data, uint16_t length, const IP_
  * @retval -1 on failure.
  */
 non_null()
-int dht_create_packet(const Memory *mem, const Random *rng,
+int dht_create_packet(const Memory *mem, const Tox_Random *rng,
                       const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
                       const uint8_t *shared_key, const uint8_t type,
                       const uint8_t *plain, size_t plain_length,
@@ -495,7 +495,7 @@ int dht_load(DHT *dht, const uint8_t *data, uint32_t length);
 
 /** Initialize DHT. */
 non_null()
-DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
+DHT *new_dht(const Logger *log, const Memory *mem, const Tox_Random *rng, const Network *ns,
              Mono_Time *mono_time, Networking_Core *net, bool hole_punching_enabled, bool lan_discovery_enabled);
 
 nullable(1)
diff --git a/toxcore/DHT_fuzz_test.cc b/toxcore/DHT_fuzz_test.cc
index e9673ae0ee5..7588ad2af3a 100644
--- a/toxcore/DHT_fuzz_test.cc
+++ b/toxcore/DHT_fuzz_test.cc
@@ -4,6 +4,7 @@
 #include <vector>
 
 #include "../testing/fuzzing/fuzz_support.h"
+#include "os_memory.h"
 
 namespace {
 
@@ -15,8 +16,8 @@ void TestHandleRequest(Fuzz_Data &input)
     uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
     uint8_t request[MAX_CRYPTO_REQUEST_SIZE];
     uint8_t request_id;
-    handle_request(
-        self_public_key, self_secret_key, public_key, request, &request_id, input.data, input.size);
+    handle_request(self_public_key, self_secret_key, public_key, request, &request_id, input.data,
+        input.size, os_memory());
 }
 
 void TestUnpackNodes(Fuzz_Data &input)
@@ -29,7 +30,7 @@ void TestUnpackNodes(Fuzz_Data &input)
     const int packed_count
         = unpack_nodes(nodes, node_count, &processed_data_len, input.data, input.size, tcp_enabled);
     if (packed_count > 0) {
-        Logger *logger = logger_new();
+        Logger *logger = logger_new(os_memory());
         std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6);
         const int packed_size
             = pack_nodes(logger, packed.data(), packed.size(), nodes, packed_count);
diff --git a/toxcore/DHT_test.cc b/toxcore/DHT_test.cc
index 84d3b9820a1..9f456e86e2f 100644
--- a/toxcore/DHT_test.cc
+++ b/toxcore/DHT_test.cc
@@ -6,6 +6,9 @@
 #include <array>
 
 #include "crypto_core.h"
+#include "os_memory.h"
+#include "os_network.h"
+#include "os_random.h"
 
 namespace {
 
@@ -36,7 +39,7 @@ PublicKey random_pk(const Random *rng)
 
 TEST(IdClosest, IdenticalKeysAreSameDistance)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     PublicKey pk0 = random_pk(rng);
@@ -48,7 +51,7 @@ TEST(IdClosest, IdenticalKeysAreSameDistance)
 
 TEST(IdClosest, DistanceIsCommutative)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     for (uint32_t i = 0; i < 100; ++i) {
@@ -130,7 +133,9 @@ TEST(AddToList, OverridesKeysWithCloserKeys)
 
 TEST(Request, CreateAndParse)
 {
-    const Random *rng = system_random();
+    const Memory *mem = os_memory();
+    ASSERT_NE(mem, nullptr);
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     // Peers.
@@ -151,31 +156,31 @@ TEST(Request, CreateAndParse)
     random_bytes(rng, outgoing.data(), outgoing.size());
 
     EXPECT_LT(create_request(rng, sender.pk.data(), sender.sk.data(), packet.data(),
-                  receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id),
+                  receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id, mem),
         0);
 
     // Pop one element so the payload is 918 bytes. Packing should now succeed.
     outgoing.pop_back();
 
     const int max_sent_length = create_request(rng, sender.pk.data(), sender.sk.data(),
-        packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id);
+        packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id, mem);
     ASSERT_GT(max_sent_length, 0);  // success.
 
     // Check that handle_request rejects packets larger than the maximum created packet size.
     EXPECT_LT(handle_request(receiver.pk.data(), receiver.sk.data(), pk.data(), incoming.data(),
-                  &recvd_pkt_id, packet.data(), max_sent_length + 1),
+                  &recvd_pkt_id, packet.data(), max_sent_length + 1, mem),
         0);
 
     // Now try all possible packet sizes from max (918) to 0.
     while (!outgoing.empty()) {
         // Pack:
         const int sent_length = create_request(rng, sender.pk.data(), sender.sk.data(),
-            packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id);
+            packet.data(), receiver.pk.data(), outgoing.data(), outgoing.size(), sent_pkt_id, mem);
         ASSERT_GT(sent_length, 0);
 
         // Unpack:
         const int recvd_length = handle_request(receiver.pk.data(), receiver.sk.data(), pk.data(),
-            incoming.data(), &recvd_pkt_id, packet.data(), sent_length);
+            incoming.data(), &recvd_pkt_id, packet.data(), sent_length, mem);
         ASSERT_GE(recvd_length, 0);
 
         EXPECT_EQ(
@@ -187,12 +192,12 @@ TEST(Request, CreateAndParse)
 
 TEST(AnnounceNodes, SetAndTest)
 {
-    const Random *rng = system_random();
-    const Network *ns = system_network();
-    const Memory *mem = system_memory();
+    const Random *rng = os_random();
+    const Network *ns = os_network();
+    const Memory *mem = os_memory();
 
-    Logger *log = logger_new();
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    Logger *log = logger_new(mem);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
     Networking_Core *net = new_networking_no_udp(log, mem, ns);
     DHT *dht = new_dht(log, mem, rng, ns, mono_time, net, true, true);
     ASSERT_NE(dht, nullptr);
diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c
index ef44d3b5525..a1f1cf56a60 100644
--- a/toxcore/LAN_discovery.c
+++ b/toxcore/LAN_discovery.c
@@ -47,6 +47,8 @@
 
 
 struct Broadcast_Info {
+    const Memory *mem;
+
     uint32_t count;
     IP ips[MAX_INTERFACES];
 };
@@ -54,28 +56,30 @@ struct Broadcast_Info {
 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
 
 non_null()
-static Broadcast_Info *fetch_broadcast_info(const Network *ns)
+static Broadcast_Info *fetch_broadcast_info(const Memory *mem, const Network *ns)
 {
-    Broadcast_Info *broadcast = (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
+    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
 
     if (broadcast == nullptr) {
         return nullptr;
     }
 
-    IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
+    broadcast->mem = mem;
+
+    IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)mem_balloc(mem, sizeof(IP_ADAPTER_INFO));
     unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO);
 
     if (pAdapterInfo == nullptr) {
-        free(broadcast);
+        mem_delete(mem, broadcast);
         return nullptr;
     }
 
     if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
-        free(pAdapterInfo);
-        pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
+        mem_delete(mem, pAdapterInfo);
+        pAdapterInfo = (IP_ADAPTER_INFO *)mem_balloc(mem, ulOutBufLen);
 
         if (pAdapterInfo == nullptr) {
-            free(broadcast);
+            mem_delete(mem, broadcast);
             return nullptr;
         }
     }
@@ -111,7 +115,7 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns)
     }
 
     if (pAdapterInfo != nullptr) {
-        free(pAdapterInfo);
+        mem_delete(mem, pAdapterInfo);
     }
 
     return broadcast;
@@ -120,14 +124,16 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns)
 #elif !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__))
 
 non_null()
-static Broadcast_Info *fetch_broadcast_info(const Network *ns)
+static Broadcast_Info *fetch_broadcast_info(const Memory *mem, const Network *ns)
 {
-    Broadcast_Info *broadcast = (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
+    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
 
     if (broadcast == nullptr) {
         return nullptr;
     }
 
+    broadcast->mem = mem;
+
     /* Not sure how many platforms this will run on,
      * so it's wrapped in `__linux__` for now.
      * Definitely won't work like this on Windows...
@@ -135,7 +141,7 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns)
     const Socket sock = net_socket(ns, net_family_ipv4(), TOX_SOCK_STREAM, 0);
 
     if (!sock_valid(sock)) {
-        free(broadcast);
+        mem_delete(mem, broadcast);
         return nullptr;
     }
 
@@ -149,7 +155,7 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns)
 
     if (ioctl(sock.sock, SIOCGIFCONF, &ifc) < 0) {
         kill_sock(ns, sock);
-        free(broadcast);
+        mem_delete(mem, broadcast);
         return nullptr;
     }
 
@@ -196,9 +202,17 @@ static Broadcast_Info *fetch_broadcast_info(const Network *ns)
 #else // TODO(irungentoo): Other platforms?
 
 non_null()
-static Broadcast_Info *fetch_broadcast_info(const Network *ns)
+static Broadcast_Info *fetch_broadcast_info(const Memory *mem, const Network *ns)
 {
-    return (Broadcast_Info *)calloc(1, sizeof(Broadcast_Info));
+    Broadcast_Info *broadcast = (Broadcast_Info *)mem_alloc(mem, sizeof(Broadcast_Info));
+
+    if (broadcast == nullptr) {
+        return nullptr;
+    }
+
+    broadcast->mem = mem;
+
+    return broadcast;
 }
 
 #endif
@@ -376,12 +390,16 @@ bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadc
 }
 
 
-Broadcast_Info *lan_discovery_init(const Network *ns)
+Broadcast_Info *lan_discovery_init(const Memory *mem, const Network *ns)
 {
-    return fetch_broadcast_info(ns);
+    return fetch_broadcast_info(mem, ns);
 }
 
 void lan_discovery_kill(Broadcast_Info *broadcast)
 {
-    free(broadcast);
+    if (broadcast == nullptr) {
+        return;
+    }
+
+    mem_delete(broadcast->mem, broadcast);
 }
diff --git a/toxcore/LAN_discovery.h b/toxcore/LAN_discovery.h
index 5d9c83335b6..b97da637758 100644
--- a/toxcore/LAN_discovery.h
+++ b/toxcore/LAN_discovery.h
@@ -31,7 +31,7 @@ bool lan_discovery_send(const Networking_Core *net, const Broadcast_Info *broadc
  * Discovers broadcast devices and IP addresses.
  */
 non_null()
-Broadcast_Info *lan_discovery_init(const Network *ns);
+Broadcast_Info *lan_discovery_init(const Memory *mem, const Network *ns);
 
 /**
  * Free all resources associated with the broadcast info.
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc
index 70df82b39e6..9821420ca1f 100644
--- a/toxcore/Makefile.inc
+++ b/toxcore/Makefile.inc
@@ -1,25 +1,39 @@
 lib_LTLIBRARIES += libtoxcore.la
 
 libtoxcore_la_include_HEADERS = \
-                        ../toxcore/tox.h
+                        ../toxcore/tox.h \
+                        ../toxcore/tox_dispatch.h \
+                        ../toxcore/tox_events.h \
+                        ../toxcore/tox_logger.h \
+                        ../toxcore/tox_memory.h \
+                        ../toxcore/tox_network.h \
+                        ../toxcore/tox_system.h \
+                        ../toxcore/tox_time.h
 
-libtoxcore_la_includedir = $(includedir)/tox
+libtoxcore_la_includedir = $(includedir)/tox/toxcore
 
 libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
                         ../third_party/cmp/cmp.h \
-                        ../toxcore/attributes.h \
+                        ../toxcore/announce.c \
+                        ../toxcore/announce.h \
                         ../toxcore/bin_pack.c \
                         ../toxcore/bin_pack.h \
                         ../toxcore/bin_unpack.c \
                         ../toxcore/bin_unpack.h \
                         ../toxcore/ccompat.c \
                         ../toxcore/ccompat.h \
+                        ../toxcore/crypto_core.c \
+                        ../toxcore/crypto_core.h \
+                        ../toxcore/DHT.c \
+                        ../toxcore/DHT.h \
                         ../toxcore/events/conference_connected.c \
                         ../toxcore/events/conference_invite.c \
                         ../toxcore/events/conference_message.c \
                         ../toxcore/events/conference_peer_list_changed.c \
                         ../toxcore/events/conference_peer_name.c \
                         ../toxcore/events/conference_title.c \
+                        ../toxcore/events/events_alloc.c \
+                        ../toxcore/events/events_alloc.h \
                         ../toxcore/events/file_chunk_request.c \
                         ../toxcore/events/file_recv.c \
                         ../toxcore/events/file_recv_chunk.c \
@@ -34,90 +48,112 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
                         ../toxcore/events/friend_status.c \
                         ../toxcore/events/friend_status_message.c \
                         ../toxcore/events/friend_typing.c \
-                        ../toxcore/events/events_alloc.c \
-                        ../toxcore/events/events_alloc.h \
                         ../toxcore/events/self_connection_status.c \
-                        ../toxcore/DHT.h \
-                        ../toxcore/DHT.c \
-                        ../toxcore/mem.h \
-                        ../toxcore/mem.c \
-                        ../toxcore/mono_time.h \
-                        ../toxcore/mono_time.c \
-                        ../toxcore/network.h \
-                        ../toxcore/network.c \
-                        ../toxcore/crypto_core.h \
-                        ../toxcore/crypto_core.c \
-                        ../toxcore/timed_auth.h \
-                        ../toxcore/timed_auth.c \
-                        ../toxcore/ping_array.h \
-                        ../toxcore/ping_array.c \
-                        ../toxcore/net_crypto.h \
-                        ../toxcore/net_crypto.c \
-                        ../toxcore/friend_requests.h \
-                        ../toxcore/friend_requests.c \
-                        ../toxcore/LAN_discovery.h \
-                        ../toxcore/LAN_discovery.c \
-                        ../toxcore/friend_connection.h \
+                        ../toxcore/forwarding.c \
+                        ../toxcore/forwarding.h \
                         ../toxcore/friend_connection.c \
-                        ../toxcore/Messenger.h \
-                        ../toxcore/Messenger.c \
-                        ../toxcore/ping.h \
-                        ../toxcore/ping.c \
-                        ../toxcore/shared_key_cache.h \
-                        ../toxcore/shared_key_cache.c \
-                        ../toxcore/state.h \
-                        ../toxcore/state.c \
-                        ../toxcore/tox.h \
-                        ../toxcore/tox.c \
-                        ../toxcore/tox_dispatch.h \
-                        ../toxcore/tox_dispatch.c \
-                        ../toxcore/tox_events.h \
-                        ../toxcore/tox_events.c \
-                        ../toxcore/tox_unpack.h \
-                        ../toxcore/tox_unpack.c \
-                        ../toxcore/tox_private.c \
-                        ../toxcore/tox_private.h \
-                        ../toxcore/tox_struct.h \
-                        ../toxcore/tox_api.c \
-                        ../toxcore/util.h \
-                        ../toxcore/util.c \
-                        ../toxcore/group.h \
-                        ../toxcore/group.c \
-                        ../toxcore/group_announce.h \
+                        ../toxcore/friend_connection.h \
+                        ../toxcore/friend_requests.c \
+                        ../toxcore/friend_requests.h \
                         ../toxcore/group_announce.c \
-                        ../toxcore/group_onion_announce.c \
-                        ../toxcore/group_onion_announce.h \
-                        ../toxcore/group_chats.h \
+                        ../toxcore/group_announce.h \
+                        ../toxcore/group.c \
                         ../toxcore/group_chats.c \
+                        ../toxcore/group_chats.h \
                         ../toxcore/group_common.h \
                         ../toxcore/group_connection.c \
                         ../toxcore/group_connection.h \
-                        ../toxcore/group_pack.c \
-                        ../toxcore/group_pack.h \
+                        ../toxcore/group.h \
                         ../toxcore/group_moderation.c \
                         ../toxcore/group_moderation.h \
-                        ../toxcore/onion.h \
-                        ../toxcore/onion.c \
-                        ../toxcore/logger.h \
+                        ../toxcore/group_onion_announce.c \
+                        ../toxcore/group_onion_announce.h \
+                        ../toxcore/group_pack.c \
+                        ../toxcore/group_pack.h \
+                        ../toxcore/LAN_discovery.c \
+                        ../toxcore/LAN_discovery.h \
+                        ../toxcore/list.c \
+                        ../toxcore/list.h \
                         ../toxcore/logger.c \
-                        ../toxcore/onion_announce.h \
+                        ../toxcore/logger.h \
+                        ../toxcore/mem.c \
+                        ../toxcore/mem.h \
+                        ../toxcore/Messenger.c \
+                        ../toxcore/Messenger.h \
+                        ../toxcore/mono_time.c \
+                        ../toxcore/mono_time.h \
+                        ../toxcore/net_crypto.c \
+                        ../toxcore/net_crypto.h \
+                        ../toxcore/network.c \
+                        ../toxcore/network.h \
                         ../toxcore/onion_announce.c \
-                        ../toxcore/onion_client.h \
+                        ../toxcore/onion_announce.h \
+                        ../toxcore/onion.c \
                         ../toxcore/onion_client.c \
-                        ../toxcore/announce.h \
-                        ../toxcore/announce.c \
-                        ../toxcore/forwarding.h \
-                        ../toxcore/forwarding.c \
-                        ../toxcore/TCP_client.h \
+                        ../toxcore/onion_client.h \
+                        ../toxcore/onion.h \
+                        ../toxcore/os_logger.c \
+                        ../toxcore/os_logger.h \
+                        ../toxcore/os_memory.c \
+                        ../toxcore/os_memory.h \
+                        ../toxcore/os_network.c \
+                        ../toxcore/os_network.h \
+                        ../toxcore/os_network_impl.h \
+                        ../toxcore/os_random.c \
+                        ../toxcore/os_random.h \
+                        ../toxcore/os_system.c \
+                        ../toxcore/os_system.h \
+                        ../toxcore/ping_array.c \
+                        ../toxcore/ping_array.h \
+                        ../toxcore/ping.c \
+                        ../toxcore/ping.h \
+                        ../toxcore/shared_key_cache.c \
+                        ../toxcore/shared_key_cache.h \
+                        ../toxcore/state.c \
+                        ../toxcore/state.h \
                         ../toxcore/TCP_client.c \
-                        ../toxcore/TCP_common.h \
+                        ../toxcore/TCP_client.h \
                         ../toxcore/TCP_common.c \
-                        ../toxcore/TCP_server.h \
-                        ../toxcore/TCP_server.c \
-                        ../toxcore/TCP_connection.h \
+                        ../toxcore/TCP_common.h \
                         ../toxcore/TCP_connection.c \
-                        ../toxcore/list.c \
-                        ../toxcore/list.h
+                        ../toxcore/TCP_connection.h \
+                        ../toxcore/TCP_server.c \
+                        ../toxcore/TCP_server.h \
+                        ../toxcore/timed_auth.c \
+                        ../toxcore/timed_auth.h \
+                        ../toxcore/tox_api.c \
+                        ../toxcore/tox_attributes.h \
+                        ../toxcore/tox.c \
+                        ../toxcore/tox_dispatch.c \
+                        ../toxcore/tox_dispatch.h \
+                        ../toxcore/tox_events.c \
+                        ../toxcore/tox_events.h \
+                        ../toxcore/tox.h \
+                        ../toxcore/tox_logger.c \
+                        ../toxcore/tox_logger.h \
+                        ../toxcore/tox_logger_impl.h \
+                        ../toxcore/tox_memory.c \
+                        ../toxcore/tox_memory.h \
+                        ../toxcore/tox_memory_impl.h \
+                        ../toxcore/tox_network.c \
+                        ../toxcore/tox_network.h \
+                        ../toxcore/tox_network_impl.h \
+                        ../toxcore/tox_private.c \
+                        ../toxcore/tox_private.h \
+                        ../toxcore/tox_random.c \
+                        ../toxcore/tox_random.h \
+                        ../toxcore/tox_random_impl.h \
+                        ../toxcore/tox_struct.h \
+                        ../toxcore/tox_system.c \
+                        ../toxcore/tox_system.h \
+                        ../toxcore/tox_system_impl.h \
+                        ../toxcore/tox_time.c \
+                        ../toxcore/tox_time.h \
+                        ../toxcore/tox_time_impl.h \
+                        ../toxcore/tox_unpack.c \
+                        ../toxcore/tox_unpack.h \
+                        ../toxcore/util.c \
+                        ../toxcore/util.h
 
 libtoxcore_la_CFLAGS =  -I$(top_srcdir) \
                         -I$(top_srcdir)/toxcore \
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index f5ae68a0f21..e409cf47e8f 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -3199,7 +3199,7 @@ static uint8_t *groups_save(const Messenger *m, uint8_t *data)
 non_null()
 static State_Load_Status groups_load(Messenger *m, const uint8_t *data, uint32_t length)
 {
-    Bin_Unpack *bu = bin_unpack_new(data, length);
+    Bin_Unpack *bu = bin_unpack_new(data, length, m->mem);
     if (bu == nullptr) {
         LOGGER_ERROR(m->log, "failed to allocate binary unpacker");
         return STATE_LOAD_STATUS_ERROR;
@@ -3503,7 +3503,7 @@ static void m_handle_friend_request(
  *
  * if error is not NULL it will be set to one of the values in the enum above.
  */
-Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *rng, const Network *ns,
+Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Tox_Random *rng, const Network *ns,
                          Messenger_Options *options, Messenger_Error *error)
 {
     if (options == nullptr) {
@@ -3525,14 +3525,14 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
     m->rng = rng;
     m->ns = ns;
 
-    m->fr = friendreq_new();
+    m->fr = friendreq_new(mem);
 
     if (m->fr == nullptr) {
         mem_delete(mem, m);
         return nullptr;
     }
 
-    m->log = logger_new();
+    m->log = logger_new(mem);
 
     if (m->log == nullptr) {
         friendreq_kill(m->fr);
@@ -3592,7 +3592,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
     }
 
 #ifndef VANILLA_NACL
-    m->group_announce = new_gca_list();
+    m->group_announce = new_gca_list(m->mem);
 
     if (m->group_announce == nullptr) {
         kill_net_crypto(m->net_crypto);
@@ -3607,7 +3607,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
 #endif /* VANILLA_NACL */
 
     if (options->dht_announcements_enabled) {
-        m->forwarding = new_forwarding(m->log, m->rng, m->mono_time, m->dht);
+        m->forwarding = new_forwarding(m->log, m->mem, m->rng, m->mono_time, m->dht);
         m->announce = new_announcements(m->log, m->mem, m->rng, m->mono_time, m->forwarding);
     } else {
         m->forwarding = nullptr;
@@ -3617,7 +3617,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
     m->onion = new_onion(m->log, m->mem, m->mono_time, m->rng, m->dht);
     m->onion_a = new_onion_announce(m->log, m->mem, m->rng, m->mono_time, m->dht);
     m->onion_c = new_onion_client(m->log, m->mem, m->rng, m->mono_time, m->net_crypto);
-    m->fr_c = new_friend_connections(m->log, m->mono_time, m->ns, m->onion_c, options->local_discovery_enabled);
+    m->fr_c = new_friend_connections(m->log, m->mono_time, m->mem, m->ns, m->onion_c, options->local_discovery_enabled);
 
     if ((options->dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
             m->onion == nullptr || m->onion_a == nullptr || m->onion_c == nullptr || m->fr_c == nullptr) {
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index cabb2af89d8..e4a42b952c4 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -246,7 +246,7 @@ struct Messenger {
     Logger *log;
     Mono_Time *mono_time;
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     const Network *ns;
 
     Networking_Core *net;
@@ -814,7 +814,7 @@ typedef enum Messenger_Error {
  * if error is not NULL it will be set to one of the values in the enum above.
  */
 non_null()
-Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *rng, const Network *ns,
+Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Tox_Random *rng, const Network *ns,
                          Messenger_Options *options, Messenger_Error *error);
 
 /** @brief Run this before closing shop.
diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c
index 5aec2337f5b..ccdebf5bbd8 100644
--- a/toxcore/TCP_client.c
+++ b/toxcore/TCP_client.c
@@ -306,7 +306,7 @@ static int generate_handshake(TCP_Client_Connection *tcp_conn)
     memcpy(tcp_conn->con.last_packet, tcp_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE);
     random_nonce(tcp_conn->con.rng, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE);
     const int len = encrypt_data_symmetric(tcp_conn->con.shared_key, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain,
-                                     sizeof(plain), tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                                     sizeof(plain), tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, tcp_conn->con.mem);
 
     if (len != sizeof(plain) + CRYPTO_MAC_SIZE) {
         return -1;
@@ -328,7 +328,7 @@ static int handle_handshake(TCP_Client_Connection *tcp_conn, const uint8_t *data
 {
     uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE];
     const int len = decrypt_data_symmetric(tcp_conn->con.shared_key, data, data + CRYPTO_NONCE_SIZE,
-                                     TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain);
+                                     TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain, tcp_conn->con.mem);
 
     if (len != sizeof(plain)) {
         return -1;
@@ -571,7 +571,7 @@ void forwarding_handler(TCP_Client_Connection *con, forwarded_response_cb *forwa
 
 /** Create new TCP connection to ip_port/public_key */
 TCP_Client_Connection *new_TCP_connection(
-        const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Random *rng, const Network *ns,
+        const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Tox_Random *rng, const Network *ns,
         const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key,
         const TCP_Proxy_Info *proxy_info)
 {
diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h
index b020aaad91a..8b0c4bc2c5b 100644
--- a/toxcore/TCP_client.h
+++ b/toxcore/TCP_client.h
@@ -59,7 +59,7 @@ void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value);
 /** Create new TCP connection to ip_port/public_key */
 non_null(1, 2, 3, 4, 5, 6, 7, 8, 9) nullable(10)
 TCP_Client_Connection *new_TCP_connection(
-        const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Random *rng, const Network *ns,
+        const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Tox_Random *rng, const Network *ns,
         const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key,
         const TCP_Proxy_Info *proxy_info);
 
diff --git a/toxcore/TCP_common.c b/toxcore/TCP_common.c
index 36a751f386d..ac442e15689 100644
--- a/toxcore/TCP_common.c
+++ b/toxcore/TCP_common.c
@@ -150,7 +150,7 @@ int write_packet_TCP_secure_connection(const Logger *logger, TCP_Connection *con
 
     uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
     memcpy(packet, &c_length, sizeof(uint16_t));
-    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
+    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t), con->mem);
 
     if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) {
         return -1;
@@ -294,7 +294,7 @@ int read_packet_TCP_secure_connection(
 
     *next_packet_length = 0;
 
-    const int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data);
+    const int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data, mem);
 
     if (len + CRYPTO_MAC_SIZE != len_packet) {
         LOGGER_ERROR(logger, "decrypted length %d does not match expected length %d", len + CRYPTO_MAC_SIZE, len_packet);
diff --git a/toxcore/TCP_common.h b/toxcore/TCP_common.h
index 44dc2e71e0d..4ac024c824c 100644
--- a/toxcore/TCP_common.h
+++ b/toxcore/TCP_common.h
@@ -65,7 +65,7 @@ void wipe_priority_list(const Memory *mem, TCP_Priority_List *p);
 
 typedef struct TCP_Connection {
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     const Network *ns;
     Socket sock;
     IP_Port ip_port;  // for debugging.
diff --git a/toxcore/TCP_connection.c b/toxcore/TCP_connection.c
index 2c75e74ea5f..5f36acf46b0 100644
--- a/toxcore/TCP_connection.c
+++ b/toxcore/TCP_connection.c
@@ -20,7 +20,7 @@
 struct TCP_Connections {
     const Logger *logger;
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     Mono_Time *mono_time;
     const Network *ns;
     DHT *dht;
@@ -1585,7 +1585,7 @@ int set_tcp_onion_status(TCP_Connections *tcp_c, bool status)
  *
  * Returns NULL on failure.
  */
-TCP_Connections *new_tcp_connections(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns,
+TCP_Connections *new_tcp_connections(const Logger *logger, const Memory *mem, const Tox_Random *rng, const Network *ns,
                                      Mono_Time *mono_time, const uint8_t *secret_key, const TCP_Proxy_Info *proxy_info)
 {
     assert(logger != nullptr);
diff --git a/toxcore/TCP_connection.h b/toxcore/TCP_connection.h
index f01e7054459..3c75cae7161 100644
--- a/toxcore/TCP_connection.h
+++ b/toxcore/TCP_connection.h
@@ -298,7 +298,7 @@ uint32_t tcp_copy_connected_relays_index(const TCP_Connections *tcp_c, Node_form
  * Returns NULL on failure.
  */
 non_null()
-TCP_Connections *new_tcp_connections(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns,
+TCP_Connections *new_tcp_connections(const Logger *logger, const Memory *mem, const Tox_Random *rng, const Network *ns,
                                      Mono_Time *mono_time, const uint8_t *secret_key, const TCP_Proxy_Info *proxy_info);
 
 non_null()
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c
index 80a1f0165aa..68d7f243ab4 100644
--- a/toxcore/TCP_server.c
+++ b/toxcore/TCP_server.c
@@ -59,7 +59,7 @@ typedef struct TCP_Secure_Connection {
 struct TCP_Server {
     const Logger *logger;
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     const Network *ns;
     Onion *onion;
     Forwarding *forwarding;
@@ -319,7 +319,8 @@ static int handle_TCP_handshake(const Logger *logger, TCP_Secure_Connection *con
     encrypt_precompute(data, self_secret_key, shared_key);
     uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE];
     int len = decrypt_data_symmetric(shared_key, data + CRYPTO_PUBLIC_KEY_SIZE,
-                                     data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE, plain);
+                                     data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
+                                     TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE, plain, con->con.mem);
 
     if (len != TCP_HANDSHAKE_PLAIN_SIZE) {
         LOGGER_ERROR(logger, "invalid TCP handshake decrypted length: %d != %d", len, TCP_HANDSHAKE_PLAIN_SIZE);
@@ -339,7 +340,7 @@ static int handle_TCP_handshake(const Logger *logger, TCP_Secure_Connection *con
     random_nonce(con->con.rng, response);
 
     len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE,
-                                 response + CRYPTO_NONCE_SIZE);
+                                 response + CRYPTO_NONCE_SIZE, con->con.mem);
 
     if (len != TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
         crypto_memzero(shared_key, sizeof(shared_key));
@@ -903,7 +904,7 @@ static int accept_connection(TCP_Server *tcp_server, Socket sock)
 }
 
 non_null()
-static Socket new_listening_TCP_socket(const Logger *logger, const Network *ns, Family family, uint16_t port)
+static Socket new_listening_TCP_socket(const Logger *logger, const Network *ns, const Memory *mem, Family family, uint16_t port)
 {
     const Socket sock = net_socket(ns, family, TOX_SOCK_STREAM, TOX_PROTO_TCP);
 
@@ -922,7 +923,7 @@ static Socket new_listening_TCP_socket(const Logger *logger, const Network *ns,
         ok = set_socket_reuseaddr(ns, sock);
     }
 
-    ok = ok && bind_to_port(ns, sock, family, port) && (net_listen(ns, sock, TCP_MAX_BACKLOG) == 0);
+    ok = ok && bind_to_port(ns, mem, sock, family, port) && (net_listen(ns, sock, TCP_MAX_BACKLOG) == 0);
 
     if (!ok) {
         char *const error = net_new_strerror(net_error());
@@ -937,7 +938,7 @@ static Socket new_listening_TCP_socket(const Logger *logger, const Network *ns,
     return sock;
 }
 
-TCP_Server *new_TCP_server(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns,
+TCP_Server *new_TCP_server(const Logger *logger, const Memory *mem, const Tox_Random *rng, const Network *ns,
                            bool ipv6_enabled, uint16_t num_sockets,
                            const uint16_t *ports, const uint8_t *secret_key, Onion *onion, Forwarding *forwarding)
 {
@@ -986,7 +987,7 @@ TCP_Server *new_TCP_server(const Logger *logger, const Memory *mem, const Random
     const Family family = ipv6_enabled ? net_family_ipv6() : net_family_ipv4();
 
     for (uint32_t i = 0; i < num_sockets; ++i) {
-        const Socket sock = new_listening_TCP_socket(logger, ns, family, ports[i]);
+        const Socket sock = new_listening_TCP_socket(logger, ns, mem, family, ports[i]);
 
         if (!sock_valid(sock)) {
             continue;
@@ -1027,7 +1028,7 @@ TCP_Server *new_TCP_server(const Logger *logger, const Memory *mem, const Random
     memcpy(temp->secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE);
     crypto_derive_public_key(temp->public_key, temp->secret_key);
 
-    bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8);
+    bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8, mem);
 
     return temp;
 }
diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h
index 090e821607d..5ec2f4f32c7 100644
--- a/toxcore/TCP_server.h
+++ b/toxcore/TCP_server.h
@@ -35,7 +35,7 @@ size_t tcp_server_listen_count(const TCP_Server *tcp_server);
 
 /** Create new TCP server instance. */
 non_null(1, 2, 3, 4, 7, 8) nullable(9, 10)
-TCP_Server *new_TCP_server(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns,
+TCP_Server *new_TCP_server(const Logger *logger, const Memory *mem, const Tox_Random *rng, const Network *ns,
                            bool ipv6_enabled, uint16_t num_sockets, const uint16_t *ports,
                            const uint8_t *secret_key, Onion *onion, Forwarding *forwarding);
 
diff --git a/toxcore/announce.c b/toxcore/announce.c
index fbbb2350c60..1215b4e6d24 100644
--- a/toxcore/announce.c
+++ b/toxcore/announce.c
@@ -51,7 +51,7 @@ typedef struct Announce_Entry {
 struct Announcements {
     const Logger *log;
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     Forwarding *forwarding;
     const Mono_Time *mono_time;
     DHT *dht;
@@ -233,10 +233,10 @@ bool announce_store_data(Announcements *announce, const uint8_t *data_public_key
         assert(data != nullptr);
 
         if (entry->data != nullptr) {
-            free(entry->data);
+            mem_delete(announce->mem, entry->data);
         }
 
-        entry->data = (uint8_t *)malloc(length);
+        entry->data = (uint8_t *)mem_balloc(announce->mem, length);
 
         if (entry->data == nullptr) {
             return false;
@@ -447,7 +447,7 @@ static int create_reply_plain_store_announce_request(Announcements *announce,
                                data + CRYPTO_PUBLIC_KEY_SIZE,
                                data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                                plain_len + CRYPTO_MAC_SIZE,
-                               plain) != plain_len) {
+                               plain, announce->mem) != plain_len) {
         return -1;
     }
 
@@ -545,11 +545,12 @@ static int create_reply_plain(Announcements *announce,
     }
 }
 
-non_null(1, 2, 5, 7) nullable(3)
+non_null(1, 2, 5, 7, 9) nullable(3)
 static int create_reply(Announcements *announce, const IP_Port *source,
                         const uint8_t *sendback, uint16_t sendback_length,
                         const uint8_t *data, uint16_t length,
-                        uint8_t *reply, uint16_t reply_max_length)
+                        uint8_t *reply, uint16_t reply_max_length,
+                        const Memory *mem)
 {
     const int plain_len = (int)length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
 
@@ -564,7 +565,7 @@ static int create_reply(Announcements *announce, const IP_Port *source,
                                data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                data + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                                plain_len + CRYPTO_MAC_SIZE,
-                               plain) != plain_len) {
+                               plain, mem) != plain_len) {
         return -1;
     }
 
@@ -609,7 +610,8 @@ static void forwarded_request_callback(void *object, const IP_Port *forwarder,
 
     const int len = create_reply(announce, forwarder,
                                  sendback, sendback_length,
-                                 data, length, reply, sizeof(reply));
+                                 data, length, reply, sizeof(reply),
+                                 announce->mem);
 
     if (len == -1) {
         return;
@@ -628,7 +630,8 @@ static int handle_dht_announce_request(void *object, const IP_Port *source,
 
     const int len = create_reply(announce, source,
                                  nullptr, 0,
-                                 data, length, reply, sizeof(reply));
+                                 data, length, reply, sizeof(reply),
+                                 announce->mem);
 
     if (len == -1) {
         return -1;
@@ -637,14 +640,14 @@ static int handle_dht_announce_request(void *object, const IP_Port *source,
     return sendpacket(announce->net, source, reply, len) == len ? 0 : -1;
 }
 
-Announcements *new_announcements(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time,
+Announcements *new_announcements(const Logger *log, const Memory *mem, const Tox_Random *rng, const Mono_Time *mono_time,
                                  Forwarding *forwarding)
 {
     if (log == nullptr || mono_time == nullptr || forwarding == nullptr) {
         return nullptr;
     }
 
-    Announcements *announce = (Announcements *)calloc(1, sizeof(Announcements));
+    Announcements *announce = (Announcements *)mem_alloc(mem, sizeof(Announcements));
 
     if (announce == nullptr) {
         return nullptr;
@@ -662,7 +665,7 @@ Announcements *new_announcements(const Logger *log, const Memory *mem, const Ran
     new_hmac_key(announce->rng, announce->hmac_key);
     announce->shared_keys = shared_key_cache_new(mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
     if (announce->shared_keys == nullptr) {
-        free(announce);
+        mem_delete(mem, announce);
         return nullptr;
     }
 
@@ -694,9 +697,9 @@ void kill_announcements(Announcements *announce)
 
     for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
         if (announce->entries[i].data != nullptr) {
-            free(announce->entries[i].data);
+            mem_delete(announce->mem, announce->entries[i].data);
         }
     }
 
-    free(announce);
+    mem_delete(announce->mem, announce);
 }
diff --git a/toxcore/announce.h b/toxcore/announce.h
index bbd7a72b452..e3e1d22b80d 100644
--- a/toxcore/announce.h
+++ b/toxcore/announce.h
@@ -16,7 +16,7 @@ uint8_t announce_response_of_request_type(uint8_t request_type);
 typedef struct Announcements Announcements;
 
 non_null()
-Announcements *new_announcements(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time,
+Announcements *new_announcements(const Logger *log, const Memory *mem, const Tox_Random *rng, const Mono_Time *mono_time,
                                  Forwarding *forwarding);
 
 /**
diff --git a/toxcore/bin_pack.c b/toxcore/bin_pack.c
index 3575803aedd..00e7ea87c56 100644
--- a/toxcore/bin_pack.c
+++ b/toxcore/bin_pack.c
@@ -12,6 +12,8 @@
 #include "ccompat.h"
 
 struct Bin_Pack {
+    const Memory *mem;
+
     uint8_t *bytes;
     uint32_t bytes_size;
     uint32_t bytes_pos;
@@ -56,6 +58,7 @@ static size_t buf_writer(cmp_ctx_t *ctx, const void *data, size_t count)
 non_null(1) nullable(2)
 static void bin_pack_init(Bin_Pack *bp, uint8_t *buf, uint32_t buf_size)
 {
+    bp->mem = nullptr;
     bp->bytes = buf;
     bp->bytes_size = buf_size;
     bp->bytes_pos = 0;
@@ -77,19 +80,24 @@ uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj)
     return bp.bytes_pos;
 }
 
-Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size)
+Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size, const Memory *mem)
 {
-    Bin_Pack *bp = (Bin_Pack *)calloc(1, sizeof(Bin_Pack));
+    Bin_Pack *bp = (Bin_Pack *)mem_alloc(mem, sizeof(Bin_Pack));
     if (bp == nullptr) {
         return nullptr;
     }
     bin_pack_init(bp, buf, buf_size);
+    bp->mem = mem;
     return bp;
 }
 
 void bin_pack_free(Bin_Pack *bp)
 {
-    free(bp);
+    if (bp == nullptr) {
+        return;
+    }
+
+    mem_delete(bp->mem, bp);
 }
 
 bool bin_pack_array(Bin_Pack *bp, uint32_t size)
diff --git a/toxcore/bin_pack.h b/toxcore/bin_pack.h
index 51646c088a5..0160b1e19d4 100644
--- a/toxcore/bin_pack.h
+++ b/toxcore/bin_pack.h
@@ -7,7 +7,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "attributes.h"
+#include "mem.h"
+#include "tox_attributes.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,7 +65,7 @@ bool bin_pack_obj(bin_pack_cb *callback, const void *obj, uint8_t *buf, uint32_t
  * @retval nullptr on allocation failure.
  */
 non_null()
-Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size);
+Bin_Pack *bin_pack_new(uint8_t *buf, uint32_t buf_size, const Memory *mem);
 
 /** @brief Deallocates a packer object.
  *
diff --git a/toxcore/bin_pack_test.cc b/toxcore/bin_pack_test.cc
index 05140146dfe..43aa4e61feb 100644
--- a/toxcore/bin_pack_test.cc
+++ b/toxcore/bin_pack_test.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "bin_unpack.h"
+#include "os_memory.h"
 
 namespace {
 
@@ -24,20 +25,22 @@ using Bin_Unpack_Ptr = std::unique_ptr<Bin_Unpack, Bin_Unpack_Deleter>;
 
 TEST(BinPack, TooSmallBufferIsNotExceeded)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 7> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     EXPECT_FALSE(bin_pack_u64_b(bp.get(), 1234567812345678LL));
 }
 
 TEST(BinPack, PackedUint64CanBeUnpacked)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 8> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     ASSERT_TRUE(bin_pack_u64_b(bp.get(), 1234567812345678LL));
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bu, nullptr);
     uint64_t val;
     ASSERT_TRUE(bin_unpack_u64_b(bu.get(), &val));
@@ -46,12 +49,13 @@ TEST(BinPack, PackedUint64CanBeUnpacked)
 
 TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 2> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     ASSERT_TRUE(bin_pack_u08(bp.get(), 123));
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bu, nullptr);
     uint32_t val;
     ASSERT_TRUE(bin_unpack_u32(bu.get(), &val));
@@ -60,12 +64,13 @@ TEST(BinPack, MsgPackedUint8CanBeUnpackedAsUint32)
 
 TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 2> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     ASSERT_TRUE(bin_pack_u32(bp.get(), 123));
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bu, nullptr);
     uint8_t val;
     ASSERT_TRUE(bin_unpack_u08(bu.get(), &val));
@@ -74,12 +79,13 @@ TEST(BinPack, MsgPackedUint32CanBeUnpackedAsUint8IfSmallEnough)
 
 TEST(BinPack, LargeMsgPackedUint32CannotBeUnpackedAsUint8)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 5> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     ASSERT_TRUE(bin_pack_u32(bp.get(), 1234567));
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bu, nullptr);
     uint8_t val;
     EXPECT_FALSE(bin_unpack_u08(bu.get(), &val));
@@ -87,14 +93,15 @@ TEST(BinPack, LargeMsgPackedUint32CannotBeUnpackedAsUint8)
 
 TEST(BinPack, BinCanHoldPackedInts)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 12> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     ASSERT_TRUE(bin_pack_bin_marker(bp.get(), 8));
     ASSERT_TRUE(bin_pack_u64_b(bp.get(), 1234567812345678LL));
     ASSERT_TRUE(bin_pack_u16_b(bp.get(), 54321));
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bu, nullptr);
     uint32_t size;
     EXPECT_TRUE(bin_unpack_bin_size(bu.get(), &size));
@@ -109,13 +116,14 @@ TEST(BinPack, BinCanHoldPackedInts)
 
 TEST(BinPack, BinCanHoldArbitraryData)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 7> buf;
-    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size()));
+    Bin_Pack_Ptr bp(bin_pack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bp, nullptr);
     ASSERT_TRUE(bin_pack_bin_marker(bp.get(), 5));
     ASSERT_TRUE(bin_pack_bin_b(bp.get(), reinterpret_cast<const uint8_t *>("hello"), 5));
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     ASSERT_NE(bu, nullptr);
     std::array<uint8_t, 5> str;
     EXPECT_TRUE(bin_unpack_bin_fixed(bu.get(), str.data(), str.size()));
@@ -124,9 +132,10 @@ TEST(BinPack, BinCanHoldArbitraryData)
 
 TEST(BinPack, OversizedArrayFailsUnpack)
 {
+    const Memory *mem = os_memory();
     std::array<uint8_t, 1> buf = {0x91};
 
-    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size()));
+    Bin_Unpack_Ptr bu(bin_unpack_new(buf.data(), buf.size(), mem));
     uint32_t size;
     EXPECT_FALSE(bin_unpack_array(bu.get(), &size));
 }
diff --git a/toxcore/bin_unpack.c b/toxcore/bin_unpack.c
index ff591ca87ad..1799e7517fe 100644
--- a/toxcore/bin_unpack.c
+++ b/toxcore/bin_unpack.c
@@ -12,6 +12,8 @@
 #include "ccompat.h"
 
 struct Bin_Unpack {
+    const Memory *mem;
+
     const uint8_t *bytes;
     uint32_t bytes_size;
     cmp_ctx_t ctx;
@@ -51,12 +53,13 @@ static size_t null_writer(cmp_ctx_t *ctx, const void *data, size_t count)
     return 0;
 }
 
-Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size)
+Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size, const Memory *mem)
 {
-    Bin_Unpack *bu = (Bin_Unpack *)calloc(1, sizeof(Bin_Unpack));
+    Bin_Unpack *bu = (Bin_Unpack *)mem_alloc(mem, sizeof(Bin_Unpack));
     if (bu == nullptr) {
         return nullptr;
     }
+    bu->mem = mem;
     bu->bytes = buf;
     bu->bytes_size = buf_size;
     cmp_init(&bu->ctx, bu, buf_reader, buf_skipper, null_writer);
@@ -65,7 +68,11 @@ Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size)
 
 void bin_unpack_free(Bin_Unpack *bu)
 {
-    free(bu);
+    if (bu == nullptr) {
+        return;
+    }
+
+    mem_delete(bu->mem, bu);
 }
 
 bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size)
@@ -116,10 +123,14 @@ bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_pt
         // There aren't as many bytes as this bin claims to want to allocate.
         return false;
     }
-    uint8_t *const data = (uint8_t *)malloc(bin_size);
+    uint8_t *const data = (uint8_t *)mem_balloc(bu->mem, bin_size);
+
+    if (data == nullptr) {
+        return false;
+    }
 
     if (!bin_unpack_bin_b(bu, data, bin_size)) {
-        free(data);
+        mem_delete(bu->mem, data);
         return false;
     }
 
diff --git a/toxcore/bin_unpack.h b/toxcore/bin_unpack.h
index bd4d8785c1f..b37a407b91f 100644
--- a/toxcore/bin_unpack.h
+++ b/toxcore/bin_unpack.h
@@ -8,7 +8,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "attributes.h"
+#include "mem.h"
+#include "tox_attributes.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -27,7 +28,7 @@ typedef struct Bin_Unpack Bin_Unpack;
  * @retval nullptr on allocation failure.
  */
 non_null()
-Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size);
+Bin_Unpack *bin_unpack_new(const uint8_t *buf, uint32_t buf_size, const Memory *mem);
 
 /** @brief Deallocates an unpacker object.
  *
diff --git a/toxcore/ccompat.h b/toxcore/ccompat.h
index 9ea6739a7d3..05525ef6691 100644
--- a/toxcore/ccompat.h
+++ b/toxcore/ccompat.h
@@ -10,7 +10,7 @@
 
 #include <stddef.h>  // NULL, size_t
 
-#include "attributes.h"
+#include "tox_attributes.h"
 
 //!TOKSTYLE-
 
diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c
index 14025252c41..85c20fcce60 100644
--- a/toxcore/crypto_core.c
+++ b/toxcore/crypto_core.c
@@ -29,6 +29,7 @@
 #endif
 
 #include "ccompat.h"
+#include "tox_random_impl.h"
 
 #ifndef crypto_box_MACBYTES
 #define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
@@ -116,9 +117,10 @@ const uint8_t *get_chat_id(const uint8_t *key)
 }
 
 #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
-static uint8_t *crypto_malloc(size_t bytes)
+non_null()
+static uint8_t *crypto_malloc(const Memory *mem, size_t bytes)
 {
-    uint8_t *ptr = (uint8_t *)malloc(bytes);
+    uint8_t *ptr = (uint8_t *)mem_balloc(mem, bytes);
 
     if (ptr != nullptr) {
         crypto_memlock(ptr, bytes);
@@ -127,15 +129,15 @@ static uint8_t *crypto_malloc(size_t bytes)
     return ptr;
 }
 
-nullable(1)
-static void crypto_free(uint8_t *ptr, size_t bytes)
+non_null(1) nullable(2)
+static void crypto_free(const Memory *mem, uint8_t *ptr, size_t bytes)
 {
     if (ptr != nullptr) {
         crypto_memzero(ptr, bytes);
         crypto_memunlock(ptr, bytes);
     }
 
-    free(ptr);
+    mem_delete(mem, ptr);
 }
 #endif  // !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 
@@ -245,7 +247,7 @@ uint64_t random_u64(const Random *rng)
 
 uint32_t random_range_u32(const Random *rng, uint32_t upper_bound)
 {
-    return rng->funcs->random_uniform(rng->obj, upper_bound);
+    return tox_random_uniform(rng, upper_bound);
 }
 
 bool crypto_signature_create(uint8_t *signature, const uint8_t *message, uint64_t message_length,
@@ -286,7 +288,8 @@ int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key,
 }
 
 int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
-                               const uint8_t *plain, size_t length, uint8_t *encrypted)
+                               const uint8_t *plain, size_t length, uint8_t *encrypted,
+                               const Memory *mem)
 {
     if (length == 0 || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
         return -1;
@@ -302,12 +305,12 @@ int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
     const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
     const size_t size_temp_encrypted = length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES;
 
-    uint8_t *temp_plain = crypto_malloc(size_temp_plain);
-    uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted);
+    uint8_t *temp_plain = crypto_malloc(mem, size_temp_plain);
+    uint8_t *temp_encrypted = crypto_malloc(mem, size_temp_encrypted);
 
     if (temp_plain == nullptr || temp_encrypted == nullptr) {
-        crypto_free(temp_plain, size_temp_plain);
-        crypto_free(temp_encrypted, size_temp_encrypted);
+        crypto_free(mem, temp_plain, size_temp_plain);
+        crypto_free(mem, temp_encrypted, size_temp_encrypted);
         return -1;
     }
 
@@ -322,23 +325,24 @@ int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
 
     if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce,
                            shared_key) != 0) {
-        crypto_free(temp_plain, size_temp_plain);
-        crypto_free(temp_encrypted, size_temp_encrypted);
+        crypto_free(mem, temp_plain, size_temp_plain);
+        crypto_free(mem, temp_encrypted, size_temp_encrypted);
         return -1;
     }
 
     // Unpad the encrypted message.
     memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES);
 
-    crypto_free(temp_plain, size_temp_plain);
-    crypto_free(temp_encrypted, size_temp_encrypted);
+    crypto_free(mem, temp_plain, size_temp_plain);
+    crypto_free(mem, temp_encrypted, size_temp_encrypted);
 #endif
     assert(length < INT32_MAX - crypto_box_MACBYTES);
     return (int32_t)(length + crypto_box_MACBYTES);
 }
 
 int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
-                               const uint8_t *encrypted, size_t length, uint8_t *plain)
+                               const uint8_t *encrypted, size_t length, uint8_t *plain,
+                               const Memory *mem)
 {
     if (length <= crypto_box_BOXZEROBYTES || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
             || plain == nullptr) {
@@ -353,12 +357,12 @@ int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
     const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
     const size_t size_temp_encrypted = length + crypto_box_BOXZEROBYTES;
 
-    uint8_t *temp_plain = crypto_malloc(size_temp_plain);
-    uint8_t *temp_encrypted = crypto_malloc(size_temp_encrypted);
+    uint8_t *temp_plain = crypto_malloc(mem, size_temp_plain);
+    uint8_t *temp_encrypted = crypto_malloc(mem, size_temp_encrypted);
 
     if (temp_plain == nullptr || temp_encrypted == nullptr) {
-        crypto_free(temp_plain, size_temp_plain);
-        crypto_free(temp_encrypted, size_temp_encrypted);
+        crypto_free(mem, temp_plain, size_temp_plain);
+        crypto_free(mem, temp_encrypted, size_temp_encrypted);
         return -1;
     }
 
@@ -373,15 +377,15 @@ int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
 
     if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce,
                                 shared_key) != 0) {
-        crypto_free(temp_plain, size_temp_plain);
-        crypto_free(temp_encrypted, size_temp_encrypted);
+        crypto_free(mem, temp_plain, size_temp_plain);
+        crypto_free(mem, temp_encrypted, size_temp_encrypted);
         return -1;
     }
 
     memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES);
 
-    crypto_free(temp_plain, size_temp_plain);
-    crypto_free(temp_encrypted, size_temp_encrypted);
+    crypto_free(mem, temp_plain, size_temp_plain);
+    crypto_free(mem, temp_encrypted, size_temp_encrypted);
 #endif
     assert(length > crypto_box_MACBYTES);
     assert(length < INT32_MAX);
@@ -389,7 +393,7 @@ int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
 }
 
 int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
-                     const uint8_t *plain, size_t length, uint8_t *encrypted)
+                     const uint8_t *plain, size_t length, uint8_t *encrypted, const Memory *mem)
 {
     if (public_key == nullptr || secret_key == nullptr) {
         return -1;
@@ -397,13 +401,13 @@ int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const
 
     uint8_t k[crypto_box_BEFORENMBYTES];
     encrypt_precompute(public_key, secret_key, k);
-    const int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted);
+    const int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted, mem);
     crypto_memzero(k, sizeof(k));
     return ret;
 }
 
 int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
-                     const uint8_t *encrypted, size_t length, uint8_t *plain)
+                     const uint8_t *encrypted, size_t length, uint8_t *plain, const Memory *mem)
 {
     if (public_key == nullptr || secret_key == nullptr) {
         return -1;
@@ -411,7 +415,7 @@ int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const
 
     uint8_t k[crypto_box_BEFORENMBYTES];
     encrypt_precompute(public_key, secret_key, k);
-    const int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain);
+    const int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain, mem);
     crypto_memzero(k, sizeof(k));
     return ret;
 }
@@ -530,53 +534,7 @@ void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length)
 #endif
 }
 
-non_null()
-static void sys_random_bytes(void *obj, uint8_t *bytes, size_t length)
-{
-    randombytes(bytes, length);
-}
-
-non_null()
-static uint32_t sys_random_uniform(void *obj, uint32_t upper_bound)
-{
-#ifdef VANILLA_NACL
-    if (upper_bound == 0) {
-        return 0;
-    }
-
-    uint32_t randnum;
-    sys_random_bytes(obj, (uint8_t *)&randnum, sizeof(randnum));
-    return randnum % upper_bound;
-#else
-    return randombytes_uniform(upper_bound);
-#endif
-}
-
-static const Random_Funcs system_random_funcs = {
-    sys_random_bytes,
-    sys_random_uniform,
-};
-
-static const Random system_random_obj = {&system_random_funcs};
-
-const Random *system_random(void)
-{
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-    if ((true)) {
-        return nullptr;
-    }
-#endif
-#ifndef VANILLA_NACL
-    // It is safe to call this function more than once and from different
-    // threads -- subsequent calls won't have any effects.
-    if (sodium_init() == -1) {
-        return nullptr;
-    }
-#endif
-    return &system_random_obj;
-}
-
 void random_bytes(const Random *rng, uint8_t *bytes, size_t length)
 {
-    rng->funcs->random_bytes(rng->obj, bytes, length);
+    tox_random_bytes(rng, bytes, length);
 }
diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h
index 3b9f27d677c..938068fc9e1 100644
--- a/toxcore/crypto_core.h
+++ b/toxcore/crypto_core.h
@@ -13,7 +13,9 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "attributes.h"
+#include "mem.h"
+#include "tox_attributes.h"
+#include "tox_random.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -75,21 +77,6 @@ extern "C" {
  */
 #define CRYPTO_SHA512_SIZE             64
 
-typedef void crypto_random_bytes_cb(void *obj, uint8_t *bytes, size_t length);
-typedef uint32_t crypto_random_uniform_cb(void *obj, uint32_t upper_bound);
-
-typedef struct Random_Funcs {
-    crypto_random_bytes_cb *random_bytes;
-    crypto_random_uniform_cb *random_uniform;
-} Random_Funcs;
-
-typedef struct Random {
-    const Random_Funcs *funcs;
-    void *obj;
-} Random;
-
-const Random *system_random(void);
-
 /**
  * @brief The number of bytes in an encryption public key used by DHT group chats.
  */
@@ -208,6 +195,8 @@ bool crypto_sha512_eq(const uint8_t *cksum1, const uint8_t *cksum2);
 non_null()
 bool crypto_sha256_eq(const uint8_t *cksum1, const uint8_t *cksum2);
 
+typedef Tox_Random Random;
+
 /**
  * @brief Return a random 8 bit integer.
  */
@@ -338,7 +327,7 @@ void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key);
  */
 non_null()
 int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain,
-                     size_t length, uint8_t *encrypted);
+                     size_t length, uint8_t *encrypted, const Memory *mem);
 
 /**
  * @brief Decrypt message from public key to secret key.
@@ -353,7 +342,7 @@ int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const
  */
 non_null()
 int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,
-                     const uint8_t *encrypted, size_t length, uint8_t *plain);
+                     const uint8_t *encrypted, size_t length, uint8_t *plain, const Memory *mem);
 
 /**
  * @brief Fast encrypt/decrypt operations.
@@ -377,7 +366,7 @@ int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key,
  */
 non_null()
 int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *plain, size_t length,
-                               uint8_t *encrypted);
+                               uint8_t *encrypted, const Memory *mem);
 
 /**
  * @brief Decrypt message with precomputed shared key.
@@ -391,7 +380,7 @@ int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce,
  */
 non_null()
 int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length,
-                               uint8_t *plain);
+                               uint8_t *plain, const Memory *mem);
 
 /**
  * @brief Increment the given nonce by 1 in big endian (rightmost byte incremented
diff --git a/toxcore/crypto_core_test.cc b/toxcore/crypto_core_test.cc
index 4f2a9f3085b..bde7ec7bac8 100644
--- a/toxcore/crypto_core_test.cc
+++ b/toxcore/crypto_core_test.cc
@@ -6,6 +6,7 @@
 #include <array>
 #include <vector>
 
+#include "os_random.h"
 #include "util.h"
 
 namespace {
@@ -52,7 +53,7 @@ TEST(CryptoCore, IncrementNonceNumber)
 
 TEST(CryptoCore, Signatures)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     ExtPublicKey pk;
@@ -76,7 +77,7 @@ TEST(CryptoCore, Signatures)
 
 TEST(CryptoCore, Hmac)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     HmacKey sk;
diff --git a/toxcore/events/events_alloc.h b/toxcore/events/events_alloc.h
index 6c5a7abd4f7..06a24942763 100644
--- a/toxcore/events/events_alloc.h
+++ b/toxcore/events/events_alloc.h
@@ -5,7 +5,7 @@
 #ifndef C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
 #define C_TOXCORE_TOXCORE_TOX_EVENTS_INTERNAL_H
 
-#include "../attributes.h"
+#include "../tox_attributes.h"
 #include "../bin_pack.h"
 #include "../bin_unpack.h"
 #include "../tox_events.h"
diff --git a/toxcore/forwarding.c b/toxcore/forwarding.c
index 5e885abd211..be98ecf24e7 100644
--- a/toxcore/forwarding.c
+++ b/toxcore/forwarding.c
@@ -14,6 +14,7 @@
 
 struct Forwarding {
     const Logger *log;
+    const Memory *mem;
     const Random *rng;
     DHT *dht;
     const Mono_Time *mono_time;
@@ -352,19 +353,20 @@ void set_callback_forward_reply(Forwarding *forwarding, forward_reply_cb *functi
     forwarding->forward_reply_callback_object = object;
 }
 
-Forwarding *new_forwarding(const Logger *log, const Random *rng, const Mono_Time *mono_time, DHT *dht)
+Forwarding *new_forwarding(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time, DHT *dht)
 {
     if (log == nullptr || mono_time == nullptr || dht == nullptr) {
         return nullptr;
     }
 
-    Forwarding *forwarding = (Forwarding *)calloc(1, sizeof(Forwarding));
+    Forwarding *forwarding = (Forwarding *)mem_alloc(mem, sizeof(Forwarding));
 
     if (forwarding == nullptr) {
         return nullptr;
     }
 
     forwarding->log = log;
+    forwarding->mem = mem;
     forwarding->rng = rng;
     forwarding->mono_time = mono_time;
     forwarding->dht = dht;
@@ -391,5 +393,5 @@ void kill_forwarding(Forwarding *forwarding)
 
     crypto_memzero(forwarding->hmac_key, CRYPTO_HMAC_KEY_SIZE);
 
-    free(forwarding);
+    mem_delete(forwarding->mem, forwarding);
 }
diff --git a/toxcore/forwarding.h b/toxcore/forwarding.h
index 36ce8ad8943..4cc47e528c3 100644
--- a/toxcore/forwarding.h
+++ b/toxcore/forwarding.h
@@ -113,7 +113,7 @@ non_null(1) nullable(2, 3)
 void set_callback_forward_reply(Forwarding *forwarding, forward_reply_cb *function, void *object);
 
 non_null()
-Forwarding *new_forwarding(const Logger *log, const Random *rng, const Mono_Time *mono_time, DHT *dht);
+Forwarding *new_forwarding(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time, DHT *dht);
 
 nullable(1)
 void kill_forwarding(Forwarding *forwarding);
diff --git a/toxcore/forwarding_fuzz_test.cc b/toxcore/forwarding_fuzz_test.cc
index ce263f1e6fd..a6c5581aa51 100644
--- a/toxcore/forwarding_fuzz_test.cc
+++ b/toxcore/forwarding_fuzz_test.cc
@@ -5,14 +5,16 @@
 
 #include "../testing/fuzzing/fuzz_support.h"
 #include "../testing/fuzzing/fuzz_tox.h"
+#include "os_memory.h"
+#include "os_network.h"
 
 namespace {
 
 void TestSendForwardRequest(Fuzz_Data &input)
 {
-    const Network *ns = system_network();  // TODO(iphydf): fuzz_network
+    const Network *ns = os_network();  // TODO(iphydf): fuzz_network
     assert(ns != nullptr);
-    const Memory *mem = system_memory();  // TODO(iphydf): fuzz_memory
+    const Memory *mem = os_memory();  // TODO(iphydf): fuzz_memory
     assert(mem != nullptr);
 
     with<Logger>{} >> with<Networking_Core>{input, ns, mem} >> [&input](Ptr<Networking_Core> net) {
@@ -29,9 +31,9 @@ void TestSendForwardRequest(Fuzz_Data &input)
 
 void TestForwardReply(Fuzz_Data &input)
 {
-    const Network *ns = system_network();  // TODO(iphydf): fuzz_network
+    const Network *ns = os_network();  // TODO(iphydf): fuzz_network
     assert(ns != nullptr);
-    const Memory *mem = system_memory();  // TODO(iphydf): fuzz_memory
+    const Memory *mem = os_memory();  // TODO(iphydf): fuzz_memory
     assert(mem != nullptr);
 
     with<Logger>{} >> with<Networking_Core>{input, ns, mem} >> [&input](Ptr<Networking_Core> net) {
diff --git a/toxcore/friend_connection.c b/toxcore/friend_connection.c
index 7b8537c7207..0e321c36933 100644
--- a/toxcore/friend_connection.c
+++ b/toxcore/friend_connection.c
@@ -60,6 +60,7 @@ static const Friend_Conn empty_friend_conn = {0};
 struct Friend_Connections {
     const Mono_Time *mono_time;
     const Logger *logger;
+    const Memory *mem;
     Net_Crypto *net_crypto;
     DHT *dht;
     Broadcast_Info *broadcast;
@@ -111,19 +112,19 @@ static bool friendconn_id_valid(const Friend_Connections *fr_c, int friendcon_id
 
 /** @brief Set the size of the friend connections list to num.
  *
- * @retval false if realloc fails.
+ * @retval false if mem_vrealloc fails.
  * @retval true if it succeeds.
  */
 non_null()
 static bool realloc_friendconns(Friend_Connections *fr_c, uint32_t num)
 {
     if (num == 0) {
-        free(fr_c->conns);
+        mem_delete(fr_c->mem, fr_c->conns);
         fr_c->conns = nullptr;
         return true;
     }
 
-    Friend_Conn *newgroup_cons = (Friend_Conn *)realloc(fr_c->conns, num * sizeof(Friend_Conn));
+    Friend_Conn *newgroup_cons = (Friend_Conn *)mem_vrealloc(fr_c->mem, fr_c->conns, num, sizeof(Friend_Conn));
 
     if (newgroup_cons == nullptr) {
         return false;
@@ -898,14 +899,14 @@ int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint3
 
 /** Create new friend_connections instance. */
 Friend_Connections *new_friend_connections(
-        const Logger *logger, const Mono_Time *mono_time, const Network *ns,
+        const Logger *logger, const Mono_Time *mono_time, const Memory *mem, const Network *ns,
         Onion_Client *onion_c, bool local_discovery_enabled)
 {
     if (onion_c == nullptr) {
         return nullptr;
     }
 
-    Friend_Connections *const temp = (Friend_Connections *)calloc(1, sizeof(Friend_Connections));
+    Friend_Connections *const temp = (Friend_Connections *)mem_alloc(mem, sizeof(Friend_Connections));
 
     if (temp == nullptr) {
         return nullptr;
@@ -913,6 +914,7 @@ Friend_Connections *new_friend_connections(
 
     temp->mono_time = mono_time;
     temp->logger = logger;
+    temp->mem = mem;
     temp->dht = onion_get_dht(onion_c);
     temp->net_crypto = onion_get_net_crypto(onion_c);
     temp->onion_c = onion_c;
@@ -923,7 +925,7 @@ Friend_Connections *new_friend_connections(
     new_connection_handler(temp->net_crypto, &handle_new_connections, temp);
 
     if (temp->local_discovery_enabled) {
-        temp->broadcast = lan_discovery_init(ns);
+        temp->broadcast = lan_discovery_init(mem, ns);
 
         if (temp->broadcast == nullptr) {
             LOGGER_ERROR(logger, "could not initialise LAN discovery");
@@ -1021,5 +1023,5 @@ void kill_friend_connections(Friend_Connections *fr_c)
     }
 
     lan_discovery_kill(fr_c->broadcast);
-    free(fr_c);
+    mem_delete(fr_c->mem, fr_c);
 }
diff --git a/toxcore/friend_connection.h b/toxcore/friend_connection.h
index 93bd5113ac5..1555ff3d4c3 100644
--- a/toxcore/friend_connection.h
+++ b/toxcore/friend_connection.h
@@ -156,7 +156,7 @@ void set_friend_request_callback(Friend_Connections *fr_c, fr_request_cb *fr_req
 /** Create new friend_connections instance. */
 non_null()
 Friend_Connections *new_friend_connections(
-        const Logger *logger, const Mono_Time *mono_time, const Network *ns,
+        const Logger *logger, const Mono_Time *mono_time, const Memory *mem, const Network *ns,
         Onion_Client *onion_c, bool local_discovery_enabled);
 
 /** main friend_connections loop. */
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c
index 7f18b1ff026..30a4363c644 100644
--- a/toxcore/friend_requests.c
+++ b/toxcore/friend_requests.c
@@ -26,6 +26,8 @@ struct Received_Requests {
 };
 
 struct Friend_Requests {
+    const Memory *mem;
+
     uint32_t nospam;
     fr_friend_request_cb *handle_friendrequest;
     uint8_t handle_friendrequest_isset;
@@ -160,12 +162,20 @@ void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c)
     set_friend_request_callback(fr_c, &friendreq_handlepacket, fr);
 }
 
-Friend_Requests *friendreq_new(void)
+Friend_Requests *friendreq_new(const Memory *mem)
 {
-    return (Friend_Requests *)calloc(1, sizeof(Friend_Requests));
+    Friend_Requests *fr = (Friend_Requests *)mem_alloc(mem, sizeof(Friend_Requests));
+
+    if (fr == nullptr) {
+        return nullptr;
+    }
+
+    fr->mem = mem;
+
+    return fr;
 }
 
 void friendreq_kill(Friend_Requests *fr)
 {
-    free(fr);
+    mem_delete(fr->mem, fr);
 }
diff --git a/toxcore/friend_requests.h b/toxcore/friend_requests.h
index 26145271636..0524c648f14 100644
--- a/toxcore/friend_requests.h
+++ b/toxcore/friend_requests.h
@@ -46,7 +46,8 @@ void set_filter_function(Friend_Requests *fr, filter_function_cb *function, void
 non_null()
 void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c);
 
-Friend_Requests *friendreq_new(void);
+non_null()
+Friend_Requests *friendreq_new(const Memory *mem);
 
 nullable(1)
 void friendreq_kill(Friend_Requests *fr);
diff --git a/toxcore/group.c b/toxcore/group.c
index 0e851b1e348..2b1c17178ea 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -138,6 +138,7 @@ typedef struct Group_c {
 } Group_c;
 
 struct Group_Chats {
+    const Memory *mem;
     const Mono_Time *mono_time;
 
     Messenger *m;
@@ -238,19 +239,19 @@ static bool is_groupnumber_valid(const Group_Chats *g_c, uint32_t groupnumber)
 
 /** @brief Set the size of the groupchat list to num.
  *
- * @retval false if realloc fails.
+ * @retval false if mem_vrealloc fails.
  * @retval true if it succeeds.
  */
 non_null()
 static bool realloc_conferences(Group_Chats *g_c, uint16_t num)
 {
     if (num == 0) {
-        free(g_c->chats);
+        mem_delete(g_c->mem, g_c->chats);
         g_c->chats = nullptr;
         return true;
     }
 
-    Group_c *newgroup_chats = (Group_c *)realloc(g_c->chats, num * sizeof(Group_c));
+    Group_c *newgroup_chats = (Group_c *)mem_vrealloc(g_c->mem, g_c->chats, num, sizeof(Group_c));
 
     if (newgroup_chats == nullptr) {
         return false;
@@ -292,10 +293,10 @@ static int32_t create_group_chat(Group_Chats *g_c)
 }
 
 non_null()
-static void wipe_group_c(Group_c *g)
+static void wipe_group_c(Group_c *g, const Memory *mem)
 {
-    free(g->frozen);
-    free(g->group);
+    mem_delete(mem, g->frozen);
+    mem_delete(mem, g->group);
     crypto_memzero(g, sizeof(Group_c));
 }
 
@@ -310,7 +311,7 @@ static bool wipe_group_chat(Group_Chats *g_c, uint32_t groupnumber)
         return false;
     }
 
-    wipe_group_c(&g_c->chats[groupnumber]);
+    wipe_group_c(&g_c->chats[groupnumber], g_c->mem);
 
     uint16_t i;
 
@@ -660,7 +661,7 @@ static int get_frozen_index(const Group_c *g, uint16_t peer_number)
 }
 
 non_null()
-static bool delete_frozen(Group_c *g, uint32_t frozen_index)
+static bool delete_frozen(Group_c *g, uint32_t frozen_index, const Memory *mem)
 {
     if (frozen_index >= g->numfrozen) {
         return false;
@@ -669,14 +670,14 @@ static bool delete_frozen(Group_c *g, uint32_t frozen_index)
     --g->numfrozen;
 
     if (g->numfrozen == 0) {
-        free(g->frozen);
+        mem_delete(mem, g->frozen);
         g->frozen = nullptr;
     } else {
         if (g->numfrozen != frozen_index) {
             g->frozen[frozen_index] = g->frozen[g->numfrozen];
         }
 
-        Group_Peer *const frozen_temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * g->numfrozen);
+        Group_Peer *const frozen_temp = (Group_Peer *)mem_vrealloc(mem, g->frozen, g->numfrozen, sizeof(Group_Peer));
 
         if (frozen_temp == nullptr) {
             return false;
@@ -693,8 +694,8 @@ static bool delete_frozen(Group_c *g, uint32_t frozen_index)
  * @return peer index if peer is in the conference.
  * @retval -1 otherwise, and on error.
  */
-non_null(1) nullable(4)
-static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_number, void *userdata)
+non_null(1, 5) nullable(4)
+static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_number, void *userdata, const Memory *mem)
 {
     Group_c *g = get_group_c(g_c, groupnumber);
 
@@ -717,7 +718,7 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
 
     /* Now thaw the peer */
 
-    Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));
+    Group_Peer *temp = (Group_Peer *)mem_vrealloc(mem, g->group, g->numpeers + 1, sizeof(Group_Peer));
 
     if (temp == nullptr) {
         return -1;
@@ -734,7 +735,7 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
 
     ++g->numpeers;
 
-    delete_frozen(g, frozen_index);
+    delete_frozen(g, frozen_index, g_c->mem);
 
     if (g_c->peer_list_changed_callback != nullptr) {
         g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata);
@@ -770,7 +771,7 @@ static void delete_any_peer_with_pk(Group_Chats *g_c, uint32_t groupnumber, cons
     const int frozen_index = frozen_in_group(g, real_pk);
 
     if (frozen_index >= 0) {
-        delete_frozen(g, frozen_index);
+        delete_frozen(g, frozen_index, g_c->mem);
     }
 }
 
@@ -797,7 +798,7 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
     }
 
     const int peer_index = fresh ?
-                           note_peer_active(g_c, groupnumber, peer_number, userdata) :
+                           note_peer_active(g_c, groupnumber, peer_number, userdata, g_c->mem) :
                            get_peer_index(g, peer_number);
 
     if (peer_index != -1) {
@@ -829,7 +830,7 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
 
     delete_any_peer_with_pk(g_c, groupnumber, real_pk, userdata);
 
-    Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));
+    Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->mem, g->group, g->numpeers + 1, sizeof(Group_Peer));
 
     if (temp == nullptr) {
         return -1;
@@ -920,14 +921,14 @@ static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
     void *peer_object = g->group[peer_index].object;
 
     if (g->numpeers == 0) {
-        free(g->group);
+        mem_delete(g_c->mem, g->group);
         g->group = nullptr;
     } else {
         if (g->numpeers != (uint32_t)peer_index) {
             g->group[peer_index] = g->group[g->numpeers];
         }
 
-        Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * g->numpeers);
+        Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->mem, g->group, g->numpeers, sizeof(Group_Peer));
 
         if (temp == nullptr) {
             return false;
@@ -971,14 +972,14 @@ static int cmp_frozen(const void *a, const void *b)
  * @retval true if any frozen peers are removed.
  */
 non_null()
-static bool delete_old_frozen(Group_c *g)
+static bool delete_old_frozen(Group_c *g, const Memory *mem)
 {
     if (g->numfrozen <= g->maxfrozen) {
         return false;
     }
 
     if (g->maxfrozen == 0) {
-        free(g->frozen);
+        mem_delete(mem, g->frozen);
         g->frozen = nullptr;
         g->numfrozen = 0;
         return true;
@@ -986,7 +987,7 @@ static bool delete_old_frozen(Group_c *g)
 
     qsort(g->frozen, g->numfrozen, sizeof(Group_Peer), cmp_frozen);
 
-    Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * g->maxfrozen);
+    Group_Peer *temp = (Group_Peer *)mem_vrealloc(mem, g->frozen, g->maxfrozen, sizeof(Group_Peer));
 
     if (temp == nullptr) {
         return false;
@@ -1011,7 +1012,7 @@ static bool freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index,
         return false;
     }
 
-    Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1));
+    Group_Peer *temp = (Group_Peer *)mem_vrealloc(g_c->mem, g->frozen, g->numfrozen + 1, sizeof(Group_Peer));
 
     if (temp == nullptr) {
         return false;
@@ -1029,7 +1030,7 @@ static bool freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index,
 
     ++g->numfrozen;
 
-    delete_old_frozen(g);
+    delete_old_frozen(g, g_c->mem);
 
     return true;
 }
@@ -1309,13 +1310,13 @@ static void remove_connection_reason(Group_Chats *g_c, Group_c *g, uint16_t i, u
 
 /** @brief Creates a new groupchat and puts it in the chats array.
  *
- * @param rng Random number generator used for generating the group ID.
+ * @param rng Tox_Random number generator used for generating the group ID.
  * @param type is one of `GROUPCHAT_TYPE_*`
  *
  * @return group number on success.
  * @retval -1 on failure.
  */
-int add_groupchat(Group_Chats *g_c, const Random *rng, uint8_t type)
+int add_groupchat(Group_Chats *g_c, const Tox_Random *rng, uint8_t type)
 {
     const int32_t groupnumber = create_group_chat(g_c);
 
@@ -1518,7 +1519,7 @@ int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t
     }
 
     g->maxfrozen = maxfrozen;
-    delete_old_frozen(g);
+    delete_old_frozen(g, g_c->mem);
     return 0;
 }
 
@@ -2857,7 +2858,7 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
     const bool ignore_frozen = message_id == GROUP_MESSAGE_FREEZE_PEER_ID;
 
     const int index = ignore_frozen ? get_peer_index(g, peer_number)
-                      : note_peer_active(g_c, groupnumber, peer_number, userdata);
+                      : note_peer_active(g_c, groupnumber, peer_number, userdata, g_c->mem);
 
     if (index == -1) {
         if (ignore_frozen) {
@@ -3610,7 +3611,7 @@ static uint32_t load_group(Group_c *g, const Group_Chats *g_c, const uint8_t *da
         }
 
         // This is inefficient, but allows us to check data consistency before allocating memory
-        Group_Peer *tmp_frozen = (Group_Peer *)realloc(g->frozen, (j + 1) * sizeof(Group_Peer));
+        Group_Peer *tmp_frozen = (Group_Peer *)mem_vrealloc(g_c->mem, g->frozen, j + 1, sizeof(Group_Peer));
 
         if (tmp_frozen == nullptr) {
             // Memory allocation failure
@@ -3748,18 +3749,19 @@ bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint3
 
 
 /** Create new groupchat instance. */
-Group_Chats *new_groupchats(const Mono_Time *mono_time, Messenger *m)
+Group_Chats *new_groupchats(const Mono_Time *mono_time, const Memory *mem, Messenger *m)
 {
     if (m == nullptr) {
         return nullptr;
     }
 
-    Group_Chats *temp = (Group_Chats *)calloc(1, sizeof(Group_Chats));
+    Group_Chats *temp = (Group_Chats *)mem_alloc(mem, sizeof(Group_Chats));
 
     if (temp == nullptr) {
         return nullptr;
     }
 
+    temp->mem = mem;
     temp->mono_time = mono_time;
     temp->m = m;
     temp->fr_c = m->fr_c;
@@ -3811,7 +3813,7 @@ void kill_groupchats(Group_Chats *g_c)
     m_callback_conference_invite(g_c->m, nullptr);
     set_global_status_callback(g_c->m->fr_c, nullptr, nullptr);
     g_c->m->conferences_object = nullptr;
-    free(g_c);
+    mem_delete(g_c->mem, g_c);
 }
 
 /**
diff --git a/toxcore/group.h b/toxcore/group.h
index e6f6c447333..1361b62c63e 100644
--- a/toxcore/group.h
+++ b/toxcore/group.h
@@ -93,14 +93,14 @@ void g_callback_peer_list_changed(Group_Chats *g_c, peer_list_changed_cb *functi
 
 /** @brief Creates a new groupchat and puts it in the chats array.
  *
- * @param rng Random number generator used for generating the group ID.
+ * @param rng Tox_Random number generator used for generating the group ID.
  * @param type is one of `GROUPCHAT_TYPE_*`
  *
  * @return group number on success.
  * @retval -1 on failure.
  */
 non_null()
-int add_groupchat(Group_Chats *g_c, const Random *rng, uint8_t type);
+int add_groupchat(Group_Chats *g_c, const Tox_Random *rng, uint8_t type);
 
 /** @brief Delete a groupchat from the chats array, informing the group first as
  * appropriate.
@@ -385,7 +385,7 @@ bool conferences_load_state_section(
 
 /** Create new groupchat instance. */
 non_null()
-Group_Chats *new_groupchats(const Mono_Time *mono_time, Messenger *m);
+Group_Chats *new_groupchats(const Mono_Time *mono_time, const Memory *mem, Messenger *m);
 
 /** main groupchats loop. */
 non_null(1) nullable(2)
diff --git a/toxcore/group_announce.c b/toxcore/group_announce.c
index 896b043dbd1..8c6d35e283e 100644
--- a/toxcore/group_announce.c
+++ b/toxcore/group_announce.c
@@ -5,7 +5,6 @@
 
 #include "group_announce.h"
 
-#include <stdlib.h>
 #include <string.h>
 
 #include "LAN_discovery.h"
@@ -33,7 +32,7 @@ static void remove_announces(GC_Announces_List *gc_announces_list, GC_Announces
         announces->next_announce->prev_announce = announces->prev_announce;
     }
 
-    free(announces);
+    mem_delete(gc_announces_list->mem, announces);
 }
 
 /**
@@ -349,7 +348,7 @@ GC_Peer_Announce *gca_add_announce(const Mono_Time *mono_time, GC_Announces_List
 
     // No entry for this chat_id exists so we create one
     if (announces == nullptr) {
-        announces = (GC_Announces *)calloc(1, sizeof(GC_Announces));
+        announces = (GC_Announces *)mem_alloc(gc_announces_list->mem, sizeof(GC_Announces));
 
         if (announces == nullptr) {
             return nullptr;
@@ -393,9 +392,16 @@ bool gca_is_valid_announce(const GC_Announce *announce)
     return announce->tcp_relays_count > 0 || announce->ip_port_is_set;
 }
 
-GC_Announces_List *new_gca_list(void)
+GC_Announces_List *new_gca_list(const Memory *mem)
 {
-    GC_Announces_List *announces_list = (GC_Announces_List *)calloc(1, sizeof(GC_Announces_List));
+    GC_Announces_List *announces_list = (GC_Announces_List *)mem_alloc(mem, sizeof(GC_Announces_List));
+
+    if (announces_list == nullptr) {
+        return nullptr;
+    }
+
+    announces_list->mem = mem;
+
     return announces_list;
 }
 
@@ -409,11 +415,11 @@ void kill_gca(GC_Announces_List *announces_list)
 
     while (root != nullptr) {
         GC_Announces *next = root->next_announce;
-        free(root);
+        mem_delete(announces_list->mem, root);
         root = next;
     }
 
-    free(announces_list);
+    mem_delete(announces_list->mem, announces_list);
 }
 
 /* How long we save a peer's announce before we consider it stale and remove it. */
diff --git a/toxcore/group_announce.h b/toxcore/group_announce.h
index 801363d6b2d..887b1d47b55 100644
--- a/toxcore/group_announce.h
+++ b/toxcore/group_announce.h
@@ -73,6 +73,8 @@ struct GC_Announces {
 
 /* A list of all announces. */
 struct GC_Announces_List {
+    const Memory *mem;
+
     GC_Announces *root_announces;
     uint64_t last_timeout_check;
 };
@@ -82,7 +84,8 @@ struct GC_Announces_List {
  *
  * The caller is responsible for freeing the memory with `kill_gca`.
  */
-GC_Announces_List *new_gca_list(void);
+non_null()
+GC_Announces_List *new_gca_list(const Memory *mem);
 
 /** @brief Frees all dynamically allocated memory associated with `announces_list`. */
 nullable(1)
diff --git a/toxcore/group_announce_fuzz_test.cc b/toxcore/group_announce_fuzz_test.cc
index 6728e712840..ef68b678f72 100644
--- a/toxcore/group_announce_fuzz_test.cc
+++ b/toxcore/group_announce_fuzz_test.cc
@@ -6,6 +6,8 @@
 #include <vector>
 
 #include "../testing/fuzzing/fuzz_support.h"
+#include "os_memory.h"
+#include "tox_time_impl.h"
 
 namespace {
 
@@ -17,7 +19,7 @@ void TestUnpackAnnouncesList(Fuzz_Data &input)
     // TODO(iphydf): How do we know the packed size?
     CONSUME1_OR_RETURN(const uint16_t packed_size, input);
 
-    Logger *logger = logger_new();
+    Logger *logger = logger_new(os_memory());
     if (gca_unpack_announces_list(logger, input.data, input.size, announces.data(), max_count)
         != -1) {
         std::vector<uint8_t> packed(packed_size);
@@ -35,7 +37,7 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
     // TODO(iphydf): How do we know the packed size?
     CONSUME1_OR_RETURN(const uint16_t packed_size, input);
 
-    Logger *logger = logger_new();
+    Logger *logger = logger_new(os_memory());
     if (gca_unpack_public_announce(logger, input.data, input.size, &public_announce) != -1) {
         std::vector<uint8_t> packed(packed_size);
         gca_pack_public_announce(logger, packed.data(), packed.size(), &public_announce);
@@ -45,16 +47,19 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
 
 void TestDoGca(Fuzz_Data &input)
 {
-    const Memory *mem = system_memory();
-    std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(), logger_kill);
+    const Memory *mem = os_memory();
+    std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(os_memory()), logger_kill);
+    constexpr Tox_Time_Funcs mock_time_funcs = {
+        [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
+    };
+    uint64_t clock = 1;
+    std::unique_ptr<Tox_Time, void (*)(Tox_Time *)> tm(
+        tox_time_new(&mock_time_funcs, &clock, mem), tox_time_free);
     std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
-        mono_time_new(mem, nullptr, nullptr), [mem](Mono_Time *ptr) { mono_time_free(mem, ptr); });
+        mono_time_new(mem, tm.get()), [mem](Mono_Time *ptr) { mono_time_free(mem, ptr); });
     assert(mono_time != nullptr);
-    uint64_t clock = 1;
-    mono_time_set_current_time_callback(
-        mono_time.get(), [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
-        &clock);
-    std::unique_ptr<GC_Announces_List, void (*)(GC_Announces_List *)> gca(new_gca_list(), kill_gca);
+    std::unique_ptr<GC_Announces_List, void (*)(GC_Announces_List *)> gca(
+        new_gca_list(mem), kill_gca);
     assert(gca != nullptr);
 
     while (input.size > 0) {
diff --git a/toxcore/group_announce_test.cc b/toxcore/group_announce_test.cc
index d3d5d715817..7dae423cd09 100644
--- a/toxcore/group_announce_test.cc
+++ b/toxcore/group_announce_test.cc
@@ -3,12 +3,18 @@
 #include <gtest/gtest.h>
 
 #include "mono_time.h"
+#include "os_memory.h"
+#include "tox_time_impl.h"
 
 namespace {
 
 struct Announces : ::testing::Test {
 protected:
-    const Memory *mem_ = system_memory();
+    const Memory *mem_ = os_memory();
+    static constexpr Tox_Time_Funcs mock_time_funcs = {
+        [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
+    };
+    Tox_Time *tm_;
     uint64_t clock_ = 0;
     Mono_Time *mono_time_ = nullptr;
     GC_Announces_List *gca_ = nullptr;
@@ -17,12 +23,12 @@ struct Announces : ::testing::Test {
 
     void SetUp() override
     {
-        mono_time_ = mono_time_new(mem_, nullptr, nullptr);
+        ASSERT_NE(mem_, nullptr);
+        tm_ = tox_time_new(&mock_time_funcs, &this->clock_, mem_);
+        ASSERT_NE(tm_, nullptr);
+        mono_time_ = mono_time_new(mem_, tm_);
         ASSERT_NE(mono_time_, nullptr);
-        mono_time_set_current_time_callback(
-            mono_time_, [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
-            &clock_);
-        gca_ = new_gca_list();
+        gca_ = new_gca_list(mem_);
         ASSERT_NE(gca_, nullptr);
     }
 
@@ -30,6 +36,7 @@ struct Announces : ::testing::Test {
     {
         kill_gca(gca_);
         mono_time_free(mem_, mono_time_);
+        tox_time_free(tm_);
     }
 
     void advance_clock(uint64_t increment)
@@ -108,12 +115,14 @@ TEST_F(Announces, AnnouncesGetAndCleanup)
 
 struct AnnouncesPack : ::testing::Test {
 protected:
+    const Memory *mem_ = os_memory();
     std::vector<GC_Announce> announces_;
     Logger *logger_ = nullptr;
 
     void SetUp() override
     {
-        logger_ = logger_new();
+        ASSERT_NE(mem_, nullptr);
+        logger_ = logger_new(mem_);
         ASSERT_NE(logger_, nullptr);
 
         // Add an announce without TCP relay.
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c
index a18ba1494c9..5d6f2cdb3a1 100644
--- a/toxcore/group_chats.c
+++ b/toxcore/group_chats.c
@@ -153,7 +153,7 @@ non_null() static bool group_exists(const GC_Session *c, const uint8_t *chat_id)
 non_null() static void add_tcp_relays_to_chat(const GC_Session *c, GC_Chat *chat);
 non_null(1, 2) nullable(4)
 static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, void *userdata);
-non_null() static void create_gc_session_keypair(const Logger *log, const Random *rng, uint8_t *public_key,
+non_null() static void create_gc_session_keypair(const Logger *log, const Tox_Random *rng, uint8_t *public_key,
         uint8_t *secret_key);
 non_null() static size_t load_gc_peers(GC_Chat *chat, const GC_SavedPeerInfo *addrs, uint16_t num_addrs);
 non_null() static bool saved_peer_is_valid(const GC_SavedPeerInfo *saved_peer);
@@ -744,7 +744,7 @@ static bool expand_chat_id(uint8_t *dest, const uint8_t *chat_id)
 
 /** Copies peer connect info from `gconn` to `addr`. */
 non_null()
-static void copy_gc_saved_peer(const Random *rng, const GC_Connection *gconn, GC_SavedPeerInfo *addr)
+static void copy_gc_saved_peer(const Tox_Random *rng, const GC_Connection *gconn, GC_SavedPeerInfo *addr)
 {
     if (!gcc_copy_tcp_relay(rng, &addr->tcp_relay, gconn)) {
         addr->tcp_relay = (Node_format) {
@@ -1412,8 +1412,9 @@ static bool sign_gc_shared_state(GC_Chat *chat)
  * Return -2 on decryption failure.
  * Return -3 if plaintext payload length is invalid.
  */
-non_null(1, 2, 3, 5, 6) nullable(4)
-static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, uint8_t *data, uint64_t *message_id,
+non_null(1, 2, 3, 4, 6, 7) nullable(5)
+static int group_packet_unwrap(const Logger *log, const Memory *mem, const GC_Connection *gconn,
+                               uint8_t *data, uint64_t *message_id,
                                uint8_t *packet_type, const uint8_t *packet, uint16_t length)
 {
     if (length <= CRYPTO_NONCE_SIZE) {
@@ -1421,7 +1422,7 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui
         return -1;
     }
 
-    uint8_t *plain = (uint8_t *)malloc(length);
+    uint8_t *plain = (uint8_t *)mem_balloc(mem, length);
 
     if (plain == nullptr) {
         LOGGER_ERROR(log, "Failed to allocate memory for plain data buffer");
@@ -1429,10 +1430,10 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui
     }
 
     int plain_len = decrypt_data_symmetric(gconn->session_shared_key, packet, packet + CRYPTO_NONCE_SIZE,
-                                           length - CRYPTO_NONCE_SIZE, plain);
+                                           length - CRYPTO_NONCE_SIZE, plain, mem);
 
     if (plain_len <= 0) {
-        free(plain);
+        mem_delete(mem, plain);
         return plain_len == 0 ? -3 : -2;
     }
 
@@ -1446,7 +1447,7 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui
         --plain_len;
 
         if (plain_len < min_plain_len) {
-            free(plain);
+            mem_delete(mem, plain);
             return -3;
         }
     }
@@ -1463,13 +1464,14 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui
 
     memcpy(data, real_plain + header_len, plain_len);
 
-    free(plain);
+    mem_delete(mem, plain);
 
     return plain_len;
 }
 
 int group_packet_wrap(
-    const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
+    const Logger *log, const Memory *mem, const Random *rng,
+    const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
     uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id,
     uint8_t gp_packet_type, uint8_t net_packet_type)
 {
@@ -1488,7 +1490,7 @@ int group_packet_wrap(
         return -1;
     }
 
-    uint8_t *plain = (uint8_t *)malloc(packet_size);
+    uint8_t *plain = (uint8_t *)mem_balloc(mem, packet_size);
 
     if (plain == nullptr) {
         return -1;
@@ -1516,20 +1518,20 @@ int group_packet_wrap(
     const uint16_t plain_len = padding_len + enc_header_len + length;
     const uint16_t encrypt_buf_size = plain_len + CRYPTO_MAC_SIZE;
 
-    uint8_t *encrypt = (uint8_t *)malloc(encrypt_buf_size);
+    uint8_t *encrypt = (uint8_t *)mem_balloc(mem, encrypt_buf_size);
 
     if (encrypt == nullptr) {
-        free(plain);
+        mem_delete(mem, plain);
         return -2;
     }
 
-    const int enc_len = encrypt_data_symmetric(shared_key, nonce, plain, plain_len, encrypt);
+    const int enc_len = encrypt_data_symmetric(shared_key, nonce, plain, plain_len, encrypt, mem);
 
-    free(plain);
+    mem_delete(mem, plain);
 
     if (enc_len != encrypt_buf_size) {
         LOGGER_ERROR(log, "encryption failed. packet type: 0x%02x, enc_len: %d", gp_packet_type, enc_len);
-        free(encrypt);
+        mem_delete(mem, encrypt);
         return -3;
     }
 
@@ -1538,7 +1540,7 @@ int group_packet_wrap(
     memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
     memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypt, enc_len);
 
-    free(encrypt);
+    mem_delete(mem, encrypt);
 
     return 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + enc_len;
 }
@@ -1562,25 +1564,25 @@ static bool send_lossy_group_packet(const GC_Chat *chat, const GC_Connection *gc
     }
 
     const uint16_t packet_size = gc_get_wrapped_packet_size(length, NET_PACKET_GC_LOSSY);
-    uint8_t *packet = (uint8_t *)malloc(packet_size);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
 
     if (packet == nullptr) {
         return false;
     }
 
     const int len = group_packet_wrap(
-                        chat->log, chat->rng, chat->self_public_key, gconn->session_shared_key, packet,
+                        chat->log, chat->mem, chat->rng, chat->self_public_key, gconn->session_shared_key, packet,
                         packet_size, data, length, 0, packet_type, NET_PACKET_GC_LOSSY);
 
     if (len < 0) {
         LOGGER_ERROR(chat->log, "Failed to encrypt packet (type: 0x%02x, error: %d)", packet_type, len);
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     const bool ret = gcc_send_packet(chat, gconn, packet, (uint16_t)len);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return ret;
 }
@@ -1819,7 +1821,7 @@ static bool sync_response_send_peers(GC_Chat *chat, GC_Connection *gconn, uint32
         return true;
     }
 
-    uint8_t *response = (uint8_t *)malloc(MAX_GC_PACKET_CHUNK_SIZE);
+    uint8_t *response = (uint8_t *)mem_balloc(chat->mem, MAX_GC_PACKET_CHUNK_SIZE);
 
     if (response == nullptr) {
         return false;
@@ -1859,7 +1861,7 @@ static bool sync_response_send_peers(GC_Chat *chat, GC_Connection *gconn, uint32
         ++num_announces;
     }
 
-    free(response);
+    mem_delete(chat->mem, response);
 
     if (num_announces == 0) {
         // we send an empty sync response even if we didn't send any peers as an acknowledgement
@@ -2293,7 +2295,7 @@ static bool send_gc_broadcast_message(const GC_Chat *chat, const uint8_t *data,
         return false;
     }
 
-    uint8_t *packet = (uint8_t *)malloc(length + GC_BROADCAST_ENC_HEADER_SIZE);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length + GC_BROADCAST_ENC_HEADER_SIZE);
 
     if (packet == nullptr) {
         return false;
@@ -2303,7 +2305,7 @@ static bool send_gc_broadcast_message(const GC_Chat *chat, const uint8_t *data,
 
     send_gc_lossless_packet_all_peers(chat, packet, packet_len, GP_BROADCAST);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -2538,7 +2540,7 @@ void gc_get_chat_id(const GC_Chat *chat, uint8_t *dest)
 non_null()
 static bool send_self_to_peer(const GC_Chat *chat, GC_Connection *gconn)
 {
-    GC_Peer *self = (GC_Peer *)calloc(1, sizeof(GC_Peer));
+    GC_Peer *self = (GC_Peer *)mem_alloc(chat->mem, sizeof(GC_Peer));
 
     if (self == nullptr) {
         return false;
@@ -2547,10 +2549,10 @@ static bool send_self_to_peer(const GC_Chat *chat, GC_Connection *gconn)
     copy_self(chat, self);
 
     const uint16_t data_size = PACKED_GC_PEER_SIZE + sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE;
-    uint8_t *data = (uint8_t *)malloc(data_size);
+    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, data_size);
 
     if (data == nullptr) {
-        free(self);
+        mem_delete(chat->mem, self);
         return false;
     }
 
@@ -2567,17 +2569,17 @@ static bool send_self_to_peer(const GC_Chat *chat, GC_Connection *gconn)
     const int packed_len = pack_gc_peer(data + length, data_size - length, self);
     length += packed_len;
 
-    free(self);
+    mem_delete(chat->mem, self);
 
     if (packed_len <= 0) {
         LOGGER_DEBUG(chat->log, "pack_gc_peer failed in handle_gc_peer_info_request_request %d", packed_len);
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
     const bool ret = send_lossless_group_packet(chat, gconn, data, length, GP_PEER_INFO_RESPONSE);
 
-    free(data);
+    mem_delete(chat->mem, data);
 
     return ret;
 }
@@ -2643,7 +2645,7 @@ static bool send_gc_peer_exchange(const GC_Chat *chat, GC_Connection *gconn)
  * Return -5 if supplied group password is invalid.
  * Return -6 if we fail to add the peer to the peer list.
  * Return -7 if peer's role cannot be validated.
- * Return -8 if malloc fails.
+ * Return -8 if memory allocation fails.
  */
 non_null(1, 2, 4) nullable(6)
 static int handle_gc_peer_info_response(const GC_Session *c, GC_Chat *chat, uint32_t peer_number,
@@ -2688,7 +2690,7 @@ static int handle_gc_peer_info_response(const GC_Session *c, GC_Chat *chat, uint
         return -1;
     }
 
-    GC_Peer *peer_info = (GC_Peer *)calloc(1, sizeof(GC_Peer));
+    GC_Peer *peer_info = (GC_Peer *)mem_alloc(chat->mem, sizeof(GC_Peer));
 
     if (peer_info == nullptr) {
         return -8;
@@ -2696,17 +2698,17 @@ static int handle_gc_peer_info_response(const GC_Session *c, GC_Chat *chat, uint
 
     if (unpack_gc_peer(peer_info, data + unpacked_len, length - unpacked_len) == -1) {
         LOGGER_ERROR(chat->log, "unpack_gc_peer() failed");
-        free(peer_info);
+        mem_delete(chat->mem, peer_info);
         return -6;
     }
 
     if (peer_update(chat, peer_info, peer_number) == -1) {
         LOGGER_WARNING(chat->log, "peer_update() failed");
-        free(peer_info);
+        mem_delete(chat->mem, peer_info);
         return -6;
     }
 
-    free(peer_info);
+    mem_delete(chat->mem, peer_info);
 
     const bool was_confirmed = gconn->confirmed;
     gconn->confirmed = true;
@@ -3090,7 +3092,7 @@ static int handle_gc_sanctions_list(const GC_Session *c, GC_Chat *chat, const ui
 
     Mod_Sanction_Creds creds;
 
-    Mod_Sanction *sanctions = (Mod_Sanction *)calloc(num_sanctions, sizeof(Mod_Sanction));
+    Mod_Sanction *sanctions = (Mod_Sanction *)mem_valloc(chat->mem, num_sanctions, sizeof(Mod_Sanction));
 
     if (sanctions == nullptr) {
         return -1;
@@ -3101,25 +3103,25 @@ static int handle_gc_sanctions_list(const GC_Session *c, GC_Chat *chat, const ui
 
     if (unpacked_num != num_sanctions) {
         LOGGER_WARNING(chat->log, "Failed to unpack sanctions list: %d", unpacked_num);
-        free(sanctions);
+        mem_delete(chat->mem, sanctions);
         return handle_gc_sanctions_list_error(chat);
     }
 
     if (!sanctions_list_check_integrity(&chat->moderation, &creds, sanctions, num_sanctions)) {
         LOGGER_WARNING(chat->log, "Sanctions list failed integrity check");
-        free(sanctions);
+        mem_delete(chat->mem, sanctions);
         return handle_gc_sanctions_list_error(chat);
     }
 
     if (creds.version < chat->moderation.sanctions_creds.version) {
-        free(sanctions);
+        mem_delete(chat->mem, sanctions);
         return 0;
     }
 
     // this may occur if two mods change the sanctions list at the exact same time
     if (creds.version == chat->moderation.sanctions_creds.version
             && creds.checksum <= chat->moderation.sanctions_creds.checksum) {
-        free(sanctions);
+        mem_delete(chat->mem, sanctions);
         return 0;
     }
 
@@ -3156,7 +3158,7 @@ static int make_gc_mod_list_packet(const GC_Chat *chat, uint8_t *data, uint32_t
     const uint16_t length = sizeof(uint16_t) + mod_list_size;
 
     if (mod_list_size > 0) {
-        uint8_t *packed_mod_list = (uint8_t *)malloc(mod_list_size);
+        uint8_t *packed_mod_list = (uint8_t *)mem_balloc(chat->mem, mod_list_size);
 
         if (packed_mod_list == nullptr) {
             return -1;
@@ -3165,7 +3167,7 @@ static int make_gc_mod_list_packet(const GC_Chat *chat, uint8_t *data, uint32_t
         mod_list_pack(&chat->moderation, packed_mod_list);
         memcpy(data + sizeof(uint16_t), packed_mod_list, mod_list_size);
 
-        free(packed_mod_list);
+        mem_delete(chat->mem, packed_mod_list);
     }
 
     return length;
@@ -3180,7 +3182,7 @@ static bool send_peer_mod_list(const GC_Chat *chat, GC_Connection *gconn)
 {
     const uint16_t mod_list_size = chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE;
     const uint16_t length = sizeof(uint16_t) + mod_list_size;
-    uint8_t *packet = (uint8_t *)malloc(length);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length);
 
     if (packet == nullptr) {
         return false;
@@ -3189,13 +3191,13 @@ static bool send_peer_mod_list(const GC_Chat *chat, GC_Connection *gconn)
     const int packet_len = make_gc_mod_list_packet(chat, packet, length, mod_list_size);
 
     if (packet_len != length) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     const bool ret = send_lossless_group_packet(chat, gconn, packet, length, GP_MOD_LIST);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return ret;
 }
@@ -3239,7 +3241,7 @@ static bool send_peer_sanctions_list(const GC_Chat *chat, GC_Connection *gconn)
     const uint16_t packet_size = MOD_SANCTION_PACKED_SIZE * chat->moderation.num_sanctions +
                                  sizeof(uint16_t) + MOD_SANCTIONS_CREDS_SIZE;
 
-    uint8_t *packet = (uint8_t *)malloc(packet_size);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
 
     if (packet == nullptr) {
         return false;
@@ -3248,13 +3250,13 @@ static bool send_peer_sanctions_list(const GC_Chat *chat, GC_Connection *gconn)
     const int packet_len = make_gc_sanctions_list_packet(chat, packet, packet_size);
 
     if (packet_len == -1) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     const bool ret = send_lossless_group_packet(chat, gconn, packet, (uint16_t)packet_len, GP_SANCTIONS_LIST);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return ret;
 }
@@ -3269,7 +3271,7 @@ static bool broadcast_gc_sanctions_list(const GC_Chat *chat)
     const uint16_t packet_size = MOD_SANCTION_PACKED_SIZE * chat->moderation.num_sanctions +
                                  sizeof(uint16_t) + MOD_SANCTIONS_CREDS_SIZE;
 
-    uint8_t *packet = (uint8_t *)malloc(packet_size);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
 
     if (packet == nullptr) {
         return false;
@@ -3278,13 +3280,13 @@ static bool broadcast_gc_sanctions_list(const GC_Chat *chat)
     const int packet_len = make_gc_sanctions_list_packet(chat, packet, packet_size);
 
     if (packet_len == -1) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SANCTIONS_LIST);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -3315,7 +3317,7 @@ static bool broadcast_gc_mod_list(const GC_Chat *chat)
 {
     const uint16_t mod_list_size = chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE;
     const uint16_t length = sizeof(uint16_t) + mod_list_size;
-    uint8_t *packet = (uint8_t *)malloc(length);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length);
 
     if (packet == nullptr) {
         return false;
@@ -3324,13 +3326,13 @@ static bool broadcast_gc_mod_list(const GC_Chat *chat)
     const int packet_len = make_gc_mod_list_packet(chat, packet, length, mod_list_size);
 
     if (packet_len != length) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     send_gc_lossless_packet_all_peers(chat, packet, length, GP_MOD_LIST);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -3551,7 +3553,7 @@ non_null()
 static bool send_peer_topic(const GC_Chat *chat, GC_Connection *gconn)
 {
     const uint16_t packet_buf_size = SIGNATURE_SIZE + chat->topic_info.length + GC_MIN_PACKED_TOPIC_INFO_SIZE;
-    uint8_t *packet = (uint8_t *)malloc(packet_buf_size);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_buf_size);
 
     if (packet == nullptr) {
         return false;
@@ -3560,16 +3562,16 @@ static bool send_peer_topic(const GC_Chat *chat, GC_Connection *gconn)
     const int packet_len = make_gc_topic_packet(chat, packet, packet_buf_size);
 
     if (packet_len != packet_buf_size) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     if (!send_lossless_group_packet(chat, gconn, packet, packet_buf_size, GP_TOPIC)) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -3619,7 +3621,7 @@ non_null()
 static bool broadcast_gc_topic(const GC_Chat *chat)
 {
     const uint16_t packet_buf_size = SIGNATURE_SIZE + chat->topic_info.length + GC_MIN_PACKED_TOPIC_INFO_SIZE;
-    uint8_t *packet = (uint8_t *)malloc(packet_buf_size);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_buf_size);
 
     if (packet == nullptr) {
         return false;
@@ -3628,13 +3630,13 @@ static bool broadcast_gc_topic(const GC_Chat *chat)
     const int packet_len = make_gc_topic_packet(chat, packet, packet_buf_size);
 
     if (packet_len != packet_buf_size) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     send_gc_lossless_packet_all_peers(chat, packet, packet_buf_size, GP_TOPIC);
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -3684,7 +3686,7 @@ int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length)
     chat->topic_info.checksum = get_gc_topic_checksum(&chat->topic_info);
 
     const uint16_t packet_buf_size = length + GC_MIN_PACKED_TOPIC_INFO_SIZE;
-    uint8_t *packed_topic = (uint8_t *)malloc(packet_buf_size);
+    uint8_t *packed_topic = (uint8_t *)mem_balloc(chat->mem, packet_buf_size);
 
     if (packed_topic == nullptr) {
         return -3;
@@ -3711,13 +3713,13 @@ int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length)
     chat->topic_prev_checksum = old_topic_info.checksum;
     chat->topic_time_set = mono_time_get(chat->mono_time);
 
-    free(packed_topic);
+    mem_delete(chat->mem, packed_topic);
     return 0;
 
 ON_ERROR:
     chat->topic_info = old_topic_info;
     memcpy(chat->topic_sig, old_topic_sig, SIGNATURE_SIZE);
-    free(packed_topic);
+    mem_delete(chat->mem, packed_topic);
     return err;
 }
 
@@ -3964,7 +3966,7 @@ int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t pas
     const uint16_t oldlen = chat->shared_state.password_length;
 
     if (oldlen > 0) {
-        oldpasswd = (uint8_t *)malloc(oldlen);
+        oldpasswd = (uint8_t *)mem_balloc(chat->mem, oldlen);
 
         if (oldpasswd == nullptr) {
             return -4;
@@ -3974,17 +3976,17 @@ int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t pas
     }
 
     if (!set_gc_password_local(chat, password, password_length)) {
-        free(oldpasswd);
+        mem_delete(chat->mem, oldpasswd);
         return -2;
     }
 
     if (!sign_gc_shared_state(chat)) {
         set_gc_password_local(chat, oldpasswd, oldlen);
-        free(oldpasswd);
+        mem_delete(chat->mem, oldpasswd);
         return -2;
     }
 
-    free(oldpasswd);
+    mem_delete(chat->mem, oldpasswd);
 
     if (!broadcast_gc_shared_state(chat)) {
         return -3;
@@ -4109,7 +4111,7 @@ non_null()
 static bool send_gc_set_mod(const GC_Chat *chat, const GC_Connection *gconn, bool add_mod)
 {
     const uint16_t length = 1 + SIG_PUBLIC_KEY_SIZE;
-    uint8_t *data = (uint8_t *)malloc(length);
+    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, length);
 
     if (data == nullptr) {
         return false;
@@ -4120,11 +4122,11 @@ static bool send_gc_set_mod(const GC_Chat *chat, const GC_Connection *gconn, boo
     memcpy(data + 1, get_sig_pk(gconn->addr.public_key), SIG_PUBLIC_KEY_SIZE);
 
     if (!send_gc_broadcast_message(chat, data, length, GM_SET_MOD)) {
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
-    free(data);
+    mem_delete(chat->mem, data);
 
     return true;
 }
@@ -4313,7 +4315,7 @@ static bool send_gc_set_observer(const GC_Chat *chat, const uint8_t *target_ext_
                                  uint16_t length, bool add_obs)
 {
     const uint16_t packet_len = 1 + EXT_PUBLIC_KEY_SIZE + length;
-    uint8_t *packet = (uint8_t *)malloc(packet_len);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_len);
 
     if (packet == nullptr) {
         return false;
@@ -4325,11 +4327,11 @@ static bool send_gc_set_observer(const GC_Chat *chat, const uint8_t *target_ext_
     memcpy(packet + 1 + EXT_PUBLIC_KEY_SIZE, sanction_data, length);
 
     if (!send_gc_broadcast_message(chat, packet, packet_len, GM_SET_OBSERVER)) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -4746,7 +4748,7 @@ int gc_send_message(const GC_Chat *chat, const uint8_t *message, uint16_t length
     const uint8_t packet_type = type == GC_MESSAGE_TYPE_NORMAL ? GM_PLAIN_MESSAGE : GM_ACTION_MESSAGE;
 
     const uint16_t length_raw = length + GC_MESSAGE_PSEUDO_ID_SIZE;
-    uint8_t *message_raw = (uint8_t *)malloc(length_raw);
+    uint8_t *message_raw = (uint8_t *)mem_balloc(chat->mem, length_raw);
 
     if (message_raw == nullptr) {
         return -5;
@@ -4758,7 +4760,7 @@ int gc_send_message(const GC_Chat *chat, const uint8_t *message, uint16_t length
     memcpy(message_raw + GC_MESSAGE_PSEUDO_ID_SIZE, message, length);
 
     if (!send_gc_broadcast_message(chat, message_raw, length_raw, packet_type)) {
-        free(message_raw);
+        mem_delete(chat->mem, message_raw);
         return -5;
     }
 
@@ -4766,7 +4768,7 @@ int gc_send_message(const GC_Chat *chat, const uint8_t *message, uint16_t length
         *message_id = pseudo_msg_id;
     }
 
-    free(message_raw);
+    mem_delete(chat->mem, message_raw);
     return 0;
 }
 
@@ -4832,7 +4834,7 @@ int gc_send_private_message(const GC_Chat *chat, uint32_t peer_id, uint8_t type,
         return -5;
     }
 
-    uint8_t *message_with_type = (uint8_t *)malloc(length + 1);
+    uint8_t *message_with_type = (uint8_t *)mem_balloc(chat->mem, length + 1);
 
     if (message_with_type == nullptr) {
         return -6;
@@ -4841,23 +4843,23 @@ int gc_send_private_message(const GC_Chat *chat, uint32_t peer_id, uint8_t type,
     message_with_type[0] = type;
     memcpy(message_with_type + 1, message, length);
 
-    uint8_t *packet = (uint8_t *)malloc(length + 1 + GC_BROADCAST_ENC_HEADER_SIZE);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, length + 1 + GC_BROADCAST_ENC_HEADER_SIZE);
 
     if (packet == nullptr) {
-        free(message_with_type);
+        mem_delete(chat->mem, message_with_type);
         return -6;
     }
 
     const uint16_t packet_len = make_gc_broadcast_header(message_with_type, length + 1, packet, GM_PRIVATE_MESSAGE);
 
-    free(message_with_type);
+    mem_delete(chat->mem, message_with_type);
 
     if (!send_lossless_group_packet(chat, gconn, packet, packet_len, GP_BROADCAST)) {
-        free(packet);
+        mem_delete(chat->mem, packet);
         return -6;
     }
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return 0;
 }
@@ -5192,7 +5194,7 @@ static int handle_gc_message_ack(const GC_Chat *chat, GC_Connection *gconn, cons
     const Group_Message_Ack_Type type = (Group_Message_Ack_Type) data[0];
 
     if (type == GR_ACK_RECV) {
-        if (!gcc_handle_ack(chat->log, gconn, message_id)) {
+        if (!gcc_handle_ack(chat->log, gconn, message_id, chat->mem)) {
             return -2;
         }
 
@@ -5371,7 +5373,7 @@ static int handle_gc_broadcast(const GC_Session *c, GC_Chat *chat, uint32_t peer
  */
 non_null()
 static int unwrap_group_handshake_packet(const Logger *log, const uint8_t *self_sk, const uint8_t *sender_pk,
-        uint8_t *plain, size_t plain_size, const uint8_t *packet, uint16_t length)
+        uint8_t *plain, size_t plain_size, const uint8_t *packet, uint16_t length, const Memory *mem)
 {
     if (length <= CRYPTO_NONCE_SIZE) {
         LOGGER_FATAL(log, "Invalid handshake packet length %u", length);
@@ -5379,7 +5381,7 @@ static int unwrap_group_handshake_packet(const Logger *log, const uint8_t *self_
     }
 
     const int plain_len = decrypt_data(sender_pk, self_sk, packet, packet + CRYPTO_NONCE_SIZE,
-                                       length - CRYPTO_NONCE_SIZE, plain);
+                                       length - CRYPTO_NONCE_SIZE, plain, mem);
 
     if (plain_len < 0 || (uint32_t)plain_len != plain_size) {
         LOGGER_DEBUG(log, "decrypt handshake request failed: len: %d, size: %zu", plain_len, plain_size);
@@ -5396,12 +5398,13 @@ static int unwrap_group_handshake_packet(const Logger *log, const uint8_t *self_
  *
  * Return length of encrypted packet on success.
  * Return -1 if packet size is invalid.
- * Return -2 on malloc failure.
+ * Return -2 on memory allocation failure.
  * Return -3 if encryption fails.
  */
 non_null()
 static int wrap_group_handshake_packet(
-    const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *self_sk,
+    const Logger *log, const Memory *mem, const Tox_Random *rng,
+    const uint8_t *self_pk, const uint8_t *self_sk,
     const uint8_t *target_pk, uint8_t *packet, uint32_t packet_size,
     const uint8_t *data, uint16_t length)
 {
@@ -5414,17 +5417,17 @@ static int wrap_group_handshake_packet(
     random_nonce(rng, nonce);
 
     const size_t encrypt_buf_size = length + CRYPTO_MAC_SIZE;
-    uint8_t *encrypt = (uint8_t *)malloc(encrypt_buf_size);
+    uint8_t *encrypt = (uint8_t *)mem_balloc(mem, encrypt_buf_size);
 
     if (encrypt == nullptr) {
         return -2;
     }
 
-    const int enc_len = encrypt_data(target_pk, self_sk, nonce, data, length, encrypt);
+    const int enc_len = encrypt_data(target_pk, self_sk, nonce, data, length, encrypt, mem);
 
     if (enc_len < 0 || (size_t)enc_len != encrypt_buf_size) {
         LOGGER_ERROR(log, "Failed to encrypt group handshake packet (len: %d)", enc_len);
-        free(encrypt);
+        mem_delete(mem, encrypt);
         return -3;
     }
 
@@ -5434,7 +5437,7 @@ static int wrap_group_handshake_packet(
     memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
     memcpy(packet + 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypt, enc_len);
 
-    free(encrypt);
+    mem_delete(mem, encrypt);
 
     return 1 + ENC_PUBLIC_KEY_SIZE + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + enc_len;
 }
@@ -5484,7 +5487,7 @@ static int make_gc_handshake_packet(const GC_Chat *chat, const GC_Connection *gc
     }
 
     const int enc_len = wrap_group_handshake_packet(
-                            chat->log, chat->rng, chat->self_public_key, chat->self_secret_key,
+                            chat->log, chat->mem, chat->rng, chat->self_public_key, chat->self_secret_key,
                             gconn->addr.public_key, packet, (uint16_t)packet_size, data, length);
 
     if (enc_len != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + nodes_size) {
@@ -5809,18 +5812,18 @@ static int handle_gc_handshake_packet(GC_Chat *chat, const uint8_t *sender_pk, c
     }
 
     const size_t data_buf_size = length - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE;
-    uint8_t *data = (uint8_t *)malloc(data_buf_size);
+    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, data_buf_size);
 
     if (data == nullptr) {
         return -1;
     }
 
     const int plain_len = unwrap_group_handshake_packet(chat->log, chat->self_secret_key, sender_pk, data,
-                          data_buf_size, packet, length);
+                          data_buf_size, packet, length, chat->mem);
 
     if (plain_len < GC_MIN_HS_PACKET_PAYLOAD_SIZE)  {
         LOGGER_DEBUG(chat->log, "Failed to unwrap handshake packet (probably a stale request using an old key)");
-        free(data);
+        mem_delete(chat->mem, data);
         return -1;
     }
 
@@ -5836,11 +5839,11 @@ static int handle_gc_handshake_packet(GC_Chat *chat, const uint8_t *sender_pk, c
     } else if (handshake_type == GH_RESPONSE) {
         peer_number = handle_gc_handshake_response(chat, sender_pk, real_data, real_len);
     } else {
-        free(data);
+        mem_delete(chat->mem, data);
         return -1;
     }
 
-    free(data);
+    mem_delete(chat->mem, data);
 
     GC_Connection *gconn = get_gc_connection(chat, peer_number);
 
@@ -6035,7 +6038,7 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const
         return true;
     }
 
-    uint8_t *data = (uint8_t *)malloc(length);
+    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, length);
 
     if (data == nullptr) {
         LOGGER_DEBUG(chat->log, "Failed to allocate memory for packet data buffer");
@@ -6045,19 +6048,19 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const
     uint8_t packet_type;
     uint64_t message_id;
 
-    const int len = group_packet_unwrap(chat->log, gconn, data, &message_id, &packet_type, packet, length);
+    const int len = group_packet_unwrap(chat->log, chat->mem, gconn, data, &message_id, &packet_type, packet, length);
 
     if (len < 0) {
         Ip_Ntoa ip_str;
         LOGGER_DEBUG(chat->log, "Failed to unwrap lossless packet from %s:%d: %d",
                      net_ip_ntoa(&gconn->addr.ip_port.ip, &ip_str), net_ntohs(gconn->addr.ip_port.port), len);
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
     if (!gconn->handshaked && (packet_type != GP_HS_RESPONSE_ACK && packet_type != GP_INVITE_REQUEST)) {
         LOGGER_DEBUG(chat->log, "Got lossless packet type 0x%02x from unconfirmed peer", packet_type);
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
@@ -6067,28 +6070,28 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const
     if (message_id == 3 && is_invite_packet && gconn->received_message_id <= 1) {
         // we missed initial handshake request. Drop this packet and wait for another handshake request.
         LOGGER_DEBUG(chat->log, "Missed handshake packet, type: 0x%02x", packet_type);
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
     const int lossless_ret = gcc_handle_received_message(chat->log, chat->mono_time, gconn, data, (uint16_t) len,
-                             packet_type, message_id, direct_conn);
+                             packet_type, message_id, direct_conn, chat->mem);
 
     if (packet_type == GP_INVITE_REQUEST && !gconn->handshaked) {  // Both peers sent request at same time
-        free(data);
+        mem_delete(chat->mem, data);
         return true;
     }
 
     if (lossless_ret < 0) {
         LOGGER_DEBUG(chat->log, "failed to handle packet %llu (type: 0x%02x, id: %llu)",
                      (unsigned long long)message_id, packet_type, (unsigned long long)message_id);
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
     /* Duplicate packet */
     if (lossless_ret == 0) {
-        free(data);
+        mem_delete(chat->mem, data);
         return gc_send_message_ack(chat, gconn, message_id, GR_ACK_RECV);
     }
 
@@ -6096,7 +6099,7 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const
     if (lossless_ret == 1) {
         LOGGER_TRACE(chat->log, "received out of order packet from peer %u. expected %llu, got %llu", peer_number,
                      (unsigned long long)gconn->received_message_id + 1, (unsigned long long)message_id);
-        free(data);
+        mem_delete(chat->mem, data);
         return gc_send_message_ack(chat, gconn, gconn->received_message_id + 1, GR_ACK_REQ);
     }
 
@@ -6104,13 +6107,13 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const
     if (lossless_ret == 3) {
         const bool frag_ret = handle_gc_packet_fragment(c, chat, peer_number, gconn, data, (uint16_t)len, packet_type,
                               message_id, userdata);
-        free(data);
+        mem_delete(chat->mem, data);
         return frag_ret;
     }
 
     const bool ret = handle_gc_lossless_helper(c, chat, peer_number, data, (uint16_t)len, packet_type, userdata);
 
-    free(data);
+    mem_delete(chat->mem, data);
 
     if (!ret) {
         return false;
@@ -6156,7 +6159,7 @@ static bool handle_gc_lossy_packet(const GC_Session *c, GC_Chat *chat, const uin
         return false;
     }
 
-    uint8_t *data = (uint8_t *)malloc(length);
+    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, length);
 
     if (data == nullptr) {
         LOGGER_ERROR(chat->log, "Failed to allocate memory for packet buffer");
@@ -6165,13 +6168,13 @@ static bool handle_gc_lossy_packet(const GC_Session *c, GC_Chat *chat, const uin
 
     uint8_t packet_type;
 
-    const int len = group_packet_unwrap(chat->log, gconn, data, nullptr, &packet_type, packet, length);
+    const int len = group_packet_unwrap(chat->log, chat->mem, gconn, data, nullptr, &packet_type, packet, length);
 
     if (len <= 0) {
         Ip_Ntoa ip_str;
         LOGGER_DEBUG(chat->log, "Failed to unwrap lossy packet from %s:%d: %d",
                      net_ip_ntoa(&gconn->addr.ip_port.ip, &ip_str), net_ntohs(gconn->addr.ip_port.port), len);
-        free(data);
+        mem_delete(chat->mem, data);
         return false;
     }
 
@@ -6206,12 +6209,12 @@ static bool handle_gc_lossy_packet(const GC_Session *c, GC_Chat *chat, const uin
 
         default: {
             LOGGER_WARNING(chat->log, "Warning: handling invalid lossy group packet type 0x%02x", packet_type);
-            free(data);
+            mem_delete(chat->mem, data);
             return false;
         }
     }
 
-    free(data);
+    mem_delete(chat->mem, data);
 
     if (ret < 0) {
         LOGGER_DEBUG(chat->log, "Lossy packet handle error %d: type: 0x%02x, peernumber %d", ret, packet_type,
@@ -6585,7 +6588,7 @@ static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number
     assert(nick_length <= MAX_GC_NICK_SIZE);
     memcpy(nick, peer->nick, nick_length);
 
-    gcc_peer_cleanup(&peer->gconn);
+    gcc_peer_cleanup(&peer->gconn, chat->mem);
 
     --chat->numpeers;
 
@@ -6597,7 +6600,7 @@ static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number
         0
     };
 
-    GC_Peer *tmp_group = (GC_Peer *)realloc(chat->group, chat->numpeers * sizeof(GC_Peer));
+    GC_Peer *tmp_group = (GC_Peer *)mem_vrealloc(chat->mem, chat->group, chat->numpeers, sizeof(GC_Peer));
 
     if (tmp_group == nullptr) {
         return false;
@@ -6673,8 +6676,8 @@ int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key)
         }
     }
 
-    GC_Message_Array_Entry *send = (GC_Message_Array_Entry *)calloc(GCC_BUFFER_SIZE, sizeof(GC_Message_Array_Entry));
-    GC_Message_Array_Entry *recv = (GC_Message_Array_Entry *)calloc(GCC_BUFFER_SIZE, sizeof(GC_Message_Array_Entry));
+    GC_Message_Array_Entry *send = (GC_Message_Array_Entry *)mem_valloc(chat->mem, GCC_BUFFER_SIZE, sizeof(GC_Message_Array_Entry));
+    GC_Message_Array_Entry *recv = (GC_Message_Array_Entry *)mem_valloc(chat->mem, GCC_BUFFER_SIZE, sizeof(GC_Message_Array_Entry));
 
     if (send == nullptr || recv == nullptr) {
         LOGGER_ERROR(chat->log, "Failed to allocate memory for gconn buffers");
@@ -6683,22 +6686,22 @@ int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key)
             kill_tcp_connection_to(chat->tcp_conn, tcp_connection_num);
         }
 
-        free(send);
-        free(recv);
+        mem_delete(chat->mem, send);
+        mem_delete(chat->mem, recv);
         return -1;
     }
 
-    GC_Peer *tmp_group = (GC_Peer *)realloc(chat->group, (chat->numpeers + 1) * sizeof(GC_Peer));
+    GC_Peer *tmp_group = (GC_Peer *)mem_vrealloc(chat->mem, chat->group, chat->numpeers + 1, sizeof(GC_Peer));
 
     if (tmp_group == nullptr) {
-        LOGGER_ERROR(chat->log, "Failed to allocate memory for group realloc");
+        LOGGER_ERROR(chat->log, "Failed to allocate memory for group mem_vrealloc");
 
         if (tcp_connection_num != -1) {
             kill_tcp_connection_to(chat->tcp_conn, tcp_connection_num);
         }
 
-        free(send);
-        free(recv);
+        mem_delete(chat->mem, send);
+        mem_delete(chat->mem, recv);
         return -1;
     }
 
@@ -6914,7 +6917,7 @@ non_null()
 static bool ping_peer(const GC_Chat *chat, const GC_Connection *gconn)
 {
     const uint16_t buf_size = GC_PING_PACKET_MIN_DATA_SIZE + sizeof(IP_Port);
-    uint8_t *data = (uint8_t *)malloc(buf_size);
+    uint8_t *data = (uint8_t *)mem_balloc(chat->mem, buf_size);
 
     if (data == nullptr) {
         return false;
@@ -6960,11 +6963,11 @@ static bool ping_peer(const GC_Chat *chat, const GC_Connection *gconn)
     }
 
     if (!send_lossy_group_packet(chat, gconn, data, packed_len, GP_PING)) {
-        free(data);
+        mem_delete(chat->mem, data);
         return true;
     }
 
-    free(data);
+    mem_delete(chat->mem, data);
 
     return false;
 }
@@ -7176,12 +7179,12 @@ non_null()
 static bool realloc_groupchats(GC_Session *c, uint32_t n)
 {
     if (n == 0) {
-        free(c->chats);
+        mem_delete(c->messenger->mem, c->chats);
         c->chats = nullptr;
         return true;
     }
 
-    GC_Chat *temp = (GC_Chat *)realloc(c->chats, n * sizeof(GC_Chat));
+    GC_Chat *temp = (GC_Chat *)mem_vrealloc(c->messenger->mem, c->chats, n, sizeof(GC_Chat));
 
     if (temp == nullptr) {
         return false;
@@ -7230,7 +7233,7 @@ static void add_tcp_relays_to_chat(const GC_Session *c, GC_Chat *chat)
         return;
     }
 
-    Node_format *tcp_relays = (Node_format *)calloc(num_relays, sizeof(Node_format));
+    Node_format *tcp_relays = (Node_format *)mem_valloc(m->mem, num_relays, sizeof(Node_format));
 
     if (tcp_relays == nullptr) {
         return;
@@ -7242,7 +7245,7 @@ static void add_tcp_relays_to_chat(const GC_Session *c, GC_Chat *chat)
         add_tcp_relay_global(chat->tcp_conn, &tcp_relays[i].ip_port, tcp_relays[i].public_key);
     }
 
-    free(tcp_relays);
+    mem_delete(m->mem, tcp_relays);
 }
 
 non_null()
@@ -7483,6 +7486,10 @@ int gc_group_load(GC_Session *c, Bin_Unpack *bu)
     chat->last_ping_interval = tm;
     chat->friend_connection_id = -1;
 
+    // Initialise these first, because we may need to log/dealloc things on cleanup.
+    chat->moderation.log = m->log;
+    chat->moderation.mem = m->mem;
+
     if (!gc_load_unpack_group(chat, bu)) {
         LOGGER_ERROR(chat->log, "Failed to unpack group");
         return -1;
@@ -7706,7 +7713,7 @@ int gc_invite_friend(const GC_Session *c, GC_Chat *chat, int32_t friend_number,
 
     assert(group_name_length <= MAX_GC_GROUP_NAME_SIZE);
 
-    uint8_t *packet = (uint8_t *)malloc(2 + CHAT_ID_SIZE + ENC_PUBLIC_KEY_SIZE + group_name_length);
+    uint8_t *packet = (uint8_t *)mem_balloc(c->messenger->mem, 2 + CHAT_ID_SIZE + ENC_PUBLIC_KEY_SIZE + group_name_length);
 
     if (packet == nullptr) {
         return -1;
@@ -7728,11 +7735,11 @@ int gc_invite_friend(const GC_Session *c, GC_Chat *chat, int32_t friend_number,
     assert(length <= MAX_GC_PACKET_SIZE);
 
     if (!callback(c->messenger, friend_number, packet, length)) {
-        free(packet);
+        mem_delete(c->messenger->mem, packet);
         return -2;
     }
 
-    free(packet);
+    mem_delete(c->messenger->mem, packet);
 
     chat->saved_invites[chat->saved_invites_index] = friend_number;
     chat->saved_invites_index = (chat->saved_invites_index + 1) % MAX_GC_SAVED_INVITES;
@@ -7801,7 +7808,7 @@ static bool send_gc_invite_confirmed_packet(const Messenger *m, const GC_Chat *c
     }
 
     const uint16_t packet_length = 2 + length;
-    uint8_t *packet = (uint8_t *)malloc(packet_length);
+    uint8_t *packet = (uint8_t *)mem_balloc(m->mem, packet_length);
 
     if (packet == nullptr) {
         return false;
@@ -7813,11 +7820,11 @@ static bool send_gc_invite_confirmed_packet(const Messenger *m, const GC_Chat *c
     memcpy(packet + 2, data, length);
 
     if (!send_group_invite_packet(m, friend_number, packet, packet_length)) {
-        free(packet);
+        mem_delete(m->mem, packet);
         return false;
     }
 
-    free(packet);
+    mem_delete(m->mem, packet);
 
     return true;
 }
@@ -8079,7 +8086,7 @@ GC_Session *new_dht_groupchats(Messenger *m)
         return nullptr;
     }
 
-    GC_Session *c = (GC_Session *)calloc(1, sizeof(GC_Session));
+    GC_Session *c = (GC_Session *)mem_alloc(m->mem, sizeof(GC_Session));
 
     if (c == nullptr) {
         return nullptr;
@@ -8110,7 +8117,7 @@ static void group_cleanup(GC_Session *c, GC_Chat *chat)
     gcc_cleanup(chat);
 
     if (chat->group != nullptr) {
-        free(chat->group);
+        mem_delete(chat->mem, chat->group);
         chat->group = nullptr;
     }
 
@@ -8183,8 +8190,8 @@ void kill_dht_groupchats(GC_Session *c)
     networking_registerhandler(c->messenger->net, NET_PACKET_GC_HANDSHAKE, nullptr, nullptr);
     onion_group_announce_register(c->messenger->onion_c, nullptr, nullptr);
 
-    free(c->chats);
-    free(c);
+    mem_delete(c->messenger->mem, c->chats);
+    mem_delete(c->messenger->mem, c);
 }
 
 bool gc_group_is_valid(const GC_Chat *chat)
@@ -8266,7 +8273,7 @@ static bool group_exists(const GC_Session *c, const uint8_t *chat_id)
 }
 
 /** Creates a new 32-byte session encryption keypair and puts the results in `public_key` and `secret_key`. */
-static void create_gc_session_keypair(const Logger *log, const Random *rng, uint8_t *public_key, uint8_t *secret_key)
+static void create_gc_session_keypair(const Logger *log, const Tox_Random *rng, uint8_t *public_key, uint8_t *secret_key)
 {
     if (crypto_new_keypair(rng, public_key, secret_key) != 0) {
         LOGGER_FATAL(log, "Failed to create group session keypair");
diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h
index 821e629a641..37661378b7b 100644
--- a/toxcore/group_chats.h
+++ b/toxcore/group_chats.h
@@ -138,9 +138,10 @@ int get_peer_number_of_enc_pk(const GC_Chat *chat, const uint8_t *public_enc_key
  * Return -2 if malloc fails.
  * Return -3 if encryption fails.
  */
-non_null(1, 2, 3, 4, 5) nullable(7)
+non_null(1, 2, 3, 4, 5, 6) nullable(8)
 int group_packet_wrap(
-    const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
+    const Logger *log, const Memory *mem, const Random *rng,
+    const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
     uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id,
     uint8_t gp_packet_type, uint8_t net_packet_type);
 
diff --git a/toxcore/group_common.h b/toxcore/group_common.h
index 34d67dc8d62..65600d5f40a 100644
--- a/toxcore/group_common.h
+++ b/toxcore/group_common.h
@@ -248,7 +248,7 @@ typedef struct GC_Chat {
     Mono_Time       *mono_time;
     const Logger    *log;
     const Memory    *mem;
-    const Random    *rng;
+    const Tox_Random    *rng;
 
     uint32_t        connected_tcp_relays;
     Self_UDP_Status self_udp_status;
diff --git a/toxcore/group_connection.c b/toxcore/group_connection.c
index 86c353c00c0..6cee962249c 100644
--- a/toxcore/group_connection.c
+++ b/toxcore/group_connection.c
@@ -37,10 +37,10 @@ static bool array_entry_is_empty(const GC_Message_Array_Entry *array_entry)
 
 /** @brief Clears an array entry. */
 non_null()
-static void clear_array_entry(GC_Message_Array_Entry *const array_entry)
+static void clear_array_entry(GC_Message_Array_Entry *const array_entry, const Memory *mem)
 {
     if (array_entry->data != nullptr) {
-        free(array_entry->data);
+        mem_delete(mem, array_entry->data);
     }
 
     *array_entry = (GC_Message_Array_Entry) {
@@ -54,14 +54,14 @@ static void clear_array_entry(GC_Message_Array_Entry *const array_entry)
  * to `start_id`.
  */
 non_null()
-static void clear_send_queue_id_range(GC_Connection *gconn, uint64_t start_id, uint64_t end_id)
+static void clear_send_queue_id_range(GC_Connection *gconn, uint64_t start_id, uint64_t end_id, const Memory *mem)
 {
     const uint16_t start_idx = gcc_get_array_index(start_id);
     const uint16_t end_idx = gcc_get_array_index(end_id);
 
     for (uint16_t i = start_idx; i != end_idx; i = (i + 1) % GCC_BUFFER_SIZE) {
         GC_Message_Array_Entry *entry = &gconn->send_array[i];
-        clear_array_entry(entry);
+        clear_array_entry(entry, mem);
     }
 
     gconn->send_message_id = start_id;
@@ -87,16 +87,16 @@ void gcc_set_recv_message_id(GC_Connection *gconn, uint64_t id)
  *
  * Return true on success.
  */
-non_null(1, 2) nullable(3)
+non_null(1, 2, 7) nullable(3)
 static bool create_array_entry(const Mono_Time *mono_time, GC_Message_Array_Entry *array_entry, const uint8_t *data,
-                               uint16_t length, uint8_t packet_type, uint64_t message_id)
+                               uint16_t length, uint8_t packet_type, uint64_t message_id, const Memory *mem)
 {
     if (length > 0) {
         if (data == nullptr) {
             return false;
         }
 
-        array_entry->data = (uint8_t *)malloc(sizeof(uint8_t) * length);
+        array_entry->data = (uint8_t *)mem_balloc(mem, sizeof(uint8_t) * length);
 
         if (array_entry->data == nullptr) {
             return false;
@@ -120,9 +120,9 @@ static bool create_array_entry(const Mono_Time *mono_time, GC_Message_Array_Entr
  *
  * Returns true on success and increments gconn's send_message_id.
  */
-non_null(1, 2, 3) nullable(4)
+non_null(1, 2, 3, 7) nullable(4)
 static bool add_to_send_array(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn, const uint8_t *data,
-                              uint16_t length, uint8_t packet_type)
+                              uint16_t length, uint8_t packet_type, const Memory *mem)
 {
     /* check if send_array is full */
     if ((gconn->send_message_id % GCC_BUFFER_SIZE) == (uint16_t)(gconn->send_array_start - 1)) {
@@ -138,7 +138,7 @@ static bool add_to_send_array(const Logger *log, const Mono_Time *mono_time, GC_
         return false;
     }
 
-    if (!create_array_entry(mono_time, array_entry, data, length, packet_type, gconn->send_message_id)) {
+    if (!create_array_entry(mono_time, array_entry, data, length, packet_type, gconn->send_message_id, mem)) {
         LOGGER_WARNING(log, "Failed to create array entry");
         return false;
     }
@@ -153,7 +153,7 @@ int gcc_send_lossless_packet(const GC_Chat *chat, GC_Connection *gconn, const ui
 {
     const uint64_t message_id = gconn->send_message_id;
 
-    if (!add_to_send_array(chat->log, chat->mono_time, gconn, data, length, packet_type)) {
+    if (!add_to_send_array(chat->log, chat->mono_time, gconn, data, length, packet_type, chat->mem)) {
         LOGGER_WARNING(chat->log, "Failed to add payload to send array: (type: 0x%02x, length: %d)", packet_type, length);
         return -1;
     }
@@ -182,7 +182,7 @@ bool gcc_send_lossless_packet_fragments(const GC_Chat *chat, GC_Connection *gcon
     chunk[0] = packet_type;
     memcpy(chunk + 1, data, MAX_GC_PACKET_CHUNK_SIZE - 1);
 
-    if (!add_to_send_array(chat->log, chat->mono_time, gconn, chunk, MAX_GC_PACKET_CHUNK_SIZE, GP_FRAGMENT)) {
+    if (!add_to_send_array(chat->log, chat->mono_time, gconn, chunk, MAX_GC_PACKET_CHUNK_SIZE, GP_FRAGMENT, chat->mem)) {
         return false;
     }
 
@@ -195,15 +195,15 @@ bool gcc_send_lossless_packet_fragments(const GC_Chat *chat, GC_Connection *gcon
         memcpy(chunk, data + processed, chunk_len);
         processed += chunk_len;
 
-        if (!add_to_send_array(chat->log, chat->mono_time, gconn, chunk, chunk_len, GP_FRAGMENT)) {
-            clear_send_queue_id_range(gconn, start_id, gconn->send_message_id);
+        if (!add_to_send_array(chat->log, chat->mono_time, gconn, chunk, chunk_len, GP_FRAGMENT, chat->mem)) {
+            clear_send_queue_id_range(gconn, start_id, gconn->send_message_id, chat->mem);
             return false;
         }
     }
 
     // empty packet signals the end of the sequence
-    if (!add_to_send_array(chat->log, chat->mono_time, gconn, nullptr, 0, GP_FRAGMENT)) {
-        clear_send_queue_id_range(gconn, start_id, gconn->send_message_id);
+    if (!add_to_send_array(chat->log, chat->mono_time, gconn, nullptr, 0, GP_FRAGMENT, chat->mem)) {
+        clear_send_queue_id_range(gconn, start_id, gconn->send_message_id, chat->mem);
         return false;
     }
 
@@ -227,7 +227,7 @@ bool gcc_send_lossless_packet_fragments(const GC_Chat *chat, GC_Connection *gcon
     return true;
 }
 
-bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id)
+bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id, const Memory *mem)
 {
     uint16_t idx = gcc_get_array_index(message_id);
     GC_Message_Array_Entry *array_entry = &gconn->send_array[idx];
@@ -241,7 +241,7 @@ bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id
         return false;
     }
 
-    clear_array_entry(array_entry);
+    clear_array_entry(array_entry, mem);
 
     /* Put send_array_start in proper position */
     if (idx == gconn->send_array_start) {
@@ -268,7 +268,7 @@ void gcc_set_ip_port(GC_Connection *gconn, const IP_Port *ipp)
     }
 }
 
-bool gcc_copy_tcp_relay(const Random *rng, Node_format *tcp_node, const GC_Connection *gconn)
+bool gcc_copy_tcp_relay(const Tox_Random *rng, Node_format *tcp_node, const GC_Connection *gconn)
 {
     if (gconn == nullptr || tcp_node == nullptr) {
         return false;
@@ -289,7 +289,7 @@ bool gcc_copy_tcp_relay(const Random *rng, Node_format *tcp_node, const GC_Conne
     return true;
 }
 
-int gcc_save_tcp_relay(const Random *rng, GC_Connection *gconn, const Node_format *tcp_node)
+int gcc_save_tcp_relay(const Tox_Random *rng, GC_Connection *gconn, const Node_format *tcp_node)
 {
     if (gconn == nullptr || tcp_node == nullptr) {
         return -1;
@@ -322,10 +322,11 @@ int gcc_save_tcp_relay(const Random *rng, GC_Connection *gconn, const Node_forma
  *
  * Return true on success.
  */
-non_null(1, 2, 3) nullable(4)
+non_null(1, 2, 3, 8) nullable(4)
 static bool store_in_recv_array(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn,
                                 const uint8_t *data,
-                                uint16_t length, uint8_t packet_type, uint64_t message_id)
+                                uint16_t length, uint8_t packet_type, uint64_t message_id,
+                                const Memory *mem)
 {
     const uint16_t idx = gcc_get_array_index(message_id);
     GC_Message_Array_Entry *ary_entry = &gconn->recv_array[idx];
@@ -335,7 +336,7 @@ static bool store_in_recv_array(const Logger *log, const Mono_Time *mono_time, G
         return false;
     }
 
-    if (!create_array_entry(mono_time, ary_entry, data, length, packet_type, message_id)) {
+    if (!create_array_entry(mono_time, ary_entry, data, length, packet_type, message_id, mem)) {
         LOGGER_WARNING(log, "Failed to create array entry");
         return false;
     }
@@ -354,8 +355,8 @@ static bool store_in_recv_array(const Logger *log, const Mono_Time *mono_time, G
  * Return the length of the fully reassembled packet on success.
  * Return 0 on failure.
  */
-non_null(1, 3) nullable(2)
-static uint16_t reassemble_packet(const Logger *log, GC_Connection *gconn, uint8_t **payload, uint64_t message_id)
+non_null(1, 3, 5) nullable(2)
+static uint16_t reassemble_packet(const Logger *log, GC_Connection *gconn, uint8_t **payload, uint64_t message_id, const Memory *mem)
 {
     uint16_t end_idx = gcc_get_array_index(message_id - 1);
     uint16_t start_idx = end_idx;
@@ -392,7 +393,7 @@ static uint16_t reassemble_packet(const Logger *log, GC_Connection *gconn, uint8
     }
 
     assert(*payload == nullptr);
-    *payload = (uint8_t *)malloc(packet_length);
+    *payload = (uint8_t *)mem_balloc(mem, packet_length);
 
     if (*payload == nullptr) {
         LOGGER_ERROR(log, "Failed to allocate %u bytes for payload buffer", packet_length);
@@ -411,7 +412,7 @@ static uint16_t reassemble_packet(const Logger *log, GC_Connection *gconn, uint8
         memcpy(*payload + processed, entry->data, entry->data_length);
         processed += entry->data_length;
 
-        clear_array_entry(entry);
+        clear_array_entry(entry, mem);
     }
 
     return processed;
@@ -422,7 +423,7 @@ int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer
                                uint64_t message_id, void *userdata)
 {
     if (length > 0) {
-        if (!store_in_recv_array(chat->log, chat->mono_time, gconn, chunk, length, packet_type, message_id)) {
+        if (!store_in_recv_array(chat->log, chat->mono_time, gconn, chunk, length, packet_type, message_id, chat->mem)) {
             return -1;
         }
 
@@ -436,15 +437,15 @@ int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer
     memcpy(sender_pk, get_enc_key(gconn->addr.public_key), ENC_PUBLIC_KEY_SIZE);
 
     uint8_t *payload = nullptr;
-    const uint16_t processed_len = reassemble_packet(chat->log, gconn, &payload, message_id);
+    const uint16_t processed_len = reassemble_packet(chat->log, gconn, &payload, message_id, chat->mem);
 
     if (processed_len == 0) {
-        free(payload);
+        mem_delete(chat->mem, payload);
         return -1;
     }
 
     if (!handle_gc_lossless_helper(c, chat, peer_number, payload + 1, processed_len - 1, payload[0], userdata)) {
-        free(payload);
+        mem_delete(chat->mem, payload);
         return -1;
     }
 
@@ -459,14 +460,14 @@ int gcc_handle_packet_fragment(const GC_Session *c, GC_Chat *chat, uint32_t peer
     gcc_set_recv_message_id(gconn, gconn->received_message_id + 1);
     gconn->last_chunk_id = 0;
 
-    free(payload);
+    mem_delete(chat->mem, payload);
 
     return 0;
 }
 
 int gcc_handle_received_message(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn,
                                 const uint8_t *data, uint16_t length, uint8_t packet_type, uint64_t message_id,
-                                bool direct_conn)
+                                bool direct_conn, const Memory *mem)
 {
     if (direct_conn) {
         gconn->last_received_direct_time = mono_time_get(mono_time);
@@ -483,7 +484,7 @@ int gcc_handle_received_message(const Logger *log, const Mono_Time *mono_time, G
 
     /* we're missing an older message from this peer so we store it in recv_array */
     if (message_id > gconn->received_message_id + 1) {
-        if (!store_in_recv_array(log, mono_time, gconn, data, length, packet_type, message_id)) {
+        if (!store_in_recv_array(log, mono_time, gconn, data, length, packet_type, message_id, mem)) {
             return -1;
         }
 
@@ -515,7 +516,7 @@ static bool process_recv_array_entry(const GC_Session *c, GC_Chat *chat, GC_Conn
     peer_number = get_peer_number_of_enc_pk(chat, sender_pk, false);
     gconn = get_gc_connection(chat, peer_number);
 
-    clear_array_entry(array_entry);
+    clear_array_entry(array_entry, chat->mem);
 
     if (gconn == nullptr) {
         return true;
@@ -614,7 +615,7 @@ bool gcc_encrypt_and_send_lossless_packet(const GC_Chat *chat, const GC_Connecti
         uint16_t length, uint64_t message_id, uint8_t packet_type)
 {
     const uint16_t packet_size = gc_get_wrapped_packet_size(length, NET_PACKET_GC_LOSSLESS);
-    uint8_t *packet = (uint8_t *)malloc(packet_size);
+    uint8_t *packet = (uint8_t *)mem_balloc(chat->mem, packet_size);
 
     if (packet == nullptr) {
         LOGGER_ERROR(chat->log, "Failed to allocate memory for packet buffer");
@@ -622,22 +623,22 @@ bool gcc_encrypt_and_send_lossless_packet(const GC_Chat *chat, const GC_Connecti
     }
 
     const int enc_len = group_packet_wrap(
-                            chat->log, chat->rng, chat->self_public_key, gconn->session_shared_key, packet,
-                            packet_size, data, length, message_id, packet_type, NET_PACKET_GC_LOSSLESS);
+                            chat->log, chat->mem, chat->rng, chat->self_public_key, gconn->session_shared_key,
+                            packet, packet_size, data, length, message_id, packet_type, NET_PACKET_GC_LOSSLESS);
 
     if (enc_len < 0) {
         LOGGER_ERROR(chat->log, "Failed to wrap packet (type: 0x%02x, error: %d)", packet_type, enc_len);
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
     if (!gcc_send_packet(chat, gconn, packet, (uint16_t)enc_len)) {
         LOGGER_DEBUG(chat->log, "Failed to send packet (type: 0x%02x, enc_len: %d)", packet_type, enc_len);
-        free(packet);
+        mem_delete(chat->mem, packet);
         return false;
     }
 
-    free(packet);
+    mem_delete(chat->mem, packet);
 
     return true;
 }
@@ -679,15 +680,15 @@ void gcc_mark_for_deletion(GC_Connection *gconn, TCP_Connections *tcp_conn, Grou
     }
 }
 
-void gcc_peer_cleanup(GC_Connection *gconn)
+void gcc_peer_cleanup(GC_Connection *gconn, const Memory *mem)
 {
     for (size_t i = 0; i < GCC_BUFFER_SIZE; ++i) {
-        free(gconn->send_array[i].data);
-        free(gconn->recv_array[i].data);
+        mem_delete(mem, gconn->send_array[i].data);
+        mem_delete(mem, gconn->recv_array[i].data);
     }
 
-    free(gconn->recv_array);
-    free(gconn->send_array);
+    mem_delete(mem, gconn->recv_array);
+    mem_delete(mem, gconn->send_array);
 
     crypto_memunlock(gconn->session_secret_key, sizeof(gconn->session_secret_key));
     crypto_memunlock(gconn->session_shared_key, sizeof(gconn->session_shared_key));
@@ -700,7 +701,7 @@ void gcc_cleanup(const GC_Chat *chat)
         GC_Connection *gconn = get_gc_connection(chat, i);
         assert(gconn != nullptr);
 
-        gcc_peer_cleanup(gconn);
+        gcc_peer_cleanup(gconn, chat->mem);
     }
 }
 
diff --git a/toxcore/group_connection.h b/toxcore/group_connection.h
index 2202c7ab36e..b6a7d5e99d0 100644
--- a/toxcore/group_connection.h
+++ b/toxcore/group_connection.h
@@ -28,10 +28,10 @@ void gcc_mark_for_deletion(GC_Connection *gconn, TCP_Connections *tcp_conn, Grou
  * Return 0 if message is a duplicate.
  * Return -1 on failure
  */
-non_null(1, 2, 3) nullable(4)
+non_null(1, 2, 3, 9) nullable(4)
 int gcc_handle_received_message(const Logger *log, const Mono_Time *mono_time, GC_Connection *gconn,
                                 const uint8_t *data, uint16_t length, uint8_t packet_type, uint64_t message_id,
-                                bool direct_conn);
+                                bool direct_conn, const Memory *mem);
 
 /** @brief Handles a packet fragment.
  *
@@ -56,7 +56,7 @@ uint16_t gcc_get_array_index(uint64_t message_id);
  * Return true on success.
  */
 non_null()
-bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id);
+bool gcc_handle_ack(const Logger *log, GC_Connection *gconn, uint64_t message_id, const Memory *mem);
 
 /** @brief Sets the send_message_id and send_array_start for `gconn` to `id`.
  *
@@ -88,7 +88,7 @@ void gcc_set_ip_port(GC_Connection *gconn, const IP_Port *ipp);
  * Return true on success.
  */
 non_null()
-bool gcc_copy_tcp_relay(const Random *rng, Node_format *tcp_node, const GC_Connection *gconn);
+bool gcc_copy_tcp_relay(const Tox_Random *rng, Node_format *tcp_node, const GC_Connection *gconn);
 
 /** @brief Saves tcp_node to gconn's list of connected tcp relays.
  *
@@ -99,7 +99,7 @@ bool gcc_copy_tcp_relay(const Random *rng, Node_format *tcp_node, const GC_Conne
  * Return -2 if node is already in list.
  */
 non_null()
-int gcc_save_tcp_relay(const Random *rng, GC_Connection *gconn, const Node_format *tcp_node);
+int gcc_save_tcp_relay(const Tox_Random *rng, GC_Connection *gconn, const Node_format *tcp_node);
 
 /** @brief Checks for and handles messages that are in proper sequence in gconn's recv_array.
  * This should always be called after a new packet is successfully handled.
@@ -180,7 +180,7 @@ bool gcc_encrypt_and_send_lossless_packet(const GC_Chat *chat, const GC_Connecti
 
 /** @brief Called when a peer leaves the group. */
 non_null()
-void gcc_peer_cleanup(GC_Connection *gconn);
+void gcc_peer_cleanup(GC_Connection *gconn, const Memory *mem);
 
 /** @brief Called on group exit. */
 non_null()
diff --git a/toxcore/group_moderation.c b/toxcore/group_moderation.c
index eeed26d00eb..c3b0e591182 100644
--- a/toxcore/group_moderation.c
+++ b/toxcore/group_moderation.c
@@ -49,7 +49,7 @@ int mod_list_unpack(Moderation *moderation, const uint8_t *data, uint16_t length
         return 0;
     }
 
-    uint8_t **tmp_list = (uint8_t **)calloc(num_mods, sizeof(uint8_t *));
+    uint8_t **tmp_list = (uint8_t **)mem_valloc(moderation->mem, num_mods, sizeof(uint8_t *));
 
     if (tmp_list == nullptr) {
         return -1;
@@ -58,7 +58,7 @@ int mod_list_unpack(Moderation *moderation, const uint8_t *data, uint16_t length
     uint16_t unpacked_len = 0;
 
     for (uint16_t i = 0; i < num_mods; ++i) {
-        tmp_list[i] = (uint8_t *)malloc(sizeof(uint8_t) * MOD_LIST_ENTRY_SIZE);
+        tmp_list[i] = (uint8_t *)mem_balloc(moderation->mem, MOD_LIST_ENTRY_SIZE);
 
         if (tmp_list[i] == nullptr) {
             free_uint8_t_pointer_array(moderation->mem, tmp_list, i);
@@ -98,7 +98,7 @@ bool mod_list_make_hash(const Moderation *moderation, uint8_t *hash)
 
     assert(data_buf_size > 0);
 
-    uint8_t *data = (uint8_t *)malloc(data_buf_size);
+    uint8_t *data = (uint8_t *)mem_balloc(moderation->mem, data_buf_size);
 
     if (data == nullptr) {
         return false;
@@ -108,7 +108,7 @@ bool mod_list_make_hash(const Moderation *moderation, uint8_t *hash)
 
     mod_list_get_data_hash(hash, data, data_buf_size);
 
-    free(data);
+    mem_delete(moderation->mem, data);
 
     return true;
 }
@@ -162,10 +162,10 @@ bool mod_list_remove_index(Moderation *moderation, uint16_t index)
                MOD_LIST_ENTRY_SIZE);
     }
 
-    free(moderation->mod_list[moderation->num_mods]);
+    mem_delete(moderation->mem, moderation->mod_list[moderation->num_mods]);
     moderation->mod_list[moderation->num_mods] = nullptr;
 
-    uint8_t **tmp_list = (uint8_t **)realloc(moderation->mod_list, moderation->num_mods * sizeof(uint8_t *));
+    uint8_t **tmp_list = (uint8_t **)mem_vrealloc(moderation->mem, moderation->mod_list, moderation->num_mods, sizeof(uint8_t *));
 
     if (tmp_list == nullptr) {
         return false;
@@ -199,7 +199,7 @@ bool mod_list_add_entry(Moderation *moderation, const uint8_t *mod_data)
         return false;
     }
 
-    uint8_t **tmp_list = (uint8_t **)realloc(moderation->mod_list, (moderation->num_mods + 1) * sizeof(uint8_t *));
+    uint8_t **tmp_list = (uint8_t **)mem_vrealloc(moderation->mem, moderation->mod_list, moderation->num_mods + 1, sizeof(uint8_t *));
 
     if (tmp_list == nullptr) {
         return false;
@@ -207,7 +207,7 @@ bool mod_list_add_entry(Moderation *moderation, const uint8_t *mod_data)
 
     moderation->mod_list = tmp_list;
 
-    tmp_list[moderation->num_mods] = (uint8_t *)malloc(sizeof(uint8_t) * MOD_LIST_ENTRY_SIZE);
+    tmp_list[moderation->num_mods] = (uint8_t *)mem_balloc(moderation->mem, MOD_LIST_ENTRY_SIZE);
 
     if (tmp_list[moderation->num_mods] == nullptr) {
         return false;
@@ -400,9 +400,9 @@ int sanctions_list_unpack(Mod_Sanction *sanctions, Mod_Sanction_Creds *creds, ui
  *
  * Return true on success.
  */
-non_null(4) nullable(1)
+non_null(4, 5) nullable(1)
 static bool sanctions_list_make_hash(const Mod_Sanction *sanctions, uint32_t new_version, uint16_t num_sanctions,
-                                     uint8_t *hash)
+                                     uint8_t *hash, const Memory *mem)
 {
     if (num_sanctions == 0 || sanctions == nullptr) {
         memset(hash, 0, MOD_SANCTION_HASH_SIZE);
@@ -417,7 +417,7 @@ static bool sanctions_list_make_hash(const Mod_Sanction *sanctions, uint32_t new
         return false;
     }
 
-    uint8_t *data = (uint8_t *)malloc(data_buf_size);
+    uint8_t *data = (uint8_t *)mem_balloc(mem, data_buf_size);
 
     if (data == nullptr) {
         return false;
@@ -430,7 +430,7 @@ static bool sanctions_list_make_hash(const Mod_Sanction *sanctions, uint32_t new
     memcpy(&data[sig_data_size], &new_version, sizeof(uint32_t));
     crypto_sha256(hash, data, data_buf_size);
 
-    free(data);
+    mem_delete(mem, data);
 
     return true;
 }
@@ -488,7 +488,7 @@ bool sanctions_list_make_creds(Moderation *moderation)
     uint8_t hash[MOD_SANCTION_HASH_SIZE];
 
     if (!sanctions_list_make_hash(moderation->sanctions, moderation->sanctions_creds.version,
-                                  moderation->num_sanctions, hash)) {
+                                  moderation->num_sanctions, hash, moderation->mem)) {
         moderation->sanctions_creds = old_creds;
         return false;
     }
@@ -528,7 +528,7 @@ static bool sanctions_creds_validate(const Moderation *moderation, const Mod_San
 
     uint8_t hash[MOD_SANCTION_HASH_SIZE];
 
-    if (!sanctions_list_make_hash(sanctions, creds->version, num_sanctions, hash)) {
+    if (!sanctions_list_make_hash(sanctions, creds->version, num_sanctions, hash, moderation->mem)) {
         return false;
     }
 
@@ -607,9 +607,9 @@ static bool sanctions_apply_new(Moderation *moderation, Mod_Sanction *new_sancti
  * memory returned by this function.
  */
 non_null()
-static Mod_Sanction *sanctions_list_copy(const Mod_Sanction *sanctions, uint16_t num_sanctions)
+static Mod_Sanction *sanctions_list_copy(const Mod_Sanction *sanctions, uint16_t num_sanctions, const Memory *mem)
 {
-    Mod_Sanction *copy = (Mod_Sanction *)calloc(num_sanctions, sizeof(Mod_Sanction));
+    Mod_Sanction *copy = (Mod_Sanction *)mem_valloc(mem, num_sanctions, sizeof(Mod_Sanction));
 
     if (copy == nullptr) {
         return nullptr;
@@ -650,7 +650,7 @@ static bool sanctions_list_remove_index(Moderation *moderation, uint16_t index,
     }
 
     /* Operate on a copy of the list in case something goes wrong. */
-    Mod_Sanction *sanctions_copy = sanctions_list_copy(moderation->sanctions, moderation->num_sanctions);
+    Mod_Sanction *sanctions_copy = sanctions_list_copy(moderation->sanctions, moderation->num_sanctions, moderation->mem);
 
     if (sanctions_copy == nullptr) {
         return false;
@@ -660,15 +660,15 @@ static bool sanctions_list_remove_index(Moderation *moderation, uint16_t index,
         sanctions_copy[index] = sanctions_copy[new_num];
     }
 
-    Mod_Sanction *new_list = (Mod_Sanction *)realloc(sanctions_copy, new_num * sizeof(Mod_Sanction));
+    Mod_Sanction *new_list = (Mod_Sanction *)mem_vrealloc(moderation->mem, sanctions_copy, new_num, sizeof(Mod_Sanction));
 
     if (new_list == nullptr) {
-        free(sanctions_copy);
+        mem_delete(moderation->mem, sanctions_copy);
         return false;
     }
 
     if (!sanctions_apply_new(moderation, new_list, creds, new_num)) {
-        free(new_list);
+        mem_delete(moderation->mem, new_list);
         return false;
     }
 
@@ -748,7 +748,7 @@ bool sanctions_list_add_entry(Moderation *moderation, const Mod_Sanction *sancti
     Mod_Sanction *sanctions_copy = nullptr;
 
     if (moderation->num_sanctions > 0) {
-        sanctions_copy = sanctions_list_copy(moderation->sanctions, moderation->num_sanctions);
+        sanctions_copy = sanctions_list_copy(moderation->sanctions, moderation->num_sanctions, moderation->mem);
 
         if (sanctions_copy == nullptr) {
             return false;
@@ -756,17 +756,17 @@ bool sanctions_list_add_entry(Moderation *moderation, const Mod_Sanction *sancti
     }
 
     const uint16_t index = moderation->num_sanctions;
-    Mod_Sanction *new_list = (Mod_Sanction *)realloc(sanctions_copy, (index + 1) * sizeof(Mod_Sanction));
+    Mod_Sanction *new_list = (Mod_Sanction *)mem_vrealloc(moderation->mem, sanctions_copy, index + 1, sizeof(Mod_Sanction));
 
     if (new_list == nullptr) {
-        free(sanctions_copy);
+        mem_delete(moderation->mem, sanctions_copy);
         return false;
     }
 
     new_list[index] = *sanction;
 
     if (!sanctions_apply_new(moderation, new_list, creds, index + 1)) {
-        free(new_list);
+        mem_delete(moderation->mem, new_list);
         return false;
     }
 
@@ -860,7 +860,7 @@ uint16_t sanctions_list_replace_sig(Moderation *moderation, const uint8_t *publi
 void sanctions_list_cleanup(Moderation *moderation)
 {
     if (moderation->sanctions != nullptr) {
-        free(moderation->sanctions);
+        mem_delete(moderation->mem, moderation->sanctions);
     }
 
     moderation->sanctions = nullptr;
diff --git a/toxcore/group_moderation_fuzz_test.cc b/toxcore/group_moderation_fuzz_test.cc
index c5f46f3417c..dc4fbed76a1 100644
--- a/toxcore/group_moderation_fuzz_test.cc
+++ b/toxcore/group_moderation_fuzz_test.cc
@@ -1,13 +1,14 @@
 #include "group_moderation.h"
 
 #include "../testing/fuzzing/fuzz_support.h"
+#include "os_memory.h"
 
 namespace {
 
 void TestModListUnpack(Fuzz_Data &input)
 {
     CONSUME1_OR_RETURN(const uint16_t num_mods, input);
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     mod_list_unpack(&mods, input.data, input.size, num_mods);
     mod_list_cleanup(&mods);
 }
diff --git a/toxcore/group_moderation_test.cc b/toxcore/group_moderation_test.cc
index e55122896ad..d007866a410 100644
--- a/toxcore/group_moderation_test.cc
+++ b/toxcore/group_moderation_test.cc
@@ -8,6 +8,8 @@
 
 #include "crypto_core.h"
 #include "logger.h"
+#include "os_memory.h"
+#include "os_random.h"
 #include "util.h"
 
 namespace {
@@ -18,7 +20,7 @@ using ModerationHash = std::array<uint8_t, MOD_MODERATION_HASH_SIZE>;
 
 TEST(ModList, PackedSizeOfEmptyModListIsZero)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     EXPECT_EQ(mod_list_packed_size(&mods), 0);
 
     uint8_t byte = 1;
@@ -28,14 +30,14 @@ TEST(ModList, PackedSizeOfEmptyModListIsZero)
 
 TEST(ModList, UnpackingZeroSizeArrayIsNoop)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     const uint8_t byte = 1;
     EXPECT_EQ(mod_list_unpack(&mods, &byte, 0, 0), 0);
 }
 
 TEST(ModList, AddRemoveMultipleMods)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     uint8_t sig_pk1[32] = {1};
     uint8_t sig_pk2[32] = {2};
     EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk1));
@@ -47,7 +49,7 @@ TEST(ModList, AddRemoveMultipleMods)
 TEST(ModList, PackingAndUnpackingList)
 {
     using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
 
     std::vector<uint8_t> packed(mod_list_packed_size(&mods));
@@ -55,7 +57,7 @@ TEST(ModList, PackingAndUnpackingList)
 
     EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
 
-    Moderation mods2{system_memory()};
+    Moderation mods2{os_memory()};
     EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 1), packed.size());
     EXPECT_TRUE(mod_list_remove_entry(&mods2, ModListEntry{}.data()));
 }
@@ -63,13 +65,13 @@ TEST(ModList, PackingAndUnpackingList)
 TEST(ModList, UnpackingTooManyModsFails)
 {
     using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
 
     std::vector<uint8_t> packed(mod_list_packed_size(&mods));
     mod_list_pack(&mods, packed.data());
 
-    Moderation mods2{system_memory()};
+    Moderation mods2{os_memory()};
     EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 2), -1);
     EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
 }
@@ -78,16 +80,16 @@ TEST(ModList, UnpackingFromEmptyBufferFails)
 {
     std::vector<uint8_t> packed(1);
 
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     EXPECT_EQ(mod_list_unpack(&mods, packed.end().base(), 0, 1), -1);
 }
 
 TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
 
     // Fill with random data, check that it's zeroed.
     ModerationHash hash;
@@ -98,21 +100,21 @@ TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
 
 TEST(ModList, RemoveIndexFromEmptyModListFails)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     EXPECT_FALSE(mod_list_remove_index(&mods, 0));
     EXPECT_FALSE(mod_list_remove_index(&mods, UINT16_MAX));
 }
 
 TEST(ModList, RemoveEntryFromEmptyModListFails)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     uint8_t sig_pk[32] = {0};
     EXPECT_FALSE(mod_list_remove_entry(&mods, sig_pk));
 }
 
 TEST(ModList, ModListRemoveIndex)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     uint8_t sig_pk[32] = {1};
     EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
     EXPECT_TRUE(mod_list_remove_index(&mods, 0));
@@ -120,20 +122,20 @@ TEST(ModList, ModListRemoveIndex)
 
 TEST(ModList, CleanupOnEmptyModsIsNoop)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     mod_list_cleanup(&mods);
 }
 
 TEST(ModList, EmptyModListCannotVerifyAnySigPk)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     uint8_t sig_pk[32] = {1};
     EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk));
 }
 
 TEST(ModList, ModListAddVerifyRemoveSigPK)
 {
-    Moderation mods{system_memory()};
+    Moderation mods{os_memory()};
     uint8_t sig_pk[32] = {1};
     EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
     EXPECT_TRUE(mod_list_verify_sig_pk(&mods, sig_pk));
@@ -143,7 +145,7 @@ TEST(ModList, ModListAddVerifyRemoveSigPK)
 
 TEST(ModList, ModListHashCheck)
 {
-    Moderation mods1{system_memory()};
+    Moderation mods1{os_memory()};
     uint8_t sig_pk1[32] = {1};
     std::array<uint8_t, MOD_MODERATION_HASH_SIZE> hash1;
 
@@ -165,7 +167,7 @@ TEST(SanctionsList, PackingIntoUndersizedBufferFails)
 
 TEST(SanctionsList, PackUnpackSanctionsCreds)
 {
-    Moderation mod{system_memory()};
+    Moderation mod{os_memory()};
     std::array<uint8_t, MOD_SANCTIONS_CREDS_SIZE> packed;
     EXPECT_EQ(sanctions_creds_pack(&mod.sanctions_creds, packed.data()), MOD_SANCTIONS_CREDS_SIZE);
     EXPECT_EQ(
@@ -176,8 +178,9 @@ struct SanctionsListMod : ::testing::Test {
 protected:
     ExtPublicKey pk;
     ExtSecretKey sk;
-    Logger *log = logger_new();
-    Moderation mod{system_memory()};
+    const Memory *mem = os_memory();
+    Logger *log = logger_new(mem);
+    Moderation mod{os_memory()};
 
     Mod_Sanction sanctions[2] = {};
     const uint8_t sanctioned_pk1[32] = {1};
diff --git a/toxcore/group_onion_announce.c b/toxcore/group_onion_announce.c
index b797770e520..8a2f8398d98 100644
--- a/toxcore/group_onion_announce.c
+++ b/toxcore/group_onion_announce.c
@@ -69,10 +69,10 @@ void gca_onion_init(GC_Announces_List *group_announce, Onion_Announce *onion_a)
 #ifndef VANILLA_NACL
 
 int create_gca_announce_request(
-    const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,
-    const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id,
-    const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data,
-    const uint8_t *gc_data, uint16_t gc_data_length)
+    const Random *rng, const Memory *mem, uint8_t *packet, uint16_t max_packet_length,
+    const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key,
+    const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key,
+    uint64_t sendback_data, const uint8_t *gc_data, uint16_t gc_data_length)
 {
     if (max_packet_length < ONION_ANNOUNCE_REQUEST_MAX_SIZE || gc_data_length == 0) {
         return -1;
@@ -102,7 +102,8 @@ int create_gca_announce_request(
     memcpy(packet + 1 + CRYPTO_NONCE_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE);
 
     const int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain,
-                                 encrypted_size, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE);
+                                 encrypted_size, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
+                                 mem);
 
     const uint32_t full_length = (uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE;
 
diff --git a/toxcore/group_onion_announce.h b/toxcore/group_onion_announce.h
index 5c6d64ec594..6c566bd4066 100644
--- a/toxcore/group_onion_announce.h
+++ b/toxcore/group_onion_announce.h
@@ -14,9 +14,9 @@ void gca_onion_init(GC_Announces_List *group_announce, Onion_Announce *onion_a);
 
 non_null()
 int create_gca_announce_request(
-    const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,
-    const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id,
-    const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data,
-    const uint8_t *gc_data, uint16_t gc_data_length);
+    const Random *rng, const Memory *mem, uint8_t *packet, uint16_t max_packet_length,
+    const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key,
+    const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key,
+    uint64_t sendback_data, const uint8_t *gc_data, uint16_t gc_data_length);
 
 #endif  // C_TOXCORE_TOXCORE_GROUP_ONION_ANNOUNCE_H
diff --git a/toxcore/group_pack.c b/toxcore/group_pack.c
index ecdd965610c..eb6391f5372 100644
--- a/toxcore/group_pack.c
+++ b/toxcore/group_pack.c
@@ -119,7 +119,7 @@ static bool load_unpack_mod_list(GC_Chat *chat, Bin_Unpack *bu)
         return false;
     }
 
-    uint8_t *packed_mod_list = (uint8_t *)malloc(chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE);
+    uint8_t *packed_mod_list = (uint8_t *)mem_balloc(chat->mem, chat->moderation.num_mods * MOD_LIST_ENTRY_SIZE);
 
     if (packed_mod_list == nullptr) {
         LOGGER_ERROR(chat->log, "Failed to allocate memory for packed mod list");
@@ -130,17 +130,17 @@ static bool load_unpack_mod_list(GC_Chat *chat, Bin_Unpack *bu)
 
     if (!bin_unpack_bin_fixed(bu, packed_mod_list, packed_size)) {
         LOGGER_ERROR(chat->log, "Failed to unpack mod list binary data");
-        free(packed_mod_list);
+        mem_delete(chat->mem, packed_mod_list);
         return false;
     }
 
     if (mod_list_unpack(&chat->moderation, packed_mod_list, packed_size, chat->moderation.num_mods) == -1) {
         LOGGER_ERROR(chat->log, "Failed to unpack mod list info");
-        free(packed_mod_list);
+        mem_delete(chat->mem, packed_mod_list);
         return false;
     }
 
-    free(packed_mod_list);
+    mem_delete(chat->mem, packed_mod_list);
 
     return true;
 }
@@ -232,7 +232,7 @@ static bool load_unpack_saved_peers(GC_Chat *chat, Bin_Unpack *bu)
         return true;
     }
 
-    uint8_t *saved_peers = (uint8_t *)malloc(saved_peers_size * GC_SAVED_PEER_SIZE);
+    uint8_t *saved_peers = (uint8_t *)mem_balloc(chat->mem, saved_peers_size * GC_SAVED_PEER_SIZE);
 
     if (saved_peers == nullptr) {
         LOGGER_ERROR(chat->log, "Failed to allocate memory for saved peer list");
@@ -241,7 +241,7 @@ static bool load_unpack_saved_peers(GC_Chat *chat, Bin_Unpack *bu)
 
     if (!bin_unpack_bin_fixed(bu, saved_peers, saved_peers_size)) {
         LOGGER_ERROR(chat->log, "Failed to unpack saved peers binary data");
-        free(saved_peers);
+        mem_delete(chat->mem, saved_peers);
         return false;
     }
 
@@ -249,7 +249,7 @@ static bool load_unpack_saved_peers(GC_Chat *chat, Bin_Unpack *bu)
         LOGGER_ERROR(chat->log, "Failed to unpack saved peers");  // recoverable error
     }
 
-    free(saved_peers);
+    mem_delete(chat->mem, saved_peers);
 
     return true;
 }
@@ -322,7 +322,7 @@ static void save_pack_mod_list(const GC_Chat *chat, Bin_Pack *bp)
         return;
     }
 
-    uint8_t *packed_mod_list = (uint8_t *)malloc(num_mods * MOD_LIST_ENTRY_SIZE);
+    uint8_t *packed_mod_list = (uint8_t *)mem_balloc(chat->mem, num_mods * MOD_LIST_ENTRY_SIZE);
 
     // we can still recover without the mod list
     if (packed_mod_list == nullptr) {
@@ -340,7 +340,7 @@ static void save_pack_mod_list(const GC_Chat *chat, Bin_Pack *bp)
 
     bin_pack_bin(bp, packed_mod_list, packed_size); // 2
 
-    free(packed_mod_list);
+    mem_delete(chat->mem, packed_mod_list);
 }
 
 non_null()
@@ -374,7 +374,7 @@ static void save_pack_saved_peers(const GC_Chat *chat, Bin_Pack *bp)
 {
     bin_pack_array(bp, 2);
 
-    uint8_t *saved_peers = (uint8_t *)malloc(GC_MAX_SAVED_PEERS * GC_SAVED_PEER_SIZE);
+    uint8_t *saved_peers = (uint8_t *)mem_balloc(chat->mem, GC_MAX_SAVED_PEERS * GC_SAVED_PEER_SIZE);
 
     // we can still recover without the saved peers list
     if (saved_peers == nullptr) {
@@ -395,13 +395,13 @@ static void save_pack_saved_peers(const GC_Chat *chat, Bin_Pack *bp)
 
     if (packed_size == 0) {
         bin_pack_nil(bp); // 2
-        free(saved_peers);
+        mem_delete(chat->mem, saved_peers);
         return;
     }
 
     bin_pack_bin(bp, saved_peers, packed_size); // 2
 
-    free(saved_peers);
+    mem_delete(chat->mem, saved_peers);
 }
 
 void gc_save_pack_group(const GC_Chat *chat, Bin_Pack *bp)
diff --git a/toxcore/list.c b/toxcore/list.c
index e3674873804..448e4f5510c 100644
--- a/toxcore/list.c
+++ b/toxcore/list.c
@@ -114,7 +114,7 @@ static bool resize(BS_List *list, uint32_t new_size)
         return true;
     }
 
-    uint8_t *data = (uint8_t *)realloc(list->data, list->element_size * new_size);
+    uint8_t *data = (uint8_t *)mem_brealloc(list->mem, list->data, new_size * list->element_size);
 
     if (data == nullptr) {
         return false;
@@ -122,7 +122,7 @@ static bool resize(BS_List *list, uint32_t new_size)
 
     list->data = data;
 
-    int *ids = (int *)realloc(list->ids, sizeof(int) * new_size);
+    int *ids = (int *)mem_brealloc(list->mem, list->ids, new_size * sizeof(int));
 
     if (ids == nullptr) {
         return false;
@@ -134,8 +134,10 @@ static bool resize(BS_List *list, uint32_t new_size)
 }
 
 
-int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity)
+int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity, const Memory *mem)
 {
+    list->mem = mem;
+
     // set initial values
     list->n = 0;
     list->element_size = element_size;
@@ -161,10 +163,10 @@ void bs_list_free(BS_List *list)
     }
 
     // free both arrays
-    free(list->data);
+    mem_delete(list->mem, list->data);
     list->data = nullptr;
 
-    free(list->ids);
+    mem_delete(list->mem, list->ids);
     list->ids = nullptr;
 }
 
diff --git a/toxcore/list.h b/toxcore/list.h
index a7c0e56c061..5d04dfa74db 100644
--- a/toxcore/list.h
+++ b/toxcore/list.h
@@ -14,13 +14,16 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "attributes.h"
+#include "mem.h"
+#include "tox_attributes.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 typedef struct BS_List {
+    const Memory *mem;
+
     uint32_t n; // number of elements
     uint32_t capacity; // number of elements memory is allocated for
     uint32_t element_size; // size of the elements
@@ -37,7 +40,7 @@ typedef struct BS_List {
  * @retval 0 failure
  */
 non_null()
-int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity);
+int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity, const Memory *mem);
 
 /** Free a list initiated with list_init */
 nullable(1)
diff --git a/toxcore/list_test.cc b/toxcore/list_test.cc
index 5bffb8a1433..8d39433948d 100644
--- a/toxcore/list_test.cc
+++ b/toxcore/list_test.cc
@@ -2,26 +2,33 @@
 
 #include <gtest/gtest.h>
 
+#include "os_memory.h"
+
 namespace {
 
-TEST(List, CreateAndDestroyWithNonZeroSize)
+struct List : ::testing::Test {
+protected:
+    const Memory *mem_ = os_memory();
+};
+
+TEST_F(List, CreateAndDestroyWithNonZeroSize)
 {
     BS_List list;
-    bs_list_init(&list, sizeof(int), 10);
+    bs_list_init(&list, sizeof(int), 10, mem_);
     bs_list_free(&list);
 }
 
-TEST(List, CreateAndDestroyWithZeroSize)
+TEST_F(List, CreateAndDestroyWithZeroSize)
 {
     BS_List list;
-    bs_list_init(&list, sizeof(int), 0);
+    bs_list_init(&list, sizeof(int), 0, mem_);
     bs_list_free(&list);
 }
 
-TEST(List, DeleteFromEmptyList)
+TEST_F(List, DeleteFromEmptyList)
 {
     BS_List list;
-    bs_list_init(&list, sizeof(int), 0);
+    bs_list_init(&list, sizeof(int), 0, mem_);
     const uint8_t data[sizeof(int)] = {0};
     bs_list_remove(&list, data, 0);
     bs_list_free(&list);
diff --git a/toxcore/logger.c b/toxcore/logger.c
index d281a66085a..a0754637503 100644
--- a/toxcore/logger.c
+++ b/toxcore/logger.c
@@ -17,6 +17,8 @@
 #include "ccompat.h"
 
 struct Logger {
+    const Memory *mem;
+
     logger_cb *callback;
     void *context;
     void *userdata;
@@ -59,6 +61,7 @@ static void logger_stderr_handler(void *context, Logger_Level level, const char
 }
 
 static const Logger logger_stderr = {
+    nullptr,
     logger_stderr_handler,
     nullptr,
     nullptr,
@@ -68,18 +71,31 @@ static const Logger logger_stderr = {
  * Public Functions
  */
 
-Logger *logger_new(void)
+Logger *logger_new(const Memory *mem)
 {
-    return (Logger *)calloc(1, sizeof(Logger));
+    Logger *log = (Logger *)mem_alloc(mem, sizeof(Logger));
+
+    if (log == nullptr) {
+        return nullptr;
+    }
+
+    log->mem = mem;
+
+    return log;
 }
 
 void logger_kill(Logger *log)
 {
-    free(log);
+    if (log == nullptr) {
+        return;
+    }
+
+    mem_delete(log->mem, log);
 }
 
 void logger_callback_log(Logger *log, logger_cb *function, void *context, void *userdata)
 {
+    assert(log != nullptr);
     log->callback = function;
     log->context  = context;
     log->userdata = userdata;
diff --git a/toxcore/logger.h b/toxcore/logger.h
index ee5838ae734..b3fe80c80f3 100644
--- a/toxcore/logger.h
+++ b/toxcore/logger.h
@@ -11,7 +11,8 @@
 
 #include <stdint.h>
 
-#include "attributes.h"
+#include "mem.h"
+#include "tox_attributes.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -38,7 +39,8 @@ typedef void logger_cb(void *context, Logger_Level level, const char *file, int
 /**
  * Creates a new logger with logging disabled (callback is NULL) by default.
  */
-Logger *logger_new(void);
+non_null()
+Logger *logger_new(const Memory *mem);
 
 /**
  * Frees all resources associated with the logger.
diff --git a/toxcore/mem.c b/toxcore/mem.c
index a15b9728df6..f7295a7eb2f 100644
--- a/toxcore/mem.c
+++ b/toxcore/mem.c
@@ -1,60 +1,32 @@
 /* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright © 2016-2018 The TokTok team.
+ * Copyright © 2016-2023 The TokTok team.
  * Copyright © 2013 Tox project.
  */
 
 #include "mem.h"
 
-#include <stdlib.h>
+#include <string.h>
 
 #include "ccompat.h"
 
-nullable(1)
-static void *sys_malloc(void *obj, uint32_t size)
-{
-    return malloc(size);
-}
-
-nullable(1)
-static void *sys_calloc(void *obj, uint32_t nmemb, uint32_t size)
-{
-    return calloc(nmemb, size);
-}
-
-nullable(1, 2)
-static void *sys_realloc(void *obj, void *ptr, uint32_t size)
-{
-    return realloc(ptr, size);
-}
-
-nullable(1, 2)
-static void sys_free(void *obj, void *ptr)
-{
-    free(ptr);
-}
-
-static const Memory_Funcs system_memory_funcs = {
-    sys_malloc,
-    sys_calloc,
-    sys_realloc,
-    sys_free,
-};
-static const Memory system_memory_obj = {&system_memory_funcs};
-
-const Memory *system_memory(void)
+void *mem_balloc(const Memory *mem, uint32_t size)
 {
-    return &system_memory_obj;
+    void *const ptr = tox_memory_malloc(mem, size);
+    return ptr;
 }
 
-void *mem_balloc(const Memory *mem, uint32_t size)
+void *mem_brealloc(const Memory *mem, void *ptr, uint32_t size)
 {
-    void *const ptr = mem->funcs->malloc(mem->obj, size);
-    return ptr;
+    void *const new_ptr = tox_memory_realloc(mem, ptr, size);
+    return new_ptr;
 }
 
 void *mem_alloc(const Memory *mem, uint32_t size)
 {
-    void *const ptr = mem->funcs->calloc(mem->obj, 1, size);
+    void *const ptr = tox_memory_malloc(mem, size);
+    if (ptr != nullptr) {
+        memset(ptr, 0, size);
+    }
     return ptr;
 }
 
@@ -66,7 +38,10 @@ void *mem_valloc(const Memory *mem, uint32_t nmemb, uint32_t size)
         return nullptr;
     }
 
-    void *const ptr = mem->funcs->calloc(mem->obj, nmemb, size);
+    void *const ptr = tox_memory_malloc(mem, bytes);
+    if (ptr != nullptr) {
+        memset(ptr, 0, bytes);
+    }
     return ptr;
 }
 
@@ -78,11 +53,11 @@ void *mem_vrealloc(const Memory *mem, void *ptr, uint32_t nmemb, uint32_t size)
         return nullptr;
     }
 
-    void *const new_ptr = mem->funcs->realloc(mem->obj, ptr, bytes);
+    void *const new_ptr = tox_memory_realloc(mem, ptr, bytes);
     return new_ptr;
 }
 
 void mem_delete(const Memory *mem, void *ptr)
 {
-    mem->funcs->free(mem->obj, ptr);
+    tox_memory_dealloc(mem, ptr);
 }
diff --git a/toxcore/mem.h b/toxcore/mem.h
index a9d9e1d2c9a..11555ef0d69 100644
--- a/toxcore/mem.h
+++ b/toxcore/mem.h
@@ -11,31 +11,14 @@
 
 #include <stdint.h>     // uint*_t
 
-#include "attributes.h"
+#include "tox_attributes.h"
+#include "tox_memory.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef void *mem_malloc_cb(void *obj, uint32_t size);
-typedef void *mem_calloc_cb(void *obj, uint32_t nmemb, uint32_t size);
-typedef void *mem_realloc_cb(void *obj, void *ptr, uint32_t size);
-typedef void mem_free_cb(void *obj, void *ptr);
-
-/** @brief Functions wrapping standard C memory allocation functions. */
-typedef struct Memory_Funcs {
-    mem_malloc_cb *malloc;
-    mem_calloc_cb *calloc;
-    mem_realloc_cb *realloc;
-    mem_free_cb *free;
-} Memory_Funcs;
-
-typedef struct Memory {
-    const Memory_Funcs *funcs;
-    void *obj;
-} Memory;
-
-const Memory *system_memory(void);
+typedef Tox_Memory Memory;
 
 /**
  * @brief Allocate an array of a given size for built-in types.
@@ -45,6 +28,14 @@ const Memory *system_memory(void);
  */
 non_null() void *mem_balloc(const Memory *mem, uint32_t size);
 
+/**
+ * @brief Resize an array of a given size for built-in types.
+ *
+ * If used for a type other than byte-sized types, `size` needs to be manually
+ * multiplied by the element size.
+ */
+non_null(1) nullable(2) void *mem_brealloc(const Memory *mem, void *ptr, uint32_t size);
+
 /**
  * @brief Allocate a single object.
  *
diff --git a/toxcore/mem_test.cc b/toxcore/mem_test.cc
index f787036616c..bdd567cf07e 100644
--- a/toxcore/mem_test.cc
+++ b/toxcore/mem_test.cc
@@ -2,6 +2,8 @@
 
 #include <gtest/gtest.h>
 
+#include "os_memory.h"
+
 namespace {
 
 TEST(Mem, AllocLarge)
@@ -9,7 +11,7 @@ TEST(Mem, AllocLarge)
     // Mebi prefix: https://en.wikipedia.org/wiki/Binary_prefix.
     constexpr uint32_t MI = 1024 * 1024;
 
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     void *ptr = mem_valloc(mem, 4, MI);
     EXPECT_NE(ptr, nullptr);
@@ -22,18 +24,18 @@ TEST(Mem, AllocOverflow)
     // Gibi prefix.
     constexpr uint32_t GI = 1024 * 1024 * 1024;
 
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     // 1 gibi-elements of 100 bytes each.
-    void *ptr = mem_valloc(mem, GI, 100);
+    void *ptr = mem_vrealloc(mem, nullptr, GI, 100);
     EXPECT_EQ(ptr, nullptr);
 
     // 100 elements of 1 gibibyte each.
-    ptr = mem_valloc(mem, 100, GI);
+    ptr = mem_vrealloc(mem, nullptr, 100, GI);
     EXPECT_EQ(ptr, nullptr);
 
     // 128 (a multiple of 2) elements of 1 gibibyte each.
-    ptr = mem_valloc(mem, 128, GI);
+    ptr = mem_vrealloc(mem, nullptr, 128, GI);
     EXPECT_EQ(ptr, nullptr);
 }
 
diff --git a/toxcore/mono_time.c b/toxcore/mono_time.c
index e03046f799a..8683810fbef 100644
--- a/toxcore/mono_time.c
+++ b/toxcore/mono_time.c
@@ -32,6 +32,7 @@
 #include <time.h>
 
 #include "ccompat.h"
+#include "tox_time_impl.h"
 
 /** don't call into system billions of times for no reason */
 struct Mono_Time {
@@ -49,8 +50,8 @@ struct Mono_Time {
     pthread_rwlock_t *time_update_lock;
 #endif
 
-    mono_time_current_time_cb *current_time_callback;
-    void *user_data;
+    const Tox_Time *tm;
+    Tox_Time default_tm;
 };
 
 #ifdef OS_WIN32
@@ -121,8 +122,12 @@ static uint64_t current_time_monotonic_default(void *user_data)
 #endif // !__APPLE__
 #endif // !OS_WIN32
 
+static const Tox_Time_Funcs os_time_funcs = {
+    current_time_monotonic_default,
+};
+
 
-Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_time_callback, void *user_data)
+Mono_Time *mono_time_new(const Memory *mem, const Tox_Time *tm)
 {
     Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time));
 
@@ -145,7 +150,10 @@ Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_t
     }
 #endif
 
-    mono_time_set_current_time_callback(mono_time, current_time_callback, user_data);
+    mono_time->default_tm.funcs = &os_time_funcs;
+    mono_time->default_tm.user_data = mono_time;
+
+    mono_time->tm = tm != nullptr ? tm : &mono_time->default_tm;
 
 #ifdef OS_WIN32
 
@@ -196,7 +204,7 @@ void mono_time_update(Mono_Time *mono_time)
     pthread_mutex_lock(&mono_time->last_clock_lock);
     mono_time->last_clock_update = true;
 #endif
-    cur_time = mono_time->current_time_callback(mono_time->user_data) / 1000ULL;
+    cur_time = tox_time_monotonic(mono_time->tm) / 1000ULL;
     cur_time += mono_time->base_time;
 #ifdef OS_WIN32
     pthread_mutex_unlock(&mono_time->last_clock_lock);
@@ -233,16 +241,9 @@ bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64
     return timestamp + timeout <= mono_time_get(mono_time);
 }
 
-void mono_time_set_current_time_callback(Mono_Time *mono_time,
-        mono_time_current_time_cb *current_time_callback, void *user_data)
+void mono_time_set_current_time_callback(Mono_Time *mono_time, const Tox_Time *tm)
 {
-    if (current_time_callback == nullptr) {
-        mono_time->current_time_callback = current_time_monotonic_default;
-        mono_time->user_data = mono_time;
-    } else {
-        mono_time->current_time_callback = current_time_callback;
-        mono_time->user_data = user_data;
-    }
+    mono_time->tm = tm != nullptr ? tm : &mono_time->default_tm;
 }
 
 /**
@@ -257,7 +258,7 @@ uint64_t current_time_monotonic(Mono_Time *mono_time)
      * but must protect against other threads */
     pthread_mutex_lock(&mono_time->last_clock_lock);
 #endif
-    const uint64_t cur_time = mono_time->current_time_callback(mono_time->user_data);
+    const uint64_t cur_time = tox_time_monotonic(mono_time->tm);
 #ifdef OS_WIN32
     pthread_mutex_unlock(&mono_time->last_clock_lock);
 #endif
diff --git a/toxcore/mono_time.h b/toxcore/mono_time.h
index fa1df840e0c..b98bcf971ae 100644
--- a/toxcore/mono_time.h
+++ b/toxcore/mono_time.h
@@ -8,8 +8,9 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "attributes.h"
 #include "mem.h"
+#include "tox_attributes.h"
+#include "tox_time.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -46,10 +47,8 @@ extern "C" {
  */
 typedef struct Mono_Time Mono_Time;
 
-typedef uint64_t mono_time_current_time_cb(void *user_data);
-
-non_null(1) nullable(2, 3)
-Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_time_callback, void *user_data);
+non_null(1) nullable(2)
+Mono_Time *mono_time_new(const Memory *mem, const Tox_Time *tm);
 
 non_null(1) nullable(2)
 void mono_time_free(const Memory *mem, Mono_Time *mono_time);
@@ -86,9 +85,8 @@ uint64_t current_time_monotonic(Mono_Time *mono_time);
  * The caller is obligated to ensure that `current_time_monotonic()` continues
  * to increase monotonically.
  */
-non_null(1) nullable(2, 3)
-void mono_time_set_current_time_callback(Mono_Time *mono_time,
-        mono_time_current_time_cb *current_time_callback, void *user_data);
+non_null(1) nullable(2)
+void mono_time_set_current_time_callback(Mono_Time *mono_time, const Tox_Time *tm);
 
 #ifdef __cplusplus
 }
diff --git a/toxcore/mono_time_test.cc b/toxcore/mono_time_test.cc
index 379b606c8e5..6544dbac162 100644
--- a/toxcore/mono_time_test.cc
+++ b/toxcore/mono_time_test.cc
@@ -2,12 +2,16 @@
 
 #include <gtest/gtest.h>
 
+#include "os_memory.h"
+#include "tox_time_impl.h"
+
 namespace {
 
 TEST(MonoTime, UnixTimeIncreasesOverTime)
 {
-    const Memory *mem = system_memory();
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    const Memory *mem = os_memory();
+    ASSERT_NE(mem, nullptr);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
     ASSERT_NE(mono_time, nullptr);
 
     mono_time_update(mono_time);
@@ -25,8 +29,9 @@ TEST(MonoTime, UnixTimeIncreasesOverTime)
 
 TEST(MonoTime, IsTimeout)
 {
-    const Memory *mem = system_memory();
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    const Memory *mem = os_memory();
+    ASSERT_NE(mem, nullptr);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
     ASSERT_NE(mono_time, nullptr);
 
     uint64_t const start = mono_time_get(mono_time);
@@ -43,14 +48,19 @@ TEST(MonoTime, IsTimeout)
 
 TEST(MonoTime, CustomTime)
 {
-    const Memory *mem = system_memory();
-    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
+    const Memory *mem = os_memory();
+    ASSERT_NE(mem, nullptr);
+    Mono_Time *mono_time = mono_time_new(mem, nullptr);
     ASSERT_NE(mono_time, nullptr);
 
     uint64_t test_time = current_time_monotonic(mono_time) + 42137;
 
-    mono_time_set_current_time_callback(
-        mono_time, [](void *user_data) { return *static_cast<uint64_t *>(user_data); }, &test_time);
+    constexpr Tox_Time_Funcs mock_time_funcs = {
+        [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
+    };
+    Tox_Time *tm = tox_time_new(&mock_time_funcs, &test_time, mem);
+    ASSERT_NE(tm, nullptr);
+    mono_time_set_current_time_callback(mono_time, tm);
     mono_time_update(mono_time);
 
     EXPECT_EQ(current_time_monotonic(mono_time), test_time);
@@ -65,6 +75,7 @@ TEST(MonoTime, CustomTime)
     EXPECT_EQ(current_time_monotonic(mono_time), test_time);
 
     mono_time_free(mem, mono_time);
+    tox_time_free(tm);
 }
 
 }  // namespace
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c
index 7fb4b3a8139..fe68f12eccf 100644
--- a/toxcore/net_crypto.c
+++ b/toxcore/net_crypto.c
@@ -128,7 +128,7 @@ static const Crypto_Connection empty_crypto_connection = {{0}};
 struct Net_Crypto {
     const Logger *log;
     const Memory *mem;
-    const Random *rng;
+    const Tox_Random *rng;
     Mono_Time *mono_time;
     const Network *ns;
 
@@ -232,7 +232,7 @@ static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, const uin
     memcpy(packet + 1, dht_get_self_public_key(c->dht), CRYPTO_PUBLIC_KEY_SIZE);
     memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
     const int len = encrypt_data_symmetric(shared_key, nonce, plain, sizeof(plain),
-                                           packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                                           packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, c->mem);
 
     if (len != COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) {
         return -1;
@@ -247,7 +247,7 @@ static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, const uin
  * @retval 0 on success.
  */
 non_null()
-static int create_cookie(const Random *rng, const Mono_Time *mono_time, uint8_t *cookie, const uint8_t *bytes,
+static int create_cookie(const Random *rng, const Memory *mem, const Mono_Time *mono_time, uint8_t *cookie, const uint8_t *bytes,
                          const uint8_t *encryption_key)
 {
     uint8_t contents[COOKIE_CONTENTS_LENGTH];
@@ -255,7 +255,7 @@ static int create_cookie(const Random *rng, const Mono_Time *mono_time, uint8_t
     memcpy(contents, &temp_time, sizeof(temp_time));
     memcpy(contents + sizeof(temp_time), bytes, COOKIE_DATA_LENGTH);
     random_nonce(rng, cookie);
-    const int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + CRYPTO_NONCE_SIZE);
+    const int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + CRYPTO_NONCE_SIZE, mem);
 
     if (len != COOKIE_LENGTH - CRYPTO_NONCE_SIZE) {
         return -1;
@@ -270,12 +270,12 @@ static int create_cookie(const Random *rng, const Mono_Time *mono_time, uint8_t
  * @retval 0 on success.
  */
 non_null()
-static int open_cookie(const Mono_Time *mono_time, uint8_t *bytes, const uint8_t *cookie,
+static int open_cookie(const Memory *mem, const Mono_Time *mono_time, uint8_t *bytes, const uint8_t *cookie,
                        const uint8_t *encryption_key)
 {
     uint8_t contents[COOKIE_CONTENTS_LENGTH];
     const int len = decrypt_data_symmetric(encryption_key, cookie, cookie + CRYPTO_NONCE_SIZE,
-                                           COOKIE_LENGTH - CRYPTO_NONCE_SIZE, contents);
+                                           COOKIE_LENGTH - CRYPTO_NONCE_SIZE, contents, mem);
 
     if (len != sizeof(contents)) {
         return -1;
@@ -310,14 +310,14 @@ static int create_cookie_response(const Net_Crypto *c, uint8_t *packet, const ui
     memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE);
     uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)];
 
-    if (create_cookie(c->rng, c->mono_time, plain, cookie_plain, c->secret_symmetric_key) != 0) {
+    if (create_cookie(c->rng, c->mem, c->mono_time, plain, cookie_plain, c->secret_symmetric_key) != 0) {
         return -1;
     }
 
     memcpy(plain + COOKIE_LENGTH, request_plain + COOKIE_DATA_LENGTH, sizeof(uint64_t));
     packet[0] = NET_PACKET_COOKIE_RESPONSE;
     random_nonce(c->rng, packet + 1);
-    const int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE);
+    const int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE, c->mem);
 
     if (len != COOKIE_RESPONSE_LENGTH - (1 + CRYPTO_NONCE_SIZE)) {
         return -1;
@@ -346,7 +346,7 @@ static int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, ui
     memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
     const int len = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                            packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE,
-                                           request_plain);
+                                           request_plain, c->mem);
 
     if (len != COOKIE_REQUEST_PLAIN_LENGTH) {
         return -1;
@@ -443,7 +443,7 @@ static int tcp_oob_handle_cookie_request(const Net_Crypto *c, unsigned int tcp_c
 non_null()
 static int handle_cookie_response(uint8_t *cookie, uint64_t *number,
                                   const uint8_t *packet, uint16_t length,
-                                  const uint8_t *shared_key)
+                                  const uint8_t *shared_key, const Memory *mem)
 {
     if (length != COOKIE_RESPONSE_LENGTH) {
         return -1;
@@ -451,7 +451,7 @@ static int handle_cookie_response(uint8_t *cookie, uint64_t *number,
 
     uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)];
     const int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE,
-                                           length - (1 + CRYPTO_NONCE_SIZE), plain);
+                                           length - (1 + CRYPTO_NONCE_SIZE), plain, mem);
 
     if (len != sizeof(plain)) {
         return -1;
@@ -483,14 +483,14 @@ static int create_crypto_handshake(const Net_Crypto *c, uint8_t *packet, const u
     memcpy(cookie_plain, peer_real_pk, CRYPTO_PUBLIC_KEY_SIZE);
     memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, peer_dht_pubkey, CRYPTO_PUBLIC_KEY_SIZE);
 
-    if (create_cookie(c->rng, c->mono_time, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE,
+    if (create_cookie(c->rng, c->mem, c->mono_time, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE,
                       cookie_plain, c->secret_symmetric_key) != 0) {
         return -1;
     }
 
     random_nonce(c->rng, packet + 1 + COOKIE_LENGTH);
     const int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain),
-                                 packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE);
+                                 packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE, c->mem);
 
     if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE)) {
         return -1;
@@ -530,7 +530,7 @@ static bool handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t
 
     uint8_t cookie_plain[COOKIE_DATA_LENGTH];
 
-    if (open_cookie(c->mono_time, cookie_plain, packet + 1, c->secret_symmetric_key) != 0) {
+    if (open_cookie(c->mem, c->mono_time, cookie_plain, packet + 1, c->secret_symmetric_key) != 0) {
         return false;
     }
 
@@ -544,7 +544,7 @@ static bool handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t
     uint8_t plain[CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH];
     const int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH,
                                  packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE,
-                                 HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain);
+                                 HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain, c->mem);
 
     if (len != sizeof(plain)) {
         return false;
@@ -1100,7 +1100,7 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_
     VLA(uint8_t, packet, packet_size);
     packet[0] = NET_PACKET_CRYPTO_DATA;
     memcpy(packet + 1, conn->sent_nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t));
-    const int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t));
+    const int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t), c->mem);
 
     if (len + 1 + sizeof(uint16_t) != packet_size) {
         LOGGER_ERROR(c->log, "encryption failed: %d", len);
@@ -1275,7 +1275,7 @@ static int handle_data_packet(const Net_Crypto *c, int crypt_connection_id, uint
     const uint16_t diff = num - num_cur_nonce;
     increment_nonce_number(nonce, diff);
     const int len = decrypt_data_symmetric(conn->shared_key, nonce, packet + 1 + sizeof(uint16_t),
-                                           length - (1 + sizeof(uint16_t)), data);
+                                           length - (1 + sizeof(uint16_t)), data, c->mem);
 
     if ((unsigned int)len != length - crypto_packet_overhead) {
         return -1;
@@ -1696,7 +1696,7 @@ static int handle_packet_cookie_response(Net_Crypto *c, int crypt_connection_id,
     uint8_t cookie[COOKIE_LENGTH];
     uint64_t number;
 
-    if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key) != sizeof(cookie)) {
+    if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key, c->mem) != sizeof(cookie)) {
         return -1;
     }
 
@@ -3108,7 +3108,7 @@ void load_secret_key(Net_Crypto *c, const uint8_t *sk)
 /** @brief Create new instance of Net_Crypto.
  * Sets all the global connection variables to their default values.
  */
-Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
+Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Tox_Random *rng, const Network *ns,
                            Mono_Time *mono_time, DHT *dht, const TCP_Proxy_Info *proxy_info)
 {
     if (dht == nullptr) {
@@ -3156,7 +3156,7 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
     networking_registerhandler(dht_get_net(dht), NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp);
     networking_registerhandler(dht_get_net(dht), NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp);
 
-    bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8);
+    bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8, mem);
 
     return temp;
 }
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h
index ac6a0b59cbd..38b58ffe61b 100644
--- a/toxcore/net_crypto.h
+++ b/toxcore/net_crypto.h
@@ -398,7 +398,7 @@ void load_secret_key(Net_Crypto *c, const uint8_t *sk);
  * Sets all the global connection variables to their default values.
  */
 non_null()
-Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
+Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Tox_Random *rng, const Network *ns,
                            Mono_Time *mono_time, DHT *dht, const TCP_Proxy_Info *proxy_info);
 
 /** return the optimal interval in ms for running do_net_crypto. */
diff --git a/toxcore/network.c b/toxcore/network.c
index 5ccf068f53c..9b2d2146fde 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -37,12 +37,6 @@
 
 #include "network.h"
 
-#ifdef PLAN9
-#include <u.h> // Plan 9 requires this is imported first
-// Comment line here to avoid reordering by source code formatters.
-#include <libc.h>
-#endif
-
 #ifdef OS_WIN32 // Put win32 includes here
 // The mingw32/64 Windows library warns about including winsock2.h after
 // windows.h even though with the above it's a valid thing to do. So, to make
@@ -53,11 +47,6 @@
 #include <ws2tcpip.h>
 #endif
 
-#ifdef __APPLE__
-#include <mach/clock.h>
-#include <mach/mach.h>
-#endif
-
 #if !defined(OS_WIN32)
 #include <arpa/inet.h>
 #include <errno.h>
@@ -87,21 +76,12 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifndef VANILLA_NACL
-// Used for sodium_init()
-#include <sodium.h>
-#endif
-
 #include "ccompat.h"
 #include "logger.h"
 #include "mono_time.h"
+#include "os_network_impl.h"
 #include "util.h"
 
-// Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD
-#if !defined(MSG_NOSIGNAL)
-#define MSG_NOSIGNAL 0
-#endif
-
 #ifndef IPV6_ADD_MEMBERSHIP
 #ifdef IPV6_JOIN_GROUP
 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@@ -377,47 +357,47 @@ IP6 get_ip6_loopback(void)
 
 const Socket net_invalid_socket = { (int)INVALID_SOCKET };
 
-Family net_family_unspec()
+Family net_family_unspec(void)
 {
     return family_unspec;
 }
 
-Family net_family_ipv4()
+Family net_family_ipv4(void)
 {
     return family_ipv4;
 }
 
-Family net_family_ipv6()
+Family net_family_ipv6(void)
 {
     return family_ipv6;
 }
 
-Family net_family_tcp_server()
+Family net_family_tcp_server(void)
 {
     return family_tcp_server;
 }
 
-Family net_family_tcp_client()
+Family net_family_tcp_client(void)
 {
     return family_tcp_client;
 }
 
-Family net_family_tcp_ipv4()
+Family net_family_tcp_ipv4(void)
 {
     return family_tcp_ipv4;
 }
 
-Family net_family_tcp_ipv6()
+Family net_family_tcp_ipv6(void)
 {
     return family_tcp_ipv6;
 }
 
-Family net_family_tox_tcp_ipv4()
+Family net_family_tox_tcp_ipv4(void)
 {
     return family_tox_tcp_ipv4;
 }
 
-Family net_family_tox_tcp_ipv6()
+Family net_family_tox_tcp_ipv6(void)
 {
     return family_tox_tcp_ipv6;
 }
@@ -472,147 +452,9 @@ bool sock_valid(Socket sock)
     return sock.sock != net_invalid_socket.sock;
 }
 
-struct Network_Addr {
-    struct sockaddr_storage addr;
-    size_t size;
-};
-
-non_null()
-static int sys_close(void *obj, int sock)
-{
-#if defined(OS_WIN32)
-    return closesocket(sock);
-#else  // !OS_WIN32
-    return close(sock);
-#endif
-}
-
-non_null()
-static int sys_accept(void *obj, int sock)
-{
-    return accept(sock, nullptr, nullptr);
-}
-
-non_null()
-static int sys_bind(void *obj, int sock, const Network_Addr *addr)
-{
-    return bind(sock, (const struct sockaddr *)&addr->addr, addr->size);
-}
-
-non_null()
-static int sys_listen(void *obj, int sock, int backlog)
-{
-    return listen(sock, backlog);
-}
-
-non_null()
-static int sys_recvbuf(void *obj, int sock)
-{
-#ifdef OS_WIN32
-    u_long count = 0;
-    ioctlsocket(sock, FIONREAD, &count);
-#else
-    int count = 0;
-    ioctl(sock, FIONREAD, &count);
-#endif
-
-    return count;
-}
-
-non_null()
-static int sys_recv(void *obj, int sock, uint8_t *buf, size_t len)
-{
-    return recv(sock, (char *)buf, len, MSG_NOSIGNAL);
-}
-
-non_null()
-static int sys_send(void *obj, int sock, const uint8_t *buf, size_t len)
-{
-    return send(sock, (const char *)buf, len, MSG_NOSIGNAL);
-}
-
-non_null()
-static int sys_sendto(void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
-    return sendto(sock, (const char *)buf, len, 0, (const struct sockaddr *)&addr->addr, addr->size);
-}
-
-non_null()
-static int sys_recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
-    socklen_t size = addr->size;
-    const int ret = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&addr->addr, &size);
-    addr->size = size;
-    return ret;
-}
-
-non_null()
-static int sys_socket(void *obj, int domain, int type, int proto)
-{
-    return (int)socket(domain, type, proto);
-}
-
-non_null()
-static int sys_socket_nonblock(void *obj, int sock, bool nonblock)
-{
-#ifdef OS_WIN32
-    u_long mode = nonblock ? 1 : 0;
-    return ioctlsocket(sock, FIONBIO, &mode);
-#else
-    return fcntl(sock, F_SETFL, O_NONBLOCK, nonblock ? 1 : 0);
-#endif /* OS_WIN32 */
-}
-
-non_null()
-static int sys_getsockopt(void *obj, int sock, int level, int optname, void *optval, size_t *optlen)
-{
-    socklen_t len = *optlen;
-    const int ret = getsockopt(sock, level, optname, optval, &len);
-    *optlen = len;
-    return ret;
-}
-
-non_null()
-static int sys_setsockopt(void *obj, int sock, int level, int optname, const void *optval, size_t optlen)
-{
-    return setsockopt(sock, level, optname, optval, optlen);
-}
-
-static const Network_Funcs system_network_funcs = {
-    sys_close,
-    sys_accept,
-    sys_bind,
-    sys_listen,
-    sys_recvbuf,
-    sys_recv,
-    sys_recvfrom,
-    sys_send,
-    sys_sendto,
-    sys_socket,
-    sys_socket_nonblock,
-    sys_getsockopt,
-    sys_setsockopt,
-};
-static const Network system_network_obj = {&system_network_funcs};
-
-const Network *system_network(void)
-{
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-    if ((true)) {
-        return nullptr;
-    }
-#endif
-#ifdef OS_WIN32
-    WSADATA wsaData;
-
-    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) {
-        return nullptr;
-    }
-#endif
-    return &system_network_obj;
-}
-
 #if 0
-/* TODO(iphydf): Call this from functions that use `system_network()`. */
-void system_network_deinit(const Network *ns)
+/* TODO(iphydf): Call this from functions that use `os_network()`. */
+void os_network_deinit(const Network *ns)
 {
 #ifdef OS_WIN32
     WSACleanup();
@@ -623,13 +465,13 @@ void system_network_deinit(const Network *ns)
 non_null()
 static int net_setsockopt(const Network *ns, Socket sock, int level, int optname, const void *optval, size_t optlen)
 {
-    return ns->funcs->setsockopt(ns->obj, sock.sock, level, optname, optval, optlen);
+    return tox_network_setsockopt(ns, sock.sock, level, optname, optval, optlen);
 }
 
 non_null()
 static int net_getsockopt(const Network *ns, Socket sock, int level, int optname, void *optval, size_t *optlen)
 {
-    return ns->funcs->getsockopt(ns->obj, sock.sock, level, optname, optval, optlen);
+    return tox_network_getsockopt(ns, sock.sock, level, optname, optval, optlen);
 }
 
 non_null()
@@ -804,7 +646,7 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu
 int net_send(const Network *ns, const Logger *log,
              Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port)
 {
-    const int res = ns->funcs->send(ns->obj, sock.sock, buf, len);
+    const int res = tox_network_send(ns, sock.sock, buf, len);
     loglogdata(log, "T=>", buf, len, ip_port, res);
     return res;
 }
@@ -814,13 +656,13 @@ static int net_sendto(
         const Network *ns,
         Socket sock, const uint8_t *buf, size_t len, const Network_Addr *addr, const IP_Port *ip_port)
 {
-    return ns->funcs->sendto(ns->obj, sock.sock, buf, len, addr);
+    return tox_network_sendto(ns, sock.sock, buf, len, addr);
 }
 
 int net_recv(const Network *ns, const Logger *log,
              Socket sock, uint8_t *buf, size_t len, const IP_Port *ip_port)
 {
-    const int res = ns->funcs->recv(ns->obj, sock.sock, buf, len);
+    const int res = tox_network_recv(ns, sock.sock, buf, len);
     loglogdata(log, "=>T", buf, len, ip_port, res);
     return res;
 }
@@ -829,35 +671,35 @@ non_null()
 static int net_recvfrom(const Network *ns,
                         Socket sock, uint8_t *buf, size_t len, Network_Addr *addr)
 {
-    return ns->funcs->recvfrom(ns->obj, sock.sock, buf, len, addr);
+    return tox_network_recvfrom(ns, sock.sock, buf, len, addr);
 }
 
 int net_listen(const Network *ns, Socket sock, int backlog)
 {
-    return ns->funcs->listen(ns->obj, sock.sock, backlog);
+    return tox_network_listen(ns, sock.sock, backlog);
 }
 
 non_null()
 static int net_bind(const Network *ns, Socket sock, const Network_Addr *addr)
 {
-    return ns->funcs->bind(ns->obj, sock.sock, addr);
+    return tox_network_bind(ns, sock.sock, addr);
 }
 
 Socket net_accept(const Network *ns, Socket sock)
 {
-    const Socket newsock = {ns->funcs->accept(ns->obj, sock.sock)};
+    const Socket newsock = {tox_network_accept(ns, sock.sock)};
     return newsock;
 }
 
 /** Close the socket. */
 void kill_sock(const Network *ns, Socket sock)
 {
-    ns->funcs->close(ns->obj, sock.sock);
+    tox_network_close(ns, sock.sock);
 }
 
 bool set_socket_nonblock(const Network *ns, Socket sock)
 {
-    return ns->funcs->socket_nonblock(ns->obj, sock.sock, true) == 0;
+    return tox_network_socket_nonblock(ns, sock.sock, true) == 0;
 }
 
 bool set_socket_nosigpipe(const Network *ns, Socket sock)
@@ -962,34 +804,41 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe
         ipp_copy.ip.ip.v6 = ip6;
     }
 
-    Network_Addr addr;
+    Network_Addr *addr;
 
     if (net_family_is_ipv4(ipp_copy.ip.family)) {
-        struct sockaddr_in *const addr4 = (struct sockaddr_in *)&addr.addr;
+        struct sockaddr_in addr4 = {0};
 
-        addr.size = sizeof(struct sockaddr_in);
-        addr4->sin_family = AF_INET;
-        addr4->sin_port = ipp_copy.port;
-        fill_addr4(&ipp_copy.ip.ip.v4, &addr4->sin_addr);
+        addr4.sin_family = AF_INET;
+        addr4.sin_port = ipp_copy.port;
+        fill_addr4(&ipp_copy.ip.ip.v4, &addr4.sin_addr);
+
+        addr = net_addr_new(&addr4, sizeof(addr4), net->mem);
     } else if (net_family_is_ipv6(ipp_copy.ip.family)) {
-        struct sockaddr_in6 *const addr6 = (struct sockaddr_in6 *)&addr.addr;
+        struct sockaddr_in6 addr6 = {0};
 
-        addr.size = sizeof(struct sockaddr_in6);
-        addr6->sin6_family = AF_INET6;
-        addr6->sin6_port = ipp_copy.port;
-        fill_addr6(&ipp_copy.ip.ip.v6, &addr6->sin6_addr);
+        addr6.sin6_family = AF_INET6;
+        addr6.sin6_port = ipp_copy.port;
+        fill_addr6(&ipp_copy.ip.ip.v6, &addr6.sin6_addr);
 
-        addr6->sin6_flowinfo = 0;
-        addr6->sin6_scope_id = 0;
+        addr6.sin6_flowinfo = 0;
+        addr6.sin6_scope_id = 0;
+
+        addr = net_addr_new(&addr6, sizeof(addr6), net->mem);
     } else {
         LOGGER_ERROR(net->log, "unknown address type: %d", ipp_copy.ip.family.value);
         return -1;
     }
 
-    const long res = net_sendto(net->ns, net->sock, packet.data, packet.length, &addr, &ipp_copy);
+    if (addr == nullptr) {
+        return -1;
+    }
+
+    const long res = net_sendto(net->ns, net->sock, packet.data, packet.length, addr, &ipp_copy);
     loglogdata(net->log, "O=>", packet.data, packet.length, ip_port, res);
 
     assert(res <= INT_MAX);
+    net_addr_free(addr, net->mem);
     return (int)res;
 }
 
@@ -1013,11 +862,14 @@ non_null()
 static int receivepacket(const Network *ns, const Memory *mem, const Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
 {
     memset(ip_port, 0, sizeof(IP_Port));
-    Network_Addr addr = {{0}};
-    addr.size = sizeof(addr.addr);
+    Network_Addr *addr = net_addr_new(nullptr, 0, mem);
     *length = 0;
 
-    const int fail_or_len = net_recvfrom(ns, sock, data, MAX_UDP_PACKET_SIZE, &addr);
+    if (addr == nullptr) {
+        return -1;
+    }
+
+    const int fail_or_len = net_recvfrom(ns, sock, data, MAX_UDP_PACKET_SIZE, addr);
 
     if (fail_or_len < 0) {
         const int error = net_error();
@@ -1028,30 +880,33 @@ static int receivepacket(const Network *ns, const Memory *mem, const Logger *log
             net_kill_strerror(strerror);
         }
 
+        net_addr_free(addr, mem);
         return -1; /* Nothing received. */
     }
 
     *length = (uint32_t)fail_or_len;
 
-    if (addr.addr.ss_family == AF_INET) {
-        const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr.addr;
+    if (net_addr_is_ipv4(addr)) {
+        const struct sockaddr_in *addr_in = (const struct sockaddr_in *)net_addr_get_addr(addr);
 
         const Family *const family = make_tox_family(addr_in->sin_family);
         assert(family != nullptr);
 
         if (family == nullptr) {
+            net_addr_free(addr, mem);
             return -1;
         }
 
         ip_port->ip.family = *family;
         get_ip4(&ip_port->ip.ip.v4, &addr_in->sin_addr);
         ip_port->port = addr_in->sin_port;
-    } else if (addr.addr.ss_family == AF_INET6) {
-        const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)&addr.addr;
+    } else if (net_addr_is_ipv6(addr)) {
+        const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)net_addr_get_addr(addr);
         const Family *const family = make_tox_family(addr_in6->sin6_family);
         assert(family != nullptr);
 
         if (family == nullptr) {
+            net_addr_free(addr, mem);
             return -1;
         }
 
@@ -1064,11 +919,13 @@ static int receivepacket(const Network *ns, const Memory *mem, const Logger *log
             ip_port->ip.ip.v4.uint32 = ip_port->ip.ip.v6.uint32[3];
         }
     } else {
+        net_addr_free(addr, mem);
         return -1;
     }
 
     loglogdata(log, "=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
 
+    net_addr_free(addr, mem);
     return 0;
 }
 
@@ -1222,23 +1079,31 @@ Networking_Core *new_networking_ex(
 
     /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
     uint16_t *portptr = nullptr;
-    Network_Addr addr;
+    Network_Addr *addr = net_addr_new(nullptr, 0, mem);
 
-    memset(&addr.addr, 0, sizeof(struct sockaddr_storage));
+    if (addr == nullptr) {
+        kill_networking(temp);
+
+        if (error != nullptr) {
+            *error = 2;
+        }
+
+        return nullptr;
+    }
 
     if (net_family_is_ipv4(temp->family)) {
-        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr;
+        struct sockaddr_in *addr4 = (struct sockaddr_in *)net_addr_mut_addr(addr);
 
-        addr.size = sizeof(struct sockaddr_in);
+        net_addr_set_size(addr, sizeof(struct sockaddr_in));
         addr4->sin_family = AF_INET;
         addr4->sin_port = 0;
         fill_addr4(&ip->ip.v4, &addr4->sin_addr);
 
         portptr = &addr4->sin_port;
     } else if (net_family_is_ipv6(temp->family)) {
-        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr;
+        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)net_addr_mut_addr(addr);
 
-        addr.size = sizeof(struct sockaddr_in6);
+        net_addr_set_size(addr, sizeof(struct sockaddr_in6));
         addr6->sin6_family = AF_INET6;
         addr6->sin6_port = 0;
         fill_addr6(&ip->ip.v6, &addr6->sin6_addr);
@@ -1249,6 +1114,7 @@ Networking_Core *new_networking_ex(
         portptr = &addr6->sin6_port;
     } else {
         mem_delete(mem, temp);
+        net_addr_free(addr, mem);
         return nullptr;
     }
 
@@ -1305,7 +1171,7 @@ Networking_Core *new_networking_ex(
     *portptr = net_htons(port_to_try);
 
     for (uint16_t tries = port_from; tries <= port_to; ++tries) {
-        const int res = net_bind(ns, temp->sock, &addr);
+        const int res = net_bind(ns, temp->sock, addr);
 
         if (res == 0) {
             temp->port = *portptr;
@@ -1325,6 +1191,7 @@ Networking_Core *new_networking_ex(
                 *error = 0;
             }
 
+            net_addr_free(addr, mem);
             return temp;
         }
 
@@ -1349,6 +1216,7 @@ Networking_Core *new_networking_ex(
         *error = 1;
     }
 
+    net_addr_free(addr, mem);
     return nullptr;
 }
 
@@ -1777,6 +1645,7 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to
         IP_Port *tmp = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
 
         if (tmp == nullptr) {
+            *res = nullptr;
             return -1;
         }
 
@@ -1788,7 +1657,11 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     if ((true)) {
         *res = (IP_Port *)mem_alloc(mem, sizeof(IP_Port));
-        assert(*res != nullptr);
+
+        if (*res == nullptr) {
+            return -1;
+        }
+
         IP_Port *ip_port = *res;
         ip_port->ip.ip.v4.uint32 = net_htonl(0x7F000003); // 127.0.0.3
         ip_port->ip.family = *make_tox_family(AF_INET);
@@ -1877,27 +1750,31 @@ void net_freeipport(const Memory *mem, IP_Port *ip_ports)
     mem_delete(mem, ip_ports);
 }
 
-bool bind_to_port(const Network *ns, Socket sock, Family family, uint16_t port)
+bool bind_to_port(const Network *ns, const Memory *mem, Socket sock, Family family, uint16_t port)
 {
-    Network_Addr addr = {{0}};
+    Network_Addr *addr;
 
     if (net_family_is_ipv4(family)) {
-        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr;
+        struct sockaddr_in addr4 = {0};
 
-        addr.size = sizeof(struct sockaddr_in);
-        addr4->sin_family = AF_INET;
-        addr4->sin_port = net_htons(port);
+        addr4.sin_family = AF_INET;
+        addr4.sin_port = net_htons(port);
+
+        addr = net_addr_new(&addr4, sizeof(addr4), mem);
     } else if (net_family_is_ipv6(family)) {
-        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr;
+        struct sockaddr_in6 addr6 = {0};
 
-        addr.size = sizeof(struct sockaddr_in6);
-        addr6->sin6_family = AF_INET6;
-        addr6->sin6_port = net_htons(port);
+        addr6.sin6_family = AF_INET6;
+        addr6.sin6_port = net_htons(port);
+
+        addr = net_addr_new(&addr6, sizeof(addr6), mem);
     } else {
         return false;
     }
 
-    return net_bind(ns, sock, &addr) == 0;
+    const bool ok = net_bind(ns, sock, addr) == 0;
+    net_addr_free(addr, mem);
+    return ok;
 }
 
 Socket net_socket(const Network *ns, Family domain, int type, int protocol)
@@ -1905,13 +1782,13 @@ Socket net_socket(const Network *ns, Family domain, int type, int protocol)
     const int platform_domain = make_family(domain);
     const int platform_type = make_socktype(type);
     const int platform_prot = make_proto(protocol);
-    const Socket sock = {ns->funcs->socket(ns->obj, platform_domain, platform_type, platform_prot)};
+    const Socket sock = {tox_network_socket(ns, platform_domain, platform_type, platform_prot)};
     return sock;
 }
 
 uint16_t net_socket_data_recv_buffer(const Network *ns, Socket sock)
 {
-    const int count = ns->funcs->recvbuf(ns->obj, sock.sock);
+    const int count = tox_network_recvbuf(ns, sock.sock);
     return (uint16_t)max_s32(0, min_s32(count, UINT16_MAX));
 }
 
diff --git a/toxcore/network.h b/toxcore/network.h
index 2f518c1d910..59b4a10a019 100644
--- a/toxcore/network.h
+++ b/toxcore/network.h
@@ -15,62 +15,12 @@
 
 #include "logger.h"
 #include "mem.h"
+#include "tox_network.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/**
- * @brief Wrapper for sockaddr_storage and size.
- */
-typedef struct Network_Addr Network_Addr;
-
-typedef int net_close_cb(void *obj, int sock);
-typedef int net_accept_cb(void *obj, int sock);
-typedef int net_bind_cb(void *obj, int sock, const Network_Addr *addr);
-typedef int net_listen_cb(void *obj, int sock, int backlog);
-typedef int net_recvbuf_cb(void *obj, int sock);
-typedef int net_recv_cb(void *obj, int sock, uint8_t *buf, size_t len);
-typedef int net_recvfrom_cb(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr);
-typedef int net_send_cb(void *obj, int sock, const uint8_t *buf, size_t len);
-typedef int net_sendto_cb(void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr);
-typedef int net_socket_cb(void *obj, int domain, int type, int proto);
-typedef int net_socket_nonblock_cb(void *obj, int sock, bool nonblock);
-typedef int net_getsockopt_cb(void *obj, int sock, int level, int optname, void *optval, size_t *optlen);
-typedef int net_setsockopt_cb(void *obj, int sock, int level, int optname, const void *optval, size_t optlen);
-typedef int net_getaddrinfo_cb(void *obj, int family, Network_Addr **addrs);
-typedef int net_freeaddrinfo_cb(void *obj, Network_Addr *addrs);
-
-/** @brief Functions wrapping POSIX network functions.
- *
- * Refer to POSIX man pages for documentation of what these functions are
- * expected to do when providing alternative Network implementations.
- */
-typedef struct Network_Funcs {
-    net_close_cb *close;
-    net_accept_cb *accept;
-    net_bind_cb *bind;
-    net_listen_cb *listen;
-    net_recvbuf_cb *recvbuf;
-    net_recv_cb *recv;
-    net_recvfrom_cb *recvfrom;
-    net_send_cb *send;
-    net_sendto_cb *sendto;
-    net_socket_cb *socket;
-    net_socket_nonblock_cb *socket_nonblock;
-    net_getsockopt_cb *getsockopt;
-    net_setsockopt_cb *setsockopt;
-    net_getaddrinfo_cb *getaddrinfo;
-    net_freeaddrinfo_cb *freeaddrinfo;
-} Network_Funcs;
-
-typedef struct Network {
-    const Network_Funcs *funcs;
-    void *obj;
-} Network;
-
-const Network *system_network(void);
-
 typedef struct Family {
     uint8_t value;
 } Family;
@@ -267,6 +217,8 @@ typedef struct Socket {
     int sock;
 } Socket;
 
+typedef Tox_Network Network;
+
 non_null()
 Socket net_socket(const Network *ns, Family domain, int type, int protocol);
 
@@ -560,7 +512,7 @@ void net_freeipport(const Memory *mem, IP_Port *ip_ports);
  * @return true on success, false on failure.
  */
 non_null()
-bool bind_to_port(const Network *ns, Socket sock, Family family, uint16_t port);
+bool bind_to_port(const Network *ns, const Memory *mem, Socket sock, Family family, uint16_t port);
 
 /** @brief Get the last networking error code.
  *
diff --git a/toxcore/onion.c b/toxcore/onion.c
index d7ec8bfd788..8a885c37ac3 100644
--- a/toxcore/onion.c
+++ b/toxcore/onion.c
@@ -113,7 +113,7 @@ static int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data
  * return -1 on failure.
  * return 0 on success.
  */
-int create_onion_path(const Random *rng, const DHT *dht, Onion_Path *new_path, const Node_format *nodes)
+int create_onion_path(const Tox_Random *rng, const DHT *dht, Onion_Path *new_path, const Node_format *nodes)
 {
     if (new_path == nullptr || nodes == nullptr) {
         return -1;
@@ -178,7 +178,7 @@ int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_
  */
 int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_length,
                         const Onion_Path *path, const IP_Port *dest,
-                        const uint8_t *data, uint16_t length)
+                        const uint8_t *data, uint16_t length, const Memory *mem)
 {
     if (1 + length + SEND_1 > max_packet_length || length == 0) {
         return -1;
@@ -197,7 +197,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_
     memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE);
 
     int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, SIZEOF_VLA(step1),
-                                     step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE);
+                                     step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) {
         return -1;
@@ -207,7 +207,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_
     ipport_pack(step3, &path->ip_port2);
     memcpy(step3 + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE);
     len = encrypt_data_symmetric(path->shared_key2, nonce, step2, SIZEOF_VLA(step2),
-                                 step3 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE);
+                                 step3 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) {
         return -1;
@@ -218,7 +218,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_
     memcpy(packet + 1 + CRYPTO_NONCE_SIZE, path->public_key1, CRYPTO_PUBLIC_KEY_SIZE);
 
     len = encrypt_data_symmetric(path->shared_key1, nonce, step3, SIZEOF_VLA(step3),
-                                 packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE);
+                                 packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if (len != SIZE_IPPORT + SEND_BASE * 2 + length + CRYPTO_MAC_SIZE) {
         return -1;
@@ -236,9 +236,9 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_
  * return -1 on failure.
  * return length of created packet on success.
  */
-int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_packet_length,
+int create_onion_packet_tcp(const Tox_Random *rng, uint8_t *packet, uint16_t max_packet_length,
                             const Onion_Path *path, const IP_Port *dest,
-                            const uint8_t *data, uint16_t length)
+                            const uint8_t *data, uint16_t length, const Memory *mem)
 {
     if (CRYPTO_NONCE_SIZE + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) {
         return -1;
@@ -257,7 +257,7 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac
     memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE);
 
     int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, SIZEOF_VLA(step1),
-                                     step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE);
+                                     step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) {
         return -1;
@@ -266,7 +266,7 @@ int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_pac
     ipport_pack(packet + CRYPTO_NONCE_SIZE, &path->ip_port2);
     memcpy(packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE);
     len = encrypt_data_symmetric(path->shared_key2, nonce, step2, SIZEOF_VLA(step2),
-                                 packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE);
+                                 packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) {
         return -1;
@@ -328,7 +328,7 @@ static int handle_send_initial(void *object, const IP_Port *source, const uint8_
     }
 
     const int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
-                                     length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain);
+                                     length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain, onion->mem);
 
     if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE)) {
         return 1;
@@ -364,7 +364,7 @@ int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, const I
     uint8_t *ret_part = data + data_len;
     random_nonce(onion->rng, ret_part);
     len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT,
-                                 ret_part + CRYPTO_NONCE_SIZE);
+                                 ret_part + CRYPTO_NONCE_SIZE, onion->mem);
 
     if (len != SIZE_IPPORT + CRYPTO_MAC_SIZE) {
         return 1;
@@ -404,7 +404,7 @@ static int handle_send_1(void *object, const IP_Port *source, const uint8_t *pac
     }
 
     int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
-                                     length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain);
+                                     length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain, onion->mem);
 
     if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1 + CRYPTO_MAC_SIZE)) {
         return 1;
@@ -427,7 +427,7 @@ static int handle_send_1(void *object, const IP_Port *source, const uint8_t *pac
     ipport_pack(ret_data, source);
     memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1);
     len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data),
-                                 ret_part + CRYPTO_NONCE_SIZE);
+                                 ret_part + CRYPTO_NONCE_SIZE, onion->mem);
 
     if (len != RETURN_2 - CRYPTO_NONCE_SIZE) {
         return 1;
@@ -467,7 +467,7 @@ static int handle_send_2(void *object, const IP_Port *source, const uint8_t *pac
     }
 
     int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
-                                     length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain);
+                                     length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain, onion->mem);
 
     if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2 + CRYPTO_MAC_SIZE)) {
         return 1;
@@ -497,7 +497,7 @@ static int handle_send_2(void *object, const IP_Port *source, const uint8_t *pac
     ipport_pack(ret_data, source);
     memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2);
     len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data),
-                                 ret_part + CRYPTO_NONCE_SIZE);
+                                 ret_part + CRYPTO_NONCE_SIZE, onion->mem);
 
     if (len != RETURN_3 - CRYPTO_NONCE_SIZE) {
         return 1;
@@ -537,7 +537,7 @@ static int handle_recv_3(void *object, const IP_Port *source, const uint8_t *pac
 
     uint8_t plain[SIZE_IPPORT + RETURN_2];
     const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE,
-                                     SIZE_IPPORT + RETURN_2 + CRYPTO_MAC_SIZE, plain);
+                                     SIZE_IPPORT + RETURN_2 + CRYPTO_MAC_SIZE, plain, onion->mem);
 
     if ((uint32_t)len != sizeof(plain)) {
         return 1;
@@ -586,7 +586,7 @@ static int handle_recv_2(void *object, const IP_Port *source, const uint8_t *pac
 
     uint8_t plain[SIZE_IPPORT + RETURN_1];
     const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE,
-                                     SIZE_IPPORT + RETURN_1 + CRYPTO_MAC_SIZE, plain);
+                                     SIZE_IPPORT + RETURN_1 + CRYPTO_MAC_SIZE, plain, onion->mem);
 
     if ((uint32_t)len != sizeof(plain)) {
         return 1;
@@ -635,7 +635,7 @@ static int handle_recv_1(void *object, const IP_Port *source, const uint8_t *pac
 
     uint8_t plain[SIZE_IPPORT];
     const int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE,
-                                     SIZE_IPPORT + CRYPTO_MAC_SIZE, plain);
+                                     SIZE_IPPORT + CRYPTO_MAC_SIZE, plain, onion->mem);
 
     if ((uint32_t)len != SIZE_IPPORT) {
         return 1;
@@ -668,7 +668,7 @@ void set_callback_handle_recv_1(Onion *onion, onion_recv_1_cb *function, void *o
     onion->callback_object = object;
 }
 
-Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_time, const Random *rng, DHT *dht)
+Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_time, const Tox_Random *rng, DHT *dht)
 {
     if (dht == nullptr) {
         return nullptr;
diff --git a/toxcore/onion.h b/toxcore/onion.h
index 7f71c2493d3..edc7013b262 100644
--- a/toxcore/onion.h
+++ b/toxcore/onion.h
@@ -19,7 +19,7 @@ typedef int onion_recv_1_cb(void *object, const IP_Port *dest, const uint8_t *da
 typedef struct Onion {
     const Logger *log;
     const Mono_Time *mono_time;
-    const Random *rng;
+    const Tox_Random *rng;
     const Memory *mem;
     DHT *dht;
     Networking_Core *net;
@@ -81,7 +81,7 @@ typedef struct Onion_Path {
  * return 0 on success.
  */
 non_null()
-int create_onion_path(const Random *rng, const DHT *dht, Onion_Path *new_path, const Node_format *nodes);
+int create_onion_path(const Tox_Random *rng, const DHT *dht, Onion_Path *new_path, const Node_format *nodes);
 
 /** @brief Dump nodes in onion path to nodes of length num_nodes.
  *
@@ -103,7 +103,7 @@ int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_
 non_null()
 int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_length,
                         const Onion_Path *path, const IP_Port *dest,
-                        const uint8_t *data, uint16_t length);
+                        const uint8_t *data, uint16_t length, const Memory *mem);
 
 
 /** @brief Create a onion packet to be sent over tcp.
@@ -118,7 +118,7 @@ int create_onion_packet(const Random *rng, uint8_t *packet, uint16_t max_packet_
 non_null()
 int create_onion_packet_tcp(const Random *rng, uint8_t *packet, uint16_t max_packet_length,
                             const Onion_Path *path, const IP_Port *dest,
-                            const uint8_t *data, uint16_t length);
+                            const uint8_t *data, uint16_t length, const Memory *mem);
 
 /** @brief Create and send a onion response sent initially to dest with.
  * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE.
@@ -148,7 +148,7 @@ non_null(1) nullable(2, 3)
 void set_callback_handle_recv_1(Onion *onion, onion_recv_1_cb *function, void *object);
 
 non_null()
-Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_time, const Random *rng, DHT *dht);
+Onion *new_onion(const Logger *log, const Memory *mem, const Mono_Time *mono_time, const Tox_Random *rng, DHT *dht);
 
 nullable(1)
 void kill_onion(Onion *onion);
diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c
index 551e7b1fae9..535678ba648 100644
--- a/toxcore/onion_announce.c
+++ b/toxcore/onion_announce.c
@@ -50,7 +50,7 @@ typedef struct Onion_Announce_Entry {
 struct Onion_Announce {
     const Logger *log;
     const Mono_Time *mono_time;
-    const Random *rng;
+    const Tox_Random *rng;
     const Memory *mem;
     DHT     *dht;
     Networking_Core *net;
@@ -97,7 +97,7 @@ void onion_announce_entry_set_time(Onion_Announce *onion_a, uint32_t entry, uint
  * return -1 on failure.
  * return packet length on success.
  */
-int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,
+int create_announce_request(const Random *rng, const Memory *mem, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,
                             const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id,
                             const uint8_t *data_public_key, uint64_t sendback_data)
 {
@@ -117,7 +117,7 @@ int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_pac
     random_nonce(rng, packet + 1);
 
     const int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, sizeof(plain),
-                                 packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE);
+                                 packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if ((uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE != ONION_ANNOUNCE_REQUEST_MIN_SIZE) {
         return -1;
@@ -140,8 +140,9 @@ int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_pac
  * return -1 on failure.
  * return 0 on success.
  */
-int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key,
-                        const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length)
+int create_data_request(const Random *rng, const Memory *mem, uint8_t *packet, uint16_t max_packet_length,
+                        const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
+                        const uint8_t *data, uint16_t length)
 {
     if (DATA_REQUEST_MIN_SIZE + length > max_packet_length) {
         return -1;
@@ -162,7 +163,7 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_
     memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, random_public_key, CRYPTO_PUBLIC_KEY_SIZE);
 
     const int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length,
-                                 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE);
+                                 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, mem);
 
     if (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len != DATA_REQUEST_MIN_SIZE +
             length) {
@@ -186,14 +187,14 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_
  * return -1 on failure.
  * return 0 on success.
  */
-int send_announce_request(const Networking_Core *net, const Random *rng,
+int send_announce_request(const Networking_Core *net, const Tox_Random *rng, const Memory *mem,
                           const Onion_Path *path, const Node_format *dest,
                           const uint8_t *public_key, const uint8_t *secret_key,
                           const uint8_t *ping_id, const uint8_t *client_id,
                           const uint8_t *data_public_key, uint64_t sendback_data)
 {
     uint8_t request[ONION_ANNOUNCE_REQUEST_MIN_SIZE];
-    int len = create_announce_request(rng, request, sizeof(request), dest->public_key, public_key, secret_key, ping_id,
+    int len = create_announce_request(rng, mem, request, sizeof(request), dest->public_key, public_key, secret_key, ping_id,
                                       client_id, data_public_key, sendback_data);
 
     if (len != sizeof(request)) {
@@ -201,7 +202,7 @@ int send_announce_request(const Networking_Core *net, const Random *rng,
     }
 
     uint8_t packet[ONION_MAX_PACKET_SIZE];
-    len = create_onion_packet(rng, packet, sizeof(packet), path, &dest->ip_port, request, sizeof(request));
+    len = create_onion_packet(rng, packet, sizeof(packet), path, &dest->ip_port, request, sizeof(request), mem);
 
     if (len == -1) {
         return -1;
@@ -230,19 +231,20 @@ int send_announce_request(const Networking_Core *net, const Random *rng,
  * return -1 on failure.
  * return 0 on success.
  */
-int send_data_request(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest,
+int send_data_request(const Networking_Core *net, const Random *rng, const Memory *mem,
+                      const Onion_Path *path, const IP_Port *dest,
                       const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
                       const uint8_t *data, uint16_t length)
 {
     uint8_t request[ONION_MAX_DATA_SIZE];
-    int len = create_data_request(rng, request, sizeof(request), public_key, encrypt_public_key, nonce, data, length);
+    int len = create_data_request(rng, mem, request, sizeof(request), public_key, encrypt_public_key, nonce, data, length);
 
     if (len == -1) {
         return -1;
     }
 
     uint8_t packet[ONION_MAX_PACKET_SIZE];
-    len = create_onion_packet(rng, packet, sizeof(packet), path, dest, request, len);
+    len = create_onion_packet(rng, packet, sizeof(packet), path, dest, request, len, mem);
 
     if (len == -1) {
         return -1;
@@ -448,7 +450,7 @@ static int handle_announce_request_common(
     }
 
     const int decrypted_len = decrypt_data_symmetric(shared_key, packet + 1,
-                              packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, plain_size + CRYPTO_MAC_SIZE, plain);
+                              packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, plain_size + CRYPTO_MAC_SIZE, plain, onion_a->mem);
 
     if ((uint32_t)decrypted_len != plain_size) {
         mem_delete(onion_a->mem, plain);
@@ -535,7 +537,7 @@ static int handle_announce_request_common(
 
     uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE];
     const int len = encrypt_data_symmetric(shared_key, nonce, response, offset,
-                                           data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE);
+                                           data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, onion_a->mem);
 
     if (len != offset + CRYPTO_MAC_SIZE) {
         LOGGER_ERROR(onion_a->log, "Failed to encrypt announce response");
@@ -642,7 +644,7 @@ static int handle_data_request(void *object, const IP_Port *source, const uint8_
     return 0;
 }
 
-Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time, DHT *dht)
+Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const Tox_Random *rng, const Mono_Time *mono_time, DHT *dht)
 {
     if (dht == nullptr) {
         return nullptr;
diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h
index 857f4706ace..4243cb7daa6 100644
--- a/toxcore/onion_announce.h
+++ b/toxcore/onion_announce.h
@@ -59,9 +59,10 @@ void onion_announce_entry_set_time(Onion_Announce *onion_a, uint32_t entry, uint
  * return packet length on success.
  */
 non_null()
-int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,
-                            const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id,
-                            const uint8_t *data_public_key, uint64_t sendback_data);
+int create_announce_request(
+        const Random *rng, const Memory *mem, uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,
+        const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id,
+        const uint8_t *data_public_key, uint64_t sendback_data);
 
 /** @brief Create an onion data request packet in packet of max_packet_length.
  *
@@ -76,8 +77,9 @@ int create_announce_request(const Random *rng, uint8_t *packet, uint16_t max_pac
  * return 0 on success.
  */
 non_null()
-int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key,
-                        const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length);
+int create_data_request(const Random *rng, const Memory *mem, uint8_t *packet, uint16_t max_packet_length,
+                        const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
+                        const uint8_t *data, uint16_t length);
 
 /** @brief Create and send an onion announce request packet.
  *
@@ -94,7 +96,7 @@ int create_data_request(const Random *rng, uint8_t *packet, uint16_t max_packet_
  * return 0 on success.
  */
 non_null()
-int send_announce_request(const Networking_Core *net, const Random *rng,
+int send_announce_request(const Networking_Core *net, const Tox_Random *rng, const Memory *mem,
                           const Onion_Path *path, const Node_format *dest,
                           const uint8_t *public_key, const uint8_t *secret_key,
                           const uint8_t *ping_id, const uint8_t *client_id,
@@ -117,7 +119,8 @@ int send_announce_request(const Networking_Core *net, const Random *rng,
  * return 0 on success.
  */
 non_null()
-int send_data_request(const Networking_Core *net, const Random *rng, const Onion_Path *path, const IP_Port *dest,
+int send_data_request(const Networking_Core *net, const Random *rng, const Memory *mem,
+                      const Onion_Path *path, const IP_Port *dest,
                       const uint8_t *public_key, const uint8_t *encrypt_public_key, const uint8_t *nonce,
                       const uint8_t *data, uint16_t length);
 
@@ -131,7 +134,7 @@ void onion_announce_extra_data_callback(Onion_Announce *onion_a, uint16_t extra_
                                         pack_extra_data_cb *extra_data_callback, void *extra_data_object);
 
 non_null()
-Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time, DHT *dht);
+Onion_Announce *new_onion_announce(const Logger *log, const Memory *mem, const Tox_Random *rng, const Mono_Time *mono_time, DHT *dht);
 
 nullable(1)
 void kill_onion_announce(Onion_Announce *onion_a);
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c
index 6aef15ec3a8..298d4f923da 100644
--- a/toxcore/onion_client.c
+++ b/toxcore/onion_client.c
@@ -105,7 +105,7 @@ typedef struct Onion_Data_Handler {
 struct Onion_Client {
     const Mono_Time *mono_time;
     const Logger *logger;
-    const Random *rng;
+    const Tox_Random *rng;
     const Memory *mem;
 
     DHT     *dht;
@@ -526,7 +526,7 @@ static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Pa
 {
     if (net_family_is_ipv4(path->ip_port1.ip.family) || net_family_is_ipv6(path->ip_port1.ip.family)) {
         uint8_t packet[ONION_MAX_PACKET_SIZE];
-        const int len = create_onion_packet(onion_c->rng, packet, sizeof(packet), path, dest, data, length);
+        const int len = create_onion_packet(onion_c->rng, packet, sizeof(packet), path, dest, data, length, onion_c->mem);
 
         if (len == -1) {
             return -1;
@@ -543,7 +543,7 @@ static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Pa
 
     if (ip_port_to_tcp_connections_number(&path->ip_port1, &tcp_connections_number)) {
         uint8_t packet[ONION_MAX_PACKET_SIZE];
-        const int len = create_onion_packet_tcp(onion_c->rng, packet, sizeof(packet), path, dest, data, length);
+        const int len = create_onion_packet_tcp(onion_c->rng, packet, sizeof(packet), path, dest, data, length, onion_c->mem);
 
         if (len == -1) {
             return -1;
@@ -655,7 +655,7 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
 
     if (num == 0) {
         len = create_announce_request(
-                  onion_c->rng, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c),
+                  onion_c->rng, onion_c->mem, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c),
                   nc_get_self_secret_key(onion_c->c), ping_id, nc_get_self_public_key(onion_c->c),
                   onion_c->temp_public_key, sendback);
     } else {
@@ -663,7 +663,7 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
 
         if (onion_friend->gc_data_length == 0) { // contact is a friend
             len = create_announce_request(
-                      onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key,
+                      onion_c->rng, onion_c->mem, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key,
                       onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key,
                       zero_ping_id, sendback);
         } else { // contact is a gc
@@ -671,7 +671,7 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
             onion_friend->is_groupchat = true;
 
             len = create_gca_announce_request(
-                      onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key,
+                      onion_c->rng, onion_c->mem, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key,
                       onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key,
                       zero_ping_id, sendback, onion_friend->gc_data,
                       onion_friend->gc_data_length);
@@ -954,7 +954,8 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
         len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c),
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
-                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
+                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain,
+                           onion_c->mem);
     } else {
         if (!onion_c->friends_list[num - 1].is_valid) {
             return 1;
@@ -963,7 +964,8 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
         len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
-                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
+                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain,
+                           onion_c->mem);
     }
 
     if ((uint32_t)len != plain_size) {
@@ -1044,7 +1046,8 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con
         len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c),
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
-                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
+                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain,
+                           onion_c->mem);
     } else {
         if (!onion_c->friends_list[num - 1].is_valid) {
             return 1;
@@ -1053,7 +1056,8 @@ static int handle_announce_response_old(void *object, const IP_Port *source, con
         len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
                            packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
-                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
+                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain,
+                           onion_c->mem);
     }
 
     if ((uint32_t)len != SIZEOF_VLA(plain)) {
@@ -1103,7 +1107,8 @@ static int handle_data_response(void *object, const IP_Port *source, const uint8
     VLA(uint8_t, temp_plain, length - ONION_DATA_RESPONSE_MIN_SIZE);
     int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, onion_c->temp_secret_key, packet + 1,
                            packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
-                           length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), temp_plain);
+                           length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), temp_plain,
+                           onion_c->mem);
 
     if ((uint32_t)len != SIZEOF_VLA(temp_plain)) {
         return 1;
@@ -1112,7 +1117,8 @@ static int handle_data_response(void *object, const IP_Port *source, const uint8
     VLA(uint8_t, plain, SIZEOF_VLA(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE);
     len = decrypt_data(temp_plain, nc_get_self_secret_key(onion_c->c),
                        packet + 1, temp_plain + CRYPTO_PUBLIC_KEY_SIZE,
-                       SIZEOF_VLA(temp_plain) - CRYPTO_PUBLIC_KEY_SIZE, plain);
+                       SIZEOF_VLA(temp_plain) - CRYPTO_PUBLIC_KEY_SIZE, plain,
+                       onion_c->mem);
 
     if ((uint32_t)len != SIZEOF_VLA(plain)) {
         return 1;
@@ -1270,7 +1276,8 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data,
     memcpy(packet, nc_get_self_public_key(onion_c->c), CRYPTO_PUBLIC_KEY_SIZE);
     int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key,
                            nc_get_self_secret_key(onion_c->c), nonce, data,
-                           length, packet + CRYPTO_PUBLIC_KEY_SIZE);
+                           length, packet + CRYPTO_PUBLIC_KEY_SIZE,
+                           onion_c->mem);
 
     if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE != SIZEOF_VLA(packet)) {
         return -1;
@@ -1287,7 +1294,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data,
 
         uint8_t o_packet[ONION_MAX_PACKET_SIZE];
         len = create_data_request(
-                  onion_c->rng, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key,
+                  onion_c->rng, onion_c->mem, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key,
                   node_list[good_nodes[i]].data_public_key, nonce, packet, SIZEOF_VLA(packet));
 
         if (len == -1) {
@@ -1328,7 +1335,8 @@ static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uin
     memcpy(temp + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
     int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key,
                            nc_get_self_secret_key(onion_c->c), nonce, data,
-                           length, temp + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                           length, temp + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
+                           onion_c->mem);
 
     if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE != SIZEOF_VLA(temp)) {
         return -1;
@@ -1337,7 +1345,7 @@ static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uin
     uint8_t packet_data[MAX_CRYPTO_REQUEST_SIZE];
     len = create_request(
               onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data,
-              onion_c->friends_list[friend_num].dht_public_key, temp, SIZEOF_VLA(temp), CRYPTO_PACKET_DHTPK);
+              onion_c->friends_list[friend_num].dht_public_key, temp, SIZEOF_VLA(temp), CRYPTO_PACKET_DHTPK, onion_c->mem);
     assert(len <= UINT16_MAX);
     const Packet packet = {packet_data, (uint16_t)len};
 
@@ -1366,7 +1374,8 @@ static int handle_dht_dhtpk(void *object, const IP_Port *source, const uint8_t *
     const int len = decrypt_data(packet, nc_get_self_secret_key(onion_c->c),
                                  packet + CRYPTO_PUBLIC_KEY_SIZE,
                                  packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
-                                 length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), plain);
+                                 length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), plain,
+                                 onion_c->mem);
 
     if (len != length - (DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE)) {
         return 1;
@@ -2075,7 +2084,7 @@ void do_onion_client(Onion_Client *onion_c)
     onion_c->last_run = mono_time_get(onion_c->mono_time);
 }
 
-Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Random *rng, const Mono_Time *mono_time, Net_Crypto *c)
+Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Tox_Random *rng, const Mono_Time *mono_time, Net_Crypto *c)
 {
     if (c == nullptr) {
         return nullptr;
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h
index 6498f8c5c39..f6db95a6a51 100644
--- a/toxcore/onion_client.h
+++ b/toxcore/onion_client.h
@@ -208,7 +208,7 @@ non_null()
 void do_onion_client(Onion_Client *onion_c);
 
 non_null()
-Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Random *rng, const Mono_Time *mono_time, Net_Crypto *c);
+Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Tox_Random *rng, const Mono_Time *mono_time, Net_Crypto *c);
 
 nullable(1)
 void kill_onion_client(Onion_Client *onion_c);
diff --git a/toxcore/os_logger.c b/toxcore/os_logger.c
new file mode 100644
index 00000000000..8c425777a66
--- /dev/null
+++ b/toxcore/os_logger.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "os_logger.h"
+
+#include "ccompat.h"
+#include "tox_logger_impl.h"
+
+non_null()
+static void os_logger_log(
+        void *self, Tox_Log_Level level,
+        const char *file, uint32_t line, const char *func,
+        const char *message)
+{
+    // Do nothing with the log message by default.
+    return;
+}
+
+static const Tox_Logger_Funcs os_logger_funcs = {
+    os_logger_log,
+};
+
+static const Tox_Logger os_logger_obj = {&os_logger_funcs};
+
+const Tox_Logger *os_logger(void)
+{
+    return &os_logger_obj;
+}
diff --git a/toxcore/os_logger.h b/toxcore/os_logger.h
new file mode 100644
index 00000000000..ff3b61100a8
--- /dev/null
+++ b/toxcore/os_logger.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_OS_LOGGER_H
+#define C_TOXCORE_TOXCORE_OS_LOGGER_H
+
+#include "tox_logger.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const Tox_Logger *os_logger(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_OS_LOGGER_H
diff --git a/toxcore/os_memory.c b/toxcore/os_memory.c
new file mode 100644
index 00000000000..90b64e45681
--- /dev/null
+++ b/toxcore/os_memory.c
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "os_memory.h"
+
+#include <stdlib.h>
+
+#include "ccompat.h"
+#include "tox_memory_impl.h"
+
+non_null()
+static void *os_malloc(void *self, uint32_t size)
+{
+    return malloc(size);
+}
+
+non_null(1) nullable(2)
+static void *os_realloc(void *self, void *ptr, uint32_t size)
+{
+    return realloc(ptr, size);
+}
+
+non_null(1) nullable(2)
+static void os_free(void *self, void *ptr)
+{
+    free(ptr);
+}
+
+static const Tox_Memory_Funcs os_memory_funcs = {
+    os_malloc,
+    os_realloc,
+    os_free,
+};
+static const Tox_Memory os_memory_obj = {&os_memory_funcs};
+
+const Tox_Memory *os_memory(void)
+{
+    return &os_memory_obj;
+}
diff --git a/toxcore/os_memory.h b/toxcore/os_memory.h
new file mode 100644
index 00000000000..8cd728e2399
--- /dev/null
+++ b/toxcore/os_memory.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_OS_MEMORY_H
+#define C_TOXCORE_TOXCORE_OS_MEMORY_H
+
+#include "tox_memory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const Tox_Memory *os_memory(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_OS_MEMORY_H
diff --git a/toxcore/os_network.c b/toxcore/os_network.c
new file mode 100644
index 00000000000..48097d43515
--- /dev/null
+++ b/toxcore/os_network.c
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#ifdef __APPLE__
+#define _DARWIN_C_SOURCE
+#endif
+
+// For Solaris.
+#ifdef __sun
+#define __EXTENSIONS__ 1
+#endif
+
+// For Linux (and some BSDs).
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 700
+#endif
+
+#if defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_WINXP
+#undef _WIN32_WINNT
+#define _WIN32_WINNT  0x501
+#endif
+
+#if !defined(OS_WIN32) && (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
+#define OS_WIN32
+#endif
+
+#if defined(OS_WIN32) && !defined(WINVER)
+// Windows XP
+#define WINVER 0x0501
+#endif
+
+#include "os_network.h"
+
+#ifdef OS_WIN32 // Put win32 includes here
+// The mingw32/64 Windows library warns about including winsock2.h after
+// windows.h even though with the above it's a valid thing to do. So, to make
+// mingw32 headers happy, we include winsock2.h first.
+#include <winsock2.h>
+// Comment line here to avoid reordering by source code formatters.
+#include <windows.h>
+#include <ws2tcpip.h>
+#endif
+
+#if !defined(OS_WIN32)
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef __sun
+#include <stropts.h>
+#include <sys/filio.h>
+#endif
+
+#else
+#ifndef IPV6_V6ONLY
+#define IPV6_V6ONLY 27
+#endif
+#endif
+
+#include <assert.h>
+#include <string.h>  // memcpy
+
+#include "ccompat.h"
+#include "os_network_impl.h"
+#include "tox_network_impl.h"
+
+// Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD
+#if !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+non_null()
+static int os_close(void *self, int sock)
+{
+#if defined(OS_WIN32)
+    return closesocket(sock);
+#else  // !OS_WIN32
+    return close(sock);
+#endif
+}
+
+struct Network_Addr {
+    struct sockaddr_storage addr;
+    size_t size;
+};
+
+Network_Addr *net_addr_new(const void *data, size_t size, const Tox_Memory *mem)
+{
+    Network_Addr *addr = (Network_Addr *)tox_memory_malloc(mem, sizeof(Network_Addr));
+
+    if (addr == nullptr) {
+        return nullptr;
+    }
+
+    if (data != nullptr) {
+        net_addr_set(addr, data, size);
+    } else {
+        addr->size = sizeof(struct sockaddr_storage);
+    }
+
+    return addr;
+}
+
+void net_addr_free(Network_Addr *addr, const Tox_Memory *mem)
+{
+    tox_memory_dealloc(mem, addr);
+}
+
+void net_addr_set(Network_Addr *addr, const void *data, size_t size)
+{
+    assert(size <= sizeof(struct sockaddr_storage));
+    memcpy(&addr->addr, data, size);
+    addr->size = size;
+}
+
+void *net_addr_mut_addr(Network_Addr *addr)
+{
+    return &addr->addr;
+}
+
+const void *net_addr_get_addr(const Network_Addr *addr)
+{
+    return &addr->addr;
+}
+
+void net_addr_set_size(Network_Addr *addr, size_t size)
+{
+    addr->size = size;
+}
+
+size_t net_addr_get_size(const Network_Addr *addr)
+{
+    return addr->size;
+}
+
+bool net_addr_is_ipv4(const Network_Addr *addr)
+{
+    return addr->addr.ss_family == AF_INET;
+}
+
+bool net_addr_is_ipv6(const Network_Addr *addr)
+{
+    return addr->addr.ss_family == AF_INET6;
+}
+
+uint16_t net_addr_get_port(const Network_Addr *addr)
+{
+    const int family = addr->addr.ss_family;
+    if (family == AF_INET6) {
+        const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)&addr->addr;
+        return addr6->sin6_port;
+    } else {
+        assert(family == AF_INET);
+        const struct sockaddr_in *addr4 = (const struct sockaddr_in *)&addr->addr;
+        return addr4->sin_port;
+    }
+}
+
+
+non_null()
+static int os_accept(void *self, int sock)
+{
+    return accept(sock, nullptr, nullptr);
+}
+
+non_null()
+static int os_bind(void *self, int sock, const Network_Addr *addr)
+{
+    return bind(sock, (const struct sockaddr *)net_addr_get_addr(addr), net_addr_get_size(addr));
+}
+
+non_null()
+static int os_listen(void *self, int sock, int backlog)
+{
+    return listen(sock, backlog);
+}
+
+non_null()
+static int os_recvbuf(void *self, int sock)
+{
+#ifdef OS_WIN32
+    u_long count = 0;
+    ioctlsocket(sock, FIONREAD, &count);
+#else
+    int count = 0;
+    ioctl(sock, FIONREAD, &count);
+#endif
+
+    return count;
+}
+
+non_null()
+static int os_recv(void *self, int sock, uint8_t *buf, size_t len)
+{
+    return recv(sock, (char *)buf, len, MSG_NOSIGNAL);
+}
+
+non_null()
+static int os_send(void *self, int sock, const uint8_t *buf, size_t len)
+{
+    return send(sock, (const char *)buf, len, MSG_NOSIGNAL);
+}
+
+non_null()
+static int os_sendto(void *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
+    return sendto(sock, (const char *)buf, len, 0, (const struct sockaddr *)&addr->addr, addr->size);
+}
+
+non_null()
+static int os_recvfrom(void *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
+    socklen_t size = addr->size;
+    const int ret = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&addr->addr, &size);
+    addr->size = size;
+    return ret;
+}
+
+non_null()
+static int os_socket(void *self, int domain, int type, int proto)
+{
+    return (int)socket(domain, type, proto);
+}
+
+non_null()
+static int os_socket_nonblock(void *self, int sock, bool nonblock)
+{
+#ifdef OS_WIN32
+    u_long mode = nonblock ? 1 : 0;
+    return ioctlsocket(sock, FIONBIO, &mode);
+#else
+    return fcntl(sock, F_SETFL, O_NONBLOCK, nonblock ? 1 : 0);
+#endif /* OS_WIN32 */
+}
+
+non_null()
+static int os_getsockopt(void *self, int sock, int level, int optname, void *optval, size_t *optlen)
+{
+    socklen_t len = *optlen;
+    const int ret = getsockopt(sock, level, optname, optval, &len);
+    *optlen = len;
+    return ret;
+}
+
+non_null()
+static int os_setsockopt(void *self, int sock, int level, int optname, const void *optval, size_t optlen)
+{
+    return setsockopt(sock, level, optname, optval, optlen);
+}
+
+static const Tox_Network_Funcs os_network_funcs = {
+    os_close,
+    os_accept,
+    os_bind,
+    os_listen,
+    os_recvbuf,
+    os_recv,
+    os_recvfrom,
+    os_send,
+    os_sendto,
+    os_socket,
+    os_socket_nonblock,
+    os_getsockopt,
+    os_setsockopt,
+};
+static const Tox_Network os_network_obj = {&os_network_funcs};
+
+const Tox_Network *os_network(void)
+{
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    if ((true)) {
+        return nullptr;
+    }
+#endif
+#ifdef OS_WIN32
+    WSADATA wsaData;
+
+    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) {
+        return nullptr;
+    }
+#endif
+    return &os_network_obj;
+}
diff --git a/toxcore/os_network.h b/toxcore/os_network.h
new file mode 100644
index 00000000000..fd144e65917
--- /dev/null
+++ b/toxcore/os_network.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_OS_NETWORK_H
+#define C_TOXCORE_TOXCORE_OS_NETWORK_H
+
+#include "tox_network.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const Tox_Network *os_network(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_OS_NETWORK_H
diff --git a/toxcore/os_network_impl.h b/toxcore/os_network_impl.h
new file mode 100644
index 00000000000..26cacf6b410
--- /dev/null
+++ b/toxcore/os_network_impl.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_OS_NETWORK_IMPL_H
+#define C_TOXCORE_TOXCORE_OS_NETWORK_IMPL_H
+
+#include "tox_network.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+non_null() Network_Addr *net_addr_new(const void *data, size_t size, const Tox_Memory *mem);
+non_null() void net_addr_free(Network_Addr *addr, const Tox_Memory *mem);
+
+non_null() void net_addr_set(Network_Addr *addr, const void *data, size_t size);
+
+non_null() void *net_addr_mut_addr(Network_Addr *addr);
+non_null() const void *net_addr_get_addr(const Network_Addr *addr);
+
+non_null() void net_addr_set_size(Network_Addr *addr, size_t size);
+non_null() size_t net_addr_get_size(const Network_Addr *addr);
+
+non_null() bool net_addr_is_ipv4(const Network_Addr *addr);
+non_null() bool net_addr_is_ipv6(const Network_Addr *addr);
+
+non_null() uint16_t net_addr_get_port(const Network_Addr *addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_OS_NETWORK_IMPL_H
diff --git a/toxcore/os_random.c b/toxcore/os_random.c
new file mode 100644
index 00000000000..66a8c5244a7
--- /dev/null
+++ b/toxcore/os_random.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "os_random.h"
+
+#ifndef VANILLA_NACL
+// We use libsodium by default.
+#include <sodium.h>
+#else
+#include <randombytes.h>
+#endif
+
+#include "ccompat.h"
+#include "tox_random_impl.h"
+
+non_null()
+static void os_random_bytes(void *self, uint8_t *bytes, uint32_t length)
+{
+    randombytes(bytes, length);
+}
+
+non_null()
+static uint32_t os_random_uniform(void *self, uint32_t upper_bound)
+{
+#ifdef VANILLA_NACL
+    if (upper_bound == 0) {
+        return 0;
+    }
+
+    uint32_t randnum;
+    os_random_bytes(self, (uint8_t *)&randnum, sizeof(randnum));
+    return randnum % upper_bound;
+#else
+    return randombytes_uniform(upper_bound);
+#endif
+}
+
+static const Tox_Random_Funcs os_random_funcs = {
+    os_random_bytes,
+    os_random_uniform,
+};
+
+static const Tox_Random os_random_obj = {&os_random_funcs};
+
+const Tox_Random *os_random(void)
+{
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    if ((true)) {
+        return nullptr;
+    }
+#endif
+#ifndef VANILLA_NACL
+    // It is safe to call this function more than once and from different
+    // threads -- subsequent calls won't have any effects.
+    if (sodium_init() == -1) {
+        return nullptr;
+    }
+#endif
+    return &os_random_obj;
+}
diff --git a/toxcore/os_random.h b/toxcore/os_random.h
new file mode 100644
index 00000000000..d265a2d26d4
--- /dev/null
+++ b/toxcore/os_random.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_OS_RANDOM_H
+#define C_TOXCORE_TOXCORE_OS_RANDOM_H
+
+#include "tox_random.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const Tox_Random *os_random(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_OS_RANDOM_H
diff --git a/toxcore/os_system.c b/toxcore/os_system.c
new file mode 100644
index 00000000000..f79edbc2002
--- /dev/null
+++ b/toxcore/os_system.c
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "os_system.h"
+
+#include "ccompat.h"
+#include "os_logger.h"
+#include "os_memory.h"
+#include "os_network.h"
+#include "os_random.h"
+#include "tox_system_impl.h"
+
+Tox_System os_system(const Tox_Logger *log, const Tox_Memory *mem, const Tox_Network *ns, const Tox_Random *rng, const Tox_Time *tm)
+{
+    const Tox_System sys = {
+        log != nullptr ? log : os_logger(),
+        mem != nullptr ? mem : os_memory(),
+        ns != nullptr ? ns : os_network(),
+        rng != nullptr ? rng : os_random(),
+        tm, // no os_time, mono_time has it.
+    };
+
+    return sys;
+}
diff --git a/toxcore/os_system.h b/toxcore/os_system.h
new file mode 100644
index 00000000000..c3fe96262ca
--- /dev/null
+++ b/toxcore/os_system.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_OS_SYSTEM_H
+#define C_TOXCORE_TOXCORE_OS_SYSTEM_H
+
+#include "tox_system.h"
+#include "tox_system_impl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Default operating-system-backed `Tox_System`.
+ *
+ * If any of the parameters are NULL, they are set to the OS instance of that
+ * subsystem. Only `Tox_Time` does not have a subsystem here, and instead is
+ * created in `mono_time`.
+ *
+ * This function, and by extension all the subsystem functions, does not
+ * allocate any dynamic memory.
+ */
+nullable(1, 2, 3, 4, 5)
+Tox_System os_system(const Tox_Logger *log, const Tox_Memory *mem, const Tox_Network *ns, const Tox_Random *rng, const Tox_Time *tm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_OS_SYSTEM_H
diff --git a/toxcore/ping.c b/toxcore/ping.c
index f8a96edfb96..3f19d3098d8 100644
--- a/toxcore/ping.c
+++ b/toxcore/ping.c
@@ -30,7 +30,8 @@
 
 struct Ping {
     const Mono_Time *mono_time;
-    const Random *rng;
+    const Tox_Random *rng;
+    const Memory *mem;
     DHT *dht;
 
     Ping_Array  *ping_array;
@@ -78,7 +79,8 @@ void ping_send_request(Ping *ping, const IP_Port *ipp, const uint8_t *public_key
     rc = encrypt_data_symmetric(shared_key,
                                 pk + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                 ping_plain, sizeof(ping_plain),
-                                pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                                pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
+                                ping->mem);
 
     if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
         return;
@@ -110,7 +112,8 @@ static int ping_send_response(const Ping *ping, const IP_Port *ipp, const uint8_
     const int rc = encrypt_data_symmetric(shared_encryption_key,
                                           pk + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                           ping_plain, sizeof(ping_plain),
-                                          pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
+                                          pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
+                                          ping->mem);
 
     if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
         return 1;
@@ -144,7 +147,8 @@ static int handle_ping_request(void *object, const IP_Port *source, const uint8_
                                           packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                           packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                                           PING_PLAIN_SIZE + CRYPTO_MAC_SIZE,
-                                          ping_plain);
+                                          ping_plain,
+                                          ping->mem);
 
     if (rc != sizeof(ping_plain)) {
         return 1;
@@ -189,7 +193,7 @@ static int handle_ping_response(void *object, const IP_Port *source, const uint8
                                 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
                                 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
                                 PING_PLAIN_SIZE + CRYPTO_MAC_SIZE,
-                                ping_plain);
+                                ping_plain, ping->mem);
 
     if (rc != sizeof(ping_plain)) {
         return 1;
@@ -336,7 +340,7 @@ void ping_iterate(Ping *ping)
 }
 
 
-Ping *ping_new(const Memory *mem, const Mono_Time *mono_time, const Random *rng, DHT *dht)
+Ping *ping_new(const Memory *mem, const Mono_Time *mono_time, const Tox_Random *rng, DHT *dht)
 {
     Ping *ping = (Ping *)mem_alloc(mem, sizeof(Ping));
 
@@ -353,6 +357,7 @@ Ping *ping_new(const Memory *mem, const Mono_Time *mono_time, const Random *rng,
 
     ping->mono_time = mono_time;
     ping->rng = rng;
+    ping->mem = mem;
     ping->dht = dht;
     networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_REQUEST, &handle_ping_request, dht);
     networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_RESPONSE, &handle_ping_response, dht);
diff --git a/toxcore/ping.h b/toxcore/ping.h
index c5613459916..ee2d1d8cbac 100644
--- a/toxcore/ping.h
+++ b/toxcore/ping.h
@@ -18,7 +18,7 @@
 typedef struct Ping Ping;
 
 non_null()
-Ping *ping_new(const Memory *mem, const Mono_Time *mono_time, const Random *rng, DHT *dht);
+Ping *ping_new(const Memory *mem, const Mono_Time *mono_time, const Tox_Random *rng, DHT *dht);
 
 non_null(1) nullable(2)
 void ping_kill(const Memory *mem, Ping *ping);
diff --git a/toxcore/ping_array.c b/toxcore/ping_array.c
index f303d802158..f475fb161dc 100644
--- a/toxcore/ping_array.c
+++ b/toxcore/ping_array.c
@@ -105,7 +105,7 @@ static void ping_array_clear_timedout(Ping_Array *array, const Mono_Time *mono_t
     }
 }
 
-uint64_t ping_array_add(Ping_Array *array, const Mono_Time *mono_time, const Random *rng,
+uint64_t ping_array_add(Ping_Array *array, const Mono_Time *mono_time, const Tox_Random *rng,
                         const uint8_t *data, uint32_t length)
 {
     ping_array_clear_timedout(array, mono_time);
diff --git a/toxcore/ping_array.h b/toxcore/ping_array.h
index 5fc04017357..cdadcfe4b40 100644
--- a/toxcore/ping_array.h
+++ b/toxcore/ping_array.h
@@ -45,7 +45,7 @@ void ping_array_kill(Ping_Array *array);
  * @return ping_id on success, 0 on failure.
  */
 non_null()
-uint64_t ping_array_add(Ping_Array *array, const Mono_Time *mono_time, const Random *rng,
+uint64_t ping_array_add(Ping_Array *array, const Mono_Time *mono_time, const Tox_Random *rng,
                         const uint8_t *data, uint32_t length);
 
 /**
diff --git a/toxcore/ping_array_test.cc b/toxcore/ping_array_test.cc
index 8ce557092e4..1924de0f39d 100644
--- a/toxcore/ping_array_test.cc
+++ b/toxcore/ping_array_test.cc
@@ -5,6 +5,8 @@
 #include <memory>
 
 #include "mono_time.h"
+#include "os_memory.h"
+#include "os_random.h"
 
 namespace {
 
@@ -29,21 +31,21 @@ using Mono_Time_Ptr = std::unique_ptr<Mono_Time, Mono_Time_Deleter>;
 
 TEST(PingArray, MinimumTimeoutIsOne)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     EXPECT_EQ(ping_array_new(mem, 1, 0), nullptr);
     EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr);
 }
 
 TEST(PingArray, MinimumArraySizeIsOne)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
     EXPECT_EQ(ping_array_new(mem, 0, 1), nullptr);
     EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr);
 }
 
 TEST(PingArray, ArraySizeMustBePowerOfTwo)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr arr;
     arr.reset(ping_array_new(mem, 2, 1));
@@ -59,12 +61,12 @@ TEST(PingArray, ArraySizeMustBePowerOfTwo)
 
 TEST(PingArray, StoredDataCanBeRetrieved)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
-    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
+    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr), mem);
     ASSERT_NE(mono_time, nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     uint64_t const ping_id = ping_array_add(
@@ -78,12 +80,12 @@ TEST(PingArray, StoredDataCanBeRetrieved)
 
 TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
-    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
+    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr), mem);
     ASSERT_NE(mono_time, nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     uint64_t const ping_id = ping_array_add(
@@ -101,12 +103,12 @@ TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect)
 
 TEST(PingArray, ZeroLengthDataCanBeAdded)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
-    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
+    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr), mem);
     ASSERT_NE(mono_time, nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     uint8_t c = 0;
@@ -118,10 +120,10 @@ TEST(PingArray, ZeroLengthDataCanBeAdded)
 
 TEST(PingArray, PingId0IsInvalid)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
-    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
+    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr), mem);
     ASSERT_NE(mono_time, nullptr);
 
     uint8_t c = 0;
@@ -131,12 +133,12 @@ TEST(PingArray, PingId0IsInvalid)
 // Protection against replay attacks.
 TEST(PingArray, DataCanOnlyBeRetrievedOnce)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
-    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
+    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr), mem);
     ASSERT_NE(mono_time, nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     uint8_t c = 0;
@@ -149,12 +151,12 @@ TEST(PingArray, DataCanOnlyBeRetrievedOnce)
 
 TEST(PingArray, PingIdMustMatchOnCheck)
 {
-    const Memory *mem = system_memory();
+    const Memory *mem = os_memory();
 
     Ping_Array_Ptr const arr(ping_array_new(mem, 1, 1));
-    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
+    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr), mem);
     ASSERT_NE(mono_time, nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
 
     uint8_t c = 0;
diff --git a/toxcore/tox.c b/toxcore/tox.c
index d17e61b70f2..2106261c4e8 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -25,6 +25,7 @@
 #include "mem.h"
 #include "mono_time.h"
 #include "network.h"
+#include "os_system.h"
 #include "tox_private.h"
 #include "tox_struct.h"
 
@@ -649,7 +650,7 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
     assert(opts != nullptr);
 
     const Tox_System *sys = tox_options_get_operating_system(opts);
-    const Tox_System default_system = tox_default_system();
+    const Tox_System default_system = os_system(nullptr, nullptr, nullptr, nullptr, nullptr);
 
     if (sys == nullptr) {
         sys = &default_system;
@@ -777,7 +778,7 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
         m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(opts));
     }
 
-    tox->mono_time = mono_time_new(tox->sys.mem, sys->mono_time_callback, sys->mono_time_user_data);
+    tox->mono_time = mono_time_new(tox->sys.mem, sys->tm);
 
     if (tox->mono_time == nullptr) {
         SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
@@ -833,7 +834,7 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
         return nullptr;
     }
 
-    if (new_groupchats(tox->mono_time, tox->m) == nullptr) {
+    if (new_groupchats(tox->mono_time, sys->mem, tox->m) == nullptr) {
         kill_messenger(tox->m);
 
         mono_time_free(tox->sys.mem, tox->mono_time);
diff --git a/toxcore/tox.h b/toxcore/tox.h
index d03e2b19b9b..f5fd4239f68 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -104,6 +104,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "tox_system.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -445,42 +447,8 @@ typedef enum Tox_Savedata_Type {
 
 } Tox_Savedata_Type;
 
-
-/**
- * @brief Severity level of log messages.
- */
-typedef enum Tox_Log_Level {
-
-    /**
-     * Very detailed traces including all network activity.
-     */
-    TOX_LOG_LEVEL_TRACE,
-
-    /**
-     * Debug messages such as which port we bind to.
-     */
-    TOX_LOG_LEVEL_DEBUG,
-
-    /**
-     * Informational log messages such as video call status changes.
-     */
-    TOX_LOG_LEVEL_INFO,
-
-    /**
-     * Warnings about events_alloc inconsistency or logic errors.
-     */
-    TOX_LOG_LEVEL_WARNING,
-
-    /**
-     * Severe unexpected errors caused by external or events_alloc inconsistency.
-     */
-    TOX_LOG_LEVEL_ERROR,
-
-} Tox_Log_Level;
-
-
 /**
- * @brief This event is triggered when the toxcore library logs an events_alloc message.
+ * @brief This event is triggered when the toxcore library logs a message.
  *
  * This is mostly useful for debugging. This callback can be called from any
  * function, not just tox_iterate. This means the user data lifetime must at
@@ -500,17 +468,6 @@ typedef enum Tox_Log_Level {
 typedef void tox_log_cb(Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
                         const char *message, void *user_data);
 
-
-/**
- * @brief Operating system functions used by Tox.
- *
- * This struct is opaque and generally shouldn't be used in clients, but in
- * combination with tox_private.h, it allows tests to inject non-IO (hermetic)
- * versions of low level network, RNG, and time keeping functions.
- */
-typedef struct Tox_System Tox_System;
-
-
 /**
  * @brief This struct contains all the startup options for Tox.
  *
diff --git a/toxcore/tox_attributes.h b/toxcore/tox_attributes.h
new file mode 100644
index 00000000000..7200763a883
--- /dev/null
+++ b/toxcore/tox_attributes.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+/**
+ * printf and nonnull attributes for GCC/Clang and Cimple.
+ */
+#ifndef C_TOXCORE_TOXCORE_TOX_ATTRIBUTES_H
+#define C_TOXCORE_TOXCORE_TOX_ATTRIBUTES_H
+
+/* No declarations here. */
+
+//!TOKSTYLE-
+
+#ifdef __GNUC__
+#define GNU_PRINTF(f, a) __attribute__((__format__(__printf__, f, a)))
+#else
+#define GNU_PRINTF(f, a)
+#endif
+
+#if defined(__GNUC__) && defined(_DEBUG) && !defined(__OPTIMIZE__)
+#define non_null(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+#define non_null(...)
+#endif
+
+#define nullable(...)
+
+//!TOKSTYLE+
+
+#endif // C_TOXCORE_TOXCORE_TOX_ATTRIBUTES_H
diff --git a/toxcore/tox_events.c b/toxcore/tox_events.c
index cae662e58ef..f500a6661fe 100644
--- a/toxcore/tox_events.c
+++ b/toxcore/tox_events.c
@@ -14,7 +14,7 @@
 #include "events/events_alloc.h"
 #include "mem.h"
 #include "tox.h"
-#include "tox_private.h"
+#include "tox_system_impl.h"
 
 
 /*****************************************************
@@ -236,7 +236,7 @@ void tox_events_get_bytes(const Tox_Events *events, uint8_t *bytes)
 
 Tox_Events *tox_events_load(const Tox_System *sys, const uint8_t *bytes, uint32_t bytes_size)
 {
-    Bin_Unpack *bu = bin_unpack_new(bytes, bytes_size);
+    Bin_Unpack *bu = bin_unpack_new(bytes, bytes_size, sys->mem);
 
     if (bu == nullptr) {
         return nullptr;
diff --git a/toxcore/tox_events.h b/toxcore/tox_events.h
index e868d89098a..8a0cd8a7d8d 100644
--- a/toxcore/tox_events.h
+++ b/toxcore/tox_events.h
@@ -343,9 +343,9 @@ void tox_events_free(Tox_Events *events);
 uint32_t tox_events_bytes_size(const Tox_Events *events);
 void tox_events_get_bytes(const Tox_Events *events, uint8_t *bytes);
 
-Tox_Events *tox_events_load(const Tox_System *sys, const uint8_t *bytes, uint32_t bytes_size);
+Tox_Events *tox_events_load(const struct Tox_System *sys, const uint8_t *bytes, uint32_t bytes_size);
 
-bool tox_events_equal(const Tox_System *sys, const Tox_Events *a, const Tox_Events *b);
+bool tox_events_equal(const struct Tox_System *sys, const Tox_Events *a, const Tox_Events *b);
 
 #ifdef __cplusplus
 }
diff --git a/toxcore/tox_events_test.cc b/toxcore/tox_events_test.cc
index 5de29b5e483..0c58e20323d 100644
--- a/toxcore/tox_events_test.cc
+++ b/toxcore/tox_events_test.cc
@@ -6,13 +6,15 @@
 #include <vector>
 
 #include "crypto_core.h"
+#include "os_system.h"
 #include "tox_private.h"
+#include "tox_system_impl.h"
 
 namespace {
 
 TEST(ToxEvents, UnpackRandomDataDoesntCrash)
 {
-    const Tox_System sys = tox_default_system();
+    const Tox_System sys = os_system(nullptr, nullptr, nullptr, nullptr, nullptr);
     ASSERT_NE(sys.rng, nullptr);
     std::array<uint8_t, 128> data;
     random_bytes(sys.rng, data.data(), data.size());
@@ -21,7 +23,7 @@ TEST(ToxEvents, UnpackRandomDataDoesntCrash)
 
 TEST(ToxEvents, UnpackEmptyDataFails)
 {
-    const Tox_System sys = tox_default_system();
+    const Tox_System sys = os_system(nullptr, nullptr, nullptr, nullptr, nullptr);
     std::array<uint8_t, 1> data;
     Tox_Events *events = tox_events_load(&sys, data.end(), 0);
     EXPECT_EQ(events, nullptr);
@@ -29,7 +31,7 @@ TEST(ToxEvents, UnpackEmptyDataFails)
 
 TEST(ToxEvents, UnpackEmptyArrayCreatesEmptyEvents)
 {
-    const Tox_System sys = tox_default_system();
+    const Tox_System sys = os_system(nullptr, nullptr, nullptr, nullptr, nullptr);
     std::array<uint8_t, 1> data{0x90};  // empty msgpack array
     Tox_Events *events = tox_events_load(&sys, data.data(), data.size());
     ASSERT_NE(events, nullptr);
@@ -47,7 +49,7 @@ TEST(ToxEvents, NullEventsPacksToEmptyArray)
 
 TEST(ToxEvents, PackedEventsCanBeUnpacked)
 {
-    const Tox_System sys = tox_default_system();
+    const Tox_System sys = os_system(nullptr, nullptr, nullptr, nullptr, nullptr);
     // [[0, 1]] == Tox_Self_Connection_Status { .connection_status = TOX_CONNECTION_TCP }
     std::array<uint8_t, 6> packed{0x91, 0x92, 0xcc, 0x00, 0xcc, 0x01};
     Tox_Events *events = tox_events_load(&sys, packed.data(), packed.size());
@@ -61,7 +63,7 @@ TEST(ToxEvents, PackedEventsCanBeUnpacked)
 
 TEST(ToxEvents, DealsWithHugeMsgpackArrays)
 {
-    const Tox_System sys = tox_default_system();
+    const Tox_System sys = os_system(nullptr, nullptr, nullptr, nullptr, nullptr);
     std::vector<uint8_t> data{0xdd, 0xff, 0xff, 0xff, 0xff};
     EXPECT_EQ(tox_events_load(&sys, data.data(), data.size()), nullptr);
 }
diff --git a/toxcore/tox_logger.c b/toxcore/tox_logger.c
new file mode 100644
index 00000000000..4eeb4f20719
--- /dev/null
+++ b/toxcore/tox_logger.c
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "tox_logger.h"
+
+#include "ccompat.h"
+#include "tox_logger_impl.h"
+
+Tox_Logger *tox_logger_new(const Tox_Logger_Funcs *funcs, void *user_data, const Tox_Memory *mem)
+{
+    Tox_Logger *log = (Tox_Logger *)tox_memory_alloc(mem, sizeof(Tox_Logger));
+
+    if (log == nullptr) {
+        return nullptr;
+    }
+
+    log->funcs = funcs;
+    log->user_data = user_data;
+
+    log->mem = mem;
+
+    return log;
+}
+
+void tox_logger_free(Tox_Logger *log)
+{
+    if (log == nullptr) {
+        return;
+    }
+    tox_memory_dealloc(log->mem, log);
+}
+
+void tox_logger_log(
+        const Tox_Logger *log, Tox_Log_Level level,
+        const char *file, uint32_t line, const char *func,
+        const char *message)
+{
+    log->funcs->log_callback(log->user_data, level, file, line, func, message);
+}
diff --git a/toxcore/tox_logger.h b/toxcore/tox_logger.h
new file mode 100644
index 00000000000..015aca55e64
--- /dev/null
+++ b/toxcore/tox_logger.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_LOGGER_H
+#define C_TOXCORE_TOXCORE_TOX_LOGGER_H
+
+#include "tox_memory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Severity level of log messages.
+ */
+typedef enum Tox_Log_Level {
+
+    /**
+     * Very detailed traces including all network activity.
+     */
+    TOX_LOG_LEVEL_TRACE,
+
+    /**
+     * Debug messages such as which port we bind to.
+     */
+    TOX_LOG_LEVEL_DEBUG,
+
+    /**
+     * Informational log messages such as video call status changes.
+     */
+    TOX_LOG_LEVEL_INFO,
+
+    /**
+     * Warnings about events_alloc inconsistency or logic errors.
+     */
+    TOX_LOG_LEVEL_WARNING,
+
+    /**
+     * Severe unexpected errors caused by external or events_alloc inconsistency.
+     */
+    TOX_LOG_LEVEL_ERROR,
+
+} Tox_Log_Level;
+
+
+typedef struct Tox_Logger_Funcs Tox_Logger_Funcs;
+
+typedef struct Tox_Logger Tox_Logger;
+
+non_null(1, 3) nullable(2)
+Tox_Logger *tox_logger_new(const Tox_Logger_Funcs *funcs, void *user_data, const Tox_Memory *mem);
+
+nullable(1) void tox_logger_free(Tox_Logger *log);
+
+non_null() void tox_logger_log(
+        const Tox_Logger *log, Tox_Log_Level level,
+        const char *file, uint32_t line, const char *func,
+        const char *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_LOGGER_H
diff --git a/toxcore/tox_logger_impl.h b/toxcore/tox_logger_impl.h
new file mode 100644
index 00000000000..9d3795a91ac
--- /dev/null
+++ b/toxcore/tox_logger_impl.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_LOGGER_IMPL_H
+#define C_TOXCORE_TOXCORE_TOX_LOGGER_IMPL_H
+
+#include "tox_logger.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief This event is triggered when the toxcore library logs a message.
+ *
+ * This is mostly useful for debugging. This callback can be called from any
+ * function, not just tox_iterate. This means the user data lifetime must at
+ * least extend between registering and unregistering it or tox_kill.
+ *
+ * Other toxcore modules such as toxav may concurrently call this callback at
+ * any time. Thus, user code must make sure it is equipped to handle concurrent
+ * execution, e.g. by employing appropriate mutex locking.
+ *
+ * @param self The user data pointer passed to `tox_logger_new`.
+ * @param level The severity of the log message.
+ * @param file The source file from which the message originated.
+ * @param line The source line from which the message originated.
+ * @param func The function from which the message originated.
+ * @param message The log message.
+ */
+typedef void tox_logger_log_cb(
+        void *self, Tox_Log_Level level,
+        const char *file, uint32_t line, const char *func,
+        const char *message);
+
+
+struct Tox_Logger_Funcs {
+    tox_logger_log_cb *log_callback;
+};
+
+struct Tox_Logger {
+    const Tox_Logger_Funcs *funcs;
+    void *user_data;
+
+    const Tox_Memory *mem;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_LOGGER_IMPL_H
diff --git a/toxcore/tox_memory.c b/toxcore/tox_memory.c
new file mode 100644
index 00000000000..9410094145a
--- /dev/null
+++ b/toxcore/tox_memory.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2016-2018 The TokTok team.
+ * Copyright © 2013 Tox project.
+ */
+#include "tox_memory.h"
+
+#include <string.h>
+
+#include "ccompat.h"
+#include "tox_memory_impl.h"
+
+Tox_Memory *tox_memory_new(const Tox_Memory_Funcs *funcs, void *user_data)
+{
+    const Tox_Memory bootstrap = {funcs, user_data};
+
+    Tox_Memory *mem = (Tox_Memory *)tox_memory_alloc(&bootstrap, sizeof(Tox_Memory));
+
+    if (mem == nullptr) {
+        return nullptr;
+    }
+
+    *mem = bootstrap;
+
+    return mem;
+}
+
+void tox_memory_free(Tox_Memory *mem)
+{
+    if (mem == nullptr) {
+        return;
+    }
+
+    tox_memory_dealloc(mem, mem);
+}
+
+void *tox_memory_malloc(const Tox_Memory *mem, uint32_t size)
+{
+    void *const ptr = mem->funcs->malloc_callback(mem->user_data, size);
+    return ptr;
+}
+
+void *tox_memory_alloc(const Tox_Memory *mem, uint32_t size)
+{
+    void *const ptr = tox_memory_malloc(mem, size);
+    if (ptr != nullptr) {
+        memset(ptr, 0, size);
+    }
+    return ptr;
+}
+
+void *tox_memory_realloc(const Tox_Memory *mem, void *ptr, uint32_t size)
+{
+    void *const new_ptr = mem->funcs->realloc_callback(mem->user_data, ptr, size);
+    return new_ptr;
+}
+
+void tox_memory_dealloc(const Tox_Memory *mem, void *ptr)
+{
+    mem->funcs->dealloc_callback(mem->user_data, ptr);
+}
diff --git a/toxcore/tox_memory.h b/toxcore/tox_memory.h
new file mode 100644
index 00000000000..a1eb0c40be3
--- /dev/null
+++ b/toxcore/tox_memory.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2016-2018 The TokTok team.
+ * Copyright © 2013 Tox project.
+ */
+
+/**
+ * Memory allocation and deallocation functions.
+ */
+#ifndef C_TOXCORE_TOXCORE_TOX_MEMORY_H
+#define C_TOXCORE_TOXCORE_TOX_MEMORY_H
+
+#include <stdint.h>     // uint*_t
+
+#include "tox_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Functions wrapping standard C memory allocation functions. */
+typedef struct Tox_Memory_Funcs Tox_Memory_Funcs;
+
+/**
+ * @brief A dynamic memory allocator.
+ */
+typedef struct Tox_Memory Tox_Memory;
+
+/**
+ * @brief Allocates a new allocator using itself to allocate its own memory.
+ *
+ * The passed `user_data` is stored and passed to allocator callbacks. It must
+ * outlive the `Tox_Memory` object, since it may be used by the callback invoked
+ * in `tox_memory_free`.
+ *
+ * @return NULL if allocation fails.
+ */
+non_null(1) nullable(2)
+Tox_Memory *tox_memory_new(const Tox_Memory_Funcs *funcs, void *user_data);
+
+/**
+ * @brief Destroys the allocator using its own deallocation function.
+ *
+ * The stored `user_data` will not be deallocated.
+ */
+nullable(1) void tox_memory_free(Tox_Memory *mem);
+
+/**
+ * @brief Allocate an array of a given size for built-in types.
+ *
+ * The array will not be initialised. Supported built-in types are
+ * `uint8_t`, `int8_t`, and `int16_t`.
+ */
+non_null() void *tox_memory_malloc(const Tox_Memory *mem, uint32_t size);
+
+/**
+ * @brief Allocate a single zero-initialised object.
+ *
+ * Always use as `(T *)tox_memory_alloc(mem, sizeof(T))`. Unlike `calloc`, this
+ * does not support allocating arrays. Use `malloc` and `memset` for that.
+ *
+ * @param mem The memory allocator.
+ * @param size Size in bytes of each element.
+ */
+non_null() void *tox_memory_alloc(const Tox_Memory *mem, uint32_t size);
+
+/** @brief Resize a memory chunk vector. */
+non_null(1) nullable(2) void *tox_memory_realloc(const Tox_Memory *mem, void *ptr, uint32_t size);
+
+/** @brief Free an array, object, or object vector. */
+non_null(1) nullable(2) void tox_memory_dealloc(const Tox_Memory *mem, void *ptr);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // C_TOXCORE_TOXCORE_TOX_MEMORY_H
diff --git a/toxcore/tox_memory_impl.h b/toxcore/tox_memory_impl.h
new file mode 100644
index 00000000000..e317fa46d2a
--- /dev/null
+++ b/toxcore/tox_memory_impl.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2016-2018 The TokTok team.
+ * Copyright © 2013 Tox project.
+ */
+
+/**
+ * Datatypes, functions and includes for the core networking.
+ */
+#ifndef C_TOXCORE_TOXCORE_TOX_MEMORY_IMPL_H
+#define C_TOXCORE_TOXCORE_TOX_MEMORY_IMPL_H
+
+#include <stdint.h>     // uint*_t
+
+#include "tox_memory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Allocate a byte array, similar to malloc. */
+typedef void *tox_memory_malloc_cb(void *self, uint32_t size);
+/** @brief Reallocate a byte array, similar to realloc. */
+typedef void *tox_memory_realloc_cb(void *self, void *ptr, uint32_t size);
+/**
+ * @brief Deallocate a byte or object array, similar to free.
+ *
+ * Note that `tox_memory_free` will use this callback to deallocate itself, so
+ * once the deallocation is done, the allocator data structures can no longer be
+ * referenced.
+ */
+typedef void tox_memory_dealloc_cb(void *self, void *ptr);
+
+/** @brief Functions wrapping standard C memory allocation functions. */
+struct Tox_Memory_Funcs {
+    tox_memory_malloc_cb *malloc_callback;
+    tox_memory_realloc_cb *realloc_callback;
+    tox_memory_dealloc_cb *dealloc_callback;
+};
+
+struct Tox_Memory {
+    const Tox_Memory_Funcs *funcs;
+    void *user_data;
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // C_TOXCORE_TOXCORE_TOX_MEMORY_IMPL_H
diff --git a/toxcore/tox_network.c b/toxcore/tox_network.c
new file mode 100644
index 00000000000..f0cee4e9527
--- /dev/null
+++ b/toxcore/tox_network.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "tox_network.h"
+
+#include "ccompat.h"
+#include "tox_network_impl.h"
+
+Tox_Network *tox_network_new(const Tox_Network_Funcs *funcs, void *user_data, const Tox_Memory *mem)
+{
+    Tox_Network *ns = (Tox_Network *)tox_memory_alloc(mem, sizeof(Tox_Network));
+
+    if (ns == nullptr) {
+        return nullptr;
+    }
+
+    ns->funcs = funcs;
+    ns->user_data = user_data;
+
+    ns->mem = mem;
+
+    return ns;
+}
+
+void tox_network_free(Tox_Network *ns)
+{
+    if (ns == nullptr) {
+        return;
+    }
+    tox_memory_dealloc(ns->mem, ns);
+}
+
+int tox_network_close(const Tox_Network *ns, int sock)
+{
+    return ns->funcs->close_callback(ns->user_data, sock);
+}
+
+int tox_network_accept(const Tox_Network *ns, int sock)
+{
+    return ns->funcs->accept_callback(ns->user_data, sock);
+}
+
+int tox_network_bind(const Tox_Network *ns, int sock, const Network_Addr *addr)
+{
+    return ns->funcs->bind_callback(ns->user_data, sock, addr);
+}
+
+int tox_network_listen(const Tox_Network *ns, int sock, int backlog)
+{
+    return ns->funcs->listen_callback(ns->user_data, sock, backlog);
+}
+
+int tox_network_recvbuf(const Tox_Network *ns, int sock)
+{
+    return ns->funcs->recvbuf_callback(ns->user_data, sock);
+}
+
+int tox_network_recv(const Tox_Network *ns, int sock, uint8_t *buf, size_t len)
+{
+    return ns->funcs->recv_callback(ns->user_data, sock, buf, len);
+}
+
+int tox_network_recvfrom(const Tox_Network *ns, int sock, uint8_t *buf, size_t len, Network_Addr *addr)
+{
+    return ns->funcs->recvfrom_callback(ns->user_data, sock, buf, len, addr);
+}
+
+int tox_network_send(const Tox_Network *ns, int sock, const uint8_t *buf, size_t len)
+{
+    return ns->funcs->send_callback(ns->user_data, sock, buf, len);
+}
+
+int tox_network_sendto(const Tox_Network *ns, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr)
+{
+    return ns->funcs->sendto_callback(ns->user_data, sock, buf, len, addr);
+}
+
+int tox_network_socket(const Tox_Network *ns, int domain, int type, int proto)
+{
+    return ns->funcs->socket_callback(ns->user_data, domain, type, proto);
+}
+
+int tox_network_socket_nonblock(const Tox_Network *ns, int sock, bool nonblock)
+{
+    return ns->funcs->socket_nonblock_callback(ns->user_data, sock, nonblock);
+}
+
+int tox_network_getsockopt(const Tox_Network *ns, int sock, int level, int optname, void *optval, size_t *optlen)
+{
+    return ns->funcs->getsockopt_callback(ns->user_data, sock, level, optname, optval, optlen);
+}
+
+int tox_network_setsockopt(const Tox_Network *ns, int sock, int level, int optname, const void *optval, size_t optlen)
+{
+    return ns->funcs->setsockopt_callback(ns->user_data, sock, level, optname, optval, optlen);
+}
+
+int tox_network_getaddrinfo(const Tox_Network *ns, int family, Network_Addr **addrs)
+{
+    return ns->funcs->getaddrinfo_callback(ns->user_data, family, addrs);
+}
+
+int tox_network_freeaddrinfo(const Tox_Network *ns, Network_Addr *addrs)
+{
+    return ns->funcs->freeaddrinfo_callback(ns->user_data, addrs);
+}
diff --git a/toxcore/tox_network.h b/toxcore/tox_network.h
new file mode 100644
index 00000000000..bb8f879ed2d
--- /dev/null
+++ b/toxcore/tox_network.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_NETWORK_H
+#define C_TOXCORE_TOXCORE_TOX_NETWORK_H
+
+#include <stdbool.h>
+#include <stddef.h>  // size_t
+
+#include "tox_memory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Tox_Network_Funcs Tox_Network_Funcs;
+
+typedef struct Tox_Network Tox_Network;
+
+non_null(1, 3) nullable(2)
+Tox_Network *tox_network_new(const Tox_Network_Funcs *funcs, void *user_data, const Tox_Memory *mem);
+
+nullable(1) void tox_network_free(Tox_Network *ns);
+
+/**
+ * @brief Wrapper for sockaddr_storage and size.
+ */
+typedef struct Network_Addr Network_Addr;
+
+non_null() int tox_network_close(const Tox_Network *ns, int sock);
+non_null() int tox_network_accept(const Tox_Network *ns, int sock);
+non_null() int tox_network_bind(const Tox_Network *ns, int sock, const Network_Addr *addr);
+non_null() int tox_network_listen(const Tox_Network *ns, int sock, int backlog);
+non_null() int tox_network_recvbuf(const Tox_Network *ns, int sock);
+non_null() int tox_network_recv(const Tox_Network *ns, int sock, uint8_t *buf, size_t len);
+non_null() int tox_network_recvfrom(const Tox_Network *ns, int sock, uint8_t *buf, size_t len, Network_Addr *addr);
+non_null() int tox_network_send(const Tox_Network *ns, int sock, const uint8_t *buf, size_t len);
+non_null() int tox_network_sendto(const Tox_Network *ns, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr);
+non_null() int tox_network_socket(const Tox_Network *ns, int domain, int type, int proto);
+non_null() int tox_network_socket_nonblock(const Tox_Network *ns, int sock, bool nonblock);
+non_null() int tox_network_getsockopt(const Tox_Network *ns, int sock, int level, int optname, void *optval, size_t *optlen);
+non_null() int tox_network_setsockopt(const Tox_Network *ns, int sock, int level, int optname, const void *optval, size_t optlen);
+non_null() int tox_network_getaddrinfo(const Tox_Network *ns, int family, Network_Addr **addrs);
+non_null() int tox_network_freeaddrinfo(const Tox_Network *ns, Network_Addr *addrs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_NETWORK_H
diff --git a/toxcore/tox_network_impl.h b/toxcore/tox_network_impl.h
new file mode 100644
index 00000000000..bc0217b7210
--- /dev/null
+++ b/toxcore/tox_network_impl.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_NETWORK_IMPL_H
+#define C_TOXCORE_TOXCORE_TOX_NETWORK_IMPL_H
+
+#include "tox_network.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int tox_network_close_cb(void *self, int sock);
+typedef int tox_network_accept_cb(void *self, int sock);
+typedef int tox_network_bind_cb(void *self, int sock, const Network_Addr *addr);
+typedef int tox_network_listen_cb(void *self, int sock, int backlog);
+typedef int tox_network_recvbuf_cb(void *self, int sock);
+typedef int tox_network_recv_cb(void *self, int sock, uint8_t *buf, size_t len);
+typedef int tox_network_recvfrom_cb(void *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr);
+typedef int tox_network_send_cb(void *self, int sock, const uint8_t *buf, size_t len);
+typedef int tox_network_sendto_cb(void *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr);
+typedef int tox_network_socket_cb(void *self, int domain, int type, int proto);
+typedef int tox_network_socket_nonblock_cb(void *self, int sock, bool nonblock);
+typedef int tox_network_getsockopt_cb(void *self, int sock, int level, int optname, void *optval, size_t *optlen);
+typedef int tox_network_setsockopt_cb(void *self, int sock, int level, int optname, const void *optval, size_t optlen);
+typedef int tox_network_getaddrinfo_cb(void *self, int family, Network_Addr **addrs);
+typedef int tox_network_freeaddrinfo_cb(void *self, Network_Addr *addrs);
+
+/** @brief Functions wrapping POSIX network functions.
+ *
+ * Refer to POSIX man pages for documentation of what these functions are
+ * expected to do when providing alternative Network implementations.
+ */
+struct Tox_Network_Funcs {
+    tox_network_close_cb *close_callback;
+    tox_network_accept_cb *accept_callback;
+    tox_network_bind_cb *bind_callback;
+    tox_network_listen_cb *listen_callback;
+    tox_network_recvbuf_cb *recvbuf_callback;
+    tox_network_recv_cb *recv_callback;
+    tox_network_recvfrom_cb *recvfrom_callback;
+    tox_network_send_cb *send_callback;
+    tox_network_sendto_cb *sendto_callback;
+    tox_network_socket_cb *socket_callback;
+    tox_network_socket_nonblock_cb *socket_nonblock_callback;
+    tox_network_getsockopt_cb *getsockopt_callback;
+    tox_network_setsockopt_cb *setsockopt_callback;
+    tox_network_getaddrinfo_cb *getaddrinfo_callback;
+    tox_network_freeaddrinfo_cb *freeaddrinfo_callback;
+};
+
+struct Tox_Network {
+    const Tox_Network_Funcs *funcs;
+    void *user_data;
+
+    const Tox_Memory *mem;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_NETWORK_IMPL_H
diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c
index 72a93358a5b..cebdd502fd3 100644
--- a/toxcore/tox_private.c
+++ b/toxcore/tox_private.c
@@ -22,18 +22,6 @@
         }                             \
     } while (0)
 
-Tox_System tox_default_system(void)
-{
-    const Tox_System sys = {
-        nullptr,  // mono_time_callback
-        nullptr,  // mono_time_user_data
-        system_random(),
-        system_network(),
-        system_memory(),
-    };
-    return sys;
-}
-
 void tox_lock(const Tox *tox)
 {
     if (tox->mutex != nullptr) {
diff --git a/toxcore/tox_private.h b/toxcore/tox_private.h
index c82357170e6..ba6c8a27eb7 100644
--- a/toxcore/tox_private.h
+++ b/toxcore/tox_private.h
@@ -16,18 +16,6 @@
 extern "C" {
 #endif
 
-typedef uint64_t tox_mono_time_cb(void *user_data);
-
-struct Tox_System {
-    tox_mono_time_cb *mono_time_callback;
-    void *mono_time_user_data;
-    const struct Random *rng;
-    const struct Network *ns;
-    const struct Memory *mem;
-};
-
-Tox_System tox_default_system(void);
-
 void tox_lock(const Tox *tox);
 void tox_unlock(const Tox *tox);
 
diff --git a/toxcore/tox_random.c b/toxcore/tox_random.c
new file mode 100644
index 00000000000..ae8156ab553
--- /dev/null
+++ b/toxcore/tox_random.c
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "tox_random.h"
+
+#include "ccompat.h"
+#include "tox_random_impl.h"
+
+Tox_Random *tox_random_new(const Tox_Random_Funcs *funcs, void *user_data, const Tox_Memory *mem)
+{
+    Tox_Random *rng = (Tox_Random *)tox_memory_alloc(mem, sizeof(Tox_Random));
+
+    if (rng == nullptr) {
+        return nullptr;
+    }
+
+    rng->funcs = funcs;
+    rng->user_data = user_data;
+
+    rng->mem = mem;
+
+    return rng;
+}
+
+void tox_random_free(Tox_Random *rng)
+{
+    if (rng == nullptr) {
+        return;
+    }
+    tox_memory_dealloc(rng->mem, rng);
+}
+
+void tox_random_bytes(const Tox_Random *rng, uint8_t *bytes, uint32_t length)
+{
+    rng->funcs->bytes_callback(rng->user_data, bytes, length);
+}
+
+uint32_t tox_random_uniform(const Tox_Random *rng, uint32_t upper_bound)
+{
+    return rng->funcs->uniform_callback(rng->user_data, upper_bound);
+}
diff --git a/toxcore/tox_random.h b/toxcore/tox_random.h
new file mode 100644
index 00000000000..82e3acbcd71
--- /dev/null
+++ b/toxcore/tox_random.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_RANDOM_H
+#define C_TOXCORE_TOXCORE_TOX_RANDOM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "tox_memory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Tox_Random_Funcs Tox_Random_Funcs;
+
+typedef struct Tox_Random Tox_Random;
+
+non_null(1, 3) nullable(2)
+Tox_Random *tox_random_new(const Tox_Random_Funcs *funcs, void *user_data, const Tox_Memory *mem);
+
+nullable(1) void tox_random_free(Tox_Random *rng);
+
+non_null() void tox_random_bytes(const Tox_Random *rng, uint8_t *bytes, uint32_t length);
+non_null() uint32_t tox_random_uniform(const Tox_Random *rng, uint32_t upper_bound);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_RANDOM_H
diff --git a/toxcore/tox_random_impl.h b/toxcore/tox_random_impl.h
new file mode 100644
index 00000000000..f11d2f26d6a
--- /dev/null
+++ b/toxcore/tox_random_impl.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_RANDOM_IMPL_H
+#define C_TOXCORE_TOXCORE_TOX_RANDOM_IMPL_H
+
+#include "tox_random.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void tox_random_bytes_cb(void *self, uint8_t *bytes, uint32_t length);
+typedef uint32_t tox_random_uniform_cb(void *self, uint32_t upper_bound);
+
+struct Tox_Random_Funcs {
+    tox_random_bytes_cb *bytes_callback;
+    tox_random_uniform_cb *uniform_callback;
+};
+
+struct Tox_Random {
+    const Tox_Random_Funcs *funcs;
+    void *user_data;
+
+    const Tox_Memory *mem;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_RANDOM_IMPL_H
diff --git a/toxcore/tox_struct.h b/toxcore/tox_struct.h
index b298269af95..ec1db247a7c 100644
--- a/toxcore/tox_struct.h
+++ b/toxcore/tox_struct.h
@@ -10,6 +10,7 @@
 #include "mem.h"
 #include "tox.h"
 #include "tox_private.h"
+#include "tox_system_impl.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/toxcore/tox_system.c b/toxcore/tox_system.c
new file mode 100644
index 00000000000..8a45574ca09
--- /dev/null
+++ b/toxcore/tox_system.c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "tox_system.h"
+
+#include "ccompat.h"
+#include "tox_system_impl.h"
+
+Tox_System *tox_system_new(const Tox_Logger *log, const Tox_Memory *mem, const Tox_Network *ns, const Tox_Random *rng, const Tox_Time *tm)
+{
+    Tox_System *sys = (Tox_System *)tox_memory_alloc(mem, sizeof(Tox_System));
+
+    if (sys == nullptr) {
+        return nullptr;
+    }
+
+    sys->log = log;
+    sys->mem = mem;
+    sys->ns = ns;
+    sys->rng = rng;
+    sys->tm = tm;
+
+    return sys;
+}
+
+void tox_system_free(Tox_System *sys)
+{
+    if (sys == nullptr) {
+        return;
+    }
+    tox_memory_dealloc(sys->mem, sys);
+}
diff --git a/toxcore/tox_system.h b/toxcore/tox_system.h
new file mode 100644
index 00000000000..49934017ff5
--- /dev/null
+++ b/toxcore/tox_system.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_SYSTEM_H
+#define C_TOXCORE_TOXCORE_TOX_SYSTEM_H
+
+#include "tox_logger.h"
+#include "tox_memory.h"
+#include "tox_network.h"
+#include "tox_random.h"
+#include "tox_time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Operating system functions used by Tox.
+ *
+ * This struct is opaque and generally shouldn't be used in clients, but in
+ * combination with tox_private.h, it allows tests to inject non-IO (hermetic)
+ * versions of low level network, RNG, and time keeping functions.
+ */
+typedef struct Tox_System Tox_System;
+
+non_null() Tox_System *tox_system_new(const Tox_Logger *log, const Tox_Memory *mem, const Tox_Network *ns, const Tox_Random *rng, const Tox_Time *tm);
+nullable(1) void tox_system_free(Tox_System *sys);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_SYSTEM_H
diff --git a/toxcore/tox_system_impl.h b/toxcore/tox_system_impl.h
new file mode 100644
index 00000000000..bd74fd6e32a
--- /dev/null
+++ b/toxcore/tox_system_impl.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_SYSTEM_IMPL_H
+#define C_TOXCORE_TOXCORE_TOX_SYSTEM_IMPL_H
+
+#include "tox_system.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Tox_System {
+    const Tox_Logger *log;
+    const Tox_Memory *mem;
+    const Tox_Network *ns;
+    const Tox_Random *rng;
+    const Tox_Time *tm;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_SYSTEM_IMPL_H
diff --git a/toxcore/tox_test.cc b/toxcore/tox_test.cc
index 530c1390a1f..2848a4fa2e6 100644
--- a/toxcore/tox_test.cc
+++ b/toxcore/tox_test.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "crypto_core.h"
+#include "os_random.h"
 #include "tox_private.h"
 
 namespace {
@@ -94,7 +95,7 @@ TEST(Tox, OneTest)
 
     Tox *tox1 = tox_new(options, nullptr);
     ASSERT_NE(tox1, nullptr);
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
     set_random_name_and_status_message(tox1, rng, name.data(), status_message.data());
     Tox *tox2 = tox_new(options, nullptr);
diff --git a/toxcore/tox_time.c b/toxcore/tox_time.c
new file mode 100644
index 00000000000..15d73c2d27e
--- /dev/null
+++ b/toxcore/tox_time.c
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+#include "tox_time.h"
+
+#include "ccompat.h"
+#include "tox_time_impl.h"
+
+Tox_Time *tox_time_new(const Tox_Time_Funcs *funcs, void *user_data, const Tox_Memory *mem)
+{
+    Tox_Time *tm = (Tox_Time *)tox_memory_alloc(mem, sizeof(Tox_Time));
+
+    if (tm == nullptr) {
+        return nullptr;
+    }
+
+    tm->funcs = funcs;
+    tm->user_data = user_data;
+
+    tm->mem = mem;
+
+    return tm;
+}
+
+void tox_time_free(Tox_Time *tm)
+{
+    if (tm == nullptr) {
+        return;
+    }
+    tox_memory_dealloc(tm->mem, tm);
+}
+
+uint64_t tox_time_monotonic(const Tox_Time *tm)
+{
+    return tm->funcs->monotonic_callback(tm->user_data);
+}
diff --git a/toxcore/tox_time.h b/toxcore/tox_time.h
new file mode 100644
index 00000000000..b8dd5c2cb6b
--- /dev/null
+++ b/toxcore/tox_time.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_TIME_H
+#define C_TOXCORE_TOXCORE_TOX_TIME_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "tox_memory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Tox_Time_Funcs Tox_Time_Funcs;
+
+typedef struct Tox_Time Tox_Time;
+
+non_null(1, 3) nullable(2)
+Tox_Time *tox_time_new(const Tox_Time_Funcs *funcs, void *user_data, const Tox_Memory *mem);
+
+nullable(1) void tox_time_free(Tox_Time *tm);
+
+non_null() uint64_t tox_time_monotonic(const Tox_Time *tm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_TIME_H
diff --git a/toxcore/tox_time_impl.h b/toxcore/tox_time_impl.h
new file mode 100644
index 00000000000..300bc12b1f8
--- /dev/null
+++ b/toxcore/tox_time_impl.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#ifndef C_TOXCORE_TOXCORE_TOX_TIME_IMPL_H
+#define C_TOXCORE_TOXCORE_TOX_TIME_IMPL_H
+
+#include "tox_time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint64_t tox_time_monotonic_cb(void *self);
+
+struct Tox_Time_Funcs {
+    tox_time_monotonic_cb *monotonic_callback;
+};
+
+struct Tox_Time {
+    const Tox_Time_Funcs *funcs;
+    void *user_data;
+
+    const Tox_Memory *mem;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_TOXCORE_TOXCORE_TOX_TIME_IMPL_H
diff --git a/toxcore/tox_unpack.h b/toxcore/tox_unpack.h
index 5f0b18ad1b8..c07fe49445d 100644
--- a/toxcore/tox_unpack.h
+++ b/toxcore/tox_unpack.h
@@ -5,7 +5,7 @@
 #ifndef C_TOXCORE_TOXCORE_TOX_UNPACK_H
 #define C_TOXCORE_TOXCORE_TOX_UNPACK_H
 
-#include "attributes.h"
+#include "tox_attributes.h"
 #include "bin_unpack.h"
 #include "tox.h"
 
diff --git a/toxcore/util.h b/toxcore/util.h
index 44091b36227..e8067dbf77b 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -15,7 +15,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "attributes.h"
+#include "tox_attributes.h"
 #include "mem.h"
 
 #ifdef __cplusplus
diff --git a/toxcore/util_test.cc b/toxcore/util_test.cc
index 47bf258766b..3a31ce39363 100644
--- a/toxcore/util_test.cc
+++ b/toxcore/util_test.cc
@@ -3,12 +3,13 @@
 #include <gtest/gtest.h>
 
 #include "crypto_core.h"
+#include "os_random.h"
 
 namespace {
 
 TEST(Util, TwoRandomIdsAreNotEqual)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
     uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE];
     uint8_t sk1[CRYPTO_SECRET_KEY_SIZE];
@@ -23,7 +24,7 @@ TEST(Util, TwoRandomIdsAreNotEqual)
 
 TEST(Util, IdCopyMakesKeysEqual)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
     ASSERT_NE(rng, nullptr);
     uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE];
     uint8_t sk1[CRYPTO_SECRET_KEY_SIZE];
diff --git a/toxencryptsave.h b/toxencryptsave.h
new file mode 100644
index 00000000000..f5901d3cc32
--- /dev/null
+++ b/toxencryptsave.h
@@ -0,0 +1,5 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright © 2022-2023 The TokTok team.
+ */
+
+#include "toxencryptsave/toxencryptsave.h"
diff --git a/toxencryptsave/BUILD.bazel b/toxencryptsave/BUILD.bazel
index bbd5e0ee88c..9cb631ac049 100644
--- a/toxencryptsave/BUILD.bazel
+++ b/toxencryptsave/BUILD.bazel
@@ -22,6 +22,8 @@ cc_library(
         ":defines",
         "//c-toxcore/toxcore:ccompat",
         "//c-toxcore/toxcore:crypto_core",
+        "//c-toxcore/toxcore:os_memory",
+        "//c-toxcore/toxcore:os_random",
         "@libsodium",
     ],
 )
@@ -36,6 +38,8 @@ cc_library(
     deps = [
         "//c-toxcore/toxcore:ccompat",
         "//c-toxcore/toxcore:crypto_core",
+        "//c-toxcore/toxcore:os_memory",
+        "//c-toxcore/toxcore:os_random",
         "@libsodium",
     ],
 )
diff --git a/toxencryptsave/Makefile.inc b/toxencryptsave/Makefile.inc
index 4b517a19f6d..716ed1b7ed0 100644
--- a/toxencryptsave/Makefile.inc
+++ b/toxencryptsave/Makefile.inc
@@ -3,7 +3,7 @@ lib_LTLIBRARIES += libtoxencryptsave.la
 libtoxencryptsave_la_include_HEADERS = \
                         ../toxencryptsave/toxencryptsave.h
 
-libtoxencryptsave_la_includedir = $(includedir)/tox
+libtoxencryptsave_la_includedir = $(includedir)/tox/toxencryptsave
 
 if !WITH_NACL
 libtoxencryptsave_la_SOURCES = ../toxencryptsave/toxencryptsave.h \
diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c
index 45003055f42..81ec450d308 100644
--- a/toxencryptsave/toxencryptsave.c
+++ b/toxencryptsave/toxencryptsave.c
@@ -15,6 +15,8 @@
 
 #include "../toxcore/ccompat.h"
 #include "../toxcore/crypto_core.h"
+#include "../toxcore/os_memory.h"
+#include "../toxcore/os_random.h"
 #include "defines.h"
 
 static_assert(TOX_PASS_SALT_LENGTH == crypto_pwhash_scryptsalsa208sha256_SALTBYTES,
@@ -115,7 +117,7 @@ bool tox_get_salt(const uint8_t *ciphertext, uint8_t *salt, Tox_Err_Get_Salt *er
 Tox_Pass_Key *tox_pass_key_derive(const uint8_t *passphrase, size_t passphrase_len,
                                   Tox_Err_Key_Derivation *error)
 {
-    const Random *rng = system_random();
+    const Random *rng = os_random();
 
     if (rng == nullptr) {
         SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED);
@@ -192,9 +194,10 @@ Tox_Pass_Key *tox_pass_key_derive_with_salt(const uint8_t *passphrase, size_t pa
 bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *plaintext, size_t plaintext_len,
                           uint8_t *ciphertext, Tox_Err_Encryption *error)
 {
-    const Random *rng = system_random();
+    const Memory *mem = os_memory();
+    const Random *rng = os_random();
 
-    if (rng == nullptr) {
+    if (mem == nullptr || rng == nullptr) {
         SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED);
         return false;
     }
@@ -225,7 +228,7 @@ bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *plaintext, siz
     ciphertext += crypto_box_NONCEBYTES;
 
     /* now encrypt */
-    if (encrypt_data_symmetric(key->key, nonce, plaintext, plaintext_len, ciphertext)
+    if (encrypt_data_symmetric(key->key, nonce, plaintext, plaintext_len, ciphertext, mem)
             != plaintext_len + crypto_box_MACBYTES) {
         SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED);
         return false;
@@ -284,6 +287,13 @@ bool tox_pass_encrypt(const uint8_t *plaintext, size_t plaintext_len, const uint
 bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *ciphertext, size_t ciphertext_len,
                           uint8_t *plaintext, Tox_Err_Decryption *error)
 {
+    const Memory *mem = os_memory();
+
+    if (mem == nullptr) {
+        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED);
+        return false;
+    }
+
     if (ciphertext_len <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {
         SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);
         return false;
@@ -309,7 +319,7 @@ bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *ciphertext, si
     ciphertext += crypto_box_NONCEBYTES;
 
     /* decrypt the ciphertext */
-    if (decrypt_data_symmetric(key->key, nonce, ciphertext, decrypt_length + crypto_box_MACBYTES, plaintext)
+    if (decrypt_data_symmetric(key->key, nonce, ciphertext, decrypt_length + crypto_box_MACBYTES, plaintext, mem)
             != decrypt_length) {
         SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED);
         return false;