{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-|
Module      : Haskoin.Keys.Common
Copyright   : No rights reserved
License     : MIT
Maintainer  : jprupp@protonmail.ch
Stability   : experimental
Portability : POSIX

ECDSA private and public key functions.
-}
module Haskoin.Keys.Common
    ( -- * Public & Private Keys
      PubKeyI(..)
    , SecKeyI(..)
    , exportPubKey
    , importPubKey
    , wrapPubKey
    , derivePubKeyI
    , wrapSecKey
    , fromMiniKey
    , tweakPubKey
    , tweakSecKey
    , getSecKey
    , secKey
    -- ** Private Key Wallet Import Format (WIF)
    , fromWif
    , toWif
    ) where

import           Control.Applicative     ((<|>))
import           Control.DeepSeq
import           Control.Monad           (guard, mzero, (<=<))
import           Crypto.Secp256k1
import           Data.Aeson              (FromJSON, ToJSON (..), Value (String),
                                          parseJSON, withText)
import           Data.Aeson.Encoding     (unsafeToEncoding)
import           Data.Binary             (Binary (..))
import           Data.ByteString         (ByteString)
import qualified Data.ByteString         as BS
import           Data.ByteString.Builder (char7)
import           Data.Bytes.Get
import           Data.Bytes.Put
import           Data.Bytes.Serial
import           Data.Hashable
import           Data.Maybe              (fromMaybe)
import           Data.Serialize          (Serialize (..))
import           Data.String             (IsString, fromString)
import           Data.String.Conversions (cs)
import           GHC.Generics            (Generic)
import           Haskoin.Address.Base58
import           Haskoin.Constants
import           Haskoin.Crypto.Hash
import           Haskoin.Util

-- | Elliptic curve public key type with expected serialized compression flag.
data PubKeyI = PubKeyI
    { PubKeyI -> PubKey
pubKeyPoint      :: !PubKey
    , PubKeyI -> Bool
pubKeyCompressed :: !Bool
    } deriving ((forall x. PubKeyI -> Rep PubKeyI x)
-> (forall x. Rep PubKeyI x -> PubKeyI) -> Generic PubKeyI
forall x. Rep PubKeyI x -> PubKeyI
forall x. PubKeyI -> Rep PubKeyI x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep PubKeyI x -> PubKeyI
$cfrom :: forall x. PubKeyI -> Rep PubKeyI x
Generic, PubKeyI -> PubKeyI -> Bool
(PubKeyI -> PubKeyI -> Bool)
-> (PubKeyI -> PubKeyI -> Bool) -> Eq PubKeyI
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PubKeyI -> PubKeyI -> Bool
$c/= :: PubKeyI -> PubKeyI -> Bool
== :: PubKeyI -> PubKeyI -> Bool
$c== :: PubKeyI -> PubKeyI -> Bool
Eq, Int -> PubKeyI -> ShowS
[PubKeyI] -> ShowS
PubKeyI -> String
(Int -> PubKeyI -> ShowS)
-> (PubKeyI -> String) -> ([PubKeyI] -> ShowS) -> Show PubKeyI
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PubKeyI] -> ShowS
$cshowList :: [PubKeyI] -> ShowS
show :: PubKeyI -> String
$cshow :: PubKeyI -> String
showsPrec :: Int -> PubKeyI -> ShowS
$cshowsPrec :: Int -> PubKeyI -> ShowS
Show, ReadPrec [PubKeyI]
ReadPrec PubKeyI
Int -> ReadS PubKeyI
ReadS [PubKeyI]
(Int -> ReadS PubKeyI)
-> ReadS [PubKeyI]
-> ReadPrec PubKeyI
-> ReadPrec [PubKeyI]
-> Read PubKeyI
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [PubKeyI]
$creadListPrec :: ReadPrec [PubKeyI]
readPrec :: ReadPrec PubKeyI
$creadPrec :: ReadPrec PubKeyI
readList :: ReadS [PubKeyI]
$creadList :: ReadS [PubKeyI]
readsPrec :: Int -> ReadS PubKeyI
$creadsPrec :: Int -> ReadS PubKeyI
Read, Int -> PubKeyI -> Int
PubKeyI -> Int
(Int -> PubKeyI -> Int) -> (PubKeyI -> Int) -> Hashable PubKeyI
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: PubKeyI -> Int
$chash :: PubKeyI -> Int
hashWithSalt :: Int -> PubKeyI -> Int
$chashWithSalt :: Int -> PubKeyI -> Int
Hashable, PubKeyI -> ()
(PubKeyI -> ()) -> NFData PubKeyI
forall a. (a -> ()) -> NFData a
rnf :: PubKeyI -> ()
$crnf :: PubKeyI -> ()
NFData)

