diff --git a/phpstan.neon b/phpstan.neon
index 5f2b3faa8f0294fa4606e64dd7edff999c070cd3..4b0aa288751dcd108a62a197e086e3aacedb4358 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -5,6 +5,7 @@ parameters:
         - tests
     ignoreErrors:
         - '#Variable property access on \$this\(OTPHP\\OTP\)\.#'
+
 includes:
     - vendor/phpstan/phpstan-strict-rules/rules.neon
     - vendor/phpstan/phpstan-phpunit/extension.neon
diff --git a/src/Factory.php b/src/Factory.php
index 42b5fbf79c2a7d7999b3e3726e4093532d60ac81..4b917749f33e120869b9bcf6ce4ea0c6aaa21d5e 100644
--- a/src/Factory.php
+++ b/src/Factory.php
@@ -7,6 +7,7 @@ namespace OTPHP;
 use Assert\Assertion;
 use function count;
 use InvalidArgumentException;
+use function Safe\sprintf;
 use Throwable;
 
 /**
diff --git a/src/HOTP.php b/src/HOTP.php
index 49d5c232614e408102f0db4ef403cb204ac92a99..7c941877223dfb28c082e1329e39f5f559d03350 100644
--- a/src/HOTP.php
+++ b/src/HOTP.php
@@ -8,14 +8,14 @@ use Assert\Assertion;
 
 final class HOTP extends OTP implements HOTPInterface
 {
-    protected function __construct(?string $secret, int $counter, string $digest, int $digits)
+    protected function __construct(null|string $secret, int $counter, string $digest, int $digits)
     {
         parent::__construct($secret, $digest, $digits);
         $this->setCounter($counter);
     }
 
     public static function create(
-        ?string $secret = null,
+        null|string $secret = null,
         int $counter = 0,
         string $digest = 'sha1',
         int $digits = 6
@@ -41,7 +41,7 @@ final class HOTP extends OTP implements HOTPInterface
     /**
      * If the counter is not provided, the OTP is verified at the actual counter.
      */
-    public function verify(string $otp, ?int $counter = null, ?int $window = null): bool
+    public function verify(string $otp, null|int $counter = null, null|int|float $window = null): bool
     {
         Assertion::greaterOrEqualThan($counter, 0, 'The counter must be at least 0.');
 
@@ -81,12 +81,12 @@ final class HOTP extends OTP implements HOTPInterface
         $this->setCounter($counter);
     }
 
-    private function getWindow(?int $window): int
+    private function getWindow(null|int|float $window): int|float
     {
         return abs($window ?? 0);
     }
 
