
В прошлой статье («Тестируем программы для вскрытия биткойн-головоломок») я сравнивал программы, которые ищут ключ по адресу — перебором. Но у части головоломок (номера, кратные пяти: 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. Образно его можно представить как поиск точки на огромном круге, который символизирует диапазон поиска:
Определённый сектор этого круга («ловушка») предварительно рассчитывается малыми шагами и сохраняется в памяти.
Тестируемая точка начинает двигаться вперед большими фиксированными прыжками.
Как только прыжок попадает в заранее сохраненный сектор-ловушку (в котором все точки известны), задача считается решенной.

Ограничение по памяти:
Для решения задачи дискретного логарифмирования на эллиптической кривой в рамках больших биткойн-головоломок ловушка должна быть колоссального размера — на практике под неё требуется объём памяти порядка . Для реальных диапазонов такого объема оперативной памяти просто не существует.
Существуют оптимизации (например, использование фильтров Блума для компактного удержания точек-кандидатов в RAM с последующей проверкой на HDD). Однако даже подобные методы не спасают: сохранить, к примеру, точек-ловушек для головоломки №140 технически невозможно. Чем больше диапазон, тем меньшую долю сектора мы способны удержать в памяти, из-за чего количество необходимых шагов лавинообразно растёт, а BSGS начинает проигрывать алгоритму Полларда в сотни тысяч и миллионы раз.
Алгоритм Кенгуру Полларда
Об алгоритме Полларда я уже кратко рассказывал в одной из прошлых публикаций — «Головоломка на 1000 BTC».
Он устроен иначе. По легенде, Джон Поллард вдохновился австралийским методом отлова кенгуру: к диким особям выпускают прирученного «домашнего» кенгуру, который возвращается на ферму, приводя с собой диких.

В алгоритме используются две группы траекторий:
«Домашние» кенгуру начинают путь от известных координат.
«Дикие» кенгуру стартуют от неизвестного ключа.
Обе группы совершают детерминированные прыжки: длина и направление каждого следующего шага жёстко привязаны к текущей точке. Как только пути дикого и домашнего кенгуру пересекаются, благодаря единому правилу перехода они начинают двигаться по абсолютно одинаковому маршруту.
Выделенные точки или Distinguished Points:
Чтобы не хранить каждый шаг, алгоритм фиксирует только так называемые «особые точки» — например, координаты, у которых заданное количество начальных или конечных бит равно нулю (примерно каждый миллиардный шаг). Это снимает жесткую зависимость от гигантских объемов RAM, присущую BSGS.
Нюансы метрик: почему нельзя напрямую сравнивать скорости
При запуске программ на базе BSGS утилиты могут демонстрировать колоссальные показатели скорости — терахеши или даже петахеши в секунду, что на порядки превосходит цифры реализаций Кенгуру.
Однако сравнивать эти значения «в лоб» некорректно:
Скорости отражают совершенно разные математические операции.
Алгоритм Кенгуру обладает квадратичной эффективностью: просмотр
состояний статистически эквивалентен проверке диапазона порядка
.
Поэтому, несмотря на визуально скромные цифры хешрейта, алгоритм Полларда на реальных дистанциях оказывается несравнимо эффективнее 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 |
Kangaroo |
CUDA |
4b6aa34 |
|
Kangaroo |
CPU и CUDA |
37576c8 |
|
keyhunt (режим bsgs) |
BSGS |
CPU |
2134a20 |
BSGS |
CPU |
5bf3bb3 |
|
btcmole |
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 |
|
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 эффективно |
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 не умеет — по публичному ключу только перебор ( |
— |
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 ООО «МТ ФИНАНС»