keygen: add the ability to use derivation path for new & grind commands (#21614)

* keygen: add --use-derivation-path for new & grind

* keygen: add prompt:// uri scheme to new and grind

* fmt

* migrate to clap-v3-utils

* Revert "migrate to clap-v3-utils"

This reverts commit 77f33262ce6c4e95ac1cc62cca32749516f7f357.

* Revert "fmt"

This reverts commit 038cd4ce9628c57dec1f5a4716e2c5baacbe57b3.

* Revert "keygen: add prompt:// uri scheme to new and grind"

This reverts commit 029ea61409a1a16ba2c45483ade2c01f84f25fac.

* - remove `use` from arg
- fix issue from first commit with default value for derivation path
- refactor arg definition and acquiring
This commit is contained in:
DimAn 2022-09-07 20:31:40 +02:00 committed by GitHub
parent d6a1e7498f
commit 6899af26b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 4 deletions

View File

@ -14,10 +14,14 @@ use {
solana_cli_config::{Config, CONFIG_FILE},
solana_remote_wallet::remote_wallet::RemoteWalletManager,
solana_sdk::{
derivation_path::DerivationPath,
instruction::{AccountMeta, Instruction},
message::Message,
pubkey::{write_pubkey_file, Pubkey},
signature::{keypair_from_seed, write_keypair, write_keypair_file, Keypair, Signer},
signature::{
keypair_from_seed, keypair_from_seed_and_derivation_path, write_keypair,
write_keypair_file, Keypair, Signer,
},
},
std::{
collections::HashSet,
@ -34,6 +38,7 @@ use {
};
const NO_PASSPHRASE: &str = "";
const DEFAULT_DERIVATION_PATH: &str = "m/44'/501'/0'/0'";
struct GrindMatch {
starts: String,
@ -325,6 +330,33 @@ fn grind_parse_args(
grind_matches
}
fn derivation_path_arg<'a>() -> Arg<'a> {
Arg::new("derivation_path")
.long("derivation-path")
.value_name("DERIVATION_PATH")
.takes_value(true)
.min_values(0)
.max_values(1)
.help("Derivation path. All indexes will be promoted to hardened. \
If arg is not presented then derivation path will not be used. \
If arg is presented with empty DERIVATION_PATH value then m/44'/501'/0'/0' will be used."
)
}
fn acquire_derivation_path(
matches: &ArgMatches,
) -> Result<Option<DerivationPath>, Box<dyn error::Error>> {
if matches.is_present("derivation_path") {
Ok(Some(DerivationPath::from_absolute_path_str(
matches
.value_of("derivation_path")
.unwrap_or(DEFAULT_DERIVATION_PATH),
)?))
} else {
Ok(None)
}
}
fn main() -> Result<(), Box<dyn error::Error>> {
let default_num_threads = num_cpus::get().to_string();
let matches = Command::new(crate_name!())
@ -389,6 +421,9 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.long("silent")
.help("Do not display seed phrase. Useful when piping output to other programs that prompt for user input, like gpg"),
)
.arg(
derivation_path_arg()
)
.key_generation_common_args()
.arg(no_outfile_arg()
.conflicts_with_all(&["outfile", "silent"])
@ -450,6 +485,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.long("use-mnemonic")
.help("Generate using a mnemonic key phrase. Expect a significant slowdown in this mode"),
)
.arg(
derivation_path_arg()
.requires("use_mnemonic")
)
.key_generation_common_args()
.arg(
no_outfile_arg()
@ -576,11 +615,17 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
if !silent {
println!("Generating a new keypair");
}
let derivation_path = acquire_derivation_path(matches)?;
let mnemonic = Mnemonic::new(mnemonic_type, language);
let (passphrase, passphrase_message) = acquire_passphrase_and_message(matches).unwrap();
let seed = Seed::new(&mnemonic, &passphrase);
let keypair = keypair_from_seed(seed.as_bytes())?;
let keypair = match derivation_path {
Some(_) => keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path),
None => keypair_from_seed(seed.as_bytes()),
}?;
if let Some(outfile) = outfile {
output_keypair(&keypair, outfile, "new")
@ -671,6 +716,8 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
let use_mnemonic = matches.is_present("use_mnemonic");
let derivation_path = acquire_derivation_path(matches)?;
let word_count: usize = matches.value_of_t(WORD_COUNT_ARG.name).unwrap();
let mnemonic_type = MnemonicType::for_word_count(word_count)?;
let language = acquire_language(matches);
@ -696,6 +743,7 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
let grind_matches_thread_safe = grind_matches_thread_safe.clone();
let passphrase = passphrase.clone();
let passphrase_message = passphrase_message.clone();
let derivation_path = derivation_path.clone();
thread::spawn(move || loop {
if done.load(Ordering::Relaxed) {
@ -713,7 +761,11 @@ fn do_main(matches: &ArgMatches) -> Result<(), Box<dyn error::Error>> {
let (keypair, phrase) = if use_mnemonic {
let mnemonic = Mnemonic::new(mnemonic_type, language);
let seed = Seed::new(&mnemonic, &passphrase);
(keypair_from_seed(seed.as_bytes()).unwrap(), mnemonic.phrase().to_string())
let keypair = match derivation_path {
Some(_) => keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path.clone()),
None => keypair_from_seed(seed.as_bytes()),
}.unwrap();
(keypair, mnemonic.phrase().to_string())
} else {
(Keypair::new(), "".to_string())
};

View File

@ -79,7 +79,7 @@ impl DerivationPath {
Ok(Self::new_bip44_with_coin(coin, account, change))
}
fn from_absolute_path_str(path: &str) -> Result<Self, DerivationPathError> {
pub fn from_absolute_path_str(path: &str) -> Result<Self, DerivationPathError> {
let inner = DerivationPath::_from_absolute_path_insecure_str(path)?
.into_iter()
.map(|c| ChildIndex::Hardened(c.to_u32()))