-- |
-- Module      : Cardano.Crypto.Wallet
-- Description : HD Wallet routines
-- Maintainer  : vincent@typed.io
--
-- This provides similar functionality to BIP32 but using
-- Ed25519 arithmetic instead of P256K1 arithmethic.
--
-- Key can be hierarchically derived from private key in two
-- fashions: Hardened or Normal.
--
-- In the hardened scheme, the child secret key is not linearly
-- derived, so that the child public key has no way
-- to be efficiently computed from the parent public key.
--
-- The normal scheme allows anyone to derive public keys from
-- public key.
--
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators       #-}
{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE PatternSynonyms     #-}

module Cardano.Crypto.Wallet
    ( ChainCode(..)
    , DerivationScheme(..)
    , DerivationIndex
    , pattern LatestScheme
    -- * Extended Private & Public types
    , XPrv
    , XPub(..)
    , XSignature
    , generate
    , generateNew
    , xprv
    , xpub
    , xsignature
    , unXPrv
    , unXPub
    , unXSignature
    , toXPub
    , xPubGetPublicKey
    , xPrvChangePass
    -- * Derivation function
    , deriveXPrv
    , deriveXPub
    -- * Signature & Verification from extended types
    , sign
    , verify
    ) where

import           Basement.Compat.Typeable
import           Control.DeepSeq                 (NFData)
import           Control.Arrow                   (second)
import           Crypto.Error                    (throwCryptoError, CryptoFailable(..), CryptoError(..))
import qualified Crypto.MAC.HMAC                 as HMAC
import qualified Crypto.PubKey.Ed25519           as Ed25519
import           Crypto.KDF.PBKDF2               (fastPBKDF2_SHA512, Parameters(..))
import           Data.ByteArray                  (ByteArrayAccess, convert)
import qualified Data.ByteArray                  as B (append, length, splitAt)
import           Data.ByteString                 (ByteString)
import qualified Data.ByteString.Char8           as BC
import           Data.Hashable                   (Hashable)
import           Data.Word
import           GHC.Generics                    (Generic)

import           Cardano.Crypto.Wallet.Encrypted
import           Cardano.Crypto.Wallet.Pure      ({-XPub (..),-} hFinalize,
                                                  hInitSeed)
import           Cardano.Crypto.Wallet.Types

import           GHC.Stack

newtype XPrv = XPrv EncryptedKey
    deriving (XPrv -> ()
(XPrv -> ()) -> NFData XPrv
forall a. (a -> ()) -> NFData a
rnf :: XPrv -> ()
$crnf :: XPrv -> ()
NFData, Typeable, XPrv -> Int
XPrv -> Ptr p -> IO ()
XPrv -> (Ptr p -> IO a) -> IO a
(XPrv -> Int)
-> (forall p a. XPrv -> (Ptr p -> IO a) -> IO a)
-> (forall p. XPrv -> Ptr p -> IO ())
-> ByteArrayAccess XPrv
forall p. XPrv -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. XPrv -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: XPrv -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. XPrv -> Ptr p -> IO ()
withByteArray :: XPrv -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. XPrv -> (Ptr p -> IO a) -> IO a
length :: XPrv -> Int
$clength :: XPrv -> Int
ByteArrayAccess)

data XPub = XPub
    { XPub -> ByteString
xpubPublicKey :: !ByteString
    , XPub -> ChainCode
xpubChaincode :: !ChainCode
    } deriving (XPub -> XPub -> Bool
(XPub -> XPub -> Bool) -> (XPub -> XPub -> Bool) -> Eq XPub
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: XPub -> XPub -> Bool
$c/= :: XPub -> XPub -> Bool
== :: XPub -> XPub -> Bool
$c== :: XPub -> XPub -> Bool
Eq, Int -> XPub -> ShowS
[XPub] -> ShowS
XPub -> String
(Int -> XPub -> ShowS)
-> (XPub -> String) -> ([XPub] -> ShowS) -> Show XPub
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [XPub] -> ShowS
$cshowList :: [XPub] -> ShowS
show :: XPub -> String
$cshow :: XPub -> String
showsPrec :: Int -> XPub -> ShowS
$cshowsPrec :: Int -> XPub -> ShowS
Show, Eq XPub
Eq XPub
-> (XPub -> XPub -> Ordering)
-> (XPub -> XPub -> Bool)
-> (XPub -> XPub -> Bool)
-> (XPub -> XPub -> Bool)
-> (XPub -> XPub -> Bool)
-> (XPub -> XPub -> XPub)
-> (XPub -> XPub -> XPub)
-> Ord XPub
XPub -> XPub -> Bool
XPub -> XPub -> Ordering
XPub -> XPub -> XPub
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: XPub -> XPub -> XPub
$cmin :: XPub -> XPub -> XPub
max :: XPub -> XPub -> XPub
$cmax :: XPub -> XPub -> XPub
>= :: XPub -> XPub -> Bool
$c>= :: XPub -> XPub -> Bool
> :: XPub -> XPub -> Bool
$c> :: XPub -> XPub -> Bool
<= :: XPub -> XPub -> Bool
$c<= :: XPub -> XPub -> Bool
< :: XPub -> XPub -> Bool
$c< :: XPub -> XPub -> Bool
compare :: XPub -> XPub -> Ordering
$ccompare :: XPub -> XPub -> Ordering
$cp1Ord :: Eq XPub
Ord, Typeable, (forall x. XPub -> Rep XPub x)
-> (forall x. Rep XPub x -> XPub) -> Generic XPub
forall x. Rep XPub x -> XPub
forall x. XPub -> Rep XPub x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep XPub x -> XPub
$cfrom :: forall x. XPub -> Rep XPub x
Generic)

instance NFData XPub
instance Hashable XPub

newtype XSignature = XSignature
    { XSignature -> ByteString
unXSignature :: ByteString
    } deriving (Int -> XSignature -> ShowS
[XSignature] -> ShowS
XSignature -> String
(Int -> XSignature -> ShowS)
-> (XSignature -> String)
-> ([XSignature] -> ShowS)
-> Show XSignature
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [XSignature] -> ShowS
$cshowList :: [XSignature] -> ShowS
show :: XSignature -> String
$cshow :: XSignature -> String
showsPrec :: Int -> XSignature -> ShowS
$cshowsPrec :: Int -> XSignature -> ShowS
Show, XSignature -> XSignature -> Bool
(XSignature -> XSignature -> Bool)
-> (XSignature -> XSignature -> Bool) -> Eq XSignature
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: XSignature -> XSignature -> Bool
$c/= :: XSignature -> XSignature -> Bool
== :: XSignature -> XSignature -> Bool
$c== :: XSignature -> XSignature -> Bool
Eq, Eq XSignature
Eq XSignature
-> (XSignature -> XSignature -> Ordering)
-> (XSignature -> XSignature -> Bool)
-> (XSignature -> XSignature -> Bool)
-> (XSignature -> XSignature -> Bool)
-> (XSignature -> XSignature -> Bool)
-> (XSignature -> XSignature -> XSignature)
-> (XSignature -> XSignature -> XSignature)
-> Ord XSignature
XSignature -> XSignature -> Bool
XSignature -> XSignature -> Ordering
XSignature -> XSignature -> XSignature
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: XSignature -> XSignature -> XSignature
$cmin :: XSignature -> XSignature -> XSignature
max :: XSignature -> XSignature -> XSignature
$cmax :: XSignature -> XSignature -> XSignature
>= :: XSignature -> XSignature -> Bool
$c>= :: XSignature -> XSignature -> Bool
> :: XSignature -> XSignature -> Bool
$c> :: XSignature -> XSignature -> Bool
<= :: XSignature -> XSignature -> Bool
$c<= :: XSignature -> XSignature -> Bool
< :: XSignature -> XSignature -> Bool
$c< :: XSignature -> XSignature -> Bool
compare :: XSignature -> XSignature -> Ordering
$ccompare :: XSignature -> XSignature -> Ordering
$cp1Ord :: Eq XSignature
Ord, XSignature -> ()
(XSignature -> ()) -> NFData XSignature
forall a. (a -> ()) -> NFData a
rnf :: XSignature -> ()
$crnf :: XSignature -> ()
NFData, Int -> XSignature -> Int
XSignature -> Int
(Int -> XSignature -> Int)
-> (XSignature -> Int) -> Hashable XSignature
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: XSignature -> Int
$chash :: XSignature -> Int
hashWithSalt :: Int -> XSignature -> Int
$chashWithSalt :: Int -> XSignature -> Int
Hashable, XSignature -> Int
XSignature -> Ptr p -> IO ()
XSignature -> (Ptr p -> IO a) -> IO a
(XSignature -> Int)
-> (forall p a. XSignature -> (Ptr p -> IO a) -> IO a)
-> (forall p. XSignature -> Ptr p -> IO ())
-> ByteArrayAccess XSignature
forall p. XSignature -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. XSignature -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: XSignature -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. XSignature -> Ptr p -> IO ()
withByteArray :: XSignature -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. XSignature -> (Ptr p -> IO a) -> IO a
length :: XSignature -> Int
$clength :: XSignature -> Int
ByteArrayAccess)

-- | Generate a new XPrv
--
-- The seed needs to be at least 32 bytes, otherwise an asynchronous error is thrown
generate :: (ByteArrayAccess passPhrase, ByteArrayAccess seed)
         => seed
         -> passPhrase
         -> XPrv
generate :: seed -> passPhrase -> XPrv
generate seed
seed passPhrase
passPhrase
    | seed -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length seed
seed Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
32 = String -> XPrv
forall a. HasCallStack => String -> a
error (String
"Wallet.generate: seed needs to be >= 32 bytes, got : " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (seed -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length seed
seed))
    | Bool
otherwise          = Int -> XPrv
loop Int
1
  where
    phrase :: Int -> ByteString
    phrase :: Int -> ByteString
phrase Int
i = ByteString
"Root Seed Chain " ByteString -> ByteString -> ByteString
forall bs. ByteArray bs => bs -> bs -> bs
`B.append` String -> ByteString
BC.pack (Int -> String
forall a. Show a => a -> String
show Int
i)

    -- repeatdly try to generate from a seed, if we reach 1000th iteration we just bail
    -- this should find a candidate after 2 tries on average
    loop :: Int -> XPrv
loop Int
i
        | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1000  = String -> XPrv
forall a. HasCallStack => String -> a
error String
"internal error: Wallet.generate looping forever"
        | Bool
otherwise =
            case ByteString
-> passPhrase -> ChainCode -> CryptoFailable EncryptedKey
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
 ByteArrayAccess cc) =>
