diff --git a/riddler.info.yml b/riddler.info.yml
index 1c4a3b7..e014ad0 100644
--- a/riddler.info.yml
+++ b/riddler.info.yml
@@ -2,6 +2,6 @@ name: Captcha Riddler
 type: module
 description: 'Provides a question and answer CAPTCHA.'
 package: Spam control
-core_version_requirement: ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 dependencies:
   - captcha:captcha
diff --git a/riddler.module b/riddler.module
index ec9f8f0..a2cc660 100755
--- a/riddler.module
+++ b/riddler.module
@@ -7,68 +7,26 @@
  * This module provides a new captcha challenge type, which consists of
  * answering a simple question to verify the user.
  */
-
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\riddler\Hook\RiddlerHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\captcha\Constants\CaptchaConstants;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function riddler_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.riddler':
-      $output = '<p>' . t('This module provides a new captcha challenge type, which consists of answering a simple question to verify the user. This is mainly used to counter spam.') . '</p>';
-      return $output;
-  }
+  return \Drupal::service(RiddlerHooks::class)->help($route_name, $route_match);
 }
 
 /**
  * Implements hook_captcha().
  */
-function riddler_captcha($op, $captcha_type = '', $captcha_sid = NULL) {
-  $riddles = \Drupal::service('entity_type.manager')->getStorage('riddle')->loadByProperties(['status' => TRUE]);
-
-  switch ($op) {
-    case 'list':
-      return ['Riddler'];
-
-    case 'generate':
-      if ($captcha_type == 'Riddler') {
-        // Generate a CAPTCHA code.
-        $key = array_rand($riddles);
-        $riddleEntity = $riddles[$key];
-
-        // Build the result to return.
-        $result = [];
-
-        $result['solution'] = $riddleEntity->getSolution();
-
-        $result['form']['captcha_response'] = [
-          '#type' => 'textfield',
-          '#title' => $riddleEntity->getQuestion(),
-          '#description' => $riddleEntity->getHint(),
-          '#weight' => 0,
-          '#required' => TRUE,
-          '#size' => 15,
-          '#attributes' => ['autocomplete' => 'off'],
-        ];
-        // If there are several random questions, we cannot cache.
-        if (count($riddles) > 1) {
-          $result['form']['captcha_response']['#cache'] = ['max-age' => 0];
-          \Drupal::service('page_cache_kill_switch')->trigger();
-        }
-        else {
-          // Indicate the riddler is cacheable, see captcha.api.php:
-          $result['cacheable'] = TRUE;
-        }
-
-        // Use custom validation so multiple answers can be tested.
-        $result['captcha_validate'] = 'riddler_captcha_validate';
-
-        return $result;
-      }
-      break;
-  }
+#[LegacyHook]
+function riddler_captcha($op, $captcha_type = '', $captcha_sid = NULL)
+{
+    return \Drupal::service(RiddlerHooks::class)->captcha($op, $captcha_type, $captcha_sid);
 }
 
 /**
diff --git a/riddler.services.yml b/riddler.services.yml
new file mode 100644
index 0000000..9de6a86
--- /dev/null
+++ b/riddler.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\riddler\Hook\RiddlerHooks:
+    class: Drupal\riddler\Hook\RiddlerHooks
+    autowire: true
diff --git a/src/Hook/RiddlerHooks.php b/src/Hook/RiddlerHooks.php
new file mode 100644
index 0000000..9d1c812
--- /dev/null
+++ b/src/Hook/RiddlerHooks.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Drupal\riddler\Hook;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\captcha\Constants\CaptchaConstants;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+/**
+ * Hook implementations for riddler.
+ */
+class RiddlerHooks
+{
+    use StringTranslationTrait;
+    /**
+     * Implements hook_help().
+     */
+    #[Hook('help')]
+    public function help($route_name, \Drupal\Core\Routing\RouteMatchInterface $route_match)
+    {
+        switch ($route_name) {
+            case 'help.page.riddler':
+                $output = '<p>' . $this->t('This module provides a new captcha challenge type, which consists of answering a simple question to verify the user. This is mainly used to counter spam.') . '</p>';
+                return $output;
+        }
+    }
+    /**
+     * Implements hook_captcha().
+     */
+    #[Hook('captcha')]
+    public static function captcha($op, $captcha_type = '', $captcha_sid = NULL)
+    {
+        $riddles = \Drupal::service('entity_type.manager')->getStorage('riddle')->loadByProperties([
+            'status' => TRUE,
+        ]);
+        switch ($op) {
+            case 'list':
+                return [
+                    'Riddler',
+                ];
+            case 'generate':
+                if ($captcha_type == 'Riddler') {
+                    // Generate a CAPTCHA code.
+                    $key = array_rand($riddles);
+                    $riddleEntity = $riddles[$key];
+                    // Build the result to return.
+                    $result = [
+                    ];
+                    $result['solution'] = $riddleEntity->getSolution();
+                    $result['form']['captcha_response'] = [
+                        '#type' => 'textfield',
+                        '#title' => $riddleEntity->getQuestion(),
+                        '#description' => $riddleEntity->getHint(),
+                        '#weight' => 0,
+                        '#required' => TRUE,
+                        '#size' => 15,
+                        '#attributes' => [
+                            'autocomplete' => 'off',
+                        ],
+                    ];
+                    // If there are several random questions, we cannot cache.
+                    if (count($riddles) > 1) {
+                        $result['form']['captcha_response']['#cache'] = [
+                            'max-age' => 0,
+                        ];
+                        \Drupal::service('page_cache_kill_switch')->trigger();
+                    } else {
+                        // Indicate the riddler is cacheable, see captcha.api.php:
+                        $result['cacheable'] = TRUE;
+                    }
+                    // Use custom validation so multiple answers can be tested.
+                    $result['captcha_validate'] = 'riddler_captcha_validate';
+                    return $result;
+                }
+                break;
+        }
+    }
+}
diff --git a/tests/src/Functional/RiddlerCaseSensitivityTest.php b/tests/src/Functional/RiddlerCaseSensitivityTest.php
index ae4024a..89c49eb 100644
--- a/tests/src/Functional/RiddlerCaseSensitivityTest.php
+++ b/tests/src/Functional/RiddlerCaseSensitivityTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\riddler\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\captcha\Constants\CaptchaConstants;
 
 /**
@@ -9,6 +11,8 @@ use Drupal\captcha\Constants\CaptchaConstants;
  *
  * @group captcha
  */
+#[Group('captcha')]
+#[RunTestsInSeparateProcesses]
 class RiddlerCaseSensitivityTest extends RiddlerFunctionalTestBase {
 
   /**
diff --git a/tests/src/Functional/RiddlerFunctionalTestBase.php b/tests/src/Functional/RiddlerFunctionalTestBase.php
index 0436fd8..4f987f0 100644
--- a/tests/src/Functional/RiddlerFunctionalTestBase.php
+++ b/tests/src/Functional/RiddlerFunctionalTestBase.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\riddler\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -9,6 +10,7 @@ use Drupal\Tests\BrowserTestBase;
  *
  * @group captcha
  */
+#[Group('captcha')]
 abstract class RiddlerFunctionalTestBase extends BrowserTestBase {
 
   /**
diff --git a/tests/src/Functional/RiddlerGeneralTest.php b/tests/src/Functional/RiddlerGeneralTest.php
index 835b45d..1c8322b 100644
--- a/tests/src/Functional/RiddlerGeneralTest.php
+++ b/tests/src/Functional/RiddlerGeneralTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\riddler\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -9,6 +11,8 @@ use Drupal\Tests\BrowserTestBase;
  *
  * @group captcha
  */
+#[Group('captcha')]
+#[RunTestsInSeparateProcesses]
 class RiddlerGeneralTest extends RiddlerFunctionalTestBase {
 
   /**