instance IsString PubKeyI where
    fromString :: String -> PubKeyI
fromString str :: String
str =
        PubKeyI -> Maybe PubKeyI -> PubKeyI
forall a. a -> Maybe a -> a
fromMaybe PubKeyI
forall a. a
e (Maybe PubKeyI -> PubKeyI) -> Maybe PubKeyI -> PubKeyI
forall a b. (a -> b) -> a -> b
$ Either String PubKeyI -> Maybe PubKeyI
forall a b. Either a b -> Maybe b
eitherToMaybe (Either String PubKeyI -> Maybe PubKeyI)
-> (ByteString -> Either String PubKeyI)
-> ByteString
-> Maybe PubKeyI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get PubKeyI -> ByteString -> Either String PubKeyI
forall a. Get a -> ByteString -> Either String a
runGetS Get PubKeyI
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize (ByteString -> Maybe PubKeyI)
-> (Text -> Maybe ByteString) -> Text -> Maybe PubKeyI
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Text -> Maybe ByteString
decodeHex (Text -> Maybe PubKeyI) -> Text -> Maybe PubKeyI
forall a b. (a -> b) -> a -> b
$ String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs String
str
      where
        e :: a
e = String -> a
forall a. HasCallStack => String -> a
error "Could not decode public key"

instance ToJSON PubKeyI where
    toJSON :: PubKeyI -> Value
toJSON = Text -> Value
String (Text -> Value) -> (PubKeyI -> Text) -> PubKeyI -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeHex (ByteString -> Text) -> (PubKeyI -> ByteString) -> PubKeyI -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> ByteString) -> (PubKeyI -> Put) -> PubKeyI -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    toEncoding :: PubKeyI -> Encoding
toEncoding s :: PubKeyI
s = Builder -> Encoding
forall a. Builder -> Encoding' a
unsafeToEncoding (Builder -> Encoding) -> Builder -> Encoding
forall a b. (a -> b) -> a -> b
$
        Char -> Builder
char7 '"' Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
        ByteString -> Builder
hexBuilder (Put -> ByteString
runPutL (PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize PubKeyI
s)) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
        Char -> Builder
char7 '"'

instance FromJSON PubKeyI where
    parseJSON :: Value -> Parser PubKeyI
parseJSON = String -> (Text -> Parser PubKeyI) -> Value -> Parser PubKeyI
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText "PubKeyI" ((Text -> Parser PubKeyI) -> Value -> Parser PubKeyI)
-> (Text -> Parser PubKeyI) -> Value -> Parser PubKeyI
forall a b. (a -> b) -> a -> b
$
        Parser PubKeyI
-> (PubKeyI -> Parser PubKeyI) -> Maybe PubKeyI -> Parser PubKeyI
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Parser PubKeyI
forall (m :: * -> *) a. MonadPlus m => m a
mzero PubKeyI -> Parser PubKeyI
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PubKeyI -> Parser PubKeyI)
-> (Text -> Maybe PubKeyI) -> Text -> Parser PubKeyI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Either String PubKeyI -> Maybe PubKeyI
forall a b. Either a b -> Maybe b
eitherToMaybe (Either String PubKeyI -> Maybe PubKeyI)
-> (ByteString -> Either String PubKeyI)
-> ByteString
-> Maybe PubKeyI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get PubKeyI -> ByteString -> Either String PubKeyI
forall a. Get a -> ByteString -> Either String a
runGetS Get PubKeyI
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize (ByteString -> Maybe PubKeyI) -> Maybe ByteString -> Maybe PubKeyI
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) (Maybe ByteString -> Maybe PubKeyI)
-> (Text -> Maybe ByteString) -> Text -> Maybe PubKeyI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Maybe ByteString
decodeHex

