diff --git a/FPE/FF1.hs b/FPE/FF1.hs
--- a/FPE/FF1.hs
+++ b/FPE/FF1.hs
@@ -1,7 +1,7 @@
 module FPE.FF1 (encrypt, decrypt, BlockCipher, Crypter, Tweak) where
 
 import Data.Bits
-import Control.Arrow
+import Control.Arrow hiding (loop)
 import Control.Monad
 import Data.Tuple (swap)
 import Math.NumberTheory.Logarithms
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2018-2019 Galen Huntington
+Copyright (c) 2018-2026 Galen Huntington
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/ff1test.hs b/ff1test.hs
deleted file mode 100644
--- a/ff1test.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-import FPE.FF1 as FF1
-import Crypto.Cipher.Types
-import Crypto.Cipher.AES
-import Crypto.Error
-import Control.Monad (when)
-
-import qualified Data.Vector.Unboxed as V
-import qualified Data.ByteString as B
-
-
---  The first two samples from
---  https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/FF1samples.pdf
-
-CryptoPassed (key :: AES128) = cipherInit $ B.pack [
-  0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]
-
-main = do
-   let cipher = ecbEncrypt key
-   let tweak = mempty
-   let plain = V.fromList @Int [0..9]
-   let crypt = FF1.encrypt cipher 10 tweak plain
-   print crypt
-   when (V.toList crypt /= [2,4,3,3,4,7,7,4,8,4]) $ error "bad encrypt"
-   when (FF1.decrypt cipher 10 tweak crypt /= plain) $ error "bad decrypt"
-   let tweak = B.pack [ 0x39, 0x38 .. 0x30]
-   let crypt = FF1.encrypt cipher 10 tweak plain
-   print crypt
-   when (V.toList crypt /= [6,1,2,4,2,0,0,7,7,3]) $ error "bad tweak encrypt"
-
diff --git a/fpe.cabal b/fpe.cabal
--- a/fpe.cabal
+++ b/fpe.cabal
@@ -1,63 +1,53 @@
-cabal-version: 1.18
-
--- This file has been generated from package.yaml by hpack version 0.35.2.
---
--- see: https://github.com/sol/hpack
---
--- hash: 7c1d4de3459a0ae08db6ac62316d35c53b83835bd66b402d61fc598469099456
-
-name:           fpe
-version:        0.1.2
-synopsis:       Format-preserving encryption.
-category:       Cryptography
-homepage:       https://github.com/galenhuntington/fpe#readme
-bug-reports:    https://github.com/galenhuntington/fpe/issues
-author:         Galen Huntington
-maintainer:     Galen Huntington
-license:        MIT
-license-file:   LICENSE
-build-type:     Simple
+cabal-version: 2.2
+name: fpe
+version: 0.1.3
+synopsis: Format-preserving encryption.
+category: Cryptography
+homepage: https://github.com/galenhuntington/fpe#readme
+bug-reports: https://github.com/galenhuntington/fpe/issues
+author: Galen Huntington
+maintainer: Galen Huntington
+license: MIT
+license-file: LICENSE
+build-type: Simple
 extra-doc-files:
-    README.md
+  README.md
 
 source-repository head
   type: git
   location: https://github.com/galenhuntington/fpe
 
+common opts
+  default-language: GHC2021
+  ghc-options:
+    -Wall
+    -Wredundant-constraints
+    -Wcompat
+
+  build-depends:
+    base >=4.16 && <5,
+    bytestring >=0.10 && <0.13,
+    vector >=0.12 && <0.14,
+
 library
+  import: opts
   exposed-modules:
-      FPE.FF1
-  other-modules:
-      Paths_fpe
-  hs-source-dirs:
-      ./
-  default-extensions:
-      TypeApplications
-      ScopedTypeVariables
-  ghc-options: -Wall -Wredundant-constraints -Wno-name-shadowing -Wno-missing-signatures -Wno-unused-do-bind -Wno-orphans -Wcompat
+    FPE.FF1
+
   build-depends:
-      base >=4.9 && <5
-    , bytestring >=0.10 && <0.13
-    , integer-logarithms >=1 && <1.1
-    , vector >=0.12 && <0.14
-  default-language: Haskell2010
+    integer-logarithms >=1 && <1.1
 
+  hs-source-dirs:
+    ./
+
 test-suite suite
+  import: opts
   type: exitcode-stdio-1.0
   main-is: ff1test.hs
-  other-modules:
-      FPE.FF1
-      Paths_fpe
   hs-source-dirs:
-      ./
-  default-extensions:
-      TypeApplications
-      ScopedTypeVariables
-  ghc-options: -Wall -Wredundant-constraints -Wno-name-shadowing -Wno-missing-signatures -Wno-unused-do-bind -Wno-orphans -Wcompat
+    test
+
   build-depends:
-      base >=4.9 && <5
-    , bytestring >=0.10 && <0.13
-    , cryptonite
-    , integer-logarithms >=1 && <1.1
-    , vector >=0.12 && <0.14
-  default-language: Haskell2010
+    crypton,
+    fpe,
+
diff --git a/test/ff1test.hs b/test/ff1test.hs
new file mode 100644
--- /dev/null
+++ b/test/ff1test.hs
@@ -0,0 +1,41 @@
+{-# OPTIONS_GHC -Wno-name-shadowing -Wno-incomplete-uni-patterns #-}
+
+import FPE.FF1 as FF1
+import Crypto.Cipher.Types
+import Crypto.Cipher.AES
+import Crypto.Error
+import Control.Monad (when)
+
+import qualified Data.Vector.Unboxed as V
+import qualified Data.ByteString as B
+
+
+--  The first three samples from
+--  https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/FF1samples.pdf
+
+key :: AES128
+CryptoPassed key = cipherInit $ B.pack [
+  0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c]
+
+main :: IO ()
+main = do
+   let cipher = ecbEncrypt key
+   let tweak = mempty
+   let plain = V.fromList @Int [0..9]
+   let crypt = FF1.encrypt cipher 10 tweak plain
+   print crypt
+   when (V.toList crypt /= [2,4,3,3,4,7,7,4,8,4]) $ error "bad encrypt"
+   when (FF1.decrypt cipher 10 tweak crypt /= plain) $ error "bad decrypt"
+   let tweak = B.pack [ 0x39, 0x38 .. 0x30]
+   let crypt = FF1.encrypt cipher 10 tweak plain
+   print crypt
+   when (V.toList crypt /= [6,1,2,4,2,0,0,7,7,3]) $ error "bad tweak encrypt"
+   let tweak = B.pack [0x37, 0x37, 0x37, 0x37, 0x70, 0x71, 0x72, 0x73, 0x37, 0x37, 0x37]
+   let plain = V.fromList @Int [0..18]
+   let crypt = FF1.encrypt cipher 36 tweak plain
+   print crypt
+   when (V.toList crypt /= [10,9,29,31,4,0,22,21,21,9,20,13,30,5,0,9,14,30,22])
+     $ error "bad radix-36 encrypt"
+   when (FF1.decrypt cipher 36 tweak crypt /= plain) $ error "bad radix-36 decrypt"
+
