Тестирование программ для решения биткойн-головоломок с известным публичным ключом
Тестирование программ для решения биткойн-головоломок с известным публичным ключом

В прошлой статье («Тестируем программы для вскрытия биткойн-головоломок») я сравнивал программы, которые ищут ключ по адресу — перебором. Но у части головоломок (номера, кратные пяти: 135, 140, 145, …) публичный ключ уже раскрыт в блокчейне, и для них работают совсем другие алгоритмы — с квадратично меньшей работой:

  • Кенгуру Полларда (Pollard’s kangaroo): два «стада» кенгуру прыгают по кривой псевдослучайными прыжками; «различимые точки» (DP) складываются в базу, совпадение точек домашнего и дикого кенгуру даёт ключ. Работа ≈ K·√N прыжков, где N — ширина диапазона, K ≈ 1.15 у лучших реализаций.

  • Baby-Step Giant-Step (BSGS): таблица «детских шагов» m точек строится заранее, затем «гигантскими шагами» по m ключей проверяется весь диапазон. Работа ≈ N/m шагов, но таблица требует памяти и большого времени на построение, поэтому мы включаем его в замер.

Алгоритмы решения биткойн-головоломок: Кенгуру Полларда vs Baby-step Giant-step

Принцип работы Baby-step Giant-step (встреча посередине)

Алгоритм BSGS часто называют методом встречи посередине или алгоритмом класса meet-in-the-middle. Образно его можно представить как поиск точки на огромном круге, который символизирует диапазон поиска:

  1. Определённый сектор этого круга («ловушка») предварительно рассчитывается малыми шагами и сохраняется в памяти.

  2. Тестируемая точка начинает двигаться вперед большими фиксированными прыжками.

  3. Как только прыжок попадает в заранее сохраненный сектор-ловушку (в котором все точки известны), задача считается решенной.

Алгоритм Baby Step-Giant Step: прыгаем через равные интервалы от неизвестного ключа, пока не попадём в ловушку — известную область малых шагов
Алгоритм Baby Step-Giant Step: прыгаем через равные интервалы от неизвестного ключа, пока не попадём в ловушку — известную область малых шагов

Ограничение по памяти:

Для решения задачи дискретного логарифмирования на эллиптической кривой в рамках больших биткойн-головоломок ловушка должна быть колоссального размера — на практике под неё требуется объём памяти порядка O(\sqrt{N}). Для реальных диапазонов такого объема оперативной памяти просто не существует.

Существуют оптимизации (например, использование фильтров Блума для компактного удержания точек-кандидатов в RAM с последующей проверкой на HDD). Однако даже подобные методы не спасают: сохранить, к примеру, 2^{70} точек-ловушек для головоломки №140 технически невозможно. Чем больше диапазон, тем меньшую долю сектора мы способны удержать в памяти, из-за чего количество необходимых шагов лавинообразно растёт, а BSGS начинает проигрывать алгоритму Полларда в сотни тысяч и миллионы раз.

Алгоритм Кенгуру Полларда

Об алгоритме Полларда я уже кратко рассказывал в одной из прошлых публикаций — «Головоломка на 1000 BTC».

Он устроен иначе. По легенде, Джон Поллард вдохновился австралийским методом отлова кенгуру: к диким особям выпускают прирученного «домашнего» кенгуру, который возвращается на ферму, приводя с собой диких.

Алгоритм кенгуру Полларда: дикий кенгуру начинает прыгать по следам домашнего
Алгоритм кенгуру Полларда: дикий кенгуру начинает прыгать по следам домашнего

В алгоритме используются две группы траекторий:

  • «Домашние» кенгуру начинают путь от известных координат.

  • «Дикие» кенгуру стартуют от неизвестного ключа.

Обе группы совершают детерминированные прыжки: длина и направление каждого следующего шага жёстко привязаны к текущей точке. Как только пути дикого и домашнего кенгуру пересекаются, благодаря единому правилу перехода они начинают двигаться по абсолютно одинаковому маршруту.

Выделенные точки или Distinguished Points:

Чтобы не хранить каждый шаг, алгоритм фиксирует только так называемые «особые точки» — например, координаты, у которых заданное количество начальных или конечных бит равно нулю (примерно каждый миллиардный шаг). Это снимает жесткую зависимость от гигантских объемов RAM, присущую BSGS.

Нюансы метрик: почему нельзя напрямую сравнивать скорости

