NEEDLESPACE
가이드

keyhunt 실전 가이드

설치부터, 모드 선택에서 사람들이 왜 몇 주씩 낭비하는지, 그리고 정말로 찾았을 때 상금을 뺏기지 않는 법까지. 영어권 포럼에 흩어져 있는 내용을 한국어로 모았습니다.

1. 설치

keyhunt는 리눅스 환경을 전제로 만들어졌습니다. 윈도우라면 WSL을 쓰세요 — 네이티브 빌드는 삽질이 깁니다. macOS는 되긴 하지만 GPU 가속이 없어서 실전용은 아니고 연습용입니다.

Debian / Ubuntu / WSL
sudo apt update
sudo apt install -y git build-essential libssl-dev libgmp-dev

git clone https://github.com/albertobsd/keyhunt
cd keyhunt
make

# 빌드 확인
./keyhunt --help | head

libssl-devlibgmp-dev는 legacy 버전 빌드에만 필요하지만, 미리 깔아두면 나중에 안 막힙니다.

2. 이 도구를 믿어도 되나

설치하고 나면 당연히 이 생각이 듭니다. “이게 키를 찾는 프로그램인데, 내가 진짜 찾으면 얘가 몰래 어디로 보내버리는 거 아냐?” 정당한 의심입니다. 개인키를 계산하는 프로그램은 구조적으로 그걸 빼돌릴 수 있는 위치에 있으니까요. “오픈소스니까 괜찮다”는 대답은 답이 아닙니다 — 아무도 안 읽으면 오픈소스도 그냥 코드일 뿐입니다.

그래서 직접 확인했습니다. keyhunt는 albertobsd가 만든 C/C++ 도구이고,keyhunt.cpp 한 파일이 실행 바이너리의 본체입니다. 그 파일을 열어보면:

  • 네트워크 헤더가 하나도 없습니다. sys/socket.h, netinet/in.h, curl/curl.h — 전부 없습니다. include 목록은 stdio·stdlib·pthread와 자체 암호 라이브러리뿐입니다.
  • socket·connect·recv 호출이 없습니다. 주소·URL 비슷한 것까지 훑어도 걸리는 건 471행의 주석 한 줄뿐인데, 열어보면 난수 생성에 대한 설명 링크입니다.
  • 찾은 키는 KEYFOUNDKEYFOUND.txt에 append 로 씁니다. 로컬 파일입니다.

내 말을 믿지 말고 직접 돌려보세요. 저장소 루트에서:

네트워크 코드가 있는지 직접 확인 — 저장소 루트에서
# ① 실행 바이너리 본체에 네트워크 헤더가 있는가
#    기대 출력: 없음
grep -nE '#include <(sys/socket|netinet/in|arpa/inet|curl/curl)' keyhunt.cpp

# ② 소켓 관련 호출이나 URL 이 있는가
#    기대 출력: 471행 주석 한 줄 (난수 설명 링크)
grep -nE '\b(socket|connect|recv|getaddrinfo|curl)\b|https?://' keyhunt.cpp

# ③ 저장소 전체에서 네트워크 헤더를 include 하는 파일
#    기대 출력: bsgsd.cpp 와 base58/base58.c 두 개
grep -rln 'sys/socket\.h\|netinet/in\.h\|arpa/inet\.h\|curl/curl\.h' .

# ④ 그중 base58.c 가 실제로 네트워크 함수를 쓰는가
#    기대 출력: 없음
grep -nE 'htonl|ntohl|socket' base58/base58.c

③번이 두 개를 뱉습니다. 이게 이 검사에서 제일 중요한 부분이라 숨기지 않고 그대로 적겠습니다:

  • bsgsd.cpp진짜 소켓이 들어 있습니다. 다만 이건 BSGS를 네트워크로 제공하는 서버 데몬이고, 애초에 그러라고 만든 별개의 프로그램입니다(저장소의 BSGSD.md에 문서화돼 있습니다). 중요한 건 기본 make는 이걸 빌드하지 않는다는 점입니다.make bsgsd를 따로 쳐야 만들어집니다. 안 만들면 없는 프로그램입니다.
  • base58/base58.carpa/inet.h를 include 하지만 거기서 함수를 하나도 안 씁니다. Luke Dashjr의 libbase58(MIT) 원본에 바이트 순서 매크로 때문에 남아 있는 레거시입니다. grep -nE 'htonl|ntohl|socket' base58/base58.c 를 돌려보면 빈 결과가 나옵니다.
