Untitled
unknown
plain_text
9 days ago
10 kB
7
Indexable
import sys import argparse import itertools import multiprocessing from tqdm import tqdm # Keep the core Solana derivation and file reading functions from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins from solders.keypair import Keypair # --- Core Derivation and File Functions (Unchanged) --- def get_solana_address(mnemonic: str, passphrase: str = "") -> str: try: seed_bytes = Bip39SeedGenerator(mnemonic).Generate(passphrase) bip44_mst_ctx = Bip44.FromSeed(seed_bytes, Bip44Coins.SOLANA) bip44_acc_ctx = bip44_mst_ctx.Purpose().Coin().Account(0) private_key_bytes = bip44_acc_ctx.PrivateKey().Raw().ToBytes() keypair = Keypair.from_seed(private_key_bytes) return str(keypair.pubkey()) except ValueError: return "invalid mnemonic" def read_lines_to_list(filename: str) -> list[str]: try: with open(filename, 'r', encoding='utf-8') as f: return [line.strip() for line in f] except FileNotFoundError: print(f"ā Error: The file '{filename}' was not found.") sys.exit(1) def read_lines_to_set(filename: str) -> set[str]: try: with open(filename, 'r', encoding='utf-8') as f: return {line.strip() for line in f if line.strip()} except FileNotFoundError: print(f"ā Error: The file '{filename}' was not found.") sys.exit(1) def get_first_line(filename: str) -> str | None: try: with open(filename, 'r', encoding='utf-8') as f: for line in f: if line.strip(): return line.strip() return None except FileNotFoundError: print(f"ā Error: The file '{filename}' was not found.") sys.exit(1) # --- Typo Generation Logic (Unchanged) --- class TypoGenerator: def __init__(self, args): self.max_typos = args.typos self.typo_types = [] if args.typos_capslock: self.typo_types.append('capslock') if args.typos_swap: self.typo_types.append('swap') if args.typos_repeat: self.typo_types.append('repeat') if args.typos_delete: self.typo_types.append('delete') if args.typos_case: self.typo_types.append('case') if args.typos_map: self.typo_types.append('map') self.typos_map = self._parse_typos_map(args.typos_map) if args.typos_map else {} def _parse_typos_map(self, filename): typos_map = {} try: with open(filename, 'r', encoding='utf-8') as f: for line in f: parts = line.strip().split() if len(parts) >= 2: chars_to_replace = parts[0] replacements = parts[1] for char in chars_to_replace: typos_map[char] = replacements except FileNotFoundError: print(f"ā Error: Typos map file '{filename}' not found.") sys.exit(1) return typos_map def _apply_typo(self, password, typo_type, index): if typo_type == 'capslock': return password.swapcase() if typo_type == 'swap': return password[:index] + password[index+1] + password[index] + password[index+2:] if typo_type == 'repeat': return password[:index] + password[index] + password[index:] if typo_type == 'delete': return password[:index] + password[index+1:] if typo_type == 'case': char = password[index] if char.islower(): return password[:index] + char.upper() + password[index+1:] if char.isupper(): return password[:index] + char.lower() + password[index+1:] if typo_type == 'map': char = password[index] if char in self.typos_map: for replacement in self.typos_map[char]: yield password[:index] + replacement + password[index+1:] return yield password def generate(self, base_password): yield base_password if self.max_typos == 0 or not self.typo_types or not base_password: return possible_typos = [] if 'capslock' in self.typo_types: possible_typos.append(('capslock', 0)) char_op_types = [t for t in self.typo_types if t in ('delete', 'case', 'map', 'repeat')] for typo_type in char_op_types: for index in range(len(base_password)): possible_typos.append((typo_type, index)) if 'swap' in self.typo_types and len(base_password) > 1: for index in range(len(base_password) - 1): possible_typos.append(('swap', index)) generated = {base_password} for k in range(1, self.max_typos + 1): for combo in itertools.combinations(possible_typos, k): indices = [c[1] for c in combo if c[0] != 'capslock'] if len(indices) != len(set(indices)): continue temp_passwords = {base_password} for typo_type, index in combo: new_temp_passwords = set() for pwd in temp_passwords: for result in self._apply_typo(pwd, typo_type, index): if result is not None and result not in generated: new_temp_passwords.add(result) generated.add(result) yield result temp_passwords = new_temp_passwords # --- NEW: Initializer and Worker Functions for Multiprocessing --- def init_worker(mnemonic_arg, addresses_arg, typo_gen_arg): """ Initializer for the worker pool. Sets up global variables for each worker process. """ global static_mnemonic, addresses_to_find, typo_gen static_mnemonic = mnemonic_arg addresses_to_find = addresses_arg typo_gen = typo_gen_arg def worker(base_pass): """ This function is executed by each worker process. It checks one base passphrase and all its typo variations. """ # These globals are set by the init_worker function for final_pass in typo_gen.generate(base_pass): derived_address = get_solana_address(static_mnemonic, final_pass) if derived_address in addresses_to_find: return (base_pass, final_pass, derived_address) return None # --- Main Execution Block (Refactored for Multiprocessing) --- if __name__ == '__main__': parser = argparse.ArgumentParser( description="A tool to find a Solana address by testing passphrases and typo variations against a mnemonic.", formatter_class=argparse.RawTextHelpFormatter ) # Add all arguments as before... parser.add_argument('--seed-file', default='seed_phrases.txt', help='File with the mnemonic phrase.') parser.add_argument('--pass-file', default='passphrases.txt', help='File with the list of base passphrases.') parser.add_argument('--address-file', default='addresses_to_find.txt', help='File with target Solana addresses.') parser.add_argument('--typos', type=int, default=0, help='Maximum number of typos to generate per passphrase.') parser.add_argument('--typos-capslock', action='store_true', help='Enable capslock typo (whole word).') parser.add_argument('--typos-swap', action='store_true', help='Enable adjacent character swap typo.') parser.add_argument('--typos-repeat', action='store_true', help='Enable character repeat typo.') parser.add_argument('--typos-delete', action='store_true', help='Enable character delete typo.') parser.add_argument('--typos-case', action='store_true', help='Enable single character case change typo.') parser.add_argument('--typos-map', help='Path to a typos map file (e.g., "sS $5").') parser.add_argument('--workers', type=int, default=multiprocessing.cpu_count(), help='Number of CPU cores to use.') args = parser.parse_args() print("š Solana Address Finder with Typo Generation (Multithreaded)") print("-" * 60) # Load data that all processes will need main_static_mnemonic = get_first_line(args.seed_file) if not main_static_mnemonic: sys.exit(f"ā Error: No mnemonic found in '{args.seed_file}'.") if get_solana_address(main_static_mnemonic) == "invalid mnemonic": sys.exit("ā Error: The mnemonic phrase is not valid.") main_base_passphrases = read_lines_to_list(args.pass_file) main_addresses_to_find = read_lines_to_set(args.address_file) main_typo_gen = TypoGenerator(args) print(f"Mnemonic Loaded: '{' '.join(main_static_mnemonic.split()[:3])}...'") print(f"Base Passphrases: {len(main_base_passphrases):,}") print(f"Target Addresses: {len(main_addresses_to_find):,}") if args.typos > 0: print(f"Max Typos: {args.typos}") print(f"Using {args.workers} CPU cores for processing...") print("-" * 60) found_match = None # Define the arguments for the initializer init_args = (main_static_mnemonic, main_addresses_to_find, main_typo_gen) # Create a pool of worker processes try: with multiprocessing.Pool(processes=args.workers, initializer=init_worker, initargs=init_args) as pool: results = pool.imap_unordered(worker, main_base_passphrases) with tqdm(total=len(main_base_passphrases), desc="Processing Passphrases") as pbar: for result in results: pbar.update(1) if result: found_match = result pool.terminate() break except KeyboardInterrupt: print("\nš Search interrupted by user.") print("-" * 60) if found_match: base_p, final_p, address = found_match print("\n" + "š" * 20) print("š MATCH FOUND! š".center(40)) print("š" * 20) print(f"š Mnemonic : {' '.join(main_static_mnemonic.split()[:3])}...") print(f"š Passphrase: '{final_p}' (derived from '{base_p}')") print(f"š Address : {address}") print("ā Search complete. A matching passphrase was found!") else: print("ā Search complete. No matching passphrase was found.")
Editor is loading...
Leave a Comment