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 mnemonic sentence support #975

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ index-state:
packages:
cardano-cli

source-repository-package
type: git
location: https://github.com/intersectmbo/cardano-addresses.git
tag: b170724d92549a69fc3074b5f9b3f1871701aaab
subdir: core
--sha256: sha256-ldr7lEdME4XUjtgARPDBMMzeg3i2UojlW03ab3Pv0T0=

source-repository-package
type: git
location: https://github.com/intersectmbo/cardano-api.git
tag: 29ca290f33c8df3d54e68cd566a762fa4aad2693
subdir: cardano-api
--sha256: sha256-LuCEwN4nAiAfDelb7slBTkvfvUqQFQK0mMwaOF1kcHo=

program-options
ghc-options: -Werror

Expand Down
2 changes: 2 additions & 0 deletions cardano-cli/cardano-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ library
Cardano.CLI.Run.Debug.TransactionView
Cardano.CLI.Run.Hash
Cardano.CLI.Run.Key
Cardano.CLI.Run.Mnemonic
Cardano.CLI.Run.Node
Cardano.CLI.Run.Ping
Cardano.CLI.TopHandler
Expand Down Expand Up @@ -222,6 +223,7 @@ library
exceptions,
filepath,
formatting,
haskeline,
http-client,
http-client-tls,
http-types,
Expand Down
46 changes: 46 additions & 0 deletions cardano-cli/src/Cardano/CLI/Commands/Key.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ module Cardano.CLI.Commands.Key
( KeyCmds (..)
, KeyVerificationKeyCmdArgs (..)
, KeyNonExtendedKeyCmdArgs (..)
, KeyGenerateMnemonicCmdArgs (..)
, KeyExtendedSigningKeyFromMnemonicArgs (..)
, ExtendedSigningType (..)
, MnemonicSource (..)
, KeyConvertByronKeyCmdArgs (..)
, KeyConvertByronGenesisVKeyCmdArgs (..)
, KeyConvertITNKeyCmdArgs (..)
Expand All @@ -19,12 +23,15 @@ where
import Cardano.Api.Shelley

import Cardano.CLI.Types.Common
import Cardano.Prelude (Word32)

import Data.Text (Text)

data KeyCmds
= KeyVerificationKeyCmd !KeyVerificationKeyCmdArgs
| KeyNonExtendedKeyCmd !KeyNonExtendedKeyCmdArgs
| KeyGenerateMnemonicCmd !KeyGenerateMnemonicCmdArgs
| KeyExtendedSigningKeyFromMnemonicCmd !KeyExtendedSigningKeyFromMnemonicArgs
| KeyConvertByronKeyCmd !KeyConvertByronKeyCmdArgs
| KeyConvertByronGenesisVKeyCmd !KeyConvertByronGenesisVKeyCmdArgs
| KeyConvertITNKeyCmd !KeyConvertITNKeyCmdArgs
Expand Down Expand Up @@ -52,6 +59,41 @@ data KeyNonExtendedKeyCmdArgs = KeyNonExtendedKeyCmdArgs
}
deriving Show

-- | Generate a mnemonic phrase that can be used to derive signing keys.
data KeyGenerateMnemonicCmdArgs = KeyGenerateMnemonicCmdArgs
{ mnemonicOutputFormat :: !(Maybe (File () Out))
-- ^ Output format for the mnemonic phrase
, mnemonicWords :: !MnemonicSize
-- ^ Number of mnemonic words to generate it must be one of: 12, 15, 18, 21, or 24.
}
deriving Show

-- | Get an extended signing key from a mnemonic.
data KeyExtendedSigningKeyFromMnemonicArgs = KeyExtendedSigningKeyFromMnemonicArgs
{ keyOutputFormat :: !KeyOutputFormat
, derivedExtendedSigningKeyType :: !ExtendedSigningType
, derivationAccountNo :: !Word32
, mnemonicSource :: !MnemonicSource
, signingKeyFileOut :: !(SigningKeyFile Out)
}
deriving Show

data MnemonicSource
= MnemonicFromFile !(File () In)
| MnemonicFromInteractivePrompt
deriving Show

-- | Type of the key derived from a mnemonic
-- together with the payment key number in the derivation path
-- for cases where it is applicable.
data ExtendedSigningType
palas marked this conversation as resolved.
Show resolved Hide resolved
= ExtendedSigningPaymentKey !Word32
| ExtendedSigningStakeKey !Word32
| ExtendedSigningDRepKey
| ExtendedSigningCCColdKey
| ExtendedSigningCCHotKey
deriving Show