При запуске программ на базе BSGS утилиты могут демонстрировать колоссальные показатели скорости — терахеши или даже петахеши в секунду, что на порядки превосходит цифры реализаций Кенгуру.

Однако сравнивать эти значения «в лоб» некорректно:

  • Скорости отражают совершенно разные математические операции.

  • Алгоритм Кенгуру обладает квадратичной эффективностью: просмотр M состояний статистически эквивалентен проверке диапазона порядка M^2.

Поэтому, несмотря на визуально скромные цифры хешрейта, алгоритм Полларда на реальных дистанциях оказывается несравнимо эффективнее BSGS.

Программные решения и GPU-оптимизации

Эталонные по производительности решения для алгоритма Кенгуру принадлежат анонимусу с ником RetiredCoder (подробнее о нём — в статье «Биткойн-головоломка 135 вскрыта! Who is RetiredCoder?», его ветка на BitcoinTalk).

Его турбо-ядра для GPU используют низкоуровневый ассемблер SASS (в обход промежуточного PTX). Это позволило совершить технологический скачок и в разы поднять производительность на видеокартах поколений RTX 4090 и RTX 5090. Сегодня эти наработки лежат в основе практически всех передовых решений.

Прорыв RCKangaroo держится на трёх решениях. Состояние стада кенгуру размещено так, чтобы помещаться в кэш L2 — на картах 4000-й и 5000-й серий он достаточно велик, и прыжки почти не ходят в видеопамять. Самая дорогая операция — инверсия в поле — вынесена на отдельные блоки-инверторы на своих SM: остальные SM только прыгают и отдают им накопленные значения. И, наконец, весь горячий код написан на SASS вручную.

Практический нюанс:

Код RetiredCoder создавался в первую очередь для демонстрации рекордных скоростей. В исходном виде он держит данные непосредственно в памяти видеокарты, поэтому «из коробки» не предназначен для вскрытия сложных головоломок (для этого требуется подключение внешней БД или работа в пуле). Большинство открытых решений представляют собой скорее демонстрацию state-of-the-art скорости, тогда как реальные пулы дорабатывают и модифицируют эти ядра под свои распределённые архитектуры самостоятельно.

Какие программы участвуют

Только Linux. Всё собрано из исходников, кроме btcmole (релизный бинарник) и закрытых библиотек iceland2k14.

Программа

Алгоритм

Железо

Версия (коммит)

RCKangaroo v4.0

Kangaroo

CUDA

618473a + патч загрузки кубина

RCKangaroo v3.1

Kangaroo

CUDA

f302c4c

PSCKangaroo (форк RC)

Kangaroo

CUDA

021e997

theCollider

Kangaroo

CUDA

4b6aa34

JLP Kangaroo

Kangaroo

CPU и CUDA

37576c8

keyhunt (режим bsgs)

BSGS

CPU

2134a20

JLP BSGS

BSGS

CPU

5bf3bb3

btcmole bm kang

Kangaroo

CPU и CUDA

0.8.0 (релизный бинарник)

btcmole — программа с закрытым кодом. Для головоломок с публичным ключом это не помеха: известный публичный ключ можно перед поиском сместить на тайное значение (Q′ = Q + t·G и диапазон, сдвинутый на t), и программа ищет ключ, по которому нельзя понять, какую головоломку она решает. Поэтому btcmole включён в обзор наравне с открытыми программами.

Кого не удалось включить и почему — в конце статьи.

Методика

Та же, что в прошлый раз: замеряется только время от запуска процесса до момента, когда в поток вывода попал искомый приватный ключ. Никаких внутренних метрик в зачёт. Для каждого блока генерируется 100 случайных ключей (seed 42), все программы блока решают одни и те же ключи; раунд — один ключ для каждой программы, порядок программ сдвигается на каждом раунде; перед замером — один разогревочный ключ, в зачёт не идёт.