secret -> passphrase -> cc -> CryptoFailable EncryptedKey
encryptedCreate ByteString
iL passPhrase
passPhrase ChainCode
iR of
                    CryptoPassed EncryptedKey
k -> EncryptedKey -> XPrv
XPrv EncryptedKey
k
                    CryptoFailed CryptoError
err
                        | CryptoError
err CryptoError -> CryptoError -> Bool
forall a. Eq a => a -> a -> Bool
== CryptoError
CryptoError_SecretKeyStructureInvalid -> Int -> XPrv
loop (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
                        | Bool
otherwise                                    -> String -> XPrv
forall a. HasCallStack => String -> a
error String
"internal error: Wallet.generate: got error from encryptedCreate"
      where (ByteString
iL, ChainCode
iR) = Context SHA512 -> (ByteString, ChainCode)
hFinalize
                     (Context SHA512 -> (ByteString, ChainCode))
-> Context SHA512 -> (ByteString, ChainCode)
forall a b. (a -> b) -> a -> b
$ (Context SHA512 -> ByteString -> Context SHA512)
-> ByteString -> Context SHA512 -> Context SHA512
forall a b c. (a -> b -> c) -> b -> a -> c
flip Context SHA512 -> ByteString -> Context SHA512
forall message a.
(ByteArrayAccess message, HashAlgorithm a) =>
Context a -> message -> Context a
HMAC.update (Int -> ByteString
phrase Int
i)
                     (Context SHA512 -> Context SHA512)
-> Context SHA512 -> Context SHA512
forall a b. (a -> b) -> a -> b
$ seed -> Context SHA512
forall seed. ByteArrayAccess seed => seed -> Context SHA512
hInitSeed seed
seed

-- | Generate a new XPrv from an entropy seed
--
-- The seed should be at least 16 bytes, although it is not enforced
--
-- The passphrase encrypt the secret key in memory
generateNew :: (ByteArrayAccess keyPassPhrase, ByteArrayAccess generationPassPhrase, ByteArrayAccess seed)
            => seed                 -- ^ Raw entropy used as source of randomness for this algorithm
            -> generationPassPhrase -- ^ User chosen passphrase for the generation phase
            -> keyPassPhrase        -- ^ Symmetric encryption key passphrase used for the in-memory security
            -> XPrv
generateNew :: seed -> generationPassPhrase -> keyPassPhrase -> XPrv
generateNew seed
seed generationPassPhrase
genPassPhrase keyPassPhrase
memPassPhrase =
    EncryptedKey -> XPrv
XPrv (EncryptedKey -> XPrv) -> EncryptedKey -> XPrv
forall a b. (a -> b) -> a -> b
$ ByteString -> keyPassPhrase -> EncryptedKey
forall passphrase secret.
(ByteArrayAccess passphrase, ByteArrayAccess secret) =>
secret -> passphrase -> EncryptedKey
encryptedCreateDirectWithTweak ByteString
out keyPassPhrase
memPassPhrase
  where
    out :: ByteString
    out :: ByteString
out = Parameters -> generationPassPhrase -> seed -> ByteString
forall password salt out.
(ByteArrayAccess password, ByteArrayAccess salt, ByteArray out) =>
Parameters -> password -> salt -> out
fastPBKDF2_SHA512 (Int -> Int -> Parameters
Parameters Int
4096 Int
96) generationPassPhrase
genPassPhrase seed
seed

-- | Simple constructor
xprv :: ByteArrayAccess bin => bin -> Either String XPrv
xprv :: bin -> Either String XPrv
xprv bin
bs =
      Either String XPrv
-> (EncryptedKey -> Either String XPrv)
-> Maybe EncryptedKey
-> Either String XPrv
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Either String XPrv
forall a b. a -> Either a b
Left String
"error: xprv needs to be 128 bytes") (XPrv -> Either String XPrv
forall a b. b -> Either a b
Right (XPrv -> Either String XPrv)
-> (EncryptedKey -> XPrv) -> EncryptedKey -> Either String XPrv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EncryptedKey -> XPrv
XPrv)
    (Maybe EncryptedKey -> Either String XPrv)
