packages feed

cardano-addresses-4.0.0: lib/Command/Key/Public.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}

{-# OPTIONS_HADDOCK hide #-}

-- |
-- Copyright: 2020 Input Output (Hong Kong) Ltd., 2021-2022 Input Output Global Inc. (IOG), 2023-2025 Intersect
-- License: Apache-2.0

module Command.Key.Public
    ( Cmd (..)
    , mod
    , run
    ) where

import Prelude hiding
    ( mod )

import Cardano.Address.Derivation
    ( toXPub, xpubPublicKey, xpubToBytes )
import Codec.Binary.Encoding
    ( AbstractEncoding (..) )
import Data.Maybe
    ( fromJust )
import Data.Text
    ( Text )
import Options.Applicative
    ( CommandFields, Mod, command, footerDoc, helper, info, progDesc )
import Options.Applicative.Help.Pretty
    ( pretty )
import Options.Applicative.Public
    ( PublicType (..), publicOpt )
import System.IO
    ( stdin, stdout )
import System.IO.Extra
    ( hGetXPrv, hPutBytes )

import qualified Cardano.Codec.Bech32.Prefixes as CIP5

newtype Cmd = Public
    { chainCode :: PublicType
    } deriving (Show)

mod :: (Cmd -> parent) -> Mod CommandFields parent
mod liftCmd = command "public" $
    info (helper <*> fmap liftCmd parser) $ mempty
        <> progDesc "Get the public counterpart of a private key"
        <> footerDoc (Just $ pretty $ mconcat
            [ "The private key is read from stdin." :: Text
            , "To get extended public key pass '--with-chain-code'."
            , "To get public key pass '--without-chain-code'."
            ])
  where
    parser = Public
        <$> publicOpt

run :: Cmd -> IO ()
run Public{chainCode} = do
    (hrp, xprv) <- hGetXPrv stdin allowedPrefixes
    let xpub = toXPub xprv
    let bytes = case chainCode of
            WithChainCode    -> xpubToBytes xpub
            WithoutChainCode -> xpubPublicKey xpub
    hPutBytes stdout bytes (EBech32 $ prefixFor chainCode hrp)
  where
    prefixes =
        [ (CIP5.root_xsk, (CIP5.root_xvk, CIP5.root_vk) )
        , (CIP5.acct_xsk, (CIP5.acct_xvk, CIP5.acct_vk) )
        , (CIP5.addr_xsk, (CIP5.addr_xvk, CIP5.addr_vk) )
        , (CIP5.stake_xsk, (CIP5.stake_xvk, CIP5.stake_vk) )
        , (CIP5.root_shared_xsk, (CIP5.root_shared_xvk, CIP5.root_shared_vk) )
        , (CIP5.acct_shared_xsk, (CIP5.acct_shared_xvk, CIP5.acct_shared_vk) )
        , (CIP5.addr_shared_xsk, (CIP5.addr_shared_xvk, CIP5.addr_shared_vk) )
        , (CIP5.stake_shared_xsk, (CIP5.stake_shared_xvk, CIP5.stake_shared_vk) )
        , (CIP5.policy_xsk, (CIP5.policy_xvk, CIP5.policy_vk) )
        , (CIP5.drep_xsk, (CIP5.drep_xvk, CIP5.drep_vk) )
        , (CIP5.cc_cold_xsk, (CIP5.cc_cold_xvk, CIP5.cc_cold_vk) )
        , (CIP5.cc_hot_xsk, (CIP5.cc_hot_xvk, CIP5.cc_hot_vk) )
        ]
    allowedPrefixes = map fst prefixes
    getCC WithChainCode = fst
    getCC WithoutChainCode = snd
    prefixFor cc = getCC cc . fromJust . flip lookup prefixes