diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+1.6.3.0 [2026-05-02]
+--------------------
+* Create Mini.Random.SplitMix: An implementation of SplitMix, based on
+  <https://doi.org/10.1145/2660193.2660195>
+* Mini.Random.Class:
+  * Add class Splittable: The class of splittable generators
+  * Add instance Generator SplitMix
+  * Add instance Splittable SplitMix
+
 1.6.2.0 [2026-05-01]
 --------------------
 * Create Mini.Random.Class: A pure interface for pseudorandom value generation
diff --git a/mini.cabal b/mini.cabal
--- a/mini.cabal
+++ b/mini.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               mini
-version:            1.6.2.0
+version:            1.6.3.0
 license:            MIT
 license-file:       LICENSE
 author:             Victor Wallsten <victor.wallsten@protonmail.com>
@@ -39,6 +39,7 @@
     Mini.Hash.Murmur32
     Mini.Optics.Lens
     Mini.Random.Class
+    Mini.Random.SplitMix
     Mini.Transformers.Class
     Mini.Transformers.EitherT
     Mini.Transformers.MaybeT
diff --git a/src/Mini/Random/Class.hs b/src/Mini/Random/Class.hs
--- a/src/Mini/Random/Class.hs
+++ b/src/Mini/Random/Class.hs
@@ -5,6 +5,9 @@
     nextWord32,
     nextWord64
   ),
+  Splittable (
+    split
+  ),
   Random (
     random
   ),
@@ -43,6 +46,14 @@
   add,
   digest,
  )
+import Mini.Random.SplitMix (
+  SplitMix,
+ )
+import qualified Mini.Random.SplitMix as SplitMix (
+  nextWord32,
+  nextWord64,
+  split,
+ )
 import Prelude (
   Bool,
   Char,
@@ -76,6 +87,17 @@
         lo' = fromIntegral lo
         hi' = fromIntegral hi `shiftL` 32
      in (lo' .|. hi', g')
+
+instance Generator SplitMix where
+  nextWord32 = SplitMix.nextWord32
+  nextWord64 = SplitMix.nextWord64
+
+-- | The class of splittable pseudorandom number generators
+class (Generator g) => Splittable g where
+  split :: g -> (g, g)
+
+instance Splittable SplitMix where
+  split = SplitMix.split
 
 -- | The class of types for which pseudorandom values can be generated
 class Random a where
diff --git a/src/Mini/Random/SplitMix.hs b/src/Mini/Random/SplitMix.hs
new file mode 100644
--- /dev/null
+++ b/src/Mini/Random/SplitMix.hs
@@ -0,0 +1,108 @@
+-- | An implementation of SplitMix: <https://doi.org/10.1145/2660193.2660195>
+module Mini.Random.SplitMix (
+  -- * Type
+  SplitMix,
+
+  -- * Construction
+  seed,
+
+  -- * Operations
+  nextWord32,
+  nextWord64,
+  split,
+) where
+
+import Data.Bits (
+  popCount,
+  shiftR,
+  xor,
+  (.|.),
+ )
+import Data.Word (
+  Word32,
+  Word64,
+ )
+import Mini.Data.Recursion (
+  bool,
+ )
+import Prelude (
+  Eq,
+  Ord,
+  Show,
+  fromIntegral,
+  ($),
+  (*),
+  (+),
+  (<),
+ )
+
+-- Type
+
+-- | Abstract representation of a SplitMix generator
+data SplitMix = SplitMix Word64 Word64
+  deriving (Eq, Ord, Show)
+
+-- Construction
+
+-- | Make a generator from a seed
+seed :: Word64 -> SplitMix
+seed s = SplitMix (mix64 s) (mixGamma $ s + 0x9e3779b97f4a7c15)
+
+-- Operations
+
+-- | Generate the next 32-bit word
+nextWord32 :: SplitMix -> (Word32, SplitMix)
+nextWord32 (SplitMix s g) =
+  let s' = s + g
+   in (mix32 s', SplitMix s' g)
+
+-- | Generate the next 64-bit word
+nextWord64 :: SplitMix -> (Word64, SplitMix)
+nextWord64 (SplitMix s g) =
+  let s' = s + g
+   in (mix64 s', SplitMix s' g)
+
+-- | Split a generator into two (seemingly) independent generators
+split :: SplitMix -> (SplitMix, SplitMix)
+split (SplitMix s g) =
+  let s' = s + g
+      s'' = s' + g
+      sm = SplitMix s'' g
+      sm' = SplitMix (mix64 s') (mixGamma s'')
+   in (sm, sm')
+
+-- Helpers
+
+mix64 :: Word64 -> Word64
+mix64 z0 =
+  let z1 = z0 `xor` (z0 `shiftR` 33)
+      z2 = z1 * 0xff51afd7ed558ccd
+      z3 = z2 `xor` (z2 `shiftR` 33)
+      z4 = z3 * 0xc4ceb9fe1a85ec53
+      z5 = z4 `xor` (z4 `shiftR` 33)
+   in z5
+
+mix32 :: Word64 -> Word32
+mix32 z0 =
+  let z1 = z0 `xor` (z0 `shiftR` 33)
+      z2 = z1 * 0xff51afd7ed558ccd
+      z3 = z2 `xor` (z2 `shiftR` 33)
+      z4 = z3 * 0xc4ceb9fe1a85ec53
+      z5 = z4 `shiftR` 32
+   in fromIntegral z5
+
+mix64variant13 :: Word64 -> Word64
+mix64variant13 z0 =
+  let z1 = z0 `xor` (z0 `shiftR` 30)
+      z2 = z1 * 0xbf58476d1ce4e5b9
+      z3 = z2 `xor` (z2 `shiftR` 27)
+      z4 = z3 * 0x94d049bb133111eb
+      z5 = z4 `xor` (z4 `shiftR` 31)
+   in z5
+
+mixGamma :: Word64 -> Word64
+mixGamma z0 =
+  let z1 = mix64variant13 z0 .|. 1
+      n = popCount $ z1 `xor` (z1 `shiftR` 1)
+   in -- based on the text on p. 466, not the code with inverted logic on p. 465
+      bool z1 (z1 `xor` 0xaaaaaaaaaaaaaaaa) $ n < 24