instance Serial PubKeyI where
    deserialize :: m PubKeyI
deserialize = m Bool
s m Bool -> (Bool -> m PubKeyI) -> m PubKeyI
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        True  -> m PubKeyI
c
        False -> m PubKeyI
u
      where
        s :: m Bool
s = m Bool -> m Bool
forall (m :: * -> *) a. MonadGet m => m a -> m a
lookAhead (m Bool -> m Bool) -> m Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ m Word8
forall (m :: * -> *). MonadGet m => m Word8
getWord8 m Word8 -> (Word8 -> m Bool) -> m Bool
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            0x02 -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
            0x03 -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
            0x04 -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
            _    -> String -> m Bool
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "Not a public key"
        c :: m PubKeyI
c = do
            ByteString
bs <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString 33
            m PubKeyI -> (PubKeyI -> m PubKeyI) -> Maybe PubKeyI -> m PubKeyI
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> m PubKeyI
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "Could not decode public key") PubKeyI -> m PubKeyI
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PubKeyI -> m PubKeyI) -> Maybe PubKeyI -> m PubKeyI
forall a b. (a -> b) -> a -> b
$
                PubKey -> Bool -> PubKeyI
PubKeyI (PubKey -> Bool -> PubKeyI)
-> Maybe PubKey -> Maybe (Bool -> PubKeyI)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Maybe PubKey
importPubKey ByteString
bs Maybe (Bool -> PubKeyI) -> Maybe Bool -> Maybe PubKeyI
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Bool -> Maybe Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
        u :: m PubKeyI
u = do
            ByteString
bs <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString 65
            m PubKeyI -> (PubKeyI -> m PubKeyI) -> Maybe PubKeyI -> m PubKeyI
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> m PubKeyI
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "Could not decode public key") PubKeyI -> m PubKeyI
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PubKeyI -> m PubKeyI) -> Maybe PubKeyI -> m PubKeyI
forall a b. (a -> b) -> a -> b
$
                PubKey -> Bool -> PubKeyI
PubKeyI (PubKey -> Bool -> PubKeyI)
-> Maybe PubKey -> Maybe (Bool -> PubKeyI)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Maybe PubKey
importPubKey ByteString
bs Maybe (Bool -> PubKeyI) -> Maybe Bool -> Maybe PubKeyI
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Bool -> Maybe Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False

    serialize :: PubKeyI -> m ()
serialize pk :: PubKeyI
pk = ByteString -> m ()
forall (m :: * -> *). MonadPut m => ByteString -> m ()
putByteString (ByteString -> m ()) -> ByteString -> m ()
forall a b. (a -> b) -> a -> b
$ Bool -> PubKey -> ByteString
exportPubKey (PubKeyI -> Bool
pubKeyCompressed PubKeyI
pk) (PubKeyI -> PubKey
pubKeyPoint PubKeyI
pk)

instance Serialize PubKeyI where
    put :: PubKeyI -> Put
put = PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get PubKeyI
get = Get PubKeyI
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

instance Binary PubKeyI where
    put :: PubKeyI -> Put
put = PubKeyI -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize
    get :: Get PubKeyI
get = Get PubKeyI
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
deserialize

-- | Wrap a public key from secp256k1 library adding information about compression.
wrapPubKey :: Bool -> PubKey -> PubKeyI
wrapPubKey :: Bool -> PubKey -> PubKeyI
wrapPubKey c :: Bool
c p :: PubKey
p = PubKey -> Bool -> PubKeyI
PubKeyI PubKey
p Bool
c

