diff --git a/Cargo.toml b/Cargo.toml
index 94e4701..d601846 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,7 +65,8 @@ version = "1.21.3"
 version = "0.1"
 
 [dependencies.rand]
-version = "0.8"
+version = "0.10"
+features = ["thread_rng"]
 
 [dependencies.regex]
 version = "1.12"
@@ -80,7 +81,7 @@ version = "2.1.2"
 version = "0.5"
 
 [dev-dependencies.rand_xoshiro]
-version = "0.6"
+version = "0.8"
 
 [build-dependencies.clap]
 version = "4"
diff --git a/src/distinct.rs b/src/distinct.rs
index 402e559..d942387 100644
--- a/src/distinct.rs
+++ b/src/distinct.rs
@@ -1,4 +1,5 @@
 use rand::prelude::*;
+use rand::rng;
 
 use crate::delta_e;
 use crate::random::{self, RandomizationStrategy};
@@ -72,7 +73,7 @@ pub struct SimulatedAnnealing<R: Rng> {
 
 impl SimulatedAnnealing<ThreadRng> {
     pub fn new(initial_colors: &[Color], parameters: SimulationParameters) -> Self {
-        Self::with_rng(initial_colors, parameters, thread_rng())
+        Self::with_rng(initial_colors, parameters, rng())
     }
 }
 
@@ -96,10 +97,10 @@ impl<R: Rng> SimulatedAnnealing<R> {
     }
 
     fn modify_channel(&mut self, c: &mut u8) {
-        if self.rng.gen::<bool>() {
-            *c = c.saturating_add(self.rng.gen::<u8>() % 10);
+        if self.rng.random::<bool>() {
+            *c = c.saturating_add(self.rng.random::<u8>() % 10);
         } else {
-            *c = c.saturating_sub(self.rng.gen::<u8>() % 10);
+            *c = c.saturating_sub(self.rng.random::<u8>() % 10);
         }
     }
 
@@ -137,7 +138,7 @@ impl<R: Rng> SimulatedAnnealing<R> {
         for iter in 0..self.parameters.num_iterations {
             let random_index = if self.parameters.opt_target == OptimizationTarget::Mean {
                 self.rng
-                    .gen_range(self.parameters.num_fixed_colors..self.colors.len())
+                    .random_range(self.parameters.num_fixed_colors..self.colors.len())
             } else {
                 // first check if any of the colors cannot change, if that's the case just return
                 // the other color. Note that the closest_pair cannot contain only fixed colors.
@@ -146,7 +147,7 @@ impl<R: Rng> SimulatedAnnealing<R> {
                     result.closest_pair.1
                 } else if result.closest_pair.1 < self.parameters.num_fixed_colors {
                     result.closest_pair.0
-                } else if self.rng.gen() {
+                } else if self.rng.random() {
                     result.closest_pair.0
                 } else {
                     result.closest_pair.1
@@ -182,7 +183,7 @@ impl<R: Rng> SimulatedAnnealing<R> {
                 self.lab_values = new_lab_values;
             } else {
                 let bolzmann = Scalar::exp(-(score - new_score) / self.temperature);
-                if self.rng.gen::<Scalar>() <= bolzmann {
+                if self.rng.random::<Scalar>() <= bolzmann {
                     result = new_result;
                     self.colors[random_index] = new_colors;
                     self.lab_values = new_lab_values;
diff --git a/src/random.rs b/src/random.rs
index 38e6640..f2d0f10 100644
--- a/src/random.rs
+++ b/src/random.rs
@@ -1,13 +1,14 @@
 use crate::Color;
 
 use rand::prelude::*;
+use rand::rng;
 
 pub trait RandomizationStrategy {
     fn generate(&mut self) -> Color {
-        self.generate_with(&mut thread_rng())
+        self.generate_with(&mut rng())
     }
 
-    fn generate_with(&mut self, r: &mut dyn RngCore) -> Color;
+    fn generate_with(&mut self, r: &mut dyn Rng) -> Color;
 }
 
 pub mod strategies {
@@ -19,10 +20,10 @@ pub mod strategies {
     pub struct Vivid;
 
     impl RandomizationStrategy for Vivid {
-        fn generate_with(&mut self, rng: &mut dyn RngCore) -> Color {
-            let hue = rng.gen::<f64>() * 360.0;
-            let saturation = 0.2 + 0.6 * rng.gen::<f64>();
-            let lightness = 0.3 + 0.4 * rng.gen::<f64>();
+        fn generate_with(&mut self, rng: &mut dyn Rng) -> Color {
+            let hue = rng.random::<f64>() * 360.0;
+            let saturation = 0.2 + 0.6 * rng.random::<f64>();
+            let lightness = 0.3 + 0.4 * rng.random::<f64>();
 
             Color::from_hsl(hue, saturation, lightness)
         }
@@ -31,24 +32,24 @@ pub mod strategies {
     pub struct UniformRGB;
 
     impl RandomizationStrategy for UniformRGB {
-        fn generate_with(&mut self, rng: &mut dyn RngCore) -> Color {
-            Color::from_rgb(rng.gen::<u8>(), rng.gen::<u8>(), rng.gen::<u8>())
+        fn generate_with(&mut self, rng: &mut dyn Rng) -> Color {
+            Color::from_rgb(rng.random::<u8>(), rng.random::<u8>(), rng.random::<u8>())
         }
     }
 
     pub struct UniformGray;
 
     impl RandomizationStrategy for UniformGray {
-        fn generate_with(&mut self, rng: &mut dyn RngCore) -> Color {
-            Color::graytone(rng.gen::<f64>())
+        fn generate_with(&mut self, rng: &mut dyn Rng) -> Color {
+            Color::graytone(rng.random::<f64>())
         }
     }
 
     pub struct UniformHueLCh;
 
     impl RandomizationStrategy for UniformHueLCh {
-        fn generate_with(&mut self, rng: &mut dyn RngCore) -> Color {
-            Color::from_lch(70.0, 35.0, 360.0 * rng.gen::<f64>(), 1.0)
+        fn generate_with(&mut self, rng: &mut dyn Rng) -> Color {
+            Color::from_lch(70.0, 35.0, 360.0 * rng.random::<f64>(), 1.0)
         }
     }
 }