Отличия от прошлого замера:

  • Цель — публичный ключ (раньше был адрес).

  • Диапазоны больше, потому что алгоритмы квадратично быстрее: CPU — 2^60, GPU — 2^66.

  • Таблицы BSGS. Время построения таблицы детских шагов входит в результат. Если программа умеет сохранять таблицу (keyhunt -S), таблица строится один раз, а время её построения прибавляется к каждому запуску — результат тот же, что при построении в каждом запуске, а стенд не тратит часы. Таблица — не больше 32 ГБ RAM и не дольше 10 минут построения; размер подобран пристрелкой под минимум суммы «построение + средний поиск» на 2^60.

  • DP у кенгуру. В GPU-блоке у всех одна битность DP = 14 (минимум, который позволяет RCKangaroo). В CPU-блоке — автовыбор программы или рекомендация автора.

  • Ресурсы. CPU-программам — 112 потоков (ядра 16–127); GPU-программы привязаны к ядрам 0–15. Блоки шли одновременно, не отнимая процессор друг у друга. btcmole на CPU прогнан позже отдельно, на тех же ключах и ядрах.

  • Зависания. Таймаут 180 с на ключ и «проверяльщик запуска»: программа, молчащая 60 с, останавливается.

  • Скорость по данным программы — медиана по запускам последней скорости, которую программа напечатала сама. Это справочная колонка: программы считают «ключи в секунду» по-разному.

Репозиторий

Скрипт pubkey_bench.py в репозитории бенчмарка (рядом с bench.py из прошлой статьи): --prepare клонирует и собирает все программы, --device cpu|cuda прогоняет блок, --from-log собирает отчёт из логов. Патчи сборки — в patches/.

Стенд

  • CPU: AMD EPYC 7C13 (64 ядра / 128 потоков, 2.45 GHz base)

  • GPU: NVIDIA CMP 90HX (Ampere, sm_86, 50 SM)

  • ОС: Linux (Calculate Linux), CUDA 12.9

CPU: 2^60

100 ключей, 112 потоков, ни одного сбоя.

#

Программа

Алгоритм

OK / FAIL

Среднее, с

Медиана, с

× эталон

Скорость по данным программы

1

btcmole kang (CPU)

Kangaroo

100 / 0

5.04

4.66

2.16

283 Mkeys/s

2

JLP Kangaroo (CPU)

Kangaroo

100 / 0

10.89

9.62

1.00

288 Mkeys/s

3

keyhunt

BSGS

100 / 0

24.61

24.36

0.44

103 Pkeys/s

4

JLP BSGS

BSGS

100 / 0

50.51

51.53

0.22

248 MKey/s гигантских шагов

Эталон — JLP Kangaroo. btcmole быстрее его в 88 парах из 100 при одинаковой скорости прыжков (283 и 288 Mkeys/s): выигрыш даёт метод — путь кенгуру RCKangaroo (симметрия, K ≈ 1.15 против ≈ 2 у классической схемы), а не арифметика. Кенгуру на процессоре вдвое-вчетверо быстрее лучшего BSGS, хотя BSGS печатает скорости на восемь порядков выше.

GPU: 2^66

100 ключей, ни одного сбоя. Эталон — RCKangaroo v4.0.

#

Программа

OK / FAIL

Среднее, с

Медиана, с

× эталон

Скорость по данным программы, Mkeys/s

1

btcmole 0.8.8 (режим kang)

100 / 0

7.96

7.72

1.13

2 896

2

RCKangaroo v4.0

100 / 0

9.00

8.80

1.00

1 787

3

RCKangaroo v3.1

100 / 0

11.68

11.15

0.77

1 890

4

PSCKangaroo

100 / 0

16.01

15.45

0.56

1 910

5

theCollider (CUDA)

100 / 0

27.90

27.12

0.32

≈ 2 185 (по итогу работы)

6

JLP Kangaroo (GPU)

100 / 0

31.14

30.52

0.29

1 734

Парное сравнение на тех же ключах: btcmole быстрее RCKangaroo v4.0 в 63 случаях из 100.

Заметно, что «скорость по данным программы» плохо предсказывает время до ключа: theCollider печатает больше, чем RCKangaroo, а решает втрое медленнее; RCKangaroo v3.1 печатает больше, чем v4.0, а решает на 30% дольше. Решают K (сколько прыжков реально нужно), накладные расходы на DP и время запуска.

Современные карты: RTX 4090, 5070 Ti, 5090

На картах 4000-й и 5000-й серий RCKangaroo v4.0 включает турбо-ядра на SASS. По данным автора RCKangaroo, на RTX 5090 скорость около 19 000 Mkeys/s. В btcmole для этих серий тоже есть ядра на SASS.

Карты арендованные, поэтому главное здесь — скорости, которые печатают сами программы: в рамках одного алгоритма их можно сравнивать напрямую. Два чередующихся прогона каждой программы по 40 с на диапазоне 2^100, DP 14 у обеих. Диапазон выбран так, чтобы ключ заведомо не нашёлся за эти 40 с и программа всё время считала с полной скоростью.

Карта

btcmole, Mkeys/s