-> Maybe EncryptedKey -> Either String XPrv
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe EncryptedKey
encryptedKey
    (ByteString -> Maybe EncryptedKey)
-> ByteString -> Maybe EncryptedKey
forall a b. (a -> b) -> a -> b
$ bin -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert bin
bs

unXPrv :: XPrv -> ByteString
unXPrv :: XPrv -> ByteString
unXPrv (XPrv EncryptedKey
e) = EncryptedKey -> ByteString
unEncryptedKey EncryptedKey
e

xpub :: ByteString -> Either String XPub
xpub :: ByteString -> Either String XPub
xpub ByteString
bs
    | ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
64 = String -> Either String XPub
forall a b. a -> Either a b
Left (String
"error: xprv needs to be 64 bytes: got " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
bs) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" bytes")
    | Bool
otherwise         =
        let (ByteString
b1, ByteString
b2) = Int -> ByteString -> (ByteString, ByteString)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt Int
32 ByteString
bs
         in XPub -> Either String XPub
forall a b. b -> Either a b
Right (XPub -> Either String XPub) -> XPub -> Either String XPub
forall a b. (a -> b) -> a -> b
$ ByteString -> ChainCode -> XPub
XPub ByteString
b1 (ByteString -> ChainCode
ChainCode (ByteString -> ChainCode) -> ByteString -> ChainCode
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert ByteString
b2)

