diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,12 @@
 See also http://pvp.haskell.org/faq
 
+0.6.4.0
+-------
+
+* Make hackageIndexLayout faster
+* Stop using lukko
+* Fix bug in unPathNative
+
 0.6.3.3
 -------
 
diff --git a/hackage-security.cabal b/hackage-security.cabal
--- a/hackage-security.cabal
+++ b/hackage-security.cabal
@@ -1,6 +1,6 @@
 cabal-version:       1.18
 name:                hackage-security
-version:             0.6.3.3
+version:             0.6.4.0
 
 synopsis:            Hackage security library
 description:         The hackage security library provides both server and
@@ -205,7 +205,7 @@
                        tasty-hunit           == 0.10.*,
                        tasty-quickcheck      >= 0.10     && < 1,
                        QuickCheck            >= 2.11     && < 2.19,
-                       aeson                 >= 1.4      && < 1.6 || >= 2.0 && < 2.3,
+                       aeson                 >= 1.4      && < 1.6 || >= 2.0 && < 2.4,
                        vector                >= 0.12     && < 0.14,
                        unordered-containers  >= 0.2.8.0  && < 0.3,
                        temporary             >= 1.2      && < 1.4
diff --git a/src/Hackage/Security/TUF/Layout/Index.hs b/src/Hackage/Security/TUF/Layout/Index.hs
--- a/src/Hackage/Security/TUF/Layout/Index.hs
+++ b/src/Hackage/Security/TUF/Layout/Index.hs
@@ -10,9 +10,12 @@
   ) where
 
 import Prelude
+import Data.Char (ord)
 import Data.Kind (Type)
 import Distribution.Package
 import Distribution.Text
+import Distribution.Types.Version (mkVersion)
+import System.FilePath.Posix (isPathSeparator)
 
 import Hackage.Security.TUF.Paths
 import Hackage.Security.TUF.Signed
@@ -91,17 +94,38 @@
     fromFragments :: [String] -> IndexPath
     fromFragments = rootPath . joinFragments
 
+    -- This function is called in a hot loop, take care when modifying it.
+    -- Especially avoid 'splitFragments' / 'splitDirectories' and other high-level helpers,
+    -- they are very slow.
     fromPath :: IndexPath -> Maybe (Some IndexFile)
-    fromPath fp = case splitFragments (unrootPath fp) of
-      [pkg, version, _file] -> do
-        pkgId <- simpleParse (pkg ++ "-" ++ version)
-        case takeExtension fp of
-          ".cabal"   -> return $ Some $ IndexPkgCabal    pkgId
-          ".json"    -> return $ Some $ IndexPkgMetadata pkgId
-          _otherwise -> Nothing
-      [pkg, "preferred-versions"] ->
-        Some . IndexPkgPrefs <$> simpleParse pkg
-      _otherwise -> Nothing
+    fromPath fp = case break isPathSeparator (toUnrootedFilePath (unrootPath fp)) of
+      (pkg, "/preferred-versions") ->
+        return $ Some $ IndexPkgPrefs $ mkPackageName pkg
+      (pkg, rest) -> case break isPathSeparator (drop 1 rest) of
+        (_, []) -> Nothing
+        (version, basename) -> do
+          let pkgName = mkPackageName pkg
+              pkgVersion = mkVersion $ readVersion version
+              pkgId = PackageIdentifier { pkgName, pkgVersion }
+          case reverse basename of
+            -- ".cabal" reversed
+            'l' : 'a' : 'b' : 'a' : 'c' : '.' : _ ->
+              return $ Some $ IndexPkgCabal pkgId
+            -- ".json" reversed
+            'n' : 'o' : 's' : 'j' : '.' : _ ->
+              return $ Some $ IndexPkgMetadata pkgId
+            _ -> Nothing
+
+-- Convert "3.12.1.0" to [3,12,1,0].
+-- Copied from hackage-revdeps package.
+readVersion :: String -> [Int]
+readVersion = (\(acc, _mult, rest) -> acc : rest) . foldr go (0, 1, [])
+  where
+    go c (acc, mult, rest)
+      | fromIntegral d < (10 :: Word) = (acc + d * mult, mult * 10, rest)
+      | otherwise = (0, 1, acc : rest)
+      where
+        d = ord c - ord '0'
 
 {-------------------------------------------------------------------------------
   Utility