-- | Convert a Byron payment, genesis or genesis delegate key (signing or
-- verification) to a corresponding Shelley-format key.
data KeyConvertByronKeyCmdArgs = KeyConvertByronKeyCmdArgs
Expand Down Expand Up @@ -124,6 +166,10 @@ renderKeyCmds = \case
"key verification-key"
KeyNonExtendedKeyCmd{} ->
"key non-extended-key"
KeyGenerateMnemonicCmd{} ->
"key generate-mnemonic"
KeyExtendedSigningKeyFromMnemonicCmd{} ->
"key from-mnemonic"
KeyConvertByronKeyCmd{} ->
"key convert-byron-key"
KeyConvertByronGenesisVKeyCmd{} ->
Expand Down
121 changes: 121 additions & 0 deletions cardano-cli/src/Cardano/CLI/Options/Key.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.CLI.Options.Key
Expand All @@ -17,8 +18,10 @@ import Cardano.CLI.Types.Common

import Data.Foldable
import Data.Text (Text)
import GHC.Word (Word32)
import Options.Applicative hiding (help, str)
import qualified Options.Applicative as Opt
import Options.Applicative.Types (readerAsk)

{- HLINT ignore "Use <$>" -}
{- HLINT ignore "Move brackets to avoid $" -}
Expand All @@ -42,6 +45,23 @@ pKeyCmds =
, "extended verification key. This supports all "
, "extended key types."
]
, subParser "generate-mnemonic" $
Opt.info pKeyGenerateMnemonicCmd $
Opt.progDesc $
mconcat
[ "Generate a mnemonic sentence that can be used "
, "for key derivation."
]
, subParser "derive-from-mnemonic" $
Opt.info pKeyExtendedSigningKeyFromMnemonicCmd $
Opt.progDesc $
mconcat
[ "Derive an extended signing key from a mnemonic "
, "sentence. "
, "To ensure the safety of the mnemonic phrase, "
, "we recommend that key derivation is performed "
, "in an air-gapped environment."
]
, subParser "convert-byron-key" $
Opt.info pKeyConvertByronKeyCmd $
Opt.progDesc $
Expand Down Expand Up @@ -114,6 +134,107 @@ pKeyNonExtendedKeyCmd =
<$> pExtendedVerificationKeyFileIn
<*> pVerificationKeyFileOut

pKeyGenerateMnemonicCmd :: Parser KeyCmds
pKeyGenerateMnemonicCmd =
fmap KeyGenerateMnemonicCmd $
KeyGenerateMnemonicCmdArgs
<$> optional pOutputFile
<*> pMnemonicSize

pMnemonicSize :: Parser MnemonicSize
pMnemonicSize = do
option
parseSize
( long "size"
<> metavar "WORD32"
<> Opt.help
( mconcat
[ "Specify the desired number of words for the output"
, "mnemonic sentence (valid options are: 12, 15, 18, 21, and 24)"
]
)
)
where
parseSize :: ReadM MnemonicSize
parseSize =
readerAsk
>>= \case
"12" -> return MS12
"15" -> return MS15
"18" -> return MS18
"21" -> return MS21
"24" -> return MS24
invalidSize ->
readerError $
"Invalid mnemonic size " <> show invalidSize <> "! It must be one of: 12, 15, 18, 21, or 24."

pKeyExtendedSigningKeyFromMnemonicCmd :: Parser KeyCmds
pKeyExtendedSigningKeyFromMnemonicCmd =
fmap KeyExtendedSigningKeyFromMnemonicCmd $
KeyExtendedSigningKeyFromMnemonicArgs
<$> pKeyOutputFormat
<*> pDerivedExtendedSigningKeyType
<*> pAccountNumber
<*> pMnemonicSource
<*> pSigningKeyFileOut

pDerivedExtendedSigningKeyType :: Parser ExtendedSigningType
pDerivedExtendedSigningKeyType =
asum
[ Opt.option (ExtendedSigningPaymentKey <$> integralReader) $
mconcat
[ Opt.long "payment-key-with-number"
, Opt.metavar "WORD32"
, Opt.help
"Derive an extended payment key with the given payment address number from the derivation path."
]
, Opt.option (ExtendedSigningStakeKey <$> integralReader) $
mconcat
[ Opt.long "stake-key-with-number"
, Opt.metavar "WORD32"
, Opt.help
"Derive an extended stake key with the given stake address number from the derivation path."
]
, Opt.flag' ExtendedSigningDRepKey $
mconcat
[ Opt.long "drep-key"
, Opt.help "Derive an extended DRep key."
]
, Opt.flag' ExtendedSigningCCColdKey $
mconcat
[ Opt.long "cc-cold-key"
, Opt.help "Derive an extended committee cold key."
]
, Opt.flag' ExtendedSigningCCHotKey $
mconcat
[ Opt.long "cc-hot-key"
, Opt.help "Derive an extended committee hot key."
]
]

