{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoFieldSelectors #-}
{-# 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.Crypto.Keys.Common
  ( -- * Bitcoin Public & Private Keys
    PublicKey (..),
    PrivateKey (..),
    wrapPubKey,
    derivePublicKey,
    wrapSecKey,
    fromMiniKey,
    tweakPubKey,
    tweakSecKey,

    -- ** Private Key Wallet Import Format (WIF)
    fromWif,
    toWif,
  )
where

import Control.DeepSeq
import Control.Monad (guard, mzero, (<=<))
import Crypto.Secp256k1
import Data.Aeson
  ( Encoding,
    FromJSON,
    ToJSON (..),
    Value (String),
    object,
    parseJSON,
    withText,
  )
import Data.Aeson.Encoding (text, unsafeToEncoding)
import Data.Aeson.Types (Parser)
import Data.Binary (Binary (..))
import Data.Bool (bool)
import Data.ByteString (ByteString)
import Data.ByteString qualified 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.Crypto.Hash
import Haskoin.Network.Data
import Haskoin.Util

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

instance MarshalJSON Ctx PublicKey where
  marshalValue :: Ctx -> PublicKey -> Value
marshalValue Ctx
ctx = Text -> Value
String (Text -> Value) -> (PublicKey -> Text) -> PublicKey -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
encodeHex (ByteString -> Text)
-> (PublicKey -> ByteString) -> PublicKey -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutS (Put -> ByteString)
-> (PublicKey -> Put) -> PublicKey -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> PublicKey -> Put
forall s a (m :: * -> *).
(Marshal s a, MonadPut m) =>
s -> a -> m ()
forall (m :: * -> *). MonadPut m => Ctx -> PublicKey -> m ()
marshalPut Ctx
ctx

  marshalEncoding :: Ctx -> PublicKey -> Encoding
marshalEncoding Ctx
ctx = ByteString -> Encoding
hexEncoding (ByteString -> Encoding)
-> (PublicKey -> ByteString) -> PublicKey -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPutL (Put -> ByteString)
-> (PublicKey -> Put) -> PublicKey -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ctx -> PublicKey -> Put
forall s a (m :: * -> *).
(Marshal s a, MonadPut m) =>
s -> a -> m ()
forall (m :: * -> *). MonadPut m => Ctx -> PublicKey -> m ()
marshalPut Ctx
ctx

  unmarshalValue :: Ctx -> Value -> Parser PublicKey
unmarshalValue Ctx
ctx =
    String -> (Text -> Parser PublicKey) -> Value -> Parser PublicKey
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"PublicKey" ((Text -> Parser PublicKey) -> Value -> Parser PublicKey)
-> (Text -> Parser PublicKey) -> Value -> Parser PublicKey
forall a b. (a -> b) -> a -> b
$ \Text
t -> do
      ByteString
bs <- Parser ByteString
-> (ByteString -> Parser ByteString)
-> Maybe ByteString
-> Parser ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Parser ByteString
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Expected hex public key") ByteString -> Parser ByteString
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ByteString -> Parser ByteString)
-> Maybe ByteString -> Parser ByteString
forall a b. (a -> b) -> a -> b
$ Text -> Maybe ByteString
decodeHex Text
t
      (String -> Parser PublicKey)
-> (PublicKey -> Parser PublicKey)
-> Either String PublicKey
-> Parser PublicKey
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser PublicKey
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail PublicKey -> Parser PublicKey
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String PublicKey -> Parser PublicKey)
-> Either String PublicKey -> Parser PublicKey
forall a b. (a -> b) -> a -> b
$ Ctx -> ByteString -> Either String PublicKey
forall s a. Marshal s a => s -> ByteString -> Either String a
unmarshal Ctx
ctx ByteString
bs

instance Marshal Ctx PublicKey where
  marshalGet :: forall (m :: * -> *). MonadGet m => Ctx -> m PublicKey
marshalGet Ctx
ctx = do
    Bool
c <-
      m Bool -> m Bool
forall a. m a -> m a
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 a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
          Word8
0x02 -> Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
          Word8
0x03 -> Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
          Word8
0x04 -> Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
          Word8
_ -> String -> m Bool
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Not a public key"
    ByteString
bs <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString (Int -> m ByteString) -> Int -> m ByteString
forall a b. (a -> b) -> a -> b
$ if Bool
c then Int
33 else Int
65
    case Ctx -> ByteString -> Maybe PubKey