그래도 완벽한 보증은 아닙니다 — 이렇게 하세요
  1. 남이 컴파일한 바이너리를 절대 실행하지 마세요. 위 검사는 소스에 대한 것이지 누가 텔레그램에 올린 exe 에 대한 게 아닙니다. 실제 사고는 거의 전부 여기서 납니다. 소스에서 직접 make 하세요.
  2. 아웃바운드를 막고 돌리세요. 코드를 다 읽을 자신이 없다면 이게 가장 확실합니다. 방화벽으로 그 프로세스의 네트워크를 끊어버리면 악의가 있어도 나갈 길이 없습니다.
  3. 실제로 감시해보세요. 돌아가는 동안 lsof -i -a -p $(pgrep keyhunt) 를 쳐보면 열린 소켓이 없어야 합니다. 더 확실하게는 sudo tcpdump -i any host not 127.0.0.1.
  4. 지갑을 만지는 컴퓨터에서 돌리지 마세요. 탐색용 기계를 분리하는 게 모든 코드 감사보다 강력합니다.

덧붙이면, 이 걱정은 방향이 살짝 어긋나 있기도 합니다. keyhunt가 당신 키를 훔치려면 일단 당신이 뭔가를 찾아야 합니다. 그런데 확률을 계산해보면 그 일은 일어나지 않습니다. 진짜 위험은 도구가 아니라 인출하는 순간에 있고, 그건 아래에서 따로 다룹니다.

3. 모드 고르기 — 여기서 대부분 틀립니다

keyhunt에는 모드가 여러 개 있고, 타깃의 종류가 모드를 결정합니다. 반대로 넣으면 프로그램은 아무 불평 없이 잘 돌아가면서 영원히 아무것도 못 찾습니다. 이게 가장 흔한 시간 낭비입니다.

가진 정보모드난이도
주소만 (1PWo3Je…)-m addressO(2ⁿ)
공개키 (02…/03…)-m bsgsO(2^(n/2))
HASH160 (20바이트 hex)-m rmd160O(2ⁿ)

차이가 얼마나 큰지 감을 잡으려면: 71비트 구간에서 주소 완전탐색은 2⁷⁰번, 공개키를 아는 BSGS는 2³⁵번입니다. 340억 배 차이입니다. 그래서 공개키가 노출된 #140, #145, #150, #155, #160이 번호는 훨씬 큰데도 더 현실적인 타깃입니다.

명령어 생성기가 퍼즐 번호만 보고 이 판정을 자동으로 해줍니다.

4. 첫 실행은 이미 풀린 퍼즐로

미해결 퍼즐부터 돌리면 도구가 제대로 작동하는지조차 알 수 없습니다. 정답을 아는 퍼즐로 먼저 돌려서 몇 초 안에 찾아내는지 확인하세요.

퍼즐 #40 — 정답이 알려진 연습용
echo "1EeAxcprB2PpCnr34VfZdFrkUWuxyiNEFv" > 40.txt
./keyhunt -m address -f 40.txt -b 40 -l compress -t 8 -q -s 5

# 몇 초 안에 KEY FOUND 가 떠야 정상입니다.
# 안 뜨면 모드나 -b 값이 틀린 겁니다.

-b 40이 핵심입니다. 이게 “40비트 구간만 뒤져라”는 뜻이고, 이걸 빼면 2²⁵⁶ 전체를 뒤지기 시작해서 영원히 안 끝납니다.

5. 실제 타깃 돌리기

가장 쉬운 미해결 — #71
echo "1PWo3JeB9jrGwfHDNpdGK54CRas7fsVzXU" > 71.txt
./keyhunt -m address -f 71.txt -b 71 -l compress -t 16 -R -q -s 10
  • -t 16 — 물리 코어 수에 맞추세요. 하이퍼스레딩까지 다 쓰면 오히려 느려지는 경우가 있습니다.
  • -R — 구간 안을 무작위로 점프합니다. 여러 대를 돌릴 때 서로 겹치는 걸 줄여줍니다.
  • -s 10 — 10초마다 속도를 찍어줍니다. 이 숫자를 계산기에 넣어보세요.
  • -k — BSGS 모드에서만 씁니다. 램을 더 써서 빨라지는데, 부족하면 그냥 죽습니다. 4부터 올려보세요.
CPU로는 안 됩니다

솔직히 말해서, 미해결 퍼즐을 CPU로 노리는 건 의미가 없습니다. 16스레드로 #71을 돌리면 수백만 년입니다. 진지하게 하려면 GPU(BitCrack, VanitySearch, Kangaroo)로 가야 하고, 그것도 한 장으로는 부족합니다. keyhunt는 CPU 기반이라 학습·검증용으로 쓰고, 실전은 GPU 도구를 보세요.

6. 찾았다면 — 뺏기지 않고 인출하는 법

이게 이 가이드에서 가장 중요한 부분입니다. 정답을 찾는 것보다 지키는 게 어렵습니다.