pMnemonicSource :: Parser MnemonicSource
pMnemonicSource =
asum
[ MnemonicFromFile . File <$> parseFilePath "mnemonic-from-file" "Input text file with the mnemonic."
, Opt.flag' MnemonicFromInteractivePrompt $
mconcat
[ Opt.long "mnemonic-from-interactive-prompt"
, Opt.help $
"Input the mnemonic through an interactive prompt. "
<> "This mode also accepts receiving the mnemonic through "
<> "standard input directly, for example, by using a pipe."
]
]

pAccountNumber :: Parser Word32
pAccountNumber =
Opt.option integralReader $
mconcat
[ Opt.long "account-number"
, Opt.metavar "WORD32"
, Opt.help "Account number in the derivation path."
]

pKeyConvertByronKeyCmd :: Parser KeyCmds
pKeyConvertByronKeyCmd =
fmap KeyConvertByronKeyCmd $
Expand Down
32 changes: 30 additions & 2 deletions cardano-cli/src/Cardano/CLI/Run/Key.hs
palas marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.CLI.Run.Key
Expand Down Expand Up @@ -39,6 +37,7 @@ import qualified Cardano.Api.Ledger as L

import qualified Cardano.CLI.Byron.Key as Byron
import qualified Cardano.CLI.Commands.Key as Cmd
import Cardano.CLI.Run.Mnemonic (extendedSigningKeyFromMnemonicImpl, generateMnemonicImpl)
import Cardano.CLI.Types.Common
import Cardano.CLI.Types.Errors.CardanoAddressSigningKeyConversionError
import Cardano.CLI.Types.Errors.ItnKeyConversionError
Expand Down Expand Up @@ -112,6 +111,10 @@ runKeyCmds = \case
runVerificationKeyCmd cmd
Cmd.KeyNonExtendedKeyCmd cmd ->
runNonExtendedKeyCmd cmd
Cmd.KeyGenerateMnemonicCmd cmd ->
runGenerateMnemonicCmd cmd
Cmd.KeyExtendedSigningKeyFromMnemonicCmd cmd ->
runExtendedSigningKeyFromMnemonicCmd cmd
Cmd.KeyConvertByronKeyCmd cmd ->
runConvertByronKeyCmd cmd
Cmd.KeyConvertByronGenesisVKeyCmd cmd ->
Expand Down Expand Up @@ -202,6 +205,13 @@ runNonExtendedKeyCmd
writeLazyByteStringFile vkf' $
textEnvelopeToJSON descr vk

runGenerateMnemonicCmd :: Cmd.KeyGenerateMnemonicCmdArgs -> ExceptT KeyCmdError IO ()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think when writing to file we should at least set restrictive permissions. Can you get in touch with the wallet team and ask them what precautions they took when generating mnemonics?

runGenerateMnemonicCmd
Cmd.KeyGenerateMnemonicCmdArgs
{ mnemonicOutputFormat
, mnemonicWords
} = generateMnemonicImpl mnemonicWords mnemonicOutputFormat

readExtendedVerificationKeyFile
:: VerificationKeyFile In
-> ExceptT KeyCmdError IO SomeAddressVerificationKey
Expand Down Expand Up @@ -232,6 +242,24 @@ readExtendedVerificationKeyFile evkfile = do
where
goFail k = left $ KeyCmdExpectedExtendedVerificationKey k

runExtendedSigningKeyFromMnemonicCmd
:: Cmd.KeyExtendedSigningKeyFromMnemonicArgs
-> ExceptT KeyCmdError IO ()
runExtendedSigningKeyFromMnemonicCmd
Cmd.KeyExtendedSigningKeyFromMnemonicArgs
{ keyOutputFormat
, derivedExtendedSigningKeyType
, derivationAccountNo
, mnemonicSource
, signingKeyFileOut
} =
extendedSigningKeyFromMnemonicImpl
keyOutputFormat
derivedExtendedSigningKeyType
derivationAccountNo
mnemonicSource
signingKeyFileOut

runConvertByronKeyCmd
:: Cmd.KeyConvertByronKeyCmdArgs
-> ExceptT KeyCmdError IO ()
Expand Down
Loading
Loading