-- | Derives a public key from a private key. This function will preserve
-- compression flag.
derivePubKeyI :: SecKeyI -> PubKeyI
derivePubKeyI :: SecKeyI -> PubKeyI
derivePubKeyI (SecKeyI d :: SecKey
d c :: Bool
c) = PubKey -> Bool -> PubKeyI
PubKeyI (SecKey -> PubKey
derivePubKey SecKey
d) Bool
c

-- | Tweak a public key.
tweakPubKey :: PubKey -> Hash256 -> Maybe PubKey
tweakPubKey :: PubKey -> Hash256 -> Maybe PubKey
tweakPubKey p :: PubKey
p h :: Hash256
h = PubKey -> Tweak -> Maybe PubKey
tweakAddPubKey PubKey
p (Tweak -> Maybe PubKey) -> Maybe Tweak -> Maybe PubKey
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ByteString -> Maybe Tweak
tweak (Put -> ByteString
runPutS (Hash256 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash256
h))

-- | Elliptic curve private key type with expected public key compression
-- information. Compression information is stored in private key WIF formats and
-- needs to be preserved to generate the correct address from the corresponding
-- public key.
data SecKeyI = SecKeyI
    { SecKeyI -> SecKey
secKeyData       :: !SecKey
    , SecKeyI -> Bool
secKeyCompressed :: !Bool
    } deriving (SecKeyI -> SecKeyI -> Bool
(SecKeyI -> SecKeyI -> Bool)
-> (SecKeyI -> SecKeyI -> Bool) -> Eq SecKeyI
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SecKeyI -> SecKeyI -> Bool
$c/= :: SecKeyI -> SecKeyI -> Bool
== :: SecKeyI -> SecKeyI -> Bool
$c== :: SecKeyI -> SecKeyI -> Bool
Eq, Int -> SecKeyI -> ShowS
[SecKeyI] -> ShowS
SecKeyI -> String
(Int -> SecKeyI -> ShowS)
-> (SecKeyI -> String) -> ([SecKeyI] -> ShowS) -> Show SecKeyI
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SecKeyI] -> ShowS
$cshowList :: [SecKeyI] -> ShowS
show :: SecKeyI -> String
$cshow :: SecKeyI -> String
showsPrec :: Int -> SecKeyI -> ShowS
$cshowsPrec :: Int -> SecKeyI -> ShowS
Show, ReadPrec [SecKeyI]
ReadPrec SecKeyI
Int -> ReadS SecKeyI
ReadS [SecKeyI]
(Int -> ReadS SecKeyI)
-> ReadS [SecKeyI]
-> ReadPrec SecKeyI
-> ReadPrec [SecKeyI]
-> Read SecKeyI
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [SecKeyI]
$creadListPrec :: ReadPrec [SecKeyI]
readPrec :: ReadPrec SecKeyI
$creadPrec :: ReadPrec SecKeyI
readList :: ReadS [SecKeyI]
$creadList :: ReadS [SecKeyI]
readsPrec :: Int -> ReadS SecKeyI
$creadsPrec :: Int -> ReadS SecKeyI
Read, (forall x. SecKeyI -> Rep SecKeyI x)
-> (forall x. Rep SecKeyI x -> SecKeyI) -> Generic SecKeyI
forall x. Rep SecKeyI x -> SecKeyI
forall x. SecKeyI -> Rep SecKeyI x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SecKeyI x -> SecKeyI
$cfrom :: forall x. SecKeyI -> Rep SecKeyI x
Generic, SecKeyI -> ()
(SecKeyI -> ()) -> NFData SecKeyI
forall a. (a -> ()) -> NFData a
rnf :: SecKeyI -> ()
$crnf :: SecKeyI -> ()
NFData)

-- | Wrap private key with corresponding public key compression flag.
wrapSecKey :: Bool -> SecKey -> SecKeyI
wrapSecKey :: Bool -> SecKey -> SecKeyI
wrapSecKey c :: Bool
c d :: SecKey
d = SecKey -> Bool -> SecKeyI
SecKeyI SecKey
d Bool
c

