diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for byteslice
 
+## 0.2.1.0 -- 2020-01-22
+
+* Add `longestCommonPrefix`.
+* Fix broken `Ord` instance of `Bytes`.
+
 ## 0.2.0.0 -- 2020-01-20
 
 * Change behavior of `split`. This function previously had a special case
diff --git a/byteslice.cabal b/byteslice.cabal
--- a/byteslice.cabal
+++ b/byteslice.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: byteslice
-version: 0.2.0.0
+version: 0.2.1.0
 synopsis: Slicing managed and unmanaged memory
 description:
   This library provides types that allow the user to talk about a slice of
diff --git a/src/Data/Bytes.hs b/src/Data/Bytes.hs
--- a/src/Data/Bytes.hs
+++ b/src/Data/Bytes.hs
@@ -60,6 +60,7 @@
   , stripOptionalPrefix
   , stripSuffix
   , stripOptionalSuffix
+  , longestCommonPrefix
     -- ** Single Byte
   , isBytePrefixOf
   , isByteSuffixOf
@@ -169,6 +170,18 @@
   if aLen <= bLen
     then compareByteArrays a aOff b (bOff + bLen - aLen) aLen == EQ
     else False
+
+-- | Find the longest string which is a prefix of both arguments.
+longestCommonPrefix :: Bytes -> Bytes -> Bytes
+longestCommonPrefix a b = loop 0
+  where
+  loop :: Int -> Bytes
+  loop !into
+    | into < maxLen
+      && unsafeIndex a into == unsafeIndex b into
+      = loop (into + 1)
+    | otherwise = unsafeTake into a
+  maxLen = min (length a) (length b)
 
 -- | Create a byte sequence with one byte.
 singleton :: Word8 -> Bytes
diff --git a/src/Data/Bytes/Types.hs b/src/Data/Bytes/Types.hs
--- a/src/Data/Bytes/Types.hs
+++ b/src/Data/Bytes/Types.hs
@@ -84,7 +84,7 @@
 instance Ord Bytes where
   compare (Bytes arr1 off1 len1) (Bytes arr2 off2 len2)
     | sameByteArray arr1 arr2 && off1 == off2 && len1 == len2 = EQ
-    | otherwise = compareByteArrays arr1 off1 arr2 off2 len1
+    | otherwise = compareByteArrays arr1 off1 arr2 off2 (min len1 len2) <> compare len1 len2
 
 instance Semigroup Bytes where
   -- TODO: Do the trick to move the data constructor to the outside
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -34,7 +34,11 @@
 
 tests :: TestTree
 tests = testGroup "Bytes"
-  [ testGroup "isPrefixOf"
+  [ lawsToTest (QCC.eqLaws (Proxy :: Proxy Bytes))
+  , lawsToTest (QCC.ordLaws (Proxy :: Proxy Bytes))
+  , lawsToTest (QCC.semigroupLaws (Proxy :: Proxy Bytes))
+  , lawsToTest (QCC.monoidLaws (Proxy :: Proxy Bytes))
+  , testGroup "isPrefixOf"
     [ testCase "A" $ THU.assertBool "" $
         Bytes.isPrefixOf (bytes "hey") (bytes "hey man")
     , testCase "B" $ THU.assertBool "" $
@@ -55,6 +59,16 @@
         Bytes.fromAsciiString "hey man"
         @=?
         Bytes.stripOptionalSuffix (bytes "h") (bytes "hey man")
+    ]
+  , testGroup "longestCommonPrefix"
+    [ testProperty "finds prefix" $ \(pre :: Bytes) (a :: Bytes) (b :: Bytes) ->
+        if | Just (wa,_) <- Bytes.uncons a, Just (wb,_) <- Bytes.uncons b, wa /= wb ->
+               Bytes.longestCommonPrefix (pre <> a) (pre <> b) === pre
+           | otherwise -> property Discard
+    , testProperty "finds no prefix" $ \(a :: Bytes) (b :: Bytes) ->
+        if | Just (wa,_) <- Bytes.uncons a, Just (wb,_) <- Bytes.uncons b, wa /= wb ->
+               Bytes.longestCommonPrefix a b === mempty
+           | otherwise -> property Discard
     ]
   , testGroup "dropWhileEnd"
     [ testCase "A" $