importPubKey Ctx
ctx ByteString
bs of
      Maybe PubKey
Nothing -> String -> m PublicKey
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Could not decode public key"
      Just PubKey
k -> PublicKey -> m PublicKey
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (PublicKey -> m PublicKey) -> PublicKey -> m PublicKey
forall a b. (a -> b) -> a -> b
$ PubKey -> Bool -> PublicKey
PublicKey PubKey
k Bool
c

  marshalPut :: forall (m :: * -> *). MonadPut m => Ctx -> PublicKey -> m ()
marshalPut Ctx
ctx PublicKey
pk =
    ByteString -> m ()
forall (m :: * -> *). MonadPut m => ByteString -> m ()
putByteString (ByteString -> m ()) -> ByteString -> m ()
forall a b. (a -> b) -> a -> b
$ Ctx -> Bool -> PubKey -> ByteString
exportPubKey Ctx
ctx PublicKey
pk.compress PublicKey
pk.point

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

-- | Derives a public key from a private key. This function will preserve
-- compression flag.
derivePublicKey :: Ctx -> PrivateKey -> PublicKey
derivePublicKey :: Ctx -> PrivateKey -> PublicKey
derivePublicKey Ctx
ctx (PrivateKey SecKey
d Bool
c) = PubKey -> Bool -> PublicKey
PublicKey (Ctx -> SecKey -> PubKey
derivePubKey Ctx
ctx SecKey
d) Bool
c

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

-- | 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 PrivateKey = PrivateKey
  { PrivateKey -> SecKey
key :: !SecKey,
    PrivateKey -> Bool
compress :: !Bool
  }
  deriving (PrivateKey -> PrivateKey -> Bool
(PrivateKey -> PrivateKey -> Bool)
-> (PrivateKey -> PrivateKey -> Bool) -> Eq PrivateKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PrivateKey -> PrivateKey -> Bool
== :: PrivateKey -> PrivateKey -> Bool
$c/= :: PrivateKey -> PrivateKey -> Bool
/= :: PrivateKey -> PrivateKey -> Bool
Eq, Int -> PrivateKey -> ShowS
[PrivateKey] -> ShowS
PrivateKey -> String
(Int -> PrivateKey -> ShowS)
-> (PrivateKey -> String)
-> ([PrivateKey] -> ShowS)
-> Show PrivateKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PrivateKey -> ShowS
showsPrec :: Int -> PrivateKey -> ShowS
$cshow :: PrivateKey -> String
show :: PrivateKey -> String
$cshowList :: [PrivateKey] -> ShowS
showList :: [PrivateKey] -> ShowS
Show, ReadPrec [PrivateKey]
ReadPrec PrivateKey
Int -> ReadS PrivateKey
ReadS [PrivateKey]
(Int -> ReadS PrivateKey)
-> ReadS [PrivateKey]
-> ReadPrec PrivateKey
-> ReadPrec [PrivateKey]
-> Read PrivateKey
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS PrivateKey
readsPrec :: Int -> ReadS PrivateKey
$creadList :: ReadS [PrivateKey]
readList :: ReadS [PrivateKey]
$creadPrec :: ReadPrec PrivateKey
readPrec :: ReadPrec PrivateKey
$creadListPrec :: ReadPrec [PrivateKey]
readListPrec :: ReadPrec [PrivateKey]
Read, (forall x. PrivateKey -> Rep PrivateKey x)
-> (forall x. Rep PrivateKey x -> PrivateKey) -> Generic PrivateKey
forall x. Rep PrivateKey x -> PrivateKey
forall x. PrivateKey -> Rep PrivateKey x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. PrivateKey -> Rep PrivateKey x
from :: forall x. PrivateKey -> Rep PrivateKey x
$cto :: forall x. Rep PrivateKey x -> PrivateKey
to :: forall x. Rep PrivateKey x -> PrivateKey
Generic, PrivateKey -> ()
(PrivateKey -> ()) -> NFData PrivateKey
forall a. (a -> ()) -> NFData a
$crnf :: PrivateKey -> ()
rnf :: PrivateKey -> ()
NFData)

instance Serial PrivateKey where
  serialize :: forall (m :: * -> *). MonadPut m => PrivateKey -> m ()
serialize PrivateKey
p = do
    ByteString -> m ()
forall (m :: * -> *). MonadPut m => ByteString -> m ()
putByteString PrivateKey
p.key.get
    Bool -> m ()
