블록체인2021. 7. 9. 23:24

 가끔씩 비트코인 계좌의 비밀번호(혹은 개인키)를 잃어버렸다는 기사를 볼 수 있다. 그러면 누구나 생각하게 된다. 아무도 못찾게된 저 계좌 내가 찾아볼까?

 

 그래서 시작해보았다. 찾아보자. 사실 이 여정은 이더리움(비트코인과도 매우 유사한 계좌 체계를 갖는다)을 이해하기 위한 여정이기도 한데, 이것저것 얻은 것은 많았다. (비트코인은 이 방법과 동일한데, 같은 글을 읽고 6번을 확인해보자)

 

1. 처음에는 이더리움의 지갑체계를 이해해야 한다.

 

 이더리움같은 암호화폐의 계좌는 일반 우리가 아는 은행의 계좌와는 전혀 다르다. 자세한 설명은 다른 글을 링크하고 ( https://infoengineer.tistory.com/55) 단순하게 이더리움의 지갑주소 생성 과정을 설명해보자.

 

 이더리움의 계좌 주소는 이렇게 생겼다.

 

"0xdcc703c0e500b653ca82273b7bfad8045d85a"

 

 이것은 이더리움 계좌를 정의하기 위한 개인키/공개키 쌍에서, 공개키를 가지고 생성한다. 공개키가 주어지면 아주 빠르게 위 계좌주소를 만들 수 있다. 공개키는 어떻게 만드는가? 개인키가 주어지면 또 빠르게 공개키를 만들 수 있다. 그러나 반대는 어렵다. 그렇게 설계되어 있다. 그러면 처음부터 3가지 단계로 다시 설명해보자.

 

        A. 개인키 선택(1~2^256 숫자 중의 한개를 임의로 고른다. 그 숫자값을 개인키라 한다)

           ex> "3a78e27b1a65f17b538892288f3144f2bb032bd5a7c54e3c578ff407a497a6b0"  (32 bytes, 64글자)

 

        B. 개인키에서 공개키 생성(타원곡선 알고리즘에 의해 생성한다)

           ex> "de2b88c377e01756f51c0701f....(생략)..0ee35e9c2a3582a513178fd300c03d669b2cf877be9e16af"

 

        C. 공개키에서 지갑 주소 생성

           ex> "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"

 

 이더리움 지갑주소는 가상자산 거래소에서도 대신해 만들어 주며, 이를 통해 외부 입금도 받을 수 있는데, 신기하게도 한 개의 개인키가 정해지면 저렇게 지갑주소가 곧바로 확정된다. 그리고 이 개인키만 알면, 계좌를 송금할때 필요한 서명(signing)을 남길 수 있으므로 계좌를 통제하게 된다. 이 상황은, 마치 암호를 바꿀 수 없는 은행 계좌와 같다고 볼 수 있다. 그래서 사실 저 개인키를 잘 보관해야 하며, 유출되면 바로 돈을 인출당하기 전에 다른 계좌로 송금하는 수 밖에 없다.

 

 자, 그러면 이제 개인키가 정해지면 이더리움의 지갑주소가 생긴다는 것을 알았다. 그런데 지갑주소에서 개인키를 얻는 계산은 이해하기가 어렵다(이건 아예 포기했다) 그러면 어떻게 하는가? 오래 걸리는 것은 나중에 생각하더라도, 시도해볼 수 있는 것은, 개인키를 1부터 증가시켜 공개키/지갑주소를 계속 만들면서, 실제 존재하는 이더리움 지갑주소와 비교해보면 되지 않겠는가.

 

      A. 개인키를 1부터 시작해서 증가

      B. 공개키/계좌주소를 생성

      C. 생성된 계좌 주소를 기존의 주소들과 비교. (이상 반복)

 

 일단 개인키를 아래처럼 16진수(hex) 32 bytes 문자열로 넘겨주면 공개키, 지갑주소를 생성하는 python code를 확보해보자. 이후 계속 이 소스를 활용한다. 필요한 모든 것이 이 eachecker.py에 들어가있다.  ( https://github.com/neibc/ethereum/blob/main/eachecker.py ) 대표적으로 get_addr_fromhexstr 함수를 살펴보자.

 

    $ python3 eachecker.py

    ..

    get_addr_fromhexstr("0000000000000000000000000000000000000000000000000000000000000001",1)

    ..

 

    Ethereum account search tool ver 0.1

    Private key: 0000000000000000000000000000000000000000000000000000000000000001
    Public key:  79be667ef9dcbbac55a06295ce870b..(생략)..e1108a8fd17b448a68554199c47d08ffb10d4b8
    Address:    0x7e5f4552091a69125d5dfcb7b8c2659029395bdf

 

이 함수를 쓰면, 개인키 문자열에서 Address(계좌주소)를 알아낼 수 있게 되었다. 자 그럼 여기서 잠깐. 개인키를 1로 삼는 계좌는 과연 실제 존재할까? 우리들의 개발덕들이 해보았을까?

 

그렇다. 존재한다.

 

 그리고 이 계좌는 많은 사람이 개인키가 "1" 이라는 것을 알고 있으니, 돈을 넣어가면, 바로 빼내가는 것 같다. 아래 주소에서 지갑의 거래내역을 확인할 수 있다. 계속 내 계좌로 이체하는 트랜잭션을 날리는 프로그램을 짤 수도 있겠다 싶었다. 여하튼 그렇다.

 

https://etherscan.io/address/0x7e5f4552091a69125d5dfcb7b8c2659029395bdf

 

Address 0x7e5f4552091a69125d5dfcb7b8c2659029395bdf | Etherscan

The Address 0x7e5f4552091a69125d5dfcb7b8c2659029395bdf page allows users to view transactions, balances, token holdings and transfers of both ERC-20 and ERC-721 (NFT) tokens, and analytics.

etherscan.io

 

2. 이제 본격적으로 지갑주소를 생성해서 비교해볼, 실제 이더리움 계좌 목록을 확보해보자.

 

 여러가지 방법이 있지만, 제일 빠른 것은 구글 클라우드의 빅쿼리에서 공개DB로 제공한 이더리움 원장 테이블을 사용하는 방법이다. 고마울 뿐이다. 빅쿼리의 테스트 사용 정도는, 요금도 없다. 구글 계정으로 구글 클라우드의 빅쿼리 콘솔로 이동해 아래와 같이 쿼리를 수행하자. (가입절차는 필요하겠다)

 

https://console.cloud.google.com/bigquery

 

SELECT `address`
FROM `bigquery-public-data.crypto_ethereum.balances`
WHERE `eth_balance` > 1
ORDER BY `eth_balance` DESC
LIMIT 4000000

 

RUN 후에 중간의 SAVE RESULTS로 받을 수 있는데, 용량이 크면 google drive로 경유해 다운받자

대략 3백만개의 계좌를 export할 수 있었다. 이것을 etheracclist.csv 로 받아서 이후 활용한다 (당연히 파일 이름은 아래 프로그램의 소스파일에서 적당히 고쳐써도 좋다)

 

여기서 처럼 3백만 계좌를 python에서 dictionary로 처리하면 6.2gb가 조금 넘는 메모리가 필요하다. 속도를 위해 메모리로 올려서 처리하기 때문이다. 1천만계좌면 21gb정도 필요하다. 메모리가 부족하면 잔고가 적은 뒤쪽의 계좌들은 삭제해버리면 된다. 이더리움 잔고가 많은 계좌순으로 소팅해서 저장했기 때문이다. 기억해두자.

 

3. 그러면 이제 개인키 1~0x100,000 까지 모두 위 이더리움 계좌 목록과 대사해보자

 

다시 조금 전에 받은 eachecker.py를 살펴보자. 그대로 실행한다. 이 프로그램은 내부에 runmode = 1 이 되면 startn 변수에 명기된 숫자부터 endn으로 명기된 숫자까지 1씩 증가시키면서, 위 계좌목록에서 일치한 것을 찾으면 BINGO를 출력하고 로그 파일에도 해당 내역을 기록한다.

 

    $ more eachecker.py

    ...

    runmode = 1

    ...

    print('\nrunmode 1 : full sequence searching from startn to endn...')

    startn = int("1000000000000000000000000000000000000000000000000000000000000001", 16)
    endn = int("2000000000000000000000000000000000000000000000000000000000100000", 16)

    print('\nstart num:')
    print(startn.to_bytes(32, byteorder='big').hex())
    print('end num:')
    print(endn.to_bytes(32, byteorder='big').hex())

   ...

 

    $ head ethacclist.csv
    address
    0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
    0x00000000219ab540356cbb839cbe05303d7705fa
    0xbe0eb53f46cd790cd13851d5eff43d12404d33e8
    0x73bceb1cd57c711feac4224d062b0f6ff338501e
    0x53d284357ec70ce289d6d64134dfac8e511c8a3d
    0x61edcdf5bb737adffe5043706e7c5bb1f1a56eea
    0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5
    0x9bf4001d307dfd62b26a2f1307ee0c0307632d59
    0xdf9eb223bafbe5c5271415c75aecd68c21fe3d7f

 

    $ python3 eachecker.py

    ....

 

 실행해보면, 예상은 했으나, 돈이 있는 계좌는, 위 숫자범위에서는 전혀 매칭이 되지 않는다는 것을 알 수 있다. 개인키가 노출된 일부 계좌는(위에 소개했던 계좌) 이미 모두 돈이 인출되어, 이더리움 잔고가 0이다. 빅쿼리로 추출한 위 대상 계좌들은 1이더리움 이상 잔고를 지니는 것을 조건으로 추출했다는 것을 기억하자.

 

 이제 고백할 때가 되었다. 이 무작위 대입 비교(brute force attack) 작업을 비유하는 가장 인상깊었던 표현은

 

"1부터 2의 256제곱이라는 숫자는 그것을 단순히 세는 것에만 필요한 전력이 우주의 태양과 같은 별이 일평생을 타는 에너지보다 더 많이 필요하다"

 

라는 것이었다.

 

 2의 256제곱(=2^256)은 대략 10^77쯤 된다. 로또 당첨확률이 대략 10^7 번 중 한 번인 것을 염두해보면, 이 개인키를 찾는 일은 로또를 11번 연속 당첨된 것과 같은 확률의 작업에 속한다. 천만분의 1의 확률을 11번 통과하는 셈이다.

 

 시간으로 바꿔보면 이 작업을 하는데 대략 고사양 CPU로 1초에 1만건을 처리한다고 가정하자. 초당 10^4건이다. 그러면 PC 1대로 계산한다고 하면 10^74 초 걸리고, 1년을 1억초(10^8)로 후하게 잡아도 대략 10^66 년이 걸린다. 지구의 CPU core 전체일것 같은 1000억개(10^11)쯤 동원해도 10^55 년이다. 빅뱅이후 대략 120억년(1.2 * 10^10)이 지났다고 하니, 우주가 시작되고 지금까지 계산해도 10^45번중 1개를 처리한 셈이다. 그렇게 우주의 시간 계산을 10^45번 반복해야 한다.

 10^77이라는 숫자를 이렇게 10^45으로 내리는데도(33제곱이 줄었다), 전 우주의 시간과 모든 리소스를 동원해야 하는 수준인 것이다. 아직 줄여할 숫자가 45제곱이 더 남았다. 10배씩 시간을 절감할때마다 1씩 줄일 수 있다.

 (개인키와 계좌주소의 관계가 1:1이 아닌 것으로 조금더 따져볼 수는 있겠으나 상황은 비슷할테고, 어려워서 넘어갔다.)

 

 그렇다. 결론적으로 이래가지고서는 가망이 없다. 그렇지만 이대로 포기할 수는 없다!

 

4. 특별한 형태의 개인키가 있지 않을까?

 

 앞서 개인키 1로 된 계좌에 거래 기록이 있다는 것을 알았다. 그러면 다른 특별한 계좌 형태가 있는 것이 아닐까? 예를들면 개인키 값을 pi를 갖는 계좌는 어떨까?

 

있다!

 

Private key: 3141592653589793238462643383279502884197169399375105820974944592  #소수점 점만 뺀 32자리수. 16진수 문자열이긴 한데 이해해주자.
Public key:  cf9bfbdca0c087fde..(생략)..4096f2e2959f9959c88
Address:    0x7357589f8e367c2c31f51242fb77b350a11830f3

 

https://etherscan.io/address/0x7357589f8e367c2c31f51242fb77b350a11830f3

 

하지만 역시 잔고는 없다. 개인적으로 잠시나마 이 게임(?)에 빠져들어, pi말고 자연 상수 e를 가지고 해봤다. 엇 빙고! 아래 계좌로 생성된다.

 

https://etherscan.io/address/0xf28a2dea4608c46ffee718e5f0df1118b4eab419

 

잔고가 0.002 이더리움(약 $4)이 들어있다! 라고 놀래주고 싶으나, 사실 이건 필자가 오일러를 기념하는 마음으로, 송금해둔 이더리움이다. (이더리움 원장의 자연 상수 e로 된 개인키의 계좌를 발견하고 처음 입금한 것은 필자다. 영원히 이더리움 원장에 새겨둔 셈이다) 내 이더리움 계좌를 신규 생성한 후 개인키를 e 상수로 갖는 계좌와, 개인 휴대전화번호를 갖는 두 계좌에 소액 송금해두었다. 이렇게 영원히 새긴 셈이다. 이더리움이 충분하면 여러가지 개인키를 선점(?)할 수 있다. abcdef0 만 가지고 문장을 만들까도 잠깐 고민했다

 

 여하튼 그렇다. 이런 형태의 특별한 개인키에 숨겨둔 이더리움이 있을지도 모르겠다. 가끔씩 필자같은 마음으로 기부를 하는 사람이 있다. 위 pi 계좌의 거래를 보라.

 

5. 그러면 단순한 조합의 개인키로 누가 생성하지는 않았을까?

 

 

다시 조금 전에 받은 eachecker.py로 돌아가보자. 이 프로그램은 내부에 runmode = 0 이 되면 특정 패턴을 반복하는 형태로 개인키를 만들어서 비교해준다. 소스를 수정해 runmode = 1을 runmode = 0으로 고치자. 이 합성 방식은 이를테면

 

A. 1자리수를 0x1 ~ 0xe 까지 32번 복사하고.. (32bytes로 만들어야 하니)

B. 2자리수를 0x01 ~ 0xfe 까지 16번 복사하고.. (32bytes로 만들어야 하니)

C. 4자리수를 0x0001 ~ 0xfffe 까지 8번 복사하고.. (32bytes로 만들어야 하니)

 

하는 방식이다. 일단 실행을 해보자(아래는 이해를 위해 실제 소스보다 로그를 좀 더 찍은 버전임은 참고하자)

 

$ python3 eachecker.py

 

runmode 0 : repeated pattern searching...
2021-07-09 01:17:34 INFO     range : 1 15
2021-07-09 01:17:34 INFO     1111111111111111111111111111111111111111111111111111111111111111
2021-07-09 01:17:34 INFO     2222222222222222222222222222222222222222222222222222222222222222
2021-07-09 01:17:34 INFO     3333333333333333333333333333333333333333333333333333333333333333
2021-07-09 01:17:34 INFO     4444444444444444444444444444444444444444444444444444444444444444
2021-07-09 01:17:34 INFO     5555555555555555555555555555555555555555555555555555555555555555
2021-07-09 01:17:34 INFO     6666666666666666666666666666666666666666666666666666666666666666
2021-07-09 01:17:34 INFO     7777777777777777777777777777777777777777777777777777777777777777
2021-07-09 01:17:34 INFO     8888888888888888888888888888888888888888888888888888888888888888
2021-07-09 01:17:34 INFO     9999999999999999999999999999999999999999999999999999999999999999
2021-07-09 01:17:34 INFO     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2021-07-09 01:17:34 INFO     bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
2021-07-09 01:17:34 INFO     cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
2021-07-09 01:17:34 INFO     dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
2021-07-09 01:17:34 INFO     eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
2021-07-09 01:17:34 INFO     range : 2 255
2021-07-09 01:17:34 INFO     0101010101010101010101010101010101010101010101010101010101010101
2021-07-09 01:17:34 INFO     0202020202020202020202020202020202020202020202020202020202020202
2021-07-09 01:17:34 INFO     0303030303030303030303030303030303030303030303030303030303030303
2021-07-09 01:17:34 INFO     0404040404040404040404040404040404040404040404040404040404040404
2021-07-09 01:17:34 INFO     0505050505050505050505050505050505050505050505050505050505050505
2021-07-09 01:17:34 INFO     0606060606060606060606060606060606060606060606060606060606060606
2021-07-09 01:17:34 INFO     0707070707070707070707070707070707070707070707070707070707070707
2021-07-09 01:17:34 INFO     0808080808080808080808080808080808080808080808080808080808080808
2021-07-09 01:17:34 INFO     0909090909090909090909090909090909090909090909090909090909090909
2021-07-09 01:17:34 INFO     0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a
2021-07-09 01:17:34 INFO     0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
2021-07-09 01:17:34 INFO     0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
2021-07-09 01:17:34 INFO     0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d
2021-07-09 01:17:34 INFO     0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e
2021-07-09 15:17:34 INFO     0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f
...

 

하면 무언가 random으로 하지 않았을때 생길수 있는 개인키들을 그나마 조사할 수 있다. 사실상 random으로 하면 찾아낼 확률이 없지만, 만약에 해당 개인키를 생성하는 프로그램에서 어찌하다보니 저런 패턴에 의지해서 만들게 되었다면, 훨씬 빠른 속도로 탐지가 될 수 있다. 다만, 필자도 몇시간 구동해 본 바로는 찾아지지 않았다. 병렬로 처리하고 여러대의 서버로 돌리면 상황이 좀 나아질지 모르겠다. (그래서 이더리움 지갑 주소를 생성할때는 아예 시작과 끝 영역을 충분히 제외하고, 반드시 랜덤의 개인키로 만들어야 한다)

 

4. 기타

 

 이 작업을 하면서 수학적으로 이렇게 개인키/공개키/지갑주소의 무작위처럼 보이는 매핑 관계를 정의해놓을 수 있다는 사실에 적잖이 감동 받았다. 암호학 분야를 조금 더 이해한 셈이다. 단지 어떤 논리적인 코드만으로 전 우주보다 큰 매핑 관계를 구성하고 역으로 알아낼 수 없게 되어 있는것 아닌가. 그리고 막연히 생각했던 것보다, 실제 찾아보면 전혀(!) 나오지 않았다. 자신의 실제 돈이 저장되는 계좌는 랜덤의 개인키로 생성하므로, 로또 7번과 우주의 어딘가에 감춰놓은 상황과 같다. 분명히 어딘가에는 존재하지만, 전 우주를 뒤질 수는 없는 노릇이고, 우연히 발견할 확률은 충분히 작다. 알쏭달쏭한 설계지만, 여하튼 찾을 수가 없다.

 

 그러나 여전히 아직 이 탐구 과정에서 재미있는 계좌가 있다. 마지막으로 보고 가야할 계좌가 바로 이 녀석이다.

 

"0xdcc703c0E500B653Ca82273B7BFAd8045D85a470"

 

이 계좌는 개발자의 실수로 공개키에 아무것도 할당하지 않았을때 생성되는 지갑주소이다. 원래는 개인키에서 생성한 공개키로 주소를 만들어야 하는데, 변수를 잘못 넘기는 바람에, 아무값도 없는 변수를 넘기는 경우가 있고, 그때 생기는 지갑주소이다. 그런데 이 지갑주소에 무려 815 이더리움이 송금되어 있다. 거래소에서 송금 주소를 코딩할때 실수해서 넘어갔을 테다. 결국 이 계좌는 확실하게 아무도 개인키를 모르는 계좌이다.

 

https://etherscan.io/address/0xdcc703c0E500B653Ca82273B7BFAd8045D85a470

 

반복되는 개인키 검색으로 만약 이 지갑주소가 나오는 개인키를 찾아낸다면 아무런 양심의 가책없이 내 계좌로 송금하면 된다! 

 

그리고 여기까지 오면서 필자가 깨달은 사실이 있다. 이더리움의 계좌 보안체계는 돈을 우주 어딘가에 숨겨놓는 개념이다. 일반적인 암호로 보관하는 것과는 다르다. 센서로 검출할 수는 없는데, 광활한 우주 어느 좌표(개인키)에 숨겨놓는 것이다. 위치를 모르면 찾는 방법은 그걸 하나하나 방문해보는 수 밖에 없다. 그래서 그 좌표를 들키면 아주 쉽게 꺼내갈 수 있다. 그런데 들키지만 않으면 분명히 존재하는데도, 마치 존재하지 않는 것처럼 숨겨둘 수 있다. 그리고 그 좌표를 나도 잊으면, 실질적으로 영원히 찾을 수 없다. 그 좌표(정보)를 알고 있는 사람이 그 돈의 주인다. 그게 이 지갑 체계의 비밀이다.

 이런 단순하지만 효과적인 방법을 고안하다니. 처음 개발했을 사람에게 놀랄 따름이다.

 

 

5. 정말 개인키를 찾아내면 어떻게 하죠?

 

 사실은 이 과정을 진행하면서, 개인키를 찾는 상상은 했지만, 실제로 찾아낸 후 어떻게 할지는 고민이 되었다. 암호화폐의 계좌 소유주라는 개념은 불친절하게도 시스템 입장에서는 개인키를 소유하고 있느냐로 판단하기 때문에, 실제로 도덕적인 문제가 좀 누그러지기도 했다. 그렇다고 계좌 주인에게 물어볼 방법도 없는게 사실이다.

 

 그러나 여하튼 위에서 소개한 계좌처럼, 아무도 개인키를 모르는 혹은 누구도 괴롭힐 일이 없는 개인키가 잊혀진 계좌라고 가정해보자. 

 

 그러면 해당 알아낸 개인키로 계좌를 개설하여 내 계좌로 송금하면 된다. geth같은 이더리움 클라이언트를 설치해 이 과정을 수행할 수 있다. 이건 역시 조금은 복잡하기 때문에 링크로 안내하자. syncmode를 light로 실행하면 10분안에 필요한 동기화가 완료되고, 잔액 조회 및 송금 명령을 실행할 수 있다.  ( https://infoengineer.tistory.com/52 ) geth를 main net에 붙이기 전에 우선 해당 발견한 개인키로 계좌는 생성해 두어야 한다. 아래 명령으로 개인키 32 bytes 16진수 문자열을 통해 가능하다.

 

Ex>

$ echo "0000000000000000000000000000000000000000000000000000000000000001" > plain_key1.txt
$ geth --datadir . account import plain_key1.txt          #데이터 디렉토리가 현재디렉토리인 경우

 

 결론이 드라마틱하지 못해서 사실은 필자도 서운하다. 자, 태양을 모두 태워서 이더리움 계좌의 개인키를 알아낼 준비가 되었는가? 이 글 가운데 소개한, 필자가 숨겨둔 작은 돈을 찾아볼 수도 있겠다.

 

6. 비트코인은 어떻게 하죠?

 

이더리움과 방법이 거의 같다. 둘은 거의 쌍둥이와 같은 계좌 암호 체계를 지니기 때문이다. 다만 비트코인 계좌 목록은 여기서 다운로드가 가능하다. 대략 천만개 정도 계좌면, 0.001 비트코인 이상 보유한 계좌라고 볼 수 있어서 그정도 하면 충분하다.

 

http://addresses.loyce.club/

 

LOYCE.CLUB | List of all Bitcoin addresses with a balance

 

addresses.loyce.club

이를 테면 balance를 모두 포함한 최신 파일을 받은 후에  아래와 같이 가공할 수 있다. 상위 12백만개의 주소만 고르고, 첫번째 컬럼만 저장한다.

 

$ head -n 12000000 bitcoin_address_list.tsv > bitcoin_address_12k.tsv

$ cut -f1 bitcoin_address_12k.tsv > bit.txt

 

아래와 같은 형식인지 확인한다.

 

$ more bit.txt

address

1MGzSFisX6M1NaiTpi1MXqgzson2iNUcbk

1...

..

 

python code는 아래 소스를 활용한다. eachecker.py와 유사한 구조로 만들어 두었다.

 

https://github.com/neibc/bitcoin/blob/main/btchecker.py

 

그리고 동일한 실험을 한다. 상기 소스내 example() 함수로 여러가지 앞서의 개인키에 의한 지갑주소를 확인할 수 있다. pi 개인키나 1개인키는 여기에도 존재한다.

 

pi 개인키 계좌 : https://www.blockchain.com/btc/address/1MGzSFisX6M1NaiTpi1MXqgzson2iNUcbk

"1" 개인키 계좌 : https://www.blockchain.com/btc/address/1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm

 

나머지들은 같은 방법(runmode를 바꾸면서)으로 구동하여 확인할 수 있다. 정말 개인키를 찾으면 어떻게 해야하나?

bitcoin core오픈소스를 받아 bitcoind 설치/실행 한 후 bitcoin-cli 등을 통해 importprvkey를 실행한 후 유사한 방법으로 송금하면 된다(조금더 공부가 필요하다)

 

아래는 힌트가 될 명령어만 소개해보자. btchecker.py에 나온 prvkey를 활용하자(2개 형태가 있으니 아래 예시 통해 잘 구별해 사용하자)

 

$ bitcoin-cli walletpassphrase "#PASSWORD#" 60

$ bitcoin-cli importprivkey "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf" acc_num1
$ bitcoin-cli importprivkey "5JByjwbxuGsu7GQTpUfR5bSRA4p8WuSaoK3UbsFv13Ns6dLGkeZ" acc_pi
$ bitcoin-cli listlabels
[
  "",
  "acc_num1",
  "acc_pi"
]

$ bitcoin-cli getaddressesbylabel acc_pi
{
  "1MGzSFisX6M1NaiTpi1MXqgzson2iNUcbk": {
    "purpose": "receive"
  }
}
$ bitcoin-cli getaddressesbylabel acc_num1
{
  "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm": {
    "purpose": "receive"
  }
}

 

행운을 빌어본다.

 

반응형
Posted by 작동미학