diff --git a/libsecp256k1.cabal b/libsecp256k1.cabal
--- a/libsecp256k1.cabal
+++ b/libsecp256k1.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           libsecp256k1
-version:        0.1.1
+version:        0.1.2
 synopsis:       Bindings for secp256k1
 description:    Sign and verify signatures using the secp256k1 library.
 category:       Crypto
@@ -42,7 +42,9 @@
   build-depends:
       base >=4.9 && <5
     , bytestring >=0.10.8 && <0.12
+    , deepseq >=1.4.8 && <1.5
     , entropy >=0.3.8 && <0.5
+    , hashable >=1.4.2 && <1.5
     , hedgehog ==1.2.*
     , memory >=0.14.15 && <1.0
     , transformers >=0.4.0.0 && <1.0
@@ -67,8 +69,10 @@
       HUnit
     , base >=4.9 && <5
     , bytestring >=0.10.8 && <0.12
+    , deepseq >=1.4.8 && <1.5
     , either
     , entropy >=0.3.8 && <0.5
+    , hashable >=1.4.2 && <1.5
     , hedgehog ==1.2.*
     , hspec
     , libsecp256k1
diff --git a/src/Crypto/Secp256k1.hs b/src/Crypto/Secp256k1.hs
--- a/src/Crypto/Secp256k1.hs
+++ b/src/Crypto/Secp256k1.hs
@@ -80,6 +80,7 @@
     ecdh,
 ) where
 
+import Control.DeepSeq (NFData (..))
 import Control.Monad (replicateM, unless, (<=<))
 import Control.Monad.Trans.Class (lift)
 import Control.Monad.Trans.Cont (ContT (..), evalContT)
@@ -94,7 +95,8 @@
 import Data.ByteString.Unsafe (unsafePackCStringLen, unsafePackMallocCStringLen)
 import Data.Foldable (for_)
 import Data.Functor (($>))