RCKangaroo v4.0, Mkeys/s

btcmole / RC

RTX 5090 (лимит 600 Вт)

20 168 / 20 155

18 986 / 18 941

1.064

RTX 4090 (лимит 480 Вт)

14 697 / 14 711

14 443 / 14 443

1.018

RTX 5070 Ti (зажата до 250 Вт)

8 621 / 8 630

7 692 / 7 631

1.126

Время до ключа, ключи 2^70, DP 14, ни одного сбоя:

Карта

Ключей

btcmole, среднее / медиана, с

RCKangaroo v4.0, среднее / медиана, с

× RC

Побед btcmole

RTX 5090

100

4.39 / 4.33

4.70 / 4.49

1.07

60 из 100

RTX 5070 Ti

100

6.57 / 6.44

7.00 / 6.95

1.07

56 из 100

Код btcmole закрыт, но, судя по результатам, его автор взял на вооружение часть идей RCKangaroo и дополнил их собственными улучшениями — это и позволило обойти RCKangaroo по скорости. На это указывает и RTX 4090: там программы идут почти вровень (разница меньше 2%), как будто на этой серии btcmole повторяет схему RCKangaroo, а свои улучшения раскрывает только на 5000-й серии.

Карты AMD

Из протестированных программ на AMD запускаются только две: btcmole и oritwoen/kangaroo (Vulkan) — остальные написаны под CUDA. Карта AMD у нас одна — R9 Fury (GCN3, 2015 год); арендовать AMD не удалось: площадки предлагают почти исключительно NVIDIA.

  • btcmole — 760–830 Mkeys/s (оседает по мере нагрева карты), ключ 2^48 — за 5.3 с вместе с запуском.

  • oritwoen/kangaroo — запускается, ~7.5 млн операций/с, но ключ 2^47 за 150 с не нашёл, хотя сделал в ~30 раз больше операций, чем требует алгоритм.

BSGS между собой

Ключи CPU-блока 2^60.

Программа

Железо

Таблица

Время таблицы, с

OK / FAIL

Среднее, с

Медиана, с

Заявленная скорость

keyhunt

CPU

-k 64 (~1 ГБ)

14.2 (один раз)

100 / 0

24.61

24.36

103 PKeys/s

JLP BSGS

CPU

2^27 детских шагов

в каждом запуске

100 / 0

50.51

51.53

248 MKey/s ≈ 33 PKeys/s эффективно

keyhunt-GPU

GPU

2^24 (0.86 ГБ)

117 (один раз) + ≈ 90 загрузка в каждом запуске

—

≈ 95 + 90 (оценка)

—

3 PKeys/s

bsgs_scan

GPU

2^26

в каждом запуске

—

≈ 4 ч (оценка)

—

39 TKeys/s

iceland2k14 bsgs v6

CPU

10⁸ элементов

135.6

—

≈ 4.4 ч (оценка)

—

36.5 TKeys/s

«Петаключи в секунду» у BSGS — это ширина диапазона, вычеркнутая одной проверкой гигантского шага, умноженная на темп шагов. Для сравнения: те же 2^60 кенгуру JLP на том же процессоре решает в среднем за 11 с при «скромных» 288 Mkeys/s.

keyhunt-GPU — форк keyhunt, который выполняет BSGS на видеокарте. На CMP 90HX с таблицей из 2^24 детских шагов (0.86 ГБ) он правильно нашёл контрольный ключ 2^47 и показал 3 PKeys/s — около 180 млн гигантских шагов в секунду. Для ключа 2^60 это в среднем ≈ 95 с поиска, плюс ≈ 90 с на загрузку и проверку таблицы при каждом запуске (построение таблицы — ещё 117 с, один раз). Полного прогона на 100 ключах не было: это оценка по одному длинному прогону. keyhunt на процессоре с теми же ключами быстрее в несколько раз.

