never executed always true always false
    1 {-# LANGUAGE FlexibleContexts #-}
    2 {-# LANGUAGE NamedFieldPuns #-}
    3 {-# LANGUAGE OverloadedStrings #-}
    4 
    5 {-# OPTIONS_HADDOCK hide #-}
    6 
    7 module Command.Key.Hash
    8     ( Cmd (..)
    9     , mod
   10     , run
   11     ) where
   12 
   13 import Prelude hiding
   14     ( mod )
   15 
   16 import Cardano.Address.Derivation
   17     ( hashCredential )
   18 import Codec.Binary.Encoding
   19     ( AbstractEncoding (..) )
   20 import Control.Monad
   21     ( when )
   22 import Data.Maybe
   23     ( fromJust )
   24 import Options.Applicative
   25     ( CommandFields, Mod, command, footerDoc, helper, info, progDesc )
   26 import Options.Applicative.Format
   27     ( FormatType (..), formatOpt )
   28 import Options.Applicative.Help.Pretty
   29     ( string )
   30 import System.IO
   31     ( stdin, stdout )
   32 import System.IO.Extra
   33     ( hGetBech32, hPutBytes )
   34 
   35 import qualified Cardano.Codec.Bech32.Prefixes as CIP5
   36 import qualified Data.ByteString as BS
   37 
   38 newtype Cmd = Hash
   39     { outputFormat :: FormatType
   40     } deriving (Show)
   41 
   42 mod :: (Cmd -> parent) -> Mod CommandFields parent
   43 mod liftCmd = command "hash" $
   44     info (helper <*> fmap liftCmd parser) $ mempty
   45         <> progDesc "Get the hash of a public key"
   46         <> footerDoc (Just $ string $ mconcat
   47             [ "The public key is read from stdin."
   48             , "To get hex-encoded output pass '--hex'."
   49             , "Otherwise bech32-encoded hash is returned."
   50             ])
   51   where
   52     parser = Hash
   53         <$> formatOpt
   54 
   55 run :: Cmd -> IO ()
   56 run Hash{outputFormat} = do
   57     (hrp, bytes) <- hGetBech32 stdin allowedPrefixes
   58     guardBytes hrp bytes
   59     let encoding = case outputFormat of
   60             Hex -> EBase16
   61             Bech32 -> EBech32 $ prefixFor hrp
   62     hPutBytes stdout (hashCredential $ BS.take 32 bytes) encoding
   63   where
   64     -- Mapping of input HRP to output HRP
   65     prefixes =
   66         [ ( CIP5.addr_vk         , CIP5.addr_vkh   )
   67         , ( CIP5.addr_xvk        , CIP5.addr_vkh   )
   68         , ( CIP5.stake_vk        , CIP5.stake_vkh  )
   69         , ( CIP5.stake_xvk       , CIP5.stake_vkh  )
   70         , ( CIP5.addr_shared_vk  , CIP5.addr_shared_vkh )
   71         , ( CIP5.addr_shared_xvk , CIP5.addr_shared_vkh )
   72         , ( CIP5.stake_shared_vk , CIP5.stake_shared_vkh )
   73         , ( CIP5.stake_shared_xvk, CIP5.stake_shared_vkh )
   74         , ( CIP5.policy_vk       , CIP5.policy_vkh  )
   75         , ( CIP5.policy_xvk      , CIP5.policy_vkh  )
   76         ]
   77     allowedPrefixes = map fst prefixes
   78     prefixFor = fromJust . flip lookup prefixes
   79 
   80     guardBytes hrp bytes
   81         | hrp `elem` [CIP5.addr_xvk, CIP5.stake_xvk, CIP5.addr_shared_xvk, CIP5.stake_shared_xvk, CIP5.policy_xvk] = do
   82             when (BS.length bytes /= 64) $
   83                 fail "data should be a 32-byte public key with a 32-byte chain-code appended"
   84 
   85         | otherwise = do
   86             when (BS.length bytes /= 32) $
   87                 fail "data should be a 32-byte public key."