
Сегодня покажу, как найти (намайнить) себе красивый адрес Bitcoin кошелька. Красивый адрес, значит, что его первые несколько символов будут заданым нами словом.
Я буду использовать библиотеку bit, если вы с ней еще не знакомы, прочтите эту статью. Здесь нам очень кстати будет высокая скорость этой библиотеки в плане генерации кошельков.
Итак, я хочу, чтобы мой биткоин адрес начинался с какого-то слова, например, с названия моего канала PyWay. Нулевой символ, увы, мы изменить не можем, так как он связан с идентификатором сети биткоин (главная, segwit или тестовая). Поэтому оставим его в покое. Часть строки с первого символа должна начинаться с заданного слова:
PATTERN = 'PyWay' # ф-ция проверки def predicate(addr: str): return addr[1:].startswith(PATTERN)
Адреса всегда получаются случайными, поэтому нам нужен метод грубой силы (брутфорс) – многократная генерация адресов, пока не найдем подходящий:
from bit import Key while True: k = Key() # новый случайны ключ if predicate(k.segwit_address): print(f'{k.segwit_address} with WIF private key {k.to_wif()}') break
Время поиска зависит от длины шаблона экспоненциально!
Короткие последовательности ищутся быстро, а длинные – экстремально долго.
Так 2-3 символьные слова ищутся почти моментально. 4 символа заставляют задуматься, а 5 – ждать минут 10-20. 6 символов – могут уйти часы. И так далее! Это криптография!
Чтобы ускорить поиск, запустим несколько процессов поиска с помощью модуля multiprocessing:
from bit import Key from multiprocessing import Process, Value PATTERN = 'PyWay' # сколько процессов? N_PROCESSES = 10 # предикат проверки адреса на наше желание def predicate(addr: str): return addr[1:].startswith(PATTERN) # рабочая функция def worker(predicate: callable, stop: Value, counter: Value): # пока нам не посигналили о завершении из другого процесса while not stop.value: # новый ключ k = Key() # проверяем if predicate(k.segwit_address): print('done!') print(f'{k.segwit_address} with WIF private key {k.to_wif()}') # сигналим другим и выходим stop.value = True break # каждые 10_000 итераций – точку рисуем counter.value += 1 if counter.value % 10_000 == 0: print('.', end='') if __name__ == '__main__': # эти переменные необычные - они позволяют обмениваться инфой между процессами stop = Value('b', False) counter = Value('i', 0) procs = [] for worker_id in range(N_PROCESSES): # создадим процесс, передав рабочего и аргументы proc = Process(target=worker, args=(predicate, stop, counter)) proc.start() procs.append(proc) # будем ждать пока все процессы не завершаться for proc in procs: proc.join() # ждет процесс
FAQ
Почему у меня долго не находит даже простое слово?
Возможно, проблема в вашем слове. В нем есть символы, которых не может быть в адресе: o, O, 0, l, I
. Они похожи по написанию, и были исключены, чтобы избежать лишних ошибок при передаче адресов. Естественно, в адресе не может быть русских букв и знаков пунктуации. Только английские буквы (кроме тех, что привел выше) и цифры кроме 0
!
Почему бы не искать последовательно?
Если начать проверять все адреса подряд, это будет немного быстрее. Главное не начинать с 0 и с круглых чисел, иначе ключ будет легко подобрать! Пример последовательного поиска со случайной начальной точки seed
:
seed = random.randint(0, 1_000_000_000_000) while not stop.value: k = Key.from_int(seed) seed += 1
Почему процессы, а не потоки?
Из-за GIL. Потоки будут тормозить друг друга, а процессы работают независимо.
Если хочу слово в конце адреса или в середине?
Поменяйте условие:
return addr.endswith(PATTERN) # в конце return PATTERN in addr # можно в середине PATTERN = PATTERN.lower() return PATTERN in addr.lower() # в любом месте без учета регистра - самый быстрый поиск
Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