can the code has parameter to setup ranges with decimal ? even though is random, i want it like random through ranges.
Yes.
use bitcoin::address::Address;
use bitcoin::key::PrivateKey;
use bitcoin::network::NetworkKind;
use chrono::Local;
use clap::{App, Arg};
use hex;
use num::bigint::BigInt;
use num::traits::One;
use num_cpus;
use rand::Rng;
use rand::rngs::SmallRng;
use rand::SeedableRng;
use std::fs::File;
use std::io::{self, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc};
use std::convert::TryInto;
use threadpool::ThreadPool;
fn main() {
// Print the current time when the script starts
let current_time = Local::now();
println!(
"\x1b[38;5;226m[+] Puzzle search\n[+] Script started at:{}",
current_time.format("%Y-%m-%d %H:%M:%S")
);
let matches = App::new("Puzzle Solver")
.version("1.0")
.arg(
Arg::with_name("puzzle")
.short('p')
.long("puzzle")
.value_name("PUZZLE")
.help("Sets the puzzle number")
.takes_value(true), // No longer required
)
.arg(
Arg::with_name("address")
.short('a')
.long("address")
.value_name("ADDRESS")
.help("Sets the target address")
.required(true)
.takes_value(true),
)
.arg(
Arg::with_name("range")
.short('r')
.long("range")
.value_name("RANGE")
.help("Sets the search range in decimal format (e.g. 73786976294838206464:147573952589676412927)")
.takes_value(true),
)
.get_matches();
let puzzle_str = matches.value_of("puzzle");
let range_str = matches.value_of("range");
// Ensure either -p or -r is provided
if puzzle_str.is_none() && range_str.is_none() {
panic!("Either --puzzle (-p) or --range (-r) must be provided.");
}
let target_address = Arc::new(matches
.value_of("address")
.expect("Target address is required")
.to_string());
// Parse the range if -r is provided; otherwise calculate it based on the puzzle number
let (range_start, range_end): (BigInt, BigInt) = if let Some(range_str) = range_str {
let parts: Vec<&str> = range_str.split(':').collect();
if parts.len() != 2 {
panic!("Invalid range format. Expected format: start:end");
}
let range_start = BigInt::parse_bytes(parts[0].as_bytes(), 10)
.expect("Failed to parse range start");
let range_end = BigInt::parse_bytes(parts[1].as_bytes(), 10)
.expect("Failed to parse range end");
(range_start, range_end)
} else {
// If no range is provided, compute the range from the puzzle number
let puzzle: u128 = puzzle_str.unwrap().parse().expect("Failed to parse puzzle number");
let range_start: BigInt = num::pow(BigInt::from(2), (puzzle - 1) as usize);
let range_end: BigInt = num::pow(BigInt::from(2), puzzle as usize) - BigInt::one();
(range_start, range_end)
};
let num_threads = num_cpus::get() as usize; // Convert to usize
println!(
"[+] concurrency:{}\n[+] range:{} to:{}\n[+] target:{}",
num_threads, range_start, range_end, target_address
);
let found_flag = Arc::new(AtomicBool::new(false));
let pool = ThreadPool::new(num_threads.try_into().unwrap()); // Convert to usize
// Handling termination signals
let found_flag_clone = found_flag.clone();
ctrlc::set_handler(move || {
found_flag_clone.store(true, Ordering::Relaxed);
std::process::exit(0); // Terminate the program
})
.expect("Error setting Ctrl-C handler");
for _ in 0..num_threads {
let target_address = Arc::clone(&target_address);
let range_start_clone = range_start.clone();
let range_end_clone = range_end.clone();
let found_flag = found_flag.clone();
let pool_clone = pool.clone();
pool.execute(move || {
let mut rng = SmallRng::from_entropy();
random_lookfor(&rng.gen_range(range_start_clone.clone()..range_end_clone.clone()), &range_end_clone, &target_address, &found_flag, &pool_clone);
});
}
pool.join();
}
fn random_lookfor(
range_start: &BigInt,
range_end: &BigInt,
target_address: &Arc
,
found_flag: &Arc,
_pool: &ThreadPool,
) {
let mut rng = SmallRng::from_entropy();
let secp = bitcoin::secp256k1::Secp256k1::new();
loop {
let key: BigInt = rng.gen_range(range_start.clone()..range_end.clone());
let private_key_hex = format!("{:0>64x}", key);
let private_key_bytes =
hex::decode(&private_key_hex).expect("Failed to decode private key hex");
let private_key = PrivateKey {
compressed: true,
network: NetworkKind::Main,
inner: bitcoin::secp256k1::SecretKey::from_slice(&private_key_bytes)
.expect("Failed to create secret key from slice"),
};
let public_key = private_key.public_key(&secp);
let address = Address::p2pkh(&public_key, NetworkKind::Main).to_string();
// Check if a match has been found by another thread
if found_flag.load(Ordering::Relaxed) {
break;
}
if address == **target_address {
let current_time = Local::now();
let line_of_dashes = "-".repeat(80);
println!(
"\n[+] {}\n[+] KEY FOUND! {}\n[+] decimal: {} \n[+] private key: {} \n[+] public key: {} \n[+] address: {}\n[+] {}",
line_of_dashes,
current_time.format("%Y-%m-%d %H:%M:%S"),
key,
private_key,
public_key,
address,
line_of_dashes
);
// Set the flag to true to signal other threads to exit
found_flag.store(true, Ordering::Relaxed);
if let Ok(mut file) = File::create("KEYFOUNDKEYFOUND.txt") {
let line_of_dashes = "-".repeat(130);
writeln!(
&mut file,
"\n{}\nKEY FOUND! {}\ndecimal: {} \nprivate key: {} \npublic key: {} \naddress: {}\n{}",
line_of_dashes,
current_time.format("%Y-%m-%d %H:%M:%S"),
key,
private_key,
public_key,
address,
line_of_dashes
)
.expect("Failed to write to file");
} else {
eprintln!("Error: Failed to create or write to KEYFOUNDKEYFOUND.txt");
}
io::stdout().flush().unwrap();
break;
}
}
}
# ./puzzle -r 46346217550300000000:46346217550360000000 -a 13zb1hQbWVsc2S7ZTZnP2G4undNNpdh5so
And this is an example of how narrow the range must be to hit WIF.