diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt
index 836d6711076f67f13e889f6d051b4222a6e04e9d..a60b8f06a0ae5e6f8d060042ef7153ba70623edb 100644
--- a/Framework/CMakeLists.txt
+++ b/Framework/CMakeLists.txt
@@ -6,3 +6,4 @@ add_subdirectory (Logging)
 add_subdirectory (StackInterface)
 add_subdirectory (ProcessSequence)
 add_subdirectory (Cascade)
+add_subdirectory (Random)
diff --git a/Framework/Random/CMakeLists.txt b/Framework/Random/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3c1947d2508b318eafe6ab426bceac9af7b9e752
--- /dev/null
+++ b/Framework/Random/CMakeLists.txt
@@ -0,0 +1,49 @@
+
+set (
+  CORSIKArandom_SOURCES
+  RNGManager.cc
+  )
+
+set (
+  CORSIKArandom_HEADERS
+  RNGManager.h
+  )
+
+set (
+  CORSIKArandom_NAMESPACE
+  corsika/random
+  )
+
+add_library (CORSIKArandom STATIC ${CORSIKArandom_SOURCES})
+CORSIKA_COPY_HEADERS_TO_NAMESPACE (CORSIKArandom ${CORSIKArandom_NAMESPACE} ${CORSIKArandom_HEADERS})
+
+target_include_directories (
+  CORSIKArandom
+  PUBLIC
+  $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
+  $<INSTALL_INTERFACE:include/>
+  )
+
+# target dependencies on other libraries (also the header onlys)
+# none
+
+install (
+  TARGETS CORSIKArandom
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+  PUBLIC_HEADER DESTINATION include/${CORSIKArandom_NAMESPACE}
+  )
+
+
+# --------------------
+# code unit testing
+add_executable (testRandom testRandom.cc)
+
+target_link_libraries (
+  testRandom
+  CORSIKArandom
+  CORSIKAthirdparty # for catch2
+  )
+
+add_test (NAME testRandom COMMAND testRandom)
+
diff --git a/Framework/Random/RNGManager.cc b/Framework/Random/RNGManager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..01bc247b40232137fca29578125fb31b777f63c9
--- /dev/null
+++ b/Framework/Random/RNGManager.cc
@@ -0,0 +1,24 @@
+#include <corsika/random/RNGManager.h>
+
+void corsika::random::RNGManager::RegisterRandomStream(std::string const& pStreamName) {
+  corsika::random::RNG rng;
+
+  if (auto const& it = seeds.find(pStreamName); it != seeds.end()) {
+    rng.seed(it->second);
+  }
+
+  rngs[pStreamName] = std::move(rng);
+}
+
+corsika::random::RNG& corsika::random::RNGManager::GetRandomStream(std::string const& pStreamName) {
+  return rngs.at(pStreamName);
+}
+
+std::stringstream corsika::random::RNGManager::dumpState() const {
+  std::stringstream buffer;
+  for (auto const& [streamName, rng] : rngs) {
+    buffer << '"' << streamName << "\" = \"" << rng << '"' << std::endl;
+  }
+
+  return buffer;
+}
diff --git a/Framework/Random/RNGManager.h b/Framework/Random/RNGManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..52e53cd7570b3d7318aa1424c04cbe0c3b2c30c7
--- /dev/null
+++ b/Framework/Random/RNGManager.h
@@ -0,0 +1,44 @@
+#ifndef _include_RNGManager_h_
+#define _include_RNGManager_h_
+
+#include <map>
+#include <random>
+#include <sstream>
+#include <string>
+
+/*!
+ * With this class modules can register streams of random numbers.
+ */
+
+namespace corsika::random {
+
+  using RNG = std::mt19937; //!< the actual RNG type that will be used
+
+  class RNGManager {
+    std::map<std::string, RNG> rngs;
+    std::map<std::string, std::seed_seq> seeds;
+
+  public:
+    /*!
+     * This function is to be called by a module requiring a random-number
+     * stream during its initialization.
+     *
+     * \throws sth. when stream \a pModuleName is already registered
+     */
+    void RegisterRandomStream(std::string const& pStreamName);
+
+    /*!
+     * returns the pre-stored stream of given name \a pStreamName if
+     * available
+     */
+    RNG& GetRandomStream(std::string const& pStreamName);
+
+    /*!
+     * dumps the names and states of all registered random-number streams
+     * into a std::stringstream.
+     */
+    std::stringstream dumpState() const;
+  };
+
+} // namespace Random
+#endif
diff --git a/Framework/Random/testRandom.cc b/Framework/Random/testRandom.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f2d6fcdcad92c34bfb65f18e5701fe93ff1616f9
--- /dev/null
+++ b/Framework/Random/testRandom.cc
@@ -0,0 +1,26 @@
+#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one
+                          // cpp file
+#include <catch2/catch.hpp>
+
+#include <corsika/random/RNGManager.h>
+#include <iostream>
+
+using namespace corsika::random;
+
+SCENARIO("random-number streams can be registered and retrieved") {
+  GIVEN("a RNGManager") {
+    RNGManager rngManager;
+
+    WHEN("a sequence is registered by name") {
+      rngManager.RegisterRandomStream("stream_A");
+
+      THEN("the sequence can be retrieved") {
+        REQUIRE_NOTHROW(rngManager.GetRandomStream("stream_A"));
+      }
+
+      THEN("an unknown sequence cannot be retrieved") {
+        REQUIRE_THROWS(rngManager.GetRandomStream("stream_UNKNOWN"));
+      }
+    }
+  }
+}