퍼즐 주소에서 돈을 옮기려면 트랜잭션에 서명해야 하고, 서명에는 공개키가 함께 들어갑니다. 그 트랜잭션이 공개 멤풀에 뜨는 순간, 감시하던 봇이 공개키를 읽습니다. 그런데 퍼즐 키는 좁은 구간 안에 있다는 걸 모두가 압니다 — 공개키를 알고 구간을 알면 Pollard's Kangaroo로 몇 초 만에 개인키가 복원됩니다.

#66을 예로 들면 구간이 2⁶⁶이니 Kangaroo는 약 2³³번, GPU로 10초 남짓입니다. 봇은 그 키로 같은 자금을 더 높은 수수료로 보내는 트랜잭션을 만들어 당신 것을 밀어냅니다. 2024년 9월 #66과 #69에서 실제로 벌어진 일입니다.

효과가 없는 대응
  • RBF 비활성화 — nSequence를 final로 둬도 소용없습니다. 요즘 노드는 full-RBF가 기본이고, 채굴자는 더 비싼 트랜잭션을 넣을 이유가 충분합니다.
  • 수수료를 아주 높게 — 봇은 상금 전체를 노리니 당신보다 항상 더 낼 수 있습니다.
  • 빨리 보내기 — 봇은 사람보다 빠릅니다.
실제로 통하는 대응
  1. 공개 멤풀을 거치지 않고 채굴자에게 직접 전달합니다. 일부 채굴 풀이 비공개 트랜잭션 제출(out-of-band submission) 창구를 운영합니다. 멤풀에 안 뜨면 봇이 볼 시간 자체가 없습니다.
  2. 서명 전에 미리 준비를 끝내 두세요. 받을 주소, 수수료율, 제출 경로를 다 정해놓고 마지막에 서명 한 번만 합니다. 찾은 뒤에 알아보기 시작하면 늦습니다.
  3. 테스트는 절대 실제 키로 하지 마세요. 잔액 확인한다고 소액을 보내는 순간 공개키가 노출됩니다. 이미 풀린 퍼즐의 키로 리허설하세요.

7. 풀에 들어가기 전에 확인할 것

혼자서는 답이 안 나오니 풀에 들어가는 선택지가 있습니다. 대표적으로 btcpuzzle.info가 “솔로 풀”을 운영합니다 — 범위를 나눠 받고, 찾은 사람이 상금을 전부 가져가는 구조입니다. 클라이언트는 GitHub에 공개돼 있고 VanitySearch를 포크해 풀 통신 모듈을 붙인 CUDA 프로그램입니다.

소스를 직접 읽어보고 확인한 점들입니다:

  • 기본 설정에서는 키가 서버로 안 갑니다. save_key=false, telegram_share=false, api_share=false가 기본값이고, 이 상태에서 키를 찾으면 로컬 콘솔에만 출력됩니다.
  • 서버에 저장하는 경로는 제대로 잠가놨습니다. save_key·untrusted_computer가 둘 다 켜지고 암호화가 성공해야만 전송되며, 암호화는 사용자 본인의 RSA 공개키로 합니다. 운영자도 못 읽습니다.
  • 텔레그램·웹훅은 평문입니다. telegram_share=true로 켜고 untrusted_computer를 끈 채로 두면, 찾은 개인키가 평문으로 텔레그램 서버를 거쳐 갑니다. 알림은 받고 싶고 키는 숨기고 싶다면 둘 다 켜세요.
  • 암호화 실패 시 평문으로 폴백합니다. RSA 키 로딩이 잘못되면 에러를 로그에 남기고 그대로 평문 전송합니다. 설정 후 반드시 테스트 출력으로 암호화가 실제로 걸리는지 확인하세요.
  • 운영자는 어느 범위가 소진됐는지 전부 압니다. 이건 구조상 어쩔 수 없지만, 값진 정보라는 건 알고 들어가세요.

풀 자체는 합리적으로 설계돼 있습니다. 다만 기본값을 바꿀 때 무엇이 노출되는지는 본인이 알아야 합니다.

8. 하지 말아야 할 것

  • 퍼즐이 아닌 주소를 타깃으로 넣기. 그건 탐색이 아니라 절도 시도입니다. 그리고 어차피 성공하지 못합니다 — 규모 페이지의 숫자를 보세요.
  • “키 데이터베이스”나 복구 서비스에 돈 내기. 전부 사기입니다. 예외 없습니다.
  • 씨드 문구를 아무 사이트에나 입력하기. 잔액 조회를 해준다는 곳은 조회가 아니라 회수를 합니다.
  • 기댓값 무시하고 전기 태우기. 계산기에 전기요금을 대입해보세요. 대부분의 설정에서 상금보다 전기값이 큽니다.
  • 남의 빌드된 바이너리 실행하기. 지갑을 만지는 컴퓨터에서는 특히. 소스에서 직접 빌드하세요.