-- | Tweak a private key.
tweakSecKey :: SecKey -> Hash256 -> Maybe SecKey
tweakSecKey :: SecKey -> Hash256 -> Maybe SecKey
tweakSecKey key :: SecKey
key h :: Hash256
h = SecKey -> Tweak -> Maybe SecKey
tweakAddSecKey SecKey
key (Tweak -> Maybe SecKey) -> Maybe Tweak -> Maybe SecKey
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ByteString -> Maybe Tweak
tweak (Put -> ByteString
runPutS (Hash256 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize Hash256
h))

-- | Decode Casascius mini private keys (22 or 30 characters).
fromMiniKey :: ByteString -> Maybe SecKeyI
fromMiniKey :: ByteString -> Maybe SecKeyI
fromMiniKey bs :: ByteString
bs = do
    Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard Bool
checkShortKey
    Bool -> SecKey -> SecKeyI
wrapSecKey Bool
False (SecKey -> SecKeyI) -> Maybe SecKey -> Maybe SecKeyI
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Maybe SecKey
secKey (Put -> ByteString
runPutS (Hash256 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize (ByteString -> Hash256
forall b. ByteArrayAccess b => b -> Hash256
sha256 ByteString
bs)))
  where
    checkHash :: ByteString
checkHash = Put -> ByteString
runPutS (Put -> ByteString) -> Put -> ByteString
forall a b. (a -> b) -> a -> b
$ Hash256 -> Put
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
serialize (Hash256 -> Put) -> Hash256 -> Put
forall a b. (a -> b) -> a -> b
$ ByteString -> Hash256
forall b. ByteArrayAccess b => b -> Hash256
sha256 (ByteString -> Hash256) -> ByteString -> Hash256
forall a b. (a -> b) -> a -> b
$ ByteString
bs ByteString -> ByteString -> ByteString
`BS.append` "?"
    checkShortKey :: Bool
checkShortKey = ByteString -> Int
BS.length ByteString
bs Int -> [Int] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [22, 30] Bool -> Bool -> Bool
&& ByteString -> Word8
BS.head ByteString
checkHash Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x00

-- | Decode private key from WIF (wallet import format) string.
fromWif :: Network -> Base58 -> Maybe SecKeyI
fromWif :: Network -> Text -> Maybe SecKeyI
fromWif net :: Network
net wif :: Text
wif = do
    ByteString
bs <- Text -> Maybe ByteString
decodeBase58Check Text
wif
    -- Check that this is a private key
    Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (ByteString -> Word8
BS.head ByteString
bs Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Network -> Word8
getSecretPrefix Network
net)
    case ByteString -> Int
BS.length ByteString
bs of
        -- Uncompressed format
        33 -> Bool -> SecKey -> SecKeyI
wrapSecKey Bool
False (SecKey -> SecKeyI) -> Maybe SecKey -> Maybe SecKeyI
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Maybe SecKey
secKey (ByteString -> ByteString
BS.tail ByteString
bs)
        -- Compressed format
        34 -> do
            Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ ByteString -> Word8
BS.last ByteString
bs Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0x01
            Bool -> SecKey -> SecKeyI
wrapSecKey Bool
True (SecKey -> SecKeyI) -> Maybe SecKey -> Maybe SecKeyI
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Maybe SecKey
secKey (ByteString -> ByteString
BS.tail (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
BS.init ByteString
bs)
        -- Bad length
        _  -> Maybe SecKeyI
forall a. Maybe a
Nothing

-- | Encode private key into a WIF string.
toWif :: Network -> SecKeyI -> Base58
toWif :: Network -> SecKeyI -> Text
toWif net :: Network
net (SecKeyI k :: SecKey
k c :: Bool
c) =
    ByteString -> Text
encodeBase58Check (ByteString -> Text)
-> (ByteString -> ByteString) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> ByteString -> ByteString
BS.cons (Network -> Word8
getSecretPrefix Network
net) (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$
    if Bool
c
        then SecKey -> ByteString
getSecKey SecKey
k ByteString -> Word8 -> ByteString
`BS.snoc` 0x01
        else SecKey -> ByteString
getSecKey SecKey
k