Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command for converting various Byron keys to their Shelley counterpart #1486

Merged
merged 7 commits into from
Jul 18, 2020
Merged
425 changes: 424 additions & 1 deletion cardano-api/src/Cardano/Api/Typed.hs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions cardano-cli/cardano-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ library
Cardano.CLI.Shelley.Run.Address.Info
Cardano.CLI.Shelley.Run.Genesis
Cardano.CLI.Shelley.Run.Governance
Cardano.CLI.Shelley.Run.Key
Cardano.CLI.Shelley.Run.Node
Cardano.CLI.Shelley.Run.Pool
Cardano.CLI.Shelley.Run.Query
Expand Down Expand Up @@ -179,6 +180,7 @@ test-suite cardano-cli-pioneers
, aeson
, bech32 >= 1.1.0
, bytestring
, base16-bytestring
, cardano-api
, cardano-cli
, cardano-prelude
Expand Down
91 changes: 1 addition & 90 deletions cardano-cli/src/Cardano/CLI/Helpers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,34 @@
{-# LANGUAGE RankNTypes #-}

module Cardano.CLI.Helpers
( ConversionError(..)
, HelpersError(..)
, convertITNVerificationKey
, convertITNSigningKey
, dataPartToBase16
, decodeBech32Key
( HelpersError(..)
, ensureNewFile
, ensureNewFileLBS
, pPrintCBOR
, readCBOR
, readBech32
, renderConversionError
, renderHelpersError
, textShow
, validateCBOR
) where

import Cardano.Prelude

import Codec.Binary.Bech32 (DataPart, HumanReadablePart, dataPartToBytes,
dataPartToText)
import qualified Codec.Binary.Bech32 as Bech32
import Codec.CBOR.Pretty (prettyHexEnc)
import Codec.CBOR.Read (DeserialiseFailure, deserialiseFromBytes)
import Codec.CBOR.Term (decodeTerm, encodeTerm)
import Control.Exception (IOException)
import qualified Control.Exception as Exception
import Control.Monad.Trans.Except.Extra (handleIOExceptT, left)
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Char8 as SC
import qualified Data.ByteString.Lazy as LB
import qualified Data.Text as Text
import System.Directory (doesPathExist)

import Cardano.Api.Typed (SigningKey(..), StakeKey, VerificationKey(..))
import Cardano.Binary (Decoder, fromCBOR)
import qualified Cardano.Chain.Delegation as Delegation
import qualified Cardano.Chain.Update as Update
import Cardano.Chain.Block (fromCBORABlockOrBoundary)
import qualified Cardano.Chain.UTxO as UTxO
import Cardano.Config.Types
import qualified Cardano.Crypto.DSIGN as DSIGN

import qualified Shelley.Spec.Ledger.Keys as Shelley

data HelpersError
= CBORPrettyPrintError !DeserialiseFailure
Expand Down Expand Up @@ -120,79 +104,6 @@ validateCBOR cborObject bs =
(const () ) <$> decodeCBOR bs (fromCBOR :: Decoder s Update.Vote)
Right "Valid Byron vote."

--------------------------------------------------------------------------------
-- ITN verification/signing key conversion to Haskell verficiation/signing keys
--------------------------------------------------------------------------------

data ConversionError
= Bech32DecodingError
-- ^ Bech32 key
!Text
!Bech32.DecodingError
| Bech32ErrorExtractingByes !DataPart
| Bech32ReadError !FilePath !Text
| ITNError !HumanReadablePart !DataPart
| SigningKeyDeserializationError !ByteString
| VerificationKeyDeserializationError !ByteString
deriving Show

renderConversionError :: ConversionError -> Text
renderConversionError err =
case err of
Bech32DecodingError key decErr ->
"Error decoding Bech32 key: " <> key <> " Error: " <> textShow decErr
Bech32ErrorExtractingByes dp ->
"Unable to extract bytes from: " <> dataPartToText dp
Bech32ReadError fp readErr ->
"Error reading bech32 key at: " <> textShow fp <> " Error: " <> readErr
ITNError hRpart dp ->
"Error extracting a ByteString from DataPart: " <> Bech32.dataPartToText dp <>
" With human readable part: " <> Bech32.humanReadablePartToText hRpart
SigningKeyDeserializationError sKey ->
"Error deserialising signing key: " <> textShow (SC.unpack sKey)
VerificationKeyDeserializationError vKey ->
"Error deserialising verification key: " <> textShow (SC.unpack vKey)

-- | Convert public ed25519 key to a Shelley stake verification key
convertITNVerificationKey :: Text -> Either ConversionError (VerificationKey StakeKey)
convertITNVerificationKey pubKey = do
(_, _, keyBS) <- decodeBech32Key pubKey
case DSIGN.rawDeserialiseVerKeyDSIGN keyBS of
Just verKey -> Right . StakeVerificationKey $ Shelley.VKey verKey
Nothing -> Left $ VerificationKeyDeserializationError keyBS

-- | Convert private ed22519 key to a Shelley signing key.
convertITNSigningKey :: Text -> Either ConversionError (SigningKey StakeKey)
convertITNSigningKey privKey = do
(_, _, keyBS) <- decodeBech32Key privKey
case DSIGN.rawDeserialiseSignKeyDSIGN keyBS of
Just signKey -> Right $ StakeSigningKey signKey
Nothing -> Left $ SigningKeyDeserializationError keyBS

-- | Convert ITN Bech32 public or private keys to 'ByteString's
decodeBech32Key :: Text -> Either ConversionError (HumanReadablePart, DataPart, ByteString)
decodeBech32Key key =
case Bech32.decodeLenient key of
Left err -> Left $ Bech32DecodingError key err
Right (hRpart, dataPart) -> case Bech32.dataPartToBytes dataPart of
Nothing -> Left $ ITNError hRpart dataPart
Just bs -> Right (hRpart, dataPart, bs)

dataPartToBase16 :: DataPart -> Either ConversionError ByteString
dataPartToBase16 dp = case dataPartToBytes dp of
Just bs -> Right $ Base16.encode bs
Nothing -> Left $ Bech32ErrorExtractingByes dp

readBech32 :: FilePath -> IO (Either ConversionError Text)
readBech32 fp = do
eStr <- Exception.try $ readFile fp
case eStr of
Left e -> return . Left $ Bech32ReadError fp $ handler e
Right str -> return . Right . Text.concat $ Text.words str
where
handler :: IOException -> Text
handler e = Text.pack $ "Cardano.Api.Convert.readBech32: "
++ displayException e

textShow :: Show a => a -> Text
textShow = Text.pack . show
38 changes: 32 additions & 6 deletions cardano-cli/src/Cardano/CLI/Shelley/Commands.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Cardano.CLI.Shelley.Commands
ShelleyCommand (..)
, AddressCmd (..)
, StakeAddressCmd (..)
, KeyCmd (..)
, TransactionCmd (..)
, NodeCmd (..)
, PoolCmd (..)
Expand All @@ -17,12 +18,14 @@ module Cardano.CLI.Shelley.Commands

-- * CLI flag types
, AddressKeyType (..)
, ByronKeyType (..)
, ByronKeyFormat (..)
, GenesisDir (..)
, TxInCount (..)
, TxOutCount (..)
, TxShelleyWitnessCount (..)
, TxByronWitnessCount (..)
, ITNKeyFile (..)
, SomeKeyFile (..)
, OpCertCounterFile (..)
, OutputFile (..)
, ProtocolParamsFile (..)
Expand All @@ -31,6 +34,7 @@ module Cardano.CLI.Shelley.Commands
, TxBodyFile (..)
, TxFile (..)
, VerificationKeyFile (..)
, VerificationKeyBase64 (..)
, GenesisKeyFile (..)
, MetaDataFile (..)
, PoolId (..)
Expand Down Expand Up @@ -65,6 +69,7 @@ import Shelley.Spec.Ledger.TxData (MIRPot)
data ShelleyCommand
= AddressCmd AddressCmd
| StakeAddressCmd StakeAddressCmd
| KeyCmd KeyCmd
| TransactionCmd TransactionCmd
| NodeCmd NodeCmd
| PoolCmd PoolCmd
Expand All @@ -83,7 +88,6 @@ data AddressCmd
| AddressBuild VerificationKeyFile (Maybe VerificationKeyFile) NetworkId (Maybe OutputFile)
| AddressBuildMultiSig --TODO
| AddressInfo Text (Maybe OutputFile)
| AddressConvertKey SigningKeyFile SigningKeyFile
deriving (Eq, Show)

data StakeAddressCmd
Expand All @@ -96,9 +100,13 @@ data StakeAddressCmd
| StakeKeyRegistrationCert VerificationKeyFile OutputFile
| StakeKeyDelegationCert VerificationKeyFile StakePoolVerificationKeyHashOrFile OutputFile
| StakeKeyDeRegistrationCert VerificationKeyFile OutputFile
| StakeKeyITNConversion ITNKeyFile (Maybe OutputFile)
deriving (Eq, Show)

data KeyCmd
= KeyConvertByronKey ByronKeyType SomeKeyFile OutputFile
| KeyConvertByronGenesisVKey VerificationKeyBase64 OutputFile
| KeyConvertITNStakeKey SomeKeyFile OutputFile
deriving (Eq, Show)

data TransactionCmd
= TxBuildRaw
Expand Down Expand Up @@ -279,9 +287,12 @@ newtype GenesisDir
= GenesisDir FilePath
deriving (Eq, Show)

data ITNKeyFile
= ITNVerificationKeyFile VerificationKeyFile
| ITNSigningKeyFile SigningKeyFile
-- | Either a verification or signing key, used for conversions and other
-- commands that make sense for both.
--
data SomeKeyFile
= AVerificationKeyFile VerificationKeyFile
| ASigningKeyFile SigningKeyFile
deriving (Eq, Show)

data AddressKeyType
Expand All @@ -290,6 +301,16 @@ data AddressKeyType
| AddressKeyByron
deriving (Eq, Show)

data ByronKeyType
= ByronPaymentKey ByronKeyFormat
| ByronGenesisKey ByronKeyFormat
| ByronDelegateKey ByronKeyFormat
deriving (Eq, Show)

data ByronKeyFormat = NonLegacyByronKeyFormat
| LegacyByronKeyFormat
deriving (Eq, Show)

newtype OpCertCounterFile
= OpCertCounterFile FilePath
deriving (Eq, Show)
Expand All @@ -314,6 +335,11 @@ newtype VerificationKeyFile
= VerificationKeyFile FilePath
deriving (Eq, Show)

-- | A raw verification key given in Base64, and decoded into a ByteString.
newtype VerificationKeyBase64
= VerificationKeyBase64 String
deriving (Eq, Show)

-- | UTxO query filtering options.
data QueryFilter
= FilterByAddress !(Set (Address Shelley))
Expand Down
Loading