forall a (m :: * -> *). (Serial a, MonadPut m) => a -> m ()
forall (m :: * -> *). MonadPut m => Bool -> m ()
serialize PrivateKey
p.compress
  deserialize :: forall (m :: * -> *). MonadGet m => m PrivateKey
deserialize = do
    ByteString
k <- Int -> m ByteString
forall (m :: * -> *). MonadGet m => Int -> m ByteString
getByteString Int
32
    Bool
c <- m Bool
forall a (m :: * -> *). (Serial a, MonadGet m) => m a
forall (m :: * -> *). MonadGet m => m Bool
deserialize
    PrivateKey -> m PrivateKey
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return PrivateKey {$sel:key:PrivateKey :: SecKey
key = ByteString -> SecKey
SecKey ByteString
k, $sel:compress:PrivateKey :: Bool
compress = Bool
c}

instance MarshalJSON Network PrivateKey where
  marshalValue :: Network -> PrivateKey -> Value
marshalValue Network
net = Text -> Value
String (Text -> Value) -> (PrivateKey -> Text) -> PrivateKey -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Network -> PrivateKey -> Text
toWif Network
net
  marshalEncoding :: Network -> PrivateKey -> Encoding
marshalEncoding Network
net = Text -> Encoding
forall a. Text -> Encoding' a
text (Text -> Encoding)
-> (PrivateKey -> Text) -> PrivateKey -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Network -> PrivateKey -> Text
toWif Network
net
  unmarshalValue :: Network -> Value -> Parser PrivateKey
unmarshalValue Network
net =
    String -> (Text -> Parser PrivateKey) -> Value -> Parser PrivateKey
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"PrivateKey" ((Text -> Parser PrivateKey) -> Value -> Parser PrivateKey)
-> (Text -> Parser PrivateKey) -> Value -> Parser PrivateKey
forall a b. (a -> b) -> a -> b
$
      Parser PrivateKey
-> (PrivateKey -> Parser PrivateKey)
-> Maybe PrivateKey
-> Parser PrivateKey
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Parser PrivateKey
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Could not decode WIF") PrivateKey -> Parser PrivateKey
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PrivateKey -> Parser PrivateKey)
-> (Text -> Maybe PrivateKey) -> Text -> Parser PrivateKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Network -> Text -> Maybe PrivateKey
fromWif Network
net

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

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

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

-- | Decode private key from WIF (wallet import format) string.
fromWif :: Network -> Base58 -> Maybe PrivateKey
fromWif :: Network -> Text -> Maybe PrivateKey
fromWif Network
net 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 (HasCallStack => ByteString -> Word8
ByteString -> Word8
BS.head ByteString
bs Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Network
net.secretPrefix)
  case ByteString -> Int
BS.length ByteString
bs of
    -- Uncompressed format
    Int
33 -> Bool -> SecKey -> PrivateKey
wrapSecKey Bool
False (SecKey -> PrivateKey) -> Maybe SecKey -> Maybe PrivateKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ByteString -> Maybe SecKey
secKey (ByteString -> Maybe SecKey)
-> (ByteString -> ByteString) -> ByteString -> Maybe SecKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> ByteString
ByteString -> ByteString
BS.tail) ByteString
bs
    -- Compressed format
    Int
34 -> do
      Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ HasCallStack => ByteString -> Word8
ByteString -> Word8
BS.last ByteString
bs Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x01
      Bool -> SecKey -> PrivateKey
wrapSecKey Bool
True (SecKey -> PrivateKey) -> Maybe SecKey -> Maybe PrivateKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ByteString -> Maybe SecKey
secKey (ByteString -> Maybe SecKey)
-> (ByteString -> ByteString) -> ByteString -> Maybe SecKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> ByteString
ByteString -> ByteString
BS.tail (ByteString -> ByteString)
-> (ByteString -> ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> ByteString
ByteString -> ByteString
BS.init) ByteString
bs
    -- Bad length
    Int
_ -> Maybe PrivateKey
forall a. Maybe a
Nothing

-- | Encode private key into a WIF string.
toWif :: Network -> PrivateKey -> Base58
toWif :: Network -> PrivateKey -> Text
toWif Network
net (PrivateKey SecKey
k 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
net.secretPrefix (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$
    if Bool
c then SecKey
k.get ByteString -> Word8 -> ByteString
`BS.snoc` Word8
0x01 else SecKey
k.get