-import Data.Maybe (fromJust, fromMaybe, isJust)
+import Data.Hashable (Hashable (..))
+import Data.Maybe (fromJust, fromMaybe, isJust, maybeToList)
 import Data.Memory.PtrMethods (memCompare)
 import Data.String (IsString (..))
 import Foreign (
@@ -155,6 +157,12 @@
         -- avoid allocating a new bytestring because we are only reading from this pointer
         bs <- lift (Data.ByteString.Unsafe.unsafePackCStringLen (castPtr secKeyPtr, 32))
         pure $ "0x" <> B8.unpack (BA.convertToBase BA.Base16 bs)
+instance Read SecKey where
+    readsPrec i s = case s of
+        ('0' : 'x' : bytes) -> case decodeBase16 $ B8.pack bytes of
+            Left e -> []
+            Right a -> maybeToList $ (,"") <$> importSecKey a
+        _ -> []
 instance Eq SecKey where
     sk == sk' = unsafePerformIO . evalContT $ do
         skp <- ContT $ withForeignPtr (secKeyFPtr sk)
@@ -165,6 +173,10 @@
         skp <- ContT $ withForeignPtr (secKeyFPtr sk)
         skp' <- ContT $ withForeignPtr (secKeyFPtr sk')
         lift (memCompare (castPtr skp) (castPtr skp') 32)
+instance Hashable SecKey where
+    hashWithSalt i k = hashWithSalt i $ exportSecKey k
+instance NFData SecKey where
+    rnf SecKey{..} = seq secKeyFPtr ()
 
 
 -- | Public Key with both X and Y coordinates
@@ -173,8 +185,12 @@
 
 instance Show PubKeyXY where
     show pk = "0x" <> B8.unpack (BA.convertToBase BA.Base16 (exportPubKeyXY True pk))
-
-
+instance Read PubKeyXY where
+    readsPrec i s = case s of
+        ('0' : 'x' : bytes) -> case decodeBase16 $ B8.pack bytes of
+            Left e -> []
+            Right a -> maybeToList $ (,"") <$> importPubKeyXY a
+        _ -> []
 instance Eq PubKeyXY where
     pk == pk' = unsafePerformIO . evalContT $ do
         pkp <- ContT . withForeignPtr . pubKeyXYFPtr $ pk
@@ -187,6 +203,10 @@
         pkp' <- ContT . withForeignPtr . pubKeyXYFPtr $ pk'
         res <- lift (Prim.ecPubkeyCmp ctx pkp pkp')
         pure $ compare res 0
+instance Hashable PubKeyXY where
+    hashWithSalt i k = hashWithSalt i $ exportPubKeyXY True k
+instance NFData PubKeyXY where
+    rnf PubKeyXY{..} = seq pubKeyXYFPtr ()
 
 
 -- | Public Key with only an X coordinate.
@@ -195,8 +215,12 @@
 
 instance Show PubKeyXO where
     show pk = "0x" <> B8.unpack (BA.convertToBase BA.Base16 (exportPubKeyXO pk))
-
-
+instance Read PubKeyXO where
+    readsPrec i s = case s of
+        ('0' : 'x' : bytes) -> case decodeBase16 $ B8.pack bytes of
+            Left e -> []
+            Right a -> maybeToList $ (,"") <$> importPubKeyXO a
+        _ -> []
 instance Eq PubKeyXO where
     pk == pk' = unsafePerformIO . evalContT $ do
         pkp <- ContT . withForeignPtr . pubKeyXOFPtr $ pk
@@ -209,6 +233,10 @@
         pkp' <- ContT . withForeignPtr . pubKeyXOFPtr $ pk'
         res <- lift (Prim.xonlyPubkeyCmp ctx pkp pkp')
         pure $ compare res 0
+instance Hashable PubKeyXO where
+    hashWithSalt i k = hashWithSalt i $ exportPubKeyXO k
+instance NFData PubKeyXO where
+    rnf PubKeyXO{..} = seq pubKeyXOFPtr ()
 
 
 -- | Structure containing information equivalent to 'SecKey' and 'PubKeyXY'
@@ -220,6 +248,8 @@
         kpp <- ContT $ withForeignPtr (keyPairFPtr kp)
         kpp' <- ContT $ withForeignPtr (keyPairFPtr kp')
         (EQ ==) <$> lift (memCompare (castPtr kpp) (castPtr kpp') 32)
+instance NFData KeyPair where
+    rnf KeyPair{..} = seq keyPairFPtr ()
 
 
 -- | Structure containing Signature (R,S) data.
@@ -233,6 +263,8 @@
         sigp <- ContT $ withForeignPtr (signatureFPtr sig)
         sigp' <- ContT $ withForeignPtr (signatureFPtr sig')
         (EQ ==) <$> lift (memCompare (castPtr sigp) (castPtr sigp') 32)
+instance NFData Signature where
+    rnf Signature{..} = seq signatureFPtr ()
 
 
 -- | Structure containing Signature AND recovery ID
@@ -241,13 +273,13 @@
 
 instance Show RecoverableSignature where
     show recSig = "0x" <> (B8.unpack . encodeBase16) (exportRecoverableSignature recSig)
-
-
 instance Eq RecoverableSignature where
     rs == rs' = unsafePerformIO . evalContT $ do
         rsp <- ContT $ withForeignPtr (recoverableSignatureFPtr rs)
         rsp' <- ContT $ withForeignPtr (recoverableSignatureFPtr rs')
         (EQ ==) <$> lift (memCompare (castPtr rsp) (castPtr rsp') 32)
+instance NFData RecoverableSignature where
+    rnf RecoverableSignature{..} = seq recoverableSignatureFPtr ()
 
 
 -- | Isomorphic to 'SecKey' but specifically used for tweaking (EC Group operations) other keys
@@ -268,6 +300,8 @@
         skp <- ContT $ withForeignPtr (tweakFPtr sk)
         skp' <- ContT $ withForeignPtr (tweakFPtr sk')
         lift (memCompare (castPtr skp) (castPtr skp') 32)
+instance NFData Tweak where
+    rnf Tweak{..} = seq tweakFPtr ()
 
 
 -- | Preinitialized context for signing and verification
@@ -528,7 +562,7 @@
         else lift (free outBuf) *> error "Bug: Invalid Scalar or Overflow"
 
 
--- -- | Add 'Tweak' to 'SecKey'.
+-- | Add 'Tweak' to 'SecKey'.
 secKeyTweakAdd :: SecKey -> Tweak -> Maybe SecKey
 secKeyTweakAdd SecKey{..} Tweak{..} = unsafePerformIO . evalContT $ do
     skPtr <- ContT (withForeignPtr secKeyFPtr)
diff --git a/test/Crypto/Secp256k1Prop.hs b/test/Crypto/Secp256k1Prop.hs
--- a/test/Crypto/Secp256k1Prop.hs
+++ b/test/Crypto/Secp256k1Prop.hs
@@ -13,8 +13,18 @@
 import Hedgehog
 import Hedgehog.Gen hiding (discard, maybe)
 import Hedgehog.Range (linear, singleton)
+import Text.Read (readMaybe)
 
 
+prop_secKeyReadInvertsShow :: Property
+prop_secKeyReadInvertsShow = property $ do
+    sk <- forAll secKeyGen
+    let str = show sk
+    case readMaybe str of
+        Nothing -> failure
+        Just x -> x === sk
+
+
 prop_secKeyParseInvertsSerialize :: Property
 prop_secKeyParseInvertsSerialize = property $ do
     sk <- forAll secKeyGen
@@ -31,6 +41,15 @@
         Just sk -> exportSecKey sk === bs
 
 
+prop_pubKeyXYReadInvertsShow :: Property
+prop_pubKeyXYReadInvertsShow = property $ do
+    pk <- forAll pubKeyXYGen
+    let str = show pk
+    case readMaybe str of
+        Nothing -> failure
+        Just x -> x === pk
+
+
 prop_pubKeyXYParseInvertsSerialize :: Property
 prop_pubKeyXYParseInvertsSerialize = property $ do
     pk <- forAll pubKeyXYGen
@@ -53,6 +72,15 @@
         case importPubKeyXY withParity of
             Nothing -> discard
             Just pk -> exportPubKeyXY True pk === withParity
+
+
+prop_pubKeyXOReadInvertsShow :: Property
+prop_pubKeyXOReadInvertsShow = property $ do
+    pk <- forAll pubKeyXOGen
+    let str = show pk
+    case readMaybe str of
+        Nothing -> failure
+        Just x -> x === pk
 
 
 prop_pubKeyXOParseInvertsSerialize :: Property