unXPub :: XPub -> ByteString
unXPub :: XPub -> ByteString
unXPub (XPub ByteString
pub (ChainCode ByteString
cc)) = ByteString -> ByteString -> ByteString
forall bs. ByteArray bs => bs -> bs -> bs
B.append ByteString
pub ByteString
cc

xsignature :: ByteString -> Either String XSignature
xsignature :: ByteString -> Either String XSignature
xsignature ByteString
bs
    | ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
64 = String -> Either String XSignature
forall a b. a -> Either a b
Left (String
"error: xsignature needs to be 64 bytes: got " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (ByteString -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ByteString
bs) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" bytes")
    | Bool
otherwise         = XSignature -> Either String XSignature
forall a b. b -> Either a b
Right (XSignature -> Either String XSignature)
-> XSignature -> Either String XSignature
forall a b. (a -> b) -> a -> b
$ ByteString -> XSignature
XSignature ByteString
bs

-- | Generate extended public key from private key
toXPub :: HasCallStack => XPrv -> XPub
toXPub :: XPrv -> XPub
toXPub (XPrv EncryptedKey
ekey) = ByteString -> ChainCode -> XPub
XPub ByteString
pub (ByteString -> ChainCode
ChainCode ByteString
cc)
  where (ByteString
_,ByteString
r)     = Int -> ByteString -> (ByteString, ByteString)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt Int
64 (ByteString -> (ByteString, ByteString))
-> ByteString -> (ByteString, ByteString)
forall a b. (a -> b) -> a -> b
$ EncryptedKey -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert EncryptedKey
ekey
        (ByteString
pub, ByteString
cc) = Int -> ByteString -> (ByteString, ByteString)
forall bs. ByteArray bs => Int -> bs -> (bs, bs)
B.splitAt Int
32 ByteString
r

