From 83d5115a02da8c1cd2db2ff3cf7804b7ecb66253 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 30 Oct 2019 20:47:42 -0700 Subject: [PATCH] Add --starts-with for vanity key grinding (#6647) --- Cargo.lock | 1 + keygen/Cargo.toml | 4 +--- keygen/src/keygen.rs | 43 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c0136e55..f6c343c28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3503,6 +3503,7 @@ dependencies = [ name = "solana-keygen" version = "0.21.0" dependencies = [ + "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/keygen/Cargo.toml b/keygen/Cargo.toml index cd084bf7a..ab34215ce 100644 --- a/keygen/Cargo.toml +++ b/keygen/Cargo.toml @@ -8,10 +8,8 @@ license = "Apache-2.0" homepage = "https://solana.com/" edition = "2018" - - - [dependencies] +bs58 = "0.3.0" clap = "2.33" dirs = "2.0.2" rpassword = "4.0" diff --git a/keygen/src/keygen.rs b/keygen/src/keygen.rs index 914bf1495..380615c03 100644 --- a/keygen/src/keygen.rs +++ b/keygen/src/keygen.rs @@ -1,4 +1,5 @@ use bip39::{Language, Mnemonic, MnemonicType, Seed}; +use bs58; use clap::{ crate_description, crate_name, crate_version, App, AppSettings, Arg, ArgMatches, SubCommand, }; @@ -64,6 +65,18 @@ fn main() -> Result<(), Box> { .short("s") .long("silent") .help("Do not display mnemonic phrase. Useful when piping output to other programs that prompt for user input, like gpg"), + ) + .arg( + Arg::with_name("starts_with") + .long("starts-with") + .value_name("BASE58 PREFIX") + .takes_value(true) + .validator(|value| { + bs58::decode(value).into_vec() + .map(|_| ()) + .map_err(|err| format!("{:?}", err)) + }) + .help("Grind a keypair with public key starting with this prefix"), ), ) .subcommand( @@ -150,19 +163,37 @@ fn main() -> Result<(), Box> { check_for_overwrite(&outfile, &matches); } - let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); - let phrase: &str = mnemonic.phrase(); - let seed = Seed::new(&mnemonic, NO_PASSPHRASE); - let keypair = keypair_from_seed(seed.as_bytes())?; + let mut attempts = 0; + let (pubkey, keypair, mnemonic) = loop { + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + let seed = Seed::new(&mnemonic, NO_PASSPHRASE); + let keypair = keypair_from_seed(seed.as_bytes())?; + let pubkey = bs58::encode(keypair.pubkey()).into_string(); + + if let Some(prefix) = matches.value_of("starts_with") { + if !pubkey.starts_with(prefix) { + if attempts % 10_000 == 0 { + println!( + "Searching for pubkey prefix of {} ({} attempts)", + prefix, attempts + ); + } + attempts += 1; + continue; + } + } + break (pubkey, keypair, mnemonic); + }; output_keypair(&keypair, &outfile, "new")?; let silent = matches.is_present("silent"); if !silent { + let phrase: &str = mnemonic.phrase(); let divider = String::from_utf8(vec![b'='; phrase.len()]).unwrap(); eprintln!( - "{}\nSave this mnemonic phrase to recover your new keypair:\n{}\n{}", - ÷r, phrase, ÷r + "{}\npubkey: {}\n{}\nSave this mnemonic phrase to recover your new keypair:\n{}\n{}", + ÷r, pubkey, ÷r, phrase, ÷r ); } }