Here is some given code below. I am currently at a dead end. I am trying to figure out how I can port this program over to something related to Cuda (primarily), maybe OpenCL. Or anything that can speed up this code by ALOT.
Basically the entire while loop in this code, needs to be placed on every GPU core instead of every CPU core.
I have done a little bit of research, but I can't really find much options for Rust.
[dependencies]
num_cpus = "1.16.0"
secp256k1 = { version = "0.29.0", features = ["rand-std", "global-context"] }
tiny-keccak = { version = "2", features = ["keccak"] }
[profile.release]
strip = true
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
-----VANITY.RS-----
use secp256k1::generate_keypair;
use secp256k1::rand::thread_rng;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use tiny_keccak::{Hasher, Keccak};
use crate::VanityKeypair;
#[derive(Clone)]
struct AddressPart {
part: String,
part_lower: String,
}
impl From<String> for AddressPart {
fn from(part: String) -> Self {
let part_lower = part.to_lowercase();
Self { part_lower, part }
}
}
impl From<&str> for AddressPart {
fn from(part: &str) -> Self {
let part_lower = part.to_lowercase();
let part = part.to_owned();
Self { part_lower, part }
}
}
struct Rules {
prefix: Option<AddressPart>,
suffix: Option<AddressPart>,
}
struct Configuration {
thread_count: usize,
rules: Rules,
}
const ADDRESS_HEX_LENGTH: usize = 40;
const ADDRESS_BYTES_LENGTH: usize = ADDRESS_HEX_LENGTH / 2;
const KECCAK256_HASH_BYTES_LENGTH: usize = 32;
const KECCAK256_HASH_HEX_LENGTH: usize = KECCAK256_HASH_BYTES_LENGTH * 2;
const PUBLIC_KEY_BYTES_START_INDEX: usize = 1;
const ADDRESS_BYTES_START_INDEX: usize = KECCAK256_HASH_BYTES_LENGTH - ADDRESS_BYTES_LENGTH;
const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";
fn to_hex<'a>(bytes: &[u8], buf: &'a mut [u8]) -> &'a [u8] {
for i in 0..bytes.len() {
buf[i * 2] = HEX_CHARS_LOWER[(bytes[i] >> 4) as usize];
buf[i * 2 + 1] = HEX_CHARS_LOWER[(bytes[i] & 0xf) as usize];
}
&buf[0..bytes.len() * 2]
}
fn to_checksum_address<'a>(addr: &[u8], checksum_addr_hex_buf: &'a mut [u8]) -> &'a [u8] {
let mut hash = [0u8; KECCAK256_HASH_BYTES_LENGTH];
let mut hasher = Keccak::v256();
hasher.update(&addr);
hasher.finalize(&mut hash);
let mut buf = [0u8; KECCAK256_HASH_HEX_LENGTH];
let addr_hash = to_hex(&hash, &mut buf);
for i in 0..addr.len() {
let byte = addr[i];
checksum_addr_hex_buf[i] = if addr_hash[i] >= 56 {
byte.to_ascii_uppercase()
} else {
byte
}
}
&checksum_addr_hex_buf[0..addr.len()]
}
fn is_addr_matching(prefix: &[u8], suffix: &[u8], addr: &[u8]) -> bool {
addr.starts_with(prefix) && addr.ends_with(suffix)
}
pub fn vanity_eth_address(starts_with: String, ends_with: String) -> VanityKeypair {
let secret_key = Arc::new(Mutex::new(String::new()));
let public_key = Arc::new(Mutex::new(String::new()));
let num_cpus = num_cpus::get();
let cfg: Configuration = Configuration {
thread_count: num_cpus,
rules: Rules { prefix: Some(AddressPart::from(starts_with)), suffix: Some(AddressPart::from(ends_with)) },
};
let rules = cfg.rules;
let prefix = rules.prefix.clone().unwrap().part;
let suffix = rules.suffix.clone().unwrap().part;
let prefix = prefix.into_bytes();
let suffix = suffix.into_bytes();
let prefix_lower = rules.prefix.clone().unwrap().part_lower;
let suffix_lower = rules.suffix.clone().unwrap().part_lower;
let prefix_lower = prefix_lower.into_bytes();
let suffix_lower = suffix_lower.into_bytes();
let found = Arc::new(AtomicBool::new(false));
let mut threads = Vec::with_capacity(cfg.thread_count);
for _ in 0..cfg.thread_count {
let secret_key = Arc::clone(&secret_key);
let public_key = Arc::clone(&public_key);
let found = found.clone();
let prefix = prefix.clone();
let suffix = suffix.clone();
let prefix_lower = prefix_lower.clone();
let suffix_lower = suffix_lower.clone();
threads.push(thread::spawn(move || {
let mut hash = [0u8; KECCAK256_HASH_BYTES_LENGTH];
let mut addr_hex_buf = [0u8; ADDRESS_HEX_LENGTH];
let mut checksum_addr_hex_buf = [0u8; ADDRESS_HEX_LENGTH];
const ITERATIONS_UNTIL_CHECK: usize = 100_000;
while !found.load(Ordering::Acquire) {
for _ in 0..ITERATIONS_UNTIL_CHECK {
let (sk, pk) = generate_keypair(&mut thread_rng());
let pk_bytes = &pk.serialize_uncompressed()[PUBLIC_KEY_BYTES_START_INDEX..];
let mut hasher = Keccak::v256();
hasher.update(&pk_bytes);
hasher.finalize(&mut hash);
let addr_bytes = &hash[ADDRESS_BYTES_START_INDEX..];
let addr = to_hex(addr_bytes, &mut addr_hex_buf);
if is_addr_matching(&prefix_lower, &suffix_lower, addr)
{
let checksum_addr = to_checksum_address(&addr, &mut checksum_addr_hex_buf);
if !is_addr_matching(&prefix, &suffix, checksum_addr)
{
continue;
}
found.store(true, Ordering::Release);
let mut public = public_key.lock().unwrap();
*public = String::from_utf8(checksum_addr.to_vec()).unwrap();
let mut secret = secret_key.lock().unwrap();
*secret= sk.display_secret().to_string();
}
}
}
}));
}
for thread in threads {
thread.join().unwrap();
}
let pk = public_key.lock().unwrap().clone();
let sk = secret_key.lock().unwrap().clone();
let keypair = VanityKeypair {
pk: format!("0x{pk}"),
sk,
};
keypair
}