-- | Return the Ed25519 public key associated with a XPub context
xPubGetPublicKey :: XPub -> Ed25519.PublicKey
xPubGetPublicKey :: XPub -> PublicKey
xPubGetPublicKey (XPub ByteString
pub ChainCode
_) =
    CryptoFailable PublicKey -> PublicKey
forall a. CryptoFailable a -> a
throwCryptoError (CryptoFailable PublicKey -> PublicKey)
-> CryptoFailable PublicKey -> PublicKey
forall a b. (a -> b) -> a -> b
$ ByteString -> CryptoFailable PublicKey
forall ba. ByteArrayAccess ba => ba -> CryptoFailable PublicKey
Ed25519.publicKey ByteString
pub

xPrvChangePass :: (ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase)
               => oldPassPhrase -- ^ passphrase to decrypt the current encrypted key
               -> newPassPhrase -- ^ new passphrase to use for the new encrypted key
               -> XPrv
               -> XPrv
xPrvChangePass :: oldPassPhrase -> newPassPhrase -> XPrv -> XPrv
xPrvChangePass oldPassPhrase
oldPass newPassPhrase
newPass (XPrv EncryptedKey
ekey) =
    EncryptedKey -> XPrv
XPrv (EncryptedKey -> XPrv) -> EncryptedKey -> XPrv
forall a b. (a -> b) -> a -> b
$ oldPassPhrase -> newPassPhrase -> EncryptedKey -> EncryptedKey
forall oldPassPhrase newPassPhrase.
(ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase) =>
oldPassPhrase -> newPassPhrase -> EncryptedKey -> EncryptedKey
encryptedChangePass oldPassPhrase
oldPass newPassPhrase
newPass EncryptedKey
ekey

-- | Derive a child extended private key from an extended private key
deriveXPrv :: ByteArrayAccess passPhrase => DerivationScheme -> passPhrase -> XPrv -> Word32 -> XPrv
deriveXPrv :: DerivationScheme -> passPhrase -> XPrv -> Word32 -> XPrv
deriveXPrv DerivationScheme
ds passPhrase
passPhrase (XPrv EncryptedKey
ekey) Word32
n =
    EncryptedKey -> XPrv