-    private function verifyOtpWithWindow(string $otp, int $counter, ?int $window): bool
+    private function verifyOtpWithWindow(string $otp, int $counter, null|int|float $window): bool
     {
         $window = $this->getWindow($window);
 
diff --git a/src/HOTPInterface.php b/src/HOTPInterface.php
index a311cb29d85c9e99aa1bfa79cb8260bca32e65b7..1f9cdd7f8fd863db555beaccad5efbcce46d4b0e 100644
--- a/src/HOTPInterface.php
+++ b/src/HOTPInterface.php
@@ -17,7 +17,7 @@ interface HOTPInterface extends OTPInterface
      * If the secret is null, a random 64 bytes secret will be generated.
      */
     public static function create(
-        ?string $secret = null,
+        null|string $secret = null,
         int $counter = 0,
         string $digest = 'sha1',
         int $digits = 6
diff --git a/src/OTP.php b/src/OTP.php
index 2ff11dedc21d85de8cb950ce7f95330c5c6b3fc2..25fd4d62a98fddd1fa3bc621d22ac4d459ff0077 100644
--- a/src/OTP.php
+++ b/src/OTP.php
@@ -10,6 +10,8 @@ use function count;
 use Exception;
 use ParagonIE\ConstantTime\Base32;
 use RuntimeException;
+use function Safe\ksort;
+use function Safe\sprintf;
 use function Safe\unpack;
 use const STR_PAD_LEFT;
 
@@ -17,7 +19,7 @@ abstract class OTP implements OTPInterface
 {
     use ParameterTrait;
 
-    protected function __construct(?string $secret, string $digest, int $digits)
+    protected function __construct(null|string $secret, string $digest, int $digits)
     {
         $this->setSecret($secret);
         $this->setDigest($digest);
diff --git a/src/OTPInterface.php b/src/OTPInterface.php
index 6c28a3f7549bfddf8cf79c4215a8bc1681df32c3..0d8d888d82b4f7245a71800fe3b6fdcbd22069b4 100644
--- a/src/OTPInterface.php
+++ b/src/OTPInterface.php
@@ -15,7 +15,7 @@ interface OTPInterface
      * Verify that the OTP is valid with the specified input. If no input is provided, the input is set to a default
      * value or false is returned.
      */
-    public function verify(string $otp, ?int $input = null, ?int $window = null): bool;
+    public function verify(string $otp, null|int $input = null, null|int|float $window = null): bool;
 
     /**
      * @return string The secret of the OTP
@@ -30,7 +30,7 @@ interface OTPInterface
     /**
      * @return string|null The label of the OTP
      */
-    public function getLabel(): ?string;
+    public function getLabel(): null|string;
 
     /**
      * @return string|null The issuer
@@ -56,10 +56,7 @@ interface OTPInterface
      */
     public function getDigest(): string;
 
-    /**
-     * @return mixed|null
-     */
-    public function getParameter(string $parameter);
+    public function getParameter(string $parameter): mixed;
 
     public function hasParameter(string $parameter): bool;
 
@@ -68,10 +65,7 @@ interface OTPInterface
      */
     public function getParameters(): array;
 
-    /**
-     * @param mixed|null $value
-     */
-    public function setParameter(string $parameter, $value): void;
+    public function setParameter(string $parameter, mixed $value): void;
 
     /**
      * Get the provisioning URI.
diff --git a/src/ParameterTrait.php b/src/ParameterTrait.php
index 74c43d11b2571b65e35e4779572630e427da0688..cbc3e277a575749d4bf880c8e52472b8f369d18a 100644
--- a/src/ParameterTrait.php
+++ b/src/ParameterTrait.php
@@ -8,6 +8,7 @@ use function array_key_exists;
 use Assert\Assertion;
 use InvalidArgumentException;
 use ParagonIE\ConstantTime\Base32;
+use function Safe\sprintf;
 
 trait ParameterTrait
 {
@@ -44,7 +45,7 @@ trait ParameterTrait
         return $value;
     }
 
-    public function getLabel(): ?string
+    public function getLabel(): null|string
     {
         return $this->label;
     }
@@ -54,7 +55,7 @@ trait ParameterTrait
         $this->setParameter('label', $label);
     }
 
-    public function getIssuer(): ?string
+    public function getIssuer(): null|string
     {
         return $this->issuer;
     }
@@ -95,7 +96,7 @@ trait ParameterTrait
         return array_key_exists($parameter, $this->parameters);
     }
 
-    public function getParameter(string $parameter)
+    public function getParameter(string $parameter): mixed
     {
         if ($this->hasParameter($parameter)) {
             return $this->getParameters()[$parameter];
@@ -104,7 +105,7 @@ trait ParameterTrait
         throw new InvalidArgumentException(sprintf('Parameter "%s" does not exist', $parameter));
     }
 
-    public function setParameter(string $parameter, $value): void
+    public function setParameter(string $parameter, mixed $value): void
     {
         $map = $this->getParameterMap();
 
@@ -157,7 +158,7 @@ trait ParameterTrait
         ];
     }
 
-    private function setSecret(?string $secret): void
+    private function setSecret(null|string $secret): void
     {
         $this->setParameter('secret', $secret);
     }
diff --git a/src/TOTP.php b/src/TOTP.php
index 75805094e7fad2761194cd729105014ba1f0d972..2adf41f6a37a5dab6d4392e47a58b075a2364158 100644
--- a/src/TOTP.php
+++ b/src/TOTP.php
@@ -5,10 +5,11 @@ declare(strict_types=1);
 namespace OTPHP;
 
 use Assert\Assertion;
+use function Safe\ksort;
 
 final class TOTP extends OTP implements TOTPInterface
 {
-    protected function __construct(?string $secret, int $period, string $digest, int $digits, int $epoch = 0)
+    protected function __construct(null|string $secret, int $period, string $digest, int $digits, int $epoch = 0)
     {
         parent::__construct($secret, $digest, $digits);
         $this->setPeriod($period);
@@ -16,7 +17,7 @@ final class TOTP extends OTP implements TOTPInterface
     }
 
     public static function create(
-        ?string $secret = null,
+        null|string $secret = null,
         int $period = 30,
         string $digest = 'sha1',
         int $digits = 6,
@@ -54,7 +55,7 @@ final class TOTP extends OTP implements TOTPInterface
     /**
      * If no timestamp is provided, the OTP is verified at the actual timestamp.
      */
-    public function verify(string $otp, ?int $timestamp = null, ?int $window = null): bool
+    public function verify(string $otp, null|int $timestamp = null, null|int|float $window = null): bool
     {
         $timestamp = $this->getTimestamp($timestamp);
 
@@ -125,7 +126,7 @@ final class TOTP extends OTP implements TOTPInterface
         $this->setParameter('epoch', $epoch);
     }
 
-    private function verifyOtpWithWindow(string $otp, int $timestamp, int $window): bool
+    private function verifyOtpWithWindow(string $otp, int $timestamp, int|float $window): bool
     {
         $window = abs($window);
 
@@ -143,7 +144,7 @@ final class TOTP extends OTP implements TOTPInterface
         return false;
     }
 
-    private function getTimestamp(?int $timestamp): int
+    private function getTimestamp(null|int $timestamp): int
     {
         $timestamp = $timestamp ?? time();
         Assertion::greaterOrEqualThan($timestamp, 0, 'Timestamp must be at least 0.');
diff --git a/src/TOTPInterface.php b/src/TOTPInterface.php
index d79fd55991f818b1254b154862a49730e8b6052f..2d492f941b8180e8eaaee8bfec559b767d871f80 100644
--- a/src/TOTPInterface.php
+++ b/src/TOTPInterface.php
@@ -12,7 +12,7 @@ interface TOTPInterface extends OTPInterface
      * If the secret is null, a random 64 bytes secret will be generated.
      */
     public static function create(
-        ?string $secret = null,
+        null|string $secret = null,
         int $period = 30,
         string $digest = 'sha1',
         int $digits = 6