Почему эффективный BSGS на GPU сделать трудно.

  • Таблица не помещается туда, где поиск быстрый. Быстрая память видеокарты — shared memory (LDS): обычно это 48–99 КБ на мультипроцессор, то есть несколько тысяч точек. Фактически размер сектора детских шагов, по которому можно искать без задержек, ограничен именно ею. Всё, что больше, уходит в кэш L2 (72–96 МБ даже у RTX 4090/5090) или в видеопамять, где каждое обращение стоит сотни тактов.

  • Обращения случайные. На каждом гигантском шаге каждый поток ищет свою точку по таблице — по хешу, в случайном месте. Соседние потоки варпа идут в разные места памяти, и видеокарта теряет своё главное преимущество — слитные чтения. У keyhunt-GPU фильтр Блума делает семь таких обращений на шаг.

  • Поиск расходится внутри варпа. Проверка — это ветвления: фильтр ответил «нет» — шаг закончен, «возможно» — идём точно сравнивать по корзине, а длина корзины у каждого потока своя. Варп исполняет 32 потока одной командой, поэтому ждёт самый медленный из них: пока один поток перебирает корзину, остальные простаивают.

  • Таблица ограничена видеопамятью. Даже в видеопамяти помещается 10–24 ГБ на игровых картах, тогда как у процессора под таблицу сотни гигабайт RAM. А размер таблицы — это и есть ширина, которую вычёркивает один гигантский шаг: меньше таблица — больше шагов.

  • Таблицу надо построить и загрузить. Это время входит в решение каждого ключа, если таблицу нельзя держать в памяти между запусками; у keyhunt-GPU загрузка с проверкой занимает полторы минуты.

  • И главное — BSGS проигрывает кенгуру по самой работе. BSGS делает N/m шагов, кенгуру — порядка √N прыжков. С ростом диапазона никакая оптимизация таблицы этот разрыв не закроет: для головоломки №140 нужна таблица порядка 2^70 точек.

Кто не вошёл и почему

Программа

Причина

Данные

Mark1 (Dookoo2)

на стенде не нашёл ключ даже на примере из своего README (60 бит)

README: 60 бит — 4.1 с, 126.5 MH/s; 80 бит — 38 мин

RetiredCoder Kang-1 / Kang-2

исследовательские программы к статьям автора (Windows, MFC): каждый поток решает свой ключ, полная инверсия на каждый прыжок — годятся только для исследований

консольный порт для Linux, 48 бит, 112 ключей на 112 потоках: Kang-1 SOTA+ — K = 1.046, ≈ 305 тыс. прыжков/с на поток; Kang-2 — K = 1.196, ≈ 320 тыс. прыжков/с на поток. Автор: SOTA+ K ≈ 1.02 / 0.99 / 1.05 в зависимости от цены второй точки

theCollider и oritwoen/kangaroo, CPU-режим

запасной бэкенд: ~357 тыс. ключей/с, 2^60 за 3 мин не решён

—

oritwoen/kangaroo, Vulkan

~10 млн операций/с на CMP 90HX, 2^66 за 120 с не решён

—

bsgs_scan (GPU)

≈ 39 TKeys/s → в среднем ≈ 4 ч на ключ 2^60

—

iceland2k14 bsgs v6

поиск в одном процессе, 36.5 TKeys/s на таблице 10⁸ → ≈ 4.4 ч на ключ 2^60; таблица под заявленные 1.2 PKeys/s строится больше часа

README: 15 PetaKeys за ~11–12 с

KeyHunt-Cuda (форк keyhunt от Qalander)

BSGS не умеет — по публичному ключу только перебор (-m XPOINT): 3.8 GKeys/s на CMP 90HX → в среднем ≈ 5 лет на ключ 2^60

—

iceland2k14 bsgs v7 GPU

закрытая библиотека под CUDA 11 без кода для sm_86: «named symbol not found»

—

Etayson BSGS-cuda, Etarkangaroo, fraction-bsgs

только Windows

Etarkangaroo: RTX 3070 — 1535 Mkey/s

Выводы

Самая быстрая программа с открытым кодом — RCKangaroo (GPU), с закрытым — btcmole (GPU и CPU).

Среди BSGS-программ лучшая — keyhunt (CPU и GPU): на процессоре он решает ключ 2^60 за 25 с, его форк keyhunt-GPU выполняет BSGS на видеокарте, но упирается в объём видеопамяти под таблицу, поэтому медленнее CPU-версии.

В погоне за скоростью RetiredCoder вышел на новый уровень безумства — написал ядра прямо на SASS, машинном языке видеокарт NVIDIA, в обход компилятора. И забрал головоломку №135 («Биткойн-головоломка 135 вскрыта! Who is RetiredCoder?»).

Соревнование скоростей сегодня — способ показать пределы современных технологий и престиж. Хотя кто знает — может, появятся новые головоломки. В одиночку малореально взломать даже головоломку №140, если у тебя нет доступа к сотням карт или ты не в пуле.

© 2026 ООО «МТ ФИНАНС»

Комментарии (0)