XPrv (DerivationScheme
-> EncryptedKey -> passPhrase -> Word32 -> EncryptedKey
forall passphrase.
ByteArrayAccess passphrase =>
DerivationScheme
-> EncryptedKey -> passphrase -> Word32 -> EncryptedKey
encryptedDerivePrivate DerivationScheme
ds EncryptedKey
ekey passPhrase
passPhrase Word32
n)

-- | Derive a child extended public key from an extended public key
deriveXPub :: DerivationScheme -> XPub -> Word32 -> Maybe XPub
deriveXPub :: DerivationScheme -> XPub -> Word32 -> Maybe XPub
deriveXPub DerivationScheme
ds (XPub ByteString
pub (ChainCode ByteString
cc)) Word32
n
    | Word32
n Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word32
0x80000000 = Maybe XPub
forall a. Maybe a
Nothing
    | Bool
otherwise       = XPub -> Maybe XPub
forall a. a -> Maybe a
Just (XPub -> Maybe XPub) -> XPub -> Maybe XPub
forall a b. (a -> b) -> a -> b
$ (ByteString -> ChainCode -> XPub)
-> (ByteString, ChainCode) -> XPub
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ByteString -> ChainCode -> XPub
XPub ((ByteString, ChainCode) -> XPub)
-> (ByteString, ChainCode) -> XPub
forall a b. (a -> b) -> a -> b
$ (ByteString -> ChainCode)
-> (ByteString, ByteString) -> (ByteString, ChainCode)
forall (a :: Type -> Type -> Type) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second ByteString -> ChainCode
ChainCode ((ByteString, ByteString) -> (ByteString, ChainCode))
-> (ByteString, ByteString) -> (ByteString, ChainCode)
forall a b. (a -> b) -> a -> b
$ DerivationScheme
-> (ByteString, ByteString) -> Word32 -> (ByteString, ByteString)
encryptedDerivePublic DerivationScheme
ds (ByteString
pub,ByteString
cc) Word32
n

sign :: (ByteArrayAccess passPhrase, ByteArrayAccess msg)
     => passPhrase
     -> XPrv
     -> msg
     -> XSignature
sign :: passPhrase -> XPrv -> msg -> XSignature
sign passPhrase
passphrase (XPrv EncryptedKey
ekey) msg
ba =
    ByteString -> XSignature
XSignature (ByteString -> XSignature) -> ByteString -> XSignature
forall a b. (a -> b) -> a -> b
$ let (Signature ByteString
sig) = EncryptedKey -> passPhrase -> msg -> Signature
forall passphrase msg.
(ByteArrayAccess passphrase, ByteArrayAccess msg) =>
EncryptedKey -> passphrase -> msg -> Signature
encryptedSign EncryptedKey
ekey passPhrase
passphrase msg
ba in ByteString
sig

verify :: ByteArrayAccess msg => XPub -> msg -> XSignature -> Bool
verify :: XPub -> msg -> XSignature -> Bool
verify (XPub ByteString
point ChainCode
_) msg
ba (XSignature ByteString
signature) =
    let pub :: PublicKey
pub = CryptoFailable PublicKey -> PublicKey
forall a. CryptoFailable a -> a
throwCryptoError (CryptoFailable PublicKey -> PublicKey)
-> CryptoFailable PublicKey -> PublicKey
forall a b. (a -> b) -> a -> b
$ ByteString -> CryptoFailable PublicKey
forall ba. ByteArrayAccess ba => ba -> CryptoFailable PublicKey
Ed25519.publicKey ByteString
point
        sig :: Signature
sig = CryptoFailable Signature -> Signature
forall a. CryptoFailable a -> a
throwCryptoError (CryptoFailable Signature -> Signature)
-> CryptoFailable Signature -> Signature
forall a b. (a -> b) -> a -> b
$ ByteString -> CryptoFailable Signature
forall ba. ByteArrayAccess ba => ba -> CryptoFailable Signature
Ed25519.signature ByteString
signature
     in PublicKey -> msg -> Signature -> Bool
forall ba.
ByteArrayAccess ba =>
PublicKey -> ba -> Signature -> Bool
Ed25519.verify PublicKey
pub msg
ba Signature
sig