Full.md 174 KB

목차

Typora를 사용해 작성되었음.

시작하는 글

컴퓨터업계에 관련되있는 사람들은 한번쯤은 비트코인에 대해서 들어보았을 것이다. 이는 필자도 예외가 아니며 필자가 처음 비트코인에 대해 들어본것은 2011년 겨울, 금융학을 공부하는 캐나다 사람이 금융학과 컴퓨터공학의 결합해 만들어진 비트코인에대해 알아볼것을 권유하면서 이다. 다만 당시 비트코인은 매우 초기단계였고 그 명성은 지금과 같지 않아 필자는 단순히 사이버 머니의 아류정도로 생각하고 넘어갔다.

그렇게 무심코 넘겼던 비트코인을 다시 만나게 된 것은 2013년 겨울 비트코인의 가치가 폭등에 모두가 비트코인에 관심을 가지고 비트코인의 정체에 대해 탐구했을 때 이다. 비록 당시 광풍은 보란듯이 엄청난 폭락과 함께 대부분의 사람들의 기억속에서 잊혀졌지만, 그때 필자를 포함한 일부 사람들은 비트코인이 도대체 어떤 원리를 가지기에 이렇게 큰 붐을 일으킬 수 있었나? 에대해 탐구해보았고 블록체인이란 비트코인의 시스템의 유용성을 파악한 일부 사람들은 비트코인에 대한 정식적인 문서를 작성해 나아갔고 적어도 개발자들 입장에서는 대략적이나마 이 시스템을 이해하고 응용할 수 있을 정도의 문서들이 계속 생겨났다.

하지만 이렇게 문서가 계속 작성되었음에도, 또한 일반인이 비트코인을 사용하고 있음에도 불구하고 아직도 비트코인은 개발자들 만이 이해할 수 있는 영역인것 같다. 신문과 인터넷에는 비트코인과는 전혀 다른 온갖 루머와 잘못된 설명들이 퍼져 나가고 있고, 많은 사람들이 비트코인의 원리에 대하여 질문 글을 올림에도 불구하고 답변은 한결같이 비트코인의 사용법 그 이상의정보는 담겨있지 않아 보인다.

이러한상황에서 필자는 컴퓨터 과학적 지식이 적은 사람들이라도 비트코인에 대해 이해를 할 수 있도록 2016년말에 필자의 블로그를 통하여 “원리부터 파악하는 비트코인”이라는제목의 글을 올렸다. 비록 원래 의도했던 데로 관련분야 지식이 적은 사람도 이해하기 쉬운 글이 탄생한것 같지는 않지만 적어도 지식이 있는 사람들은 그 개념을 이해할 수 있을 정도의 글이 탄생해 나름 만족해 했고 그후 출판사로부터 연락이 와 이렇게 책으로 쓰게 되었다.

이 책은 비트코인 거래가 이루어지는 과정을 3가지 시점에서 분석하여 보여줄 것이다. 처음으로 보여줄 “거래의 생성 및 전파” 에서는나 자신이 타인에게 송금할 때 어떤 과정을 통하여 거래데이터가 만들어지는지, “블록체인,채굴의 시작”에서는 만들어진 거래데이터가 어떻게 블록체인에 포함되는지, 마지막으로 “블록의 전파”에서는 새로 생성된 블록이 어떻게 네트워크전역으로 퍼지며 왜 이 시스템이 안정적인지에 대하여 보여줄 것이다.# 비트코인에 대한 얘기

비트코인은 무엇이 다른가?

비트코인은 여러가지 형태로 불린다. 세계최초의 암호화폐처럼 그 진위여부를 즉각적으로 판단할 수있는것 부터, 전세계에서 하고있는 도박이라는 부정적인 시야도 있고 심지어는 4차 산업혁명을 앞당긴 주역처럼 엄청나게 긍정적인 시야도 있다. 하지만 인터넷은 상용화된지 20~30년이 넘어가고 있고 그동안 많은 전자화폐가 생겨나고 사라졌는데 왜 비트코인은 유명해 졌을까?

일반적으로 볼 때 비트코인은 그냥 평범한 전자화폐랑 다른 것이 없어 보인다. PayPal같은 것을 생각해보자. 송금을 통해 PayPal을 충전하고 사용하면 인터넷 돌아다니다가 자신이 원하는 것을 발견하면 클릭 몇 번으로 즉각 구매할 수 있다. 비트코인도 마찬가지로 계좌를 만들고 비트코인을 구매한후 인터넷을 돌아다니다가 자신이 원하는 것을 발견하면 클릭 몇 번으로 즉각 구매할 수 있다. 하지만 단지 그것뿐이라면 세상이 비트코인에 열광했을 리가 없을 것이다. 사실 편리성을 따지면 PayPal을 충전할 필요도 없이 그냥 카드 등록하고 쓰는게 제일 편하고, 송금도 어렵게 비트코인을 살 필요없이 그냥 인터넷뱅킹 쓰는게 더 빠르다. 그럼 왜 세상은 비트코인에 열광했을까?

그 이유로는 여러가지가 있겠지만 필자가 생각하기에 가장 큰 이유는 기존 화폐와는 대비되는 전혀 새로운 방식의 안정성과 고정적인 요금만 받는 수수료 시스템에 있다고 생각한다.

일단 전혀 새로운 방식의 안정성에 대해 얘기해보자. 우리가 쓰는 국가에서 발행해주는 화폐는 (KRW나 USD같은) 겉보기에는 매우 안정적인 자산처럼 보이지만 사실 그 가치는 한 권력자에 의해 심하게 변동될 수 있다. 대표적인 예로 1차세계대전 직후 독일을 보자. 1차세계대전동안 흥청망청 돈을 뽑아 전쟁을 벌였던 독일정부는 놀랍게도 종전 직후 3년만에 당시 독일의 화폐 마르크화의 가치를 1조배나 폭락시켜버렸다. 좀 더 체감에 와닿는 비유를 해보자면 어느날 갑자기 우리나라 돈 그 자체의 가치가 하락해 맥도날드에서 팔던 5천원짜리 빅맥세트가 하룻밤사이에 5천조원이 되버렸다는것이다. 이로인해 당시 독일은 떌감을 살 돈을 태우는게 오히려 이득이라는 현상 부터 아침에 먹을 빵을사러 돈을 수레에 담아가는 현상까지 발생했으며 당시 돈의 가치는 말그대로 휴지조각보다 못한 상태가 되어버렸다. 물론 지금과 같은 금융시스템이 없던 근대에 일어난 일이었지만, 그럼 현대의 화폐 가치는 안정적인것일까? 아쉽게도 그렇지 않아 보인다. 2012년 아베노믹스의 경우를 보자. 당시 일본총리 아베는 일본내 장기불황을 타파하기위해 무제한 양적완화, 즉 돈을 무제한으로 찍어내는 정책을 실시했다. 이러한 정책의 효과나 의의에 대해서는 말이 많지만 결과를 보면 2012년 7월 100엔에 1,477원하던 엔화가치가 불과 3년도 안되서 100엔에 885원이라는 엔화의 가치에 엄청난 변화를 일으켰고 이 현상으로부터 우리는 국가가 발행한 통화라도 한 권력자의 의지만으로도 그 가치가 크게 변할 수 있다는 사실을 알아낼 수 있다. 그 뿐 아니라 인터넷뱅킹이나 간편결제시스템에서 사용되는 전자화폐들도 그 화폐를 관리하는 중앙기관이 파산 혹은 화폐 포기 선언을 해버리면 그 화폐의 가치는 순식간에 증발해 버리는 것이다.

그럼 비트코인은 다른가? 그렇다. 다르다. 위 예시의 근본적인 문제는 모두 화폐의 가치가 발행주체 혹은 그와 유사한 중앙기관의 입맛따라 변동될 수 있다는 것이다. 반면 비트코인은 이러한 중앙기관이 존재하지 않는다. 굳이 따지자면 비트코인에서 이러한 권한은 누구나 될 수있는 채굴자들이 가지고 있다. 만약 채굴자들이 비트코인의 가치를 변동시키려 한다면 전체 채굴자의 최소 51%이상의 동의를 얻어야한다. 만약 어느 한 채굴자가 비트코인의 가치를 변동시키려 애쓴다 해도 나머지 채굴자들의 힘에의해 묻힐 뿐이다. 이것이 바로 우리나라 여러 매체들이 앞다투어 말하는 비트코인의 특징, 분산적인 구조라는 것이다. 이는 비트코인에서 블록체인이라는 기발하지만 단순한 형태로 구현되어 있으며 이에대한 내용은 이 책 후반에서 다룰 예정이다.

그 다음으로는수수료에 대해서 얘기해보자. 우리나라는 비교적 송금 혹은 구매 수수료의 제약으로부터 자유로운 나라에속한다. 일단 은행이체도 타행으로 얼마를 이체를 하던 높아봤자 천원 근처이며 그나마도 은행에서 주는혜택을 잘만 이용하면 수수료가 면제 된다. 하지만 이는 국내에서 국내로의 거래 얘기이며 해외구매의 경우, 혹은 해외로 송금하는 경우, 혹은 금융시스템이 발달하지 않은 나라에서는 어떨까? 일단 해외 이체의 경우 기본으로 수천원을 수수료를지불하고 그후 송금 금액에 따라 더 많은 수수료를 요구하기도 하며 해외 결제의 경우 사정이 좀 나아 보이기는 하지만 그래도 환전수수료를 포함에서 약 2% 이상의 수수료를 지불해야 된다. 10만원의 2%가 2천원이라는점을 생각할 때 결코 적어 보이는 금액은 아니다.

여기서 비트코인이 수수료를 받아가는 방식은 일반적인 수수료 지불방식과 조금 색다르다. 여러분도 알고있다시피 비트코인은 모든것이 컴퓨터상에서 이루어진다. 그말은 즉슨 모든 거래는 0과 1의 조합으로 이루어진 어떤 데이터로써 처리된다는 것이고 이러한 모든 거래 데이터는 비트코인상에서 블록체인에 저장되게 되는데, 여기서 비트코인은 블록체인상에서 차지하는 공간을 수수료로 책정하는 정책을 택하였다. 일반적인 거래는 항상 블록체인상에서 차지하는 공간이 일정하다는점을 생각해 볼 때, 이러한 수수료 책정방식은 비트코인 사용자가 얼마를 쓰던 상관없이 항상 고정된 양의 수수료를 요구하게 된다는 것이다.

일반적으로 1500원정도를 수수료를 지불하면 10분안에 여러분의 거래는 블록체인속에 저장되며, 급하지 않은 거래는 500원정도만 수수료로 지불하면 대략 1시간 안에는 블록체인속에 저장되고, 수수료를 진심으로 아끼려고 한다면 단 100원만 지불해도 언젠가는 블록체인속에 저장되어 여러분의 거래가 공식적으로 인정받는다는 점과, 일반적인 해외 신용카드가 2%의 수수료를 물어 10만원짜리 물건을 결제할때 2000원을 카드사가 가져간다는점을 생각할때 금액이 커지면 커질수록 비트코인이 유리해진다는점은 자명하다.

이러한 금융기관대비 유리한 수수료 정책과 비트코인 사용자가 나눠가지는 비트코인 그 자체에대한 권한은 2009년 막 시작한 비트코인의 위상을 하늘을 찌르게 만들어주었고 그와 함께 비트코인을 따라하는 수많은 전자화폐를 만들어 내었다. 하지만 이러한 비트코인은 어떻게 탄생하게 되었을까?

비트코인이란 어떻게 쓸 수 있는가?

비트코인의 작동방법은 매우 복잡해 책 전반에 거쳐 설명을 해도 모든것을 담아내지는 못하겠지만, 사용방법은 무척이나 간단하다.

일단 먼저 비트코인 지갑을 여러분의 컴퓨터, 스마트폰 혹은 태블릿에 설치하자. 비트코인 지갑은 사용자의 비트코인 잔액을 보여주며, 타인으로부터 비트코인을 받고싶을때 필요한 비트코인 주소를 제공해고, 타인에게 비트코인을 보내고 싶을 때는 비트코인 지갑에 상대방의 비트코인 주소와 보낼 금액만 입력하면 된다. 한마디로 정리하면, 비트코인 지갑만 있으면 비트코인을 사용하는 입장에 있어서는 비트코인에서 할 수 있는 모든것을 다 할 수 있다.

다만 비트코인 지갑은 여러 개발자가 만든 여러가지 버전이 존재하고, 그 형태도 다양해 컴퓨터에 설치하는 것부터, 웹브라우저에서 바로 사용가능한것, 심지어는 하드웨어가 존재해 완벽한 보안을 자랑하는 지갑도 존재한다. 하지만 그중에는 보안에 취약한 지갑이나 심지어는 악의적으로 사용자의 비트코인을 빼돌리는 지갑도 존재한다는것이 문제다. 이러한 위험으로부터 벗어나기위해 비트코인 공식사이트는 처음 사용하는사람들에게 적합한 비트코인 지갑의 종류와 해당 비트코인 지갑을 선택했을때 발생가능한 위험들에대한 정보를 제공해준다. 다음은 그 중 필자가 추천하는 세가지 비트코인 지갑에 대한 정보이다.

이름 플랫폼 설명
Bitcoin Core 컴퓨터(윈도우, 리눅스, 맥) 비트코인 개발진들에의해 만들어진 비트코인 지갑이다. 지갑뿐 아닌 채굴같은 부수적인 기능도 포함되어 있으며, 비트코인의 신기능이 가장먼저 적용된다는 특징을 가지고 있으나, 이러한 기능들을 사용하려면 관련 지식이 있어야 한다. 그래도 일반적으로 사용하기엔 무리가 없다
BlockChain.info 웹브라우져, 스마트폰(안드로이드, iOS) 웹상에서 운영되는 비트코인 지갑이다. 높은 보안수준에 도달할수록 익명성이 사라진다는 단점이 존재하지만 사용하기 쉽고, 관리하기 편하며 자신과 관련된 거래를 실시간으로 시각화해서 볼 수 있으며 거래소와 연계되어 현재 보유한 비트코인이 어느정도 가치를 지니는지 보여준다.
Copay 컴퓨터(윈도우, 리눅스, 맥), 스마트폰(안드로이드, iOS, 윈도우) 깔끔한 UI에 사용하기쉬운 비트코인 지갑이다. 사용하기 쉬우며 한가지 특이한 기능이 있는데, 어떤 금액을 사용하는데 있어 여러명의 동의가 필요한 다중서명 거래가 가능하다. 일반적으로 개인이 사용할 일은 별로 없겠지만 가족 공용 자금이나 회사 자금을 비트코인으로 운용할때 유용하다.

물론 이것말고도 다양한 종류가 있으니 천천히 비교를 통해서 고르면 된다. 한가지 참고할만한 점은 자신이 고른 지갑에 "HD지갑", "hierarchical-deterministic wallet" 혹은 그와 유사한 기능이 담겨있는 지갑을 고르는 것이 좋다. 모두가 알고있는것처럼 비트코인은 컴퓨터상에서 작동하는 하나의 프로그램이고 만약 컴퓨터가 고장나거나 실수로 해당 프로그램을 지울경우 당연히 비트코인 지갑속에 남아있던 잔액도 사라지는것이다. (정확히는 사라진다라는 표현보다는 못쓰게된다. 해당 비트코인 주소에 얼마가 있었는지에 대한 기록은 블록체인속에 남아있다.) 이런 경우를 대비해 비트코인 포럼에서는 HD 지갑이라는 표준을 제안했는데, 이 표준안에는 사용자가 지갑을 백업할필요없이 단 12개의 영어단어만 기억하면 언제 어디서든, 심지어는 다른 종류의 비트코인 지갑을 사용해도 복구가 가능하도록 하는 내용이 담겨있어 이러한 표준을 지킨 비트코인 지갑은 관리하기가 더욱 유리하다.

이렇게 지갑을 얻었으면 다음으로 필요한것은 비트코인이다. 비트코인을 구하는법은 크게 두가지로 나뉜다. 직접 거래소에가서 비트코인을 구매하는 방법과 개인 혹은 기업판매자를 찾아가 비트코인을 구매하는 방법. 전자는 절차가 까다롭고 신분이 증명하기 쉬운사람이 아니면 이용하기 힘들다는 단점이 있지만 그 대신 더 싸게 비트코인을 구할 수 있고, 후자의 경우 절차가 간단하고 쉽고 빠르다는 장점이 있지만 그만큼 비싼 비용을 지불하고 비트코인을 구매해야 한다는 단점이 있다.

우리나라의 경우 빗썸, 코인원, 코빗 이 세개의 거래소가 대표적으로 가상화폐를 거래할 수 있으며 UI나 기능의 차이는 소소하게 존재하나 비트코인 시세부터 인증 절차까지 대체로 비슷하므로 자신이 선호하는곳을 사용하면 되며, 그 외의 경우 비트코인 공식 홈페이지에 소개된 방법을 이용해보거나 새로 생겨나는 비트코인 관련 벤처기업의 서비스를 이용하면 된다.

이렇게 얻은 비트코인을 사용할곳은 유감스럽게도 국내에는 아직 별로 존재하지 않는다. 오프라인에서 비트코인을 사용할 수 있는 장소를 보여주는 사이트인 코인맵에 따르면 국내에는 수십개의 비트코인을 사용 가능한 매장이 있다고는 하는데 필자가 서울 신촌과 강남근처에 표시된 장소를 실제 가본 결과 대부분의 경우는 받는다고는 하지만 실제로는 받지 않는경우가 대다수 였다. 이는 어찌보면 당연한데 시골 촌동네 구멍가게에서도 신용카드를 사용할 수 있는 우리나라의 금융 인프라는 솔직히 너무 훌륭해서 비트코인이 끼어들 여지가 없다.

하지만 해외의 경우 사정이 다른데, 세계 어느사람도 고객이 될 수 있는 인터넷 호스팅 기업을 중심으로 비트코인을 받는 업체가 하나둘씩 늘어나고 있다. 필자의 블로그도 이러한 비트코인을 받는 업체를 이용하고 있으며, 100달러가량의 상품을 결제하는데 370원가량의 수수료만 지불하여 비트코인 고유의 이득을 보게되었다. 물론 이뿐이 아니며 다음 사이트에 들어가보면 비트코인으로 재화 혹은 서비스를 판매하겠다는 사람들의 글을 많이 확인할 수 있다.

https://bitcointalk.org/

BitcoinTalk : 비트코인 초기 개발자들이 만들어낸 비트코인 포럼이며, 현재 가장 규모가 큰 비트코인 커뮤니티이다. 이 커뮤니티에서는 비트코인의 기술적인 내용부터, 초보자들을 위한 가이드까지 비트코인과 관련된 거의 모든 분야를 다루고 있다. 그중 MarketPlace라는 게시판에서 비트코인의 사용처를 쉽게 찾을 수 있다.

위 사이트에 올라와 있는 게시글 들을 보면 음식점 홍보, 전자제품 판매, 인터넷 호스팅 같은것 부터 시작해 비트코인 대출, 금괴 판매 까지 다양한 비트코인 사용처를 확인할 수 있다. 하지만 대부분은 검증된 글은 아니며 사기일경우도 종종 있기에 주의를 요한다.

이렇게 각자 자신이 구매할 물건을 정했으면 그 다음은 지불이다. 아쉽게도 비트코인의 거래과정은 우리가 신용카드를 긁으면 바로 결제가 승인 되는것처럼 빠르게 진행되지 않는다. 비트코인 거래가 승인되기까지는 많은 일이 벌어져 이 책 "거래의 생성"부터 "블록의 전파"까지 이에대한 과정을 다룰것인데, 사용하는 입장에서 중요한 것은

  1. 여러분의 거래데이터가 블록체인에 저장되는 시점이 거래가 인정되는 시점이고
  2. 수수료를 많이 지불할수록 더 빠르게 블록체인에 저장되고
  3. 아무리 빨라봤자 최소 평균 약 10분의 시간을 기다려야 한다

는 것이다.

비록 기존 신용카드대비 사용하기 불편하다는 점에서 여러가지 단점은 존재하지만, 비트코인은 신용카드와는 다르게 아직 생긴지 10년도 지나지 않은 금융수단이고, 사람들은 비트코인에 열광하고 있으며(적어도 여러분이 이 책을 보고있을정도로 여러분의 관심을 끌고는 있다.) 조금씩이지만 꾸준히 그 규모를 키우며 비트코인 내부적으로도 지속적으로 업그레이드가 이루어 지고있는 사실로 보아 앞으로 비트코인이 어떻게 바뀔지에대해 관심을 갖을 필요가 있다.

비트코인의 역사

2008년 10월 31일사토시 나가모토라는 닉네임을 가진 유저가 “Bitcoin: A Peer-to-Peer ElectronicCash System”라는 제목으로 소논문을 하나 공개하였다. 불과 9페이지에 불구한 이 논문에는 블록체인, 거래의 진행, 최소한의 저장공간으로 거래를 증명하는 법부터 이러한구조가 왜 안전한지, 이렇게 했을 때 예상되는 취약점은 무엇인지까지 현재 사용되고있는 비트코인의 아주 핵심적인 내용이 전부 담겨있었다. 같은 해 11월 9일 프로그래머들이 오픈소스 소프트웨어를 개발할 때 자주 쓰이는 SourceForge라는사이트에 이 논문을 기반으로 bitcoin이라는 이름의 첫 프로젝트를 시작하였다. 그리고 바로 그 다음해 2009년 1월 3일 오후 6시 15분경 우리를 놀라게하고 전세계가 관심을 가진 대망의 블록체인에 첫 거래가 등록되었다. 이것이 바로 비트코인의시작이다.

물론 비트코인시작 초기에는 별로 사람들의 시선을 끌지는 못했다. 오늘날과 같은 대규모는 커녕 소규모 거래소도 없었고 비트코인 채굴만을 위한 공장같은 존재도 없었으며, 단지 컴퓨터 기술자들이 포럼에서 만나 심심풀이정도로 개발하고 있던 소규모 프로그램에 불과했다. 현재 매년 50GB씩 커지는 블록체인의 크기도 초기에는 계속 부동을 유지하며 조금씩 조금씩 커지다가 간신히 1GB를 처음 넘긴것은 블록체인에 첫 거래 등록 이후 3년이 지난 2012년 5월경 이었다. 그러다가 2010년이 되면서 1만BTC로 라지사이즈 피자 2판을거래한 사람을 시작으로 최초의 비트코인 거래소, 최초의 마이닝 풀 등이 생겨 나가기 시작하더니 2011년에는 미국 TIMES에 위키리크스의 후원수단의 방법 중 하나로서비트코인이 소개되며 착실히 그 위상을 높혀나가고 2013년 그 가치가 폭등하면서 결국에는 우리나라에까지 대대적으로 알려졌다. 물론 사이트가 해킹 당해서 비트코인이 도난 당했다 같은 사건도 여러 번 발생했지만, 이렇게 수많은 사람들이 관심을 가지고 수많은 해커가 비트코인의 결함을 찾으려고 노력했음에도 불구하고 결국 그들이 해킹한것 (혹은 해킹당한것)은 비트코인을 거래하는 거래소이지, 한번도 비트코인 그 자체에 대한 공격이 성공한적이 없었다는 점을 생각해볼때 비트코인의 구조적인 안정성은 완벽하며 그 이유를 책 전반에 거쳐 설명할 예정이다. 이렇게 2017년기준 약 8년간 실제 운영하면서 그 안정성을 입증해온 비트코인은 현재 컴퓨터과학 뿐이 아닌 다양한 분야에서기존에는 존재하지 않았던 새로운 시스템의 개발에 큰 영감을 주어 현대사에까지 큰 한발자국을 남긴 가상 화폐라 개인적으로 생각한다.

위키리크스 수정하라는 요청은 솔직히...... 이거 모르는사람이 있나요?

비트코인의 현황

2017년 현재 비트코인의 시세는 하룻밤만에 10%가 변동되기도 하면서 매우 요동치고 있는 불안정한 자산이어서 아무도 비트코인의 미래를 예측하지 못하는 상황이다. 다만 비트코인은 자산적인 가치만을 지닌것이 아니며 특히 기술적가치의 경우 현재 매우 촉망받는다고 할 수 있다. 일단 대표적인 예가 블록체인이다. 블록체인이란 방법은여태껏 신뢰할 만한 기관없이 유저와 유저 간의 거래 시 누군가가 부정을 일으키면 그 부정을 어떻게 방지 혹은 파악할 수 있는가? 라는 의문에 대한 명쾌한 해결책을 제시해 주었다. 이러한 방법은 은행간 장부거래부터 iot기기간의 데이터 공유까지 적용될 수 있는 분야가 말그대로 무궁무진하며, 여기서 끝이 아니라 앞으로 설명할 비트코인에서 사용된 스크립트 방식의 서명이나 ECDSA같은암호화방식, P2P 통신의 구현방식은 이미 알려진 방식이긴 하지만 비트코인에서 수년간 문제없이 사용되어 오면서 이 존재를 모르고 있었던 컴퓨터 개발자들로 하여금 다시 쓸수있게 해주었다.

비록 이 책에서 비트코인의 모든 기술적 가치에 대하여 상세히 설명해주기는 힘들겠지만 부디 편한마음으로 읽어 향후 관련분야에 연구할때 비트코인의 아이디어를 응용해 사용하게 되었으면 하는 바람이다. :)

비트코인의 짧막한 지식

트랜젝션

비트코인을 이용해 누군가와 거래를 하면 송금하는 자의 디바이스에서는 트랜젝션(Transactions)이라 불리는 거래 데이터를 만들어낸다. 이 데이터에는 누가 누구에게 얼만큼의 비트코인을 보내는지에대한 정보가 담겨있다.

블록

채굴이란 비트코인 네트워크에서 발생한 트랜젝션을 모아서 하나의 블록을 만들고 만든 블록을 블록체인에 포함되도록 만들어주는 과정을 말한다. 블록은 약 매 10분마다 하나씩 발생하며 1MB의 크기가 넘지 않도록 되어있으며 평균적으로 약 1000건의 트랜젝션이 포함된다.

블록체인

n번째 블록이 n-1번쨰 블록이 위조되지 않았음을 증명해주는 형태로 그 모습이 블록을 체인으로 엮어논것 같다는 의미로 붙어진 이름이다.

비트코인 주소

은행에서 통장을 통해 거래를 할때 필요한것이 계좌번호라면 비트코인에서 거래할 때 필요한것은 비트코인 주소이다. 필자의 비트코인 주소의 경우 19iZnngPRx7Tcf5ydAyiFGp97SavWCPg7y 이런식으로 생겼으며 대게 처음 문자는 1, 그 다음은 임의의 숫자와 문자가 섞여있는 형태이다. 그 이유에 대해서는 비트코인 주소 에서 상세하게 다룬다.

채굴

비트코인에서의 거래가 승인되는 시점은 트렌젝션을 만들때가 아닌 해당 트렌젝션이 블록체인에 포함될때를 말한다. 채굴과정이란 트렌젝션이 포함된 블록을 블록체인속에 포함시키는 과정을 의미한다. 블록을 완성해 블록체인에 포함시키는데 성공할 경우 그 보상으로 채굴자는 일정량의 비트코인을 얻을 수 있다.

지갑

비트코인에서는 보안을 위해 한번 사용한 비트코인 주소는 버릴것을 권장한다. 다만 그러면 내가 지금 가지고 있는 비트코인을 알아보기위해 여태껏 사용해온 비트코인 주소와 비트코인 주소의 소유주임을 증명해줄 비밀키를 모두 기록해둬야한다. 이러한 정보들을 관리하는데 지갑이라는 소프트웨어가 사용된다.

Bitcoin Core

비트코인을 사용할 수 있는법은 다양하다. 스마트폰 앱으로 구현되어 있는 비트코인 지갑을 사용할 수도 있고 웹에 구현되어 있는 비트코인 지갑을 사용할 수도 있으나, 이 모든 지갑 소프트웨어의 원조이자 지금은 레퍼런스처럼 자리잡은 것이 Bitcoin Core이다.

먼저 알아두고 가야할 개념

개요

비트코인은 보안과 관련된 컴퓨터 과학적 지식의 총집합 이라해도 과언이 아니다. 이와 관련된 전문적인 지식들의 대부분은 관련된 파트에서 알려주겠지만 몇몇가지개념은 모든분야에 거쳐 상식적으로 쓰이기때문에 미리 알고 넘어가야할 필요가 있다. 처음에는 이해하기 힘들지도 모르나 알고나면 간단한 개념이기에 (작동원리를 이해할 필요는 없다.) 시간적 여유를 두고 곰곰히 생각해 볼것을 권장한다.

해시함수

우리손가락에 있는 지문에 대해서 생각해보자. 일반적으로 모든 사람은 각기 고유한 지문을 가지고 있다고 한다. 또한 A라는 사람과 B라는사람이 지문이 같을 확률은 약 640억분의 1이라고 한다. 지구상의 인구가 640억명을 넘어가면 한명쯤은 나와 같은 지문을가진 사람이 나타날 수 있지만 현실에서 지구상의 인구는 70억명밖에 안되고 70억명중에 나와 같은 지문을 가진사람이 있을 확률은 매우 적기 때문에 사실상 나의 지문은 나만의 것이라고 해도좋으며 많은 정부기관에서 개개인의 신원을 특정하는데 부터 스마트폰의 소유자 확인까지 지문을 많이 사용한다. 그럼 컴퓨터 파일상에도 지문을 만들 수 없을까? 라는발상에서 나온 것이 해시함수이다.

정의적으로 해시함수는 임의의 길이를 가지는 임의의 데이터를 고정된 길이의 데이터로 바꿔주는 함수를 총칭한다. 무슨 의미냐 하면 워드파일부터 온라인게임 통신 데이터까지 우리가 컴퓨터에서 다루는 모든것은 0과 1로 이루어진 데이터 덩어리 이며 이 데이터 덩어리를 해시함수에 넣고 돌리면 고정된 개수의 0과 1을 내보내 준다는 것이다. 예시를 들어보자면 SHA2라는 해시함수에다 "Hello World"라는 문자열을 입력하면 대략 다음과 같은 모습을 보이며 출력값으로 보이는 저 문자열은 언제나 일정한 길이를 가진다는 것이다.

​```flow
st=>start: "Hello World"
io=>inputoutput: SHA2
e=>end: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e

st->io->e->
​```

다만 이게 어떻게 사람의지문과 연결되는 것일까? SHA2의 경우 데이터를 입력받았을때 입력받은 데이터를 256개의 0과 1로 바꾸어준다. 여기서 핵심은 이 256개의 0과 1은 총 2^256가지의 경우를 표현해 낼 수 있는데 워낙 표현해낼 수 있는 가능성이 많다보니 서로 다른 두 데이터가 같은 해시값을 가질 확률이 1/2^256 밖에 안된다는 것이다. 우주를 나이(137억년)를 나노초단위로 표현할때 10^24 단위의 숫자가 사용되고 2^256이 10^77 단위의 숫자가 사용된다는 점과 지구상의 컴퓨터로 일일히 비교해봐서 서로다른 데이터가 같은 해시값을 가지는 경우를 찾으려면 우주의 나이가 넘는 시간이 필요하다는점을 생각할때 해시값이 같은 서로다른 두 데이터를 노가다로 찾는것은 사실상 불가능 하고 수학적으로 찾기에는 애초에 수학적으로 찾을 수 없게 설계해 놓았기에 어떤 데이터의 해시값은 그 데이터 고유의 지문이라 할 수 있는것이다.

그럼 이 컴퓨터상의 지문인 해시함수는 주로 어떻게 사용될까? 많은 사용법이 알려져있지만 그 중 비트코인과 관련된 사용법을 말해보자면 그 중 하나는 바로 데이터 검증이다. 생각해보자, 현실세계에서 많은 정부기관이 국민들의 지문데이터를 보관해둔다. 그리고 이렇게 보관된 지문데이터로 범죄현장에서 지문으로 범인 판별부터 해외로 입출국시 본인인증까지 다양한 곳에서 실제 본인인지에 대해 검증해낸다. 해시값도 마찬가지이다. 인터넷에 파일을 다운로드할때 데이터 원본과 해당 데이터의 해시값을 같이 다운로드하면 다운받은 뒤 데이터의 해시값을 구해 다운받은 해시값과 비교해보면 이 데이터가 업로더가 의도한 파일과 같은 파일인지 아님 무언가 변조된 파일인지 알아낼 수 있는것이다. 이런 방법으로 해시함수를 통해 우리는 어떤 데이터가 어떠한 변조도 없는 데이터인지 판별해낼 수 있다.

또 다른 비트코인에서 해시함수의 사용방법으로는 작업증명(POW:Proof Of Work) 이라는 사용방식이 있다. 위에서 말했다시피 SHA2의 결과값으로는 우리가 예측할수 없는 256개의 0과 1이 나온다. 이러한 256개의 0과 1은 수적인 관점으로보면 2진수로 표현된 어떤 큰 자연수 라고 할 수있는데, 이 큰 자연수가 1,024=2^10보다 작은 수가 나올 확률은 2^10/2^256 = 1/2^246 이라고 할 수 있다. 즉, 컴퓨터가 1,024보다 작은 어떤 자연수를 노가다 뛰면서 발견할 확률은 1/2^246이며 2^246번정도 연산하면 하나쯤은 발견해 낼 수 있다는 것이다. 만약 어떤 컴퓨터가 해시값을 구해봤더니 1,024보다 작은 어떤 값을 발견해냈다면 우리는 대략 이 컴퓨터가 (엄청 운이 좋은경우가 아니면) 2^246번의 연산을 해봤음을 추측할 수 있고 이를 비트코인에서는 POW라고 부른다.

서로 다른 두 데이터 간에 같은 해시 값이 나오면 어떻게 되나요?

엄청나게 적은 확률이긴 하지만 그래도 서로다른 두 데이터간에 같은 해시값이 나올 가능성은 존재한다. 이런 상황을 해시충돌이라는 용어로 표현한며 이는 서로다른 두 데이터가 같은 데이터라고 주장해 버릴수가 있어 데이터 검증목적으로 사용되는 모든 해시함수에게 악몽같은 상황이다. 물론 악몽이라 불리는만큼 애초에 이런일이 발생하지 않게 함수를 설계하기는 하지만 그래도 시간이 지나면서 해시충돌을 의도적으로 찾아낼 수 있는 방법이 발견되가고 있다. 대표적인 경우가 md5와 SHA1이라는 해시함수이다. 먼저 md5의 경우 1991년 개발되어 처음나올당시 준수한 성능을 자랑했지만 시간이 지나고 컴퓨터 성능이 비약적으로 좋아지면서 2017년 현재와서는 스마트폰만으로도 1분 안에 A라는 데이터와 해시충돌이 발생하는 B라는 데이터를 찾아낼 수 있다. 또 SHA1의 경우 2017년 2월 구글이 공개한 방법을 사용하면 특정 데이터에 한해서 본래 12,000,000개의 그래픽카드를 병렬로 1년동안 쉬지않고 탐색해봐야 해시충돌이 일어나는 데이터를 찾아낼 수 있어야 하는데, 단 110개의 그래픽을 1년동안 쉬지않고 돌리면 해시충돌을 찾아낼 수 있게 되었다. SHA2는 아직 그 어떤 알려진 방법도 존재하지 않고 SHA1보다 훨씬 더 많은 연산량을 요구하긴 하지만 시간이 지나면 SHA2도 쉽게 해시충돌을 발견해낼 수 있게 될지도 모르며 그때는 블록체인이라는 시스템에 부정행위가 개입될 수 있다. 다만 이는 블록체인만의 문제는 아니고 SHA2를 사용하는 모든 금융기관, 정부기관에도 해당하는 문제이기에 필자는 아마 수년에서 수십년 안에는 모든 비트코인을 포함한 모든 해시함수가 SHA2에서 SHA3를 사용하게되지 않을까? 생각하게 된다.

비대칭 암호화 (공개키암호화)

비대칭 암호화 (혹은 공개키 암호화)는 어떤 특이한 보물상자를 상상하면 쉽다. 이 보물상자는 서로다른 두개의 열쇠가 있는데 열쇠 하나는 이 보물상자를 열수만 있으며 나머지 하나는 잠글수만 있다. 잠그는 열쇠로 보물상자를 열지는 못하며 여는열쇠로 보물상자를 잠그지는 못한다. 이 특이한 보물상자를 컴퓨터로 구현한 방법이 비대칭 암호화 방식이다. 여기서 두 열쇠는 공개키와 비밀키라는 이름으로 불리며 공개키와 비밀키중 어느쪽이 잠그는역할을 하고 어느쪽이 여는 역할을 하는지는 상황에 따라 달라지며 공개키는 모두가 그 내용을 확인할 수 있으며 비밀키는 자신만이 알고있다는 특징을 가진다.

개념적으로는 알겠지만 이것이 수학적으로 어떻게 가능한 것일까? 언젠가 임의의 두 소수 p와 q를 곱해서 생긴 값 p*q로부터 원래 p와 q값을 알아내긴 힘든 것을 원리로 암호화 하는 방식이 있다는 것을 들어본 적이 있는가? 이 방법이 바로 RSA라 불리는 대표적인 비대칭 암호화 방식중 하나이다. 다음과 같은 상황을 생각해보자. A라는 사람이 B라는 사람으로부터 숫자를 알아내고 싶은데 C라는 사람이 계속 엿듣고 있다. 그럼 어떻게 C는 모르지만 A는 B로부터 정보를 가져올 수 있을까?

일단 A는 서로다른 두 소수 p=11, q=37을 생각해둔다. 그리고 11*37=407 이라는 값과 p-1과 q-1와 서로소인 한 숫자 7을 B에게 알려준다. 그럼 B는 자신이 생각해둔 숫자 240의 e=7 제곱을 407로 나눈 값, 즉 240^7(mod 407) = 235를 A에게 알려준다. 그럼 A는 407의 오일러함수 값 360을 구해내고 7*103 – 360*2 = 1 이라는 사실을 이용해서 235^103(mod 407) = 240, B가 보내려고 한 숫자가 240임을 알 수 있다. 반면 407이 어떤 소수로부터 나온지 모르는 C는 오일러함수값을 구하는데 1부터 407까지의 숫자를 일일히 계산해보거나 407을 이루는 두 소수의 값을 찾아봐야하는데 이 과정은 시간이 꽤 소모된다. 만약 이를 11과 37이 아닌 A4종이에 적기도 힘든 긴 소수 2개를 사용하면 컴퓨터라도 복호화를 하는데 최소 수백년이 걸린다. 이것이 바로 RSA의 아주 기본적인 원리이다.

Note left of A: C가 볼수있는 내용들
A->B:p*q = 407
A->B: e = 7
Note over B: B encrypts 240 \nusing data \ngiven by A.
B->A: 235
Note over A: A decrypts 235 \nusing p and q.

복잡하다 느껴지는가? 괜찮다. 비트코인에서는 RSA를 안쓰고 ECC라는 더 복잡한걸 쓴다. (음...?) 그리고 둘다 제대로 이해하려면 기초적인 수학부터 전문적인 수학까지 그 자체를 마스터 하는데만 상당한 시간이 걸린다. 하지만 이 둘이 어떻게 작동되는지는 몰라도 이 둘의 특징만 파악하면 비트코인을 이해하는데는 문제가 없다. 그 특징이란 위 과정에서 p와 q라는 두 소수를 비밀키로 암호화된걸 복호화 했으며, p*q 와 e라는 두 수를 공개키로 암호화를 진행했고, 비밀키로부터 공개키를 만들어 낼 수 있고, 비밀키를 모르는 상태로 복호화를 하려면 엄청난 시간이 든다. 라는 것이다. 이는 비트코인에서 ECC의 원리를 이용한 ECDSA에도 비슷하게 나타난 특징이니 (단, 여기서는 비밀키가 암호화를 한다.) 참고해두자.

전자서명

처음 해시함수를 설명할때 해시값은 데이터가 변조되었는지 확인하는데 쓰인다고 언급했다. 만약 데이터 변조가 단순히 통신오류때문에 발생한것이라면 변조확인과정은 아주 쉽게 진행될 것이다. 하지만 만약 데이터가 악의적인 해커에의해 조작된 것이라면? 그 해커도 해시함수의 원리는 알고있을테니 당연히 우리에게 제공되는 데이터만 조작하지 않고 해시값도 조작해서 줄 것이다. 그럼 우리는 조작된 해시값과 데이터로 받은 데이터가 정상적인것이라고 속게 되어 해커는 성공적으로 조작된 데이터를 배포할 수 있을것이다. 이러한 상황을 어떻게 못하나? 라는 생각에서 나온것이 전자서명이다.

전자서명의 원리는 간단하다. 해시값을 비밀키로 암호화한 뒤, 공개키와 함께 암호화된 해시값을 배포한다. 암호화된 해시값을 받은 우리는 공개키를 이용해 복호화를 하고 파일의 해시값을 구해 복호화한 값과 구한 해시값을 비교해본다. 둘이 같은값이면 이 데이터는 조작되지 않았고 다르면 뭔가 문제가있다. 무척 간단한 방법이지만 이런 조치는 엄청 강력하게 작용한다.

note left of 송신자: 해커가 볼 수 있는 내용들
송신자->수신자: Data
송신자->수신자: Encrypted Hash
송신자->수신자: Public key

일단 해커가 데이터를 받는사람이 조작된줄 모르게 데이터를 조작하려면 어떻게 해야할까? 방법은 두가지이다. 조작된 데이터의 해시값과 원래 데이터의 해시값이 같게 조작을 하던가, 아니면 암호화된 해시값을 복호화했더니 조작된 데이터의 해시값이 나오게 하면 된다. 하지만 전자의 경우 위에서 밝혔다시피 우주의 나이정도의 기간도 매우 부족할정도로 오래걸리고 후자의 경우 비밀키를 모르면 조작된 데이터의 해시값의 암호화값을 구해낼 수 없다. 그러므로 이러한 단순한 조치만으로도 해커는 데이터를 남몰래 조작할 수 없다...... 라고하고 싶지만 눈치빠른사람은 눈치챘을 것이다. 그것은 바로 공개키도 같이 조작하면 수신자는 속을 수 밖에 없지 않은가? 라는 것이다.

맞다. 위 과정에서 공개키도 조작하면 수신자는 데이터가 제대로된건지 조작된건지 알길이 없다. 그래서 존재하는것이 신뢰기관이다. 신뢰기관이란 다른건 다 믿을 수 없어도 이거 하나만큼은 믿을 수 있어! 라는 느낌의 존재인데 여기서 제공된 공개키만큼은 아무런 개입이 없었다는걸 전재하에 모든 전자서명 시스템이 작동한다. 윈도우즈의 경우 출고때부터 마이크로소프트에서 제공하는 공개키가 내장되어 신뢰 가능한 소프트웨어를 구분하고, 웹사이트의 경우 인터넷 브라우저자체에 신뢰 가능한 몇몇가지 공개키가 저장되어 https 프로토콜을 구현하고 있다. 비트코인에서는 약간 기발한 방법으로 신뢰기관의 존재 없이 공개키가 믿을 수 있다는걸 보여주는데 이는 *트랜젝션*부분에서 자세히 다루겠다,# 지갑과 비트코인 주소

비트코인 주소

개요

은행에서 송금을 하기위해서는 상대방의 계좌번호가 필요하듯이 비트코인에서 거래를 발생하기 위해서는 상대방의 비트코인 주소가 필요하다. 또한 어떤 비트코인 주소의 소유주가 나 자신임을 증명하기 위해서 비트코인은 전자서명에서 공개키를 이용하여 비트코인 주소를 생성하는 방법을 채택하였다.

이 파트에서는 어떻게 비트코인 주소가 만들어지는지에 대해서 살펴본다.

ECDSA

비대칭 암호화에 대해서 설명할떄 비트코인은 RSA를 사용하지 않고 ECC를 사용한다고 했던부분 기억하는가? ECC란 Elliptic curve cryptography 의 약자로 한국어로는 "타원곡선 암호"정도로 번역되는 존재이다. ECC는 그 원리에 대해서만 설명하는 책이 있을정도로 기초적으로 알아야할 지식이 많고 복잡해서 이 책에서 자세히 다루지 않겠지만 추상적으로나마 표현해보자면 RSA가 두 소수의 곱을 통해 암호화된 어떤 값은 두 소수를 모르면 해독하는데 엄청난 시간이 걸린다는 점을 이용했다면 ECC는 아래 그림과 같은 타원곡선 상에서 알려진 어떤 시작점을 기준으로 특별한 규칙에 따라 n번 움직인 점으로 암호화한 값은 정확히 몇 번 움직였는지 모르면 해독하는데 엄청난 시간이 소모된다는 점을 이용한 암호화 방법이다.

공개키와 비밀키에 잠깐 얘기해보자면 ECDSA의 한 표준안인 secp256k1의 경우 $$y^2 = x^3 + 7$$ 라는 함수를 가지는 타원곡선 상에서 G = 04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8 로 표현되는 G를 출발점으로 하는것으로 정해져 있으며 움직인 횟수 n이 그대로 256bits 크기의 비밀키, 움직인 결과 나온 타원곡선상의 한 점이 그대로 520bits 크기의 공개키가 된다.

다만, 여기서 한가지 짚고 넘어가볼만한 사항이 위에서 엄청나게 긴 16진수 숫자열로 표시된 G의 값이 사실을 x좌표와 y좌표를 표시했다는 것이다. 04부분은 뒤쪽에 표시되는 내용이 어떤 양식인지를 보여주고, 앞쪽의 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798부분은 좌표평면상의 x좌표, 뒤쪽의 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8부분은 좌표평면상의 y좌표를 나타낸다. 하지만 조금만 생각해보면 알 수 있다시피 그래프의 형태를 이미 $$y^2 = x^3 + 7$$ 으로 알고 있으므로 우리는 x좌표와 y좌표 모두의 존재를 알 필요없이 x좌표만 알고있으면 나머지 y좌표는 컴퓨터 연산으로 알아낼 수 있고 추가적으로 필요한 정보는 y좌표의 값이 양수(위쪽)이냐 음수(아래쪽)이냐 인 것이다. 그래서 좌표를 표현할때 압축형이라는 형태가 존재하는데 앞에 접두부가 y좌표가 양수면 02가 되고 음수면 03이 되며 그후 x좌표만 추가되어 위에서 밝힌 점 G의 좌표의 경우 기본형에서 520bits크기를 점유했었지만 압축형이되면 264bits 크기의 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798가 되어 256bits 상당의 공간을 절약할 수 있게된다. 이는 공개키 또한 마찬가지이며 압축된 공개키를 사용하면 트랜젝션의 크기가 32byte=256bits 줄어들어 조금이나마 수수료를 아낄 수 있으니 참고하자.

$$y^2 = x^3 + 7$$ 그래프 개형

비트코인에서 금융권에서 많이 쓰여 이미 안정성이 입증된 RSA를 활용한 전자서명을 사용하지 않고 ECC를 활용한 ECDSA를 사용하는 이유는 간단한데, 그것은 바로 RSA보다 더 적은양의 데이터만으로도 RSA보다 뛰어난 안정성을 보장해주기 때문이다.

위 도표를 보면 현재 금융권에서 가장 활발히 쓰고있는 RSA2048의 경우 키 크기로2048bits를 사용하면 해독을 해내는데 초당 백만건씩 비교를 해볼때 약 10^20년정도가 걸리지만 ECC의 경우 단 210bits만을 이용해도 같은 10^20년정도가 걸리게 할 수 있으며 당연하게도 만약 ECC가 2048bits를 사용하면 RSA는 같은 수준의 보안을 유지하기위해서는 훨씬더 많은 bits를 사용하는 키가 필요하게 될것이다.

현재 비트코인에서 사용하는 ECDSA는 미국립표준기술원(NIST)에서 2000년 중순에 발표한 secp256k1라는 표준을 따른다. 이 표준안에 따라 비트코인에서는 256bits 크기의 비밀키와 512bits 크기의 공개키를 가진다.

비트코인 주소의 생성과정

공인인증서를 사용하며 나 자신이 비밀키를 사용해 서명을 했을때 금융기관이 정말 본인이 한 서명인지 맞는지 확인하는 법은 신뢰할 수 있는 인증기관에서 보관하고 있는 공개키와 나 자신이 첨부한 공개키가 서로 일치하는지 보는 것이다. 이러한 방법으로 나 자신이 어떤 행동을 했음을 증명할 수 있고, 그에따라 나 자신의 자산을 마음대로 사용할 수 있게된다. 하지만 비트코인은 어떨까? 일단 완벽한 분산화로 인해 인증기관이란 존재도 없을 뿐더러 모든것은 익명으로 진행되어 나 자신임을 증명하는 것도 의미가 없다. 그럼 어떻게 어떤 계좌의 존재가 나 자신이 소유하고 있음을 증명할 수 있을까? 이에대한 해결책으로 비트코인은 비밀키로부터 나온 공개키를 사용해 비트코인 주소로 만들어 버렸다. 이렇게 하므로써 비트코인은 아주 간단한 진리를 만들었는데 그것은 바로 "비밀키를 소유한자가 이 주소의 소유자이다!"라는 것이다.

그럼 지금부터 비트코인 주소의 생성과정을 한번 살펴보자. 일단 secp256k1표준에 맞게 비밀키를 생성할 필요가 있다. 방법은 간단하다. 남들이 예측하지 못하게 256개의 0과 1을 적당히 늘어놓으면 된다. 좀 더 쉽게 표현하자면전세계 아무도 예측하지 못할 0 에서 2^256-1 사이의 아무숫자나 하나 고르면 된다. 물론 모든 비트코인 사용자가 같은 방법으로 비밀키를 생성하므로 우연히 같은 비밀키를 가지게 될 확률이 존재는 하지만 이는 1/2^256 이라는 엄청나게 적은 확률로 완벽하게 임의로 비밀키를 골랐다면 겹치는 상황은 거의 불가능에 가깝다는것을 생각해두자.

초기 비트코인의 경우 1에서 2^256 사이의 숫자를 고를때 운영체제 자체에서 제공하는 난수발생기를 이용하던가 자신이 직접 아무숫자나 고를 수 도 있었지만 요즘 대부분의 비트코인 특정 규칙에따라 난수를 발생시키는데 이는 지갑파트에서 자세히 다룰것이다.

비밀키가 만들어졌으면, 다음으로 필요한 것은 공개키 이다. 공개키를 구하는 과정은 앞쪽에서 ECDSA를 설명하면서 그 과정만을 설명한 책이 있을정도로 분량이 많고 복잡하다면서 건너뛰었으나, 사실 이 개념은 필자 본인도 대략적으로 이해만 할뿐 정확히 수학적으로 어떻게 구현되는지는 모른다. 다만 이건 비트코인 개발자들도 마찬가지였는지 원조 비트코인 프로그램인 Bitcoin Core도 개발 초기에는 직접 구현하지 않고 OpenSSL라는 다른 오픈소스 프로젝트에 구현된 secp256k1을 그대로 가져와 사용했다. 현재는 OpenSSL 대신 비트코인을 위해 개발된 libsecp256k1을 사용해 ECDSA관련 연산을 행하고 있는데 libsecp256k1 자체가 sipa라는 Github유저에 의해 2013년 중순에 개발되기 시작해 2015년 11월에 와서야 완성되고 Bitcoin Core에 통합되었다는 점을 생각해보면 그 복잡도를 간접접으로 상상해 볼 수 있을꺼라 믿는다.

이제 이 완성된 공개키를 이용해서 비트코인 주소를 만들어볼 차례이다. 공개키로부터 비트코인 주소를 만드는 과정은 아래와 같은 그림으로 간단히 표현할 수 있다.

graph TD

비밀키-->공개키
공개키-->|RIPEMD160, SHA2|Public_Key_Hash
Public_Key_Hash-->|Base58Check|비트코인주소

먼저 공개키를 SHA2 해시함수에 넣고 돌려서 256bits크기의 해시값 A를 얻어낸다. 그 후 얻어낸 해시값A를 RIPEMD160이라는 해시함수에 넣고 돌려서 160bits크기의 해시값 B를 얻어낸다. 이 해시값 B는 Public Key Hash라 불리며 비트코인 주소 대신에 이 값으로 송금을 할 수도 있다. (거래 생성부분에서 P2PKH 참고) 근데 Public Key Hash만으로도 거래가 가능하면 왜 비트코인 주소가 따로있는 것일까? 그 이유는 미관에 있다. 공개키를 해시함수를 두번돌려서 나온 160bits크기의 값은 0과 1로만 구성되어있는 2진수 데이터 이고 이를 그나마 보기쉬운 16진수표기법으로 바꾸면 005F9D6E944D5B968DADE7EFABFA02395A8733F6086E43E710이런 형태로 나타나는데 미관상 보기 좋지 않을뿐더러 입력하다가 실수하기도 좋은 형태이기도 하다. 이렇게 실수하기 좋은 형태를한 2진수 데이터를 사람이 입력할때 실수가 잘 발생하지 않도록 보기좋은 형태로 바꿔주는 것이 바로 Base58 인코딩이다. 개념은 아스키코드랑 똑같다. 어떤 비트조합이 있으면 해당 비트열을 그에 해당하는 문자로 치환시켜주는 것이다.

img

이미 잘 알려진 Base64인코딩과 다른점은 글꼴에 따라 혼동하기 쉬운 0(숫자), O(알파벳), l(소문자 L), I(대문자 i), +, / 등의 글자가 빠져 사람이 옮겨적을때 실수할 가능성을 낮춰졌다는 정도이다.

다만, 비트코인 주소가 실제 자산이 옮겨가는 주소이고 사소한 실수로 주소 입력과정에서 오타 하나 나온것 때문에 송금하는 금액이 모두 증발해버리면 매우 슬플것이다. (은행과 다르게 비트코인은 중앙관리기관이 없어서 송금취소도 못한다!) 여기서 그 존재감을 들어내는게 Base58Check라는 존재이다. Base58Check는 그냥 Base58로 변환된 문자열도 쓰기 복잡해서 솔직히 실수가 일어날 수 있으니 문자열 자체에 자신의 오류를 감지하는 정보를 조금 넣어두어 오타가 났을때 감지할 수 있게하자! 라는 아이디어를 실현시킨 방법이다. 그 구현법은 간단하여 일단 변환하려는 데이터 앞쪽에 이 데이터의 정체를 알려주는 정보를 붙힌 데이터를 SHA2 를 두번 돌려 나온 해시값을 변환하려는 데이터 뒤에다 붙히고 Base58 인코딩을 하자!, 아 잠만, 해시값이 256bit=32Byte는 너무 크다 앞쪽 4바이트만 남기고 나머지는 버리자! 라는 느낌이다. 이렇게 하므로써 우리는 Base58Check로 인코딩된 어떤 문자열을 봤을때 이 문자열이 공개키에 관한건지, 주소에 관한건지, 비밀키에 관한건지 같은 이 데이터의 정체를 짐작할 수 있게 되며, 그뿐 아니라 만약 오타가 났을시에는 입력한 데이터가 제대로 되어있지 않음을 높은 확률로 즉각 판단할 수 있게된다. (물론 천문학적인 확률로 두번 해싱한값의 첫 4바이트가 같은값이 나오게 오타가날경우 판단 못한다.)

graph TD
How_Base58Check_Works
Public_Key_Hash-->|Adding Prefix|Prefix+Public_Key_Hash
Prefix+Public_Key_Hash-->|Adding first 4bytes of double SHA2|Prefix+Public_Key_Hash+Hash
Prefix+Public_Key_Hash+Hash-->|Base58Encoding|비트코인주소

Base58Check의 경우 비트코인 주소 말고도 몇가지 용도로 사용되는데 그에따른 Prefix는 아래 표와 같이 표현된다.

Decimal version Leading symbol Use
0 1 Bitcoin pubkey hash
5 3 Bitcoin script hash
21 4 Bitcoin (compact) public key (proposed)
128 5 Private key (uncompressed pubkey)
128 K or L Private key (compressed pubkey)
98 6P Encrypted Private Key

비트코인 주소에서 사용하는 Public Key Hash의 경우 Prefix에 의해 항상 맨앞에는 1이 오게되는데 실제 거래에 사용되는 비트코인 주소들을 보면 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa(첫 비트코인 채굴자의 주소) 나 19iZnngPRx7Tcf5ydAyiFGp97SavWCPg7y (필자의 비트코인 주소) 처럼 항상 처음은 1로 시작하는 것을 알 수 있다.

비밀키 하나에 비트코인 주소가 두개?

비트코인 주소를 만들때는 공개키를 두번 해시함수에 돌린값을 이용한다. 하지만 앞서 밝혔다시피 공개키는 같은 정보를 가지고 있지만 압축형과 기본형 두가지 형태가 있다. 그럼 여기서 문제가 생긴다. 기본형을 사용할때랑 압축키를 사용할때랑 같은 해시값이 나올리가 없다. 그러므로 결국 비트코인 주소는 두개가 탄생할 것이다. 과연 그럴까? 정답은 그렇다! 이다. 다만 본래 기본형 공개키를 사용했으며 압축형 공개키를 사용한건 비교적 최근일이여서 구형 비트코인 클라이언트가 오류를 내는것을 방지하고 최신형 비트코인 클라이언트와 호환성을 유지하기 위해 압축형 공개키를 사용하는 비밀키 양식과 기본형 공개키를 사용하는 비밀키 양식을 나눠 놓았다. 그 양식은 위 표에 나와있으며 간단한 확인법은 비트코인 클라이언트에 비트코인 비밀키를 출력하게해 5로 시작하면 해당 비밀키는 기본형 공개키를 사용하며 K혹은 L로 시작하게되면 압축형 공개키를 사용해 수수료를 지불할때 조금이나마 이득을 볼 수 있게된다.

암호화된 비밀키

비밀키는 삭제되면 영영 해당 비밀키에 해당되는 비트코인 주소는 사용하지 못하게 된다. 또한 하드디스크나 SSD는 언제나 정보가 삭제될 위험이 존재한다. 그럼 가장 안전한 매체는 무엇일까? 라는 의문에대한 답은 바로 종이이다. 종이는 고대 이집트 파피루스가 현재까지 그 정보와 함께 보관되어 올 정도로 그 안정성이 보장되어 왔으며 내용을 적기 쉽고, 우리 주변에서 쉽게 구할 수 있으며, 가지고다니기 종이만큼 쉬운것도 없다. 하지만 한가지 문제가 있는데 훔쳐지거나 카메라 촬영과 같은 형태로 그 정보가 도난당할 위험이 있는 것이다. 이 때 만약 종이에 비밀키가 그대로 적혀있다면? 그 돈은 도난당한거나 마찬가지이다.

이러한 불편한 상황으로부터 벗어나기위해 BIP38에 비트코인 비밀키를 암호화 해서 보관할 것이 제안되었다. AES라는 대칭 암호화 기법을 사용하여 자신이 정한 비밀번호로 암호화 되며, 암호화된 비밀키는 Base58Check인코딩으로 항상 "6P"로 시작하는것으로 정해져 있다.

예시: 6PnYPn11mffTbYcp21YBhLjN8B9wPruaWeLcctDft9RHaH5Lu21pG23beG

이렇게 암호된 비밀키는 남에게 노출되어도 비밀번호를 모르면 쓸모없는 정보이므로 종이와같은 형태로 출력할때는 암호화된 비밀키를 사용할것을 권장한다.

사소한 팁으로 https://bitaddress.org 에서 지갑을 생성하고 그에 해당하는 비밀키와 비트코인 주소를 멋있는 형태로 출력할 수 있다.

지갑

개요

비트코인에서는 모든 거래내역이 투명하게 공개된다. 하지만 동시에 익명성을 보장하기위해 비트코인이 접근한 방법은 송금받기위한 비트코인 주소를 1회용으로 사용하게 하는 것이다. 비트코인 주소를 한번쓰고 버리게 하여 결과적으로 해당 주소의 소유주가 현실세계에서 누군지를 특정하는데 방해하는 것이다. 다만 이런과정에서 문제가 발생하는데 현재 내가 보유하고있는 잔액을 파악하기위해 필요한 비트코인 주소가 따로따로 관리하기에는 너무 많아진다는 것이다. 이를 위해 비트코인은 사용한 주소들을 통합관리 해주는 지갑이란 개념을 도입하였다. 초기 비트코인 지갑은 무식하게 모든 주소를 저장하는 방법을 택했지만 그 후 몇가지 트릭을 더하여 지금와서는 사람이 몇개의 단어만 기억해두면 언제 어디서든 여태껏 사용해온 모든 주소를 불러올 수 있게 되었다. 이 파트에서는 대표적인 지갑양식에 대하여 간략히 소개해 주겠다.

graph TD

지갑-->비결정적지갑
지갑-->결정적지갑
결정적지갑-->HD지갑

비결정적 지갑

비트코인에서 가장 처음으로 구현된 지갑 양식이며 가장 단순한 방법이다. 그 원리는 너무 간단하여 딱 한마디로 정리 할 수 있는데 "여태껏 사용한 모든 비밀키를 그냥 저장한다."이다. 다만 단순무식한만큼 몇가지 문제가 발생하게 되는데 비록 수백바이트에 불과하긴 하지만 거래를 할때마다 계속 지갑의 용량이 커지게되며, 언제나 디지털상태로 어딘가에 저장되어 있어야하다 보니깐 실수로 삭제라도 하게되다간.....다음은 상상에 맡기겠다. 물론 그런만큼 결정적지갑대비 장점도 존재하는데, 결정적지갑은 최초의 단서가 유출되면 그동안 사용한 모든 비밀키도 같이 유출되는 반면 비결정적지갑은 지갑전체가 유출되어야 모든 비밀키가 유출된다는점을 생각해볼때 보안이 조금더 강하다고 할 수 있다. 다만 생각보다 그렇게 큰 보안적 이득이 생기는것이 아니며, 실수로 삭제하게되어 모든 비밀키를 날려버릴 개연성이 더 큼으로 비결정적 지갑보다는 결정적지갑을 사용하는것을 권장한다.

결정적 지갑

결정적 지갑은 다음과 같은 아이디어를 생각해보면 쉽다. 일단 자신이 기억하기 쉽지만 남은 추측하는게 어려운 어떤 문자열을 정한다. (여러분의 네이버 비밀번호정도를 상상하면 좋을것 같다.) 그리고 이 문자열의 해시값을 구하고 그 해시값을 비밀키로 정한다. 그 다음은 이전 비밀키의 해시값을 비밀키로 정한다. 그 다음은..... 이걸 계속 반복하다보면 우리는 어떤 문자열 하나만 기억해두면 특별히 백업을 고민할 필요도 없이 우리가 사용하기에 충분한 비밀키를 생성할 수 있으며, 컴퓨터가 랜섬웨어에 걸려 모든 비밀키에대한 정보가 암호화되어 결국 복원 못하게 삭제되게 되어도 어떤 문자열만 알고있으면 쉽게 복원할 수 있게된다.

graph LR

어떤문자열-->|해시함수|비밀키1
비밀키1-->|해시함수|비밀키2
비밀키1-->공개키1
공개키1-->비트코인주소1
비밀키2-->|해시함수|비밀키3
비밀키2-->공개키2
공개키2-->비트코인주소2
비밀키3-->공개키3
공개키3-->비트코인주소3
비밀키3-->...이하생략

이게 결정적 지갑에대한 기초적인 아이디어 이다. 다만 편한만큼 보안적으로 위험하기도 한데, 위 방법의 경우 처음 문자열만 알면, 아니 중간에 사용되는 비밀키 하나만 알아내는데 성공하면 다른 비밀키도 유출될 수 있다는 것이다. 이런 상황을 조금이나마 방지하기위해 다음과 BIP32를 통해 HD지갑, Hierarchical Deterministic Wallets,이 제안되었다. 현재 대다수의 지갑프로그램은 이 표준안에 따르고 있어, 사용자가 12개의 단어만 기억하면 기기 자체에 비밀키가 저장되어있지 않아도 언제 어디서든 어떤 프로그램을 통해서든 비밀키와 그에따른 비트코인 주소를 불러올 수 있다.

연상기호(mnemonic)

프로그램에 따라 다르긴하지만, 비트코인 지갑을 처음 생성할때 12개의 단어를 기억하라는 메세지를 본적 있을것이다. 이부분은 앞에서든 예시에서 처음 "어떤문자열"을 어떻게 정할까?의 부분과 상관이 있다. 개개인이 모두 알아서 정말 예측불가능해서 컴퓨터로 일일히 대입해봐도 수백년뒤에 뚫릴만한 문자열을 사용한다면 이런방법이 나올 필요도 없었겠지만, 아쉽게도 대부분의 경우 "0000"같은 간단한 문자열을 사용하거나 다른 사이트에서 비밀번호로 사용했던 문자열을 그대로 가져오는것이 현실이다. 게다가 일반적인 웹사이트가 아이디와 비밀번호를 동시에 맞춰야한다면, 비트코인의 경우 비밀번호만 맞추면 그대로 비밀키가 유출되어 훨씬더 안전한 수단이 필요하다. 가장 간단한 방법은 컴퓨터가 완벽한 임의의 문자열, 아니 비트열을 골라주는것이다. 컴퓨터가 임의의 128bits를 만들어주기만 해도 $$2^{128}$$개의 경우의수가 발생하여 전세계의 모든 컴퓨터를 연산에 투입해도 어느 누구의 비밀키를 1세기 안에 찾아내는것은 불가능할정도의 안전함을 보장할 수 있다. 하지만 이것 또한 한가지 문제가 있으니, 사람이 기억하기가 힘들다. 이를 위해 생겨난 방법이 비트열을 12~24개의 문자열로 바꿔주는 "연상기호"이다.

사실 이는 비트코인에서 처음 제시된 방법은 아니고 기존에 쓰던방법을 비트코인에서 채용한것에 가까운데, 일단 128bits~256bits 사이의 임의의 데이터를 난수발생기를 통해 발생시킨다. 그 후 만들어진 데이터 뒤에 나중에 입력 실수했을때 잡아내기 위해 데이터의 해시값의 첫 몇바이트를 뒤에다 붙힌다. (이는 Base58Check에서 행한 과정과 목적이 비슷하다.)(이를 검사합이라 부른다.) 그리고 이를 11비트 단위로 나눈다. 그럼 각 11비트는 1에서 2048=2^11 사이의 숫자로 표현 가능한데 이를 미리 정해둔 기억하기 쉬운 영어단어와 매칭시킨다. 그럼 상황에 따라 12단어에서 24단어 사이의 영어단어가 나타나게 되는데 사용자는 이 12~24개의 단어만 기억하면 된다. 만약 잘못기억해도 맨뒤에 포함된 오류보정 데이터가 확인해주기 때문에 몇번 시행착오를 거듭하다보면된다. 이렇게 완성된 영어단어는 대략 다음과 같은 모습을 지닌다.

scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump

이걸 어떻게 왜울지는 각자의 재량에 달렸고, 개인적으로는 그냥 나온 영어단어를 외우기보다는 연상해서 외우기 쉬운 문자배치가 나올때까지 여러번 돌려보는걸 추천한다. 다만 아쉽게도 이 방법은 영어 이외에도 일본어, 스페인어, 중국어, 프랑스어, 이탈리아어 버전이 있지만 한국어는 현재 없는 상태이니 참고 바란다.

HD지갑 BIP32

일단 BIP란 Bitcoin Improvement Proposals 의 약자로 한국어로는 대략 "비트코인 개선을 위한 제안사항"정도 되는 존재이다. 일반적으로 비트코인 포럼에서 논의되고 결정된 사항이 BIP문서로 작성되고 각 제안에대해서는 순서대로 번호가 붙게된다. BIP32의 경우 32번째로 등록된 BIP정도의 의미를 가지며 구글에 검색해보면 그 원본문서를 쉽게 관람할 수 있다.

이러한 비트코인에 대한 개선사항이 담겨있는 BIP32에는 결정적인 지갑의 표준화를 위해 HD지갑을 제시하였다. HD지갑은 Hierachical Deterministic Wallets의 약자로 한국어로 번역하면 "계층 결정적 지갑"정도의 의미를 가진다. 여기서 계층이란 HD지갑이 계층적인 구조로 사용자가 기억하는 비트열(정확히는 연상기호)로 각각의 개인키와 공개키를 유도해내는 상황을 빗대어 지어진 이름인데, 자세히 들어가면 길고 복잡하며 위에서 해시함수를 예로들어 설명한 방법과 개념적으로 유사하기에 이에대한 설명은 넘어가도록 한다.

다만 처음에 제안될때 그 방법이 꽤 느슨하고 열려있게 제안되어서 같은 문서를 보고 작성한 프로그램간에 서로 호환이 안될 여지가 보였기에 BIP43과 BIP44에서 추가적인 문서가 작성되었고, 위에서 말한 연상기호법은 BIP39에서 추가되었다는점을 참고해두자.

현재 대부분의 비트코인 결정적 지갑은 BIP32에 따르거나 따를 예정이라고 하며 대다수의 주어진 12개에서 24개 사이의 단어를 외우라고 요구하는 지갑은 HD지갑일 확률이 높다. 만약 자신이 외운 단어가 정말 HD지갑을 따라 생겼는지, 자신이 외운 단어로부터 어떤 비트코인 주소가 생성될 수 있는지 확인해보고 싶다면 다음 주소에 들어가보자. https://github.com/iancoleman/bip39/releases 이 프로그램은 웹브라우저에서 작동하며 사용자가 기억한 단어로부터 생성가능한 비트코인 주소와 비밀키를 알려준다.

거래의 생성 및 전파

개요

비트코인 거래는 Transaction(이하 Tx라 표현함)이라는 "어떤 비트코인 주소로부터 어떤 비트코인주소로 얼만큼의 금액을 보낸다."같은 정보가 담긱 거래 데이터를 생성하는 것 으로부터 모든것이 시작된다. 이러한 거래데이터는 작성될때 같은 주소로부터 두번 지불되는, 즉 이중지불문제를 해결하기위해 비트코인은 input, output, UTXO라는 개념을 만들어 내었고, 또 개인과 개인간의 거래뿐만이 아닌 기업과 기업간의 거래도 지원하기위해 스크립트형식의 인증수단을 도입하였다. 이 파트에서는 이에대한 개념을 가능한 쉽게 이해할 수 있도록 간략적이면서도 자세히 설명한다.

표 읽기

컴퓨터 관련분야에대한 경험이 있으면 당연한 내용이긴하지만 컴퓨터를 접한적없는 사람들을 위해 데이터 구조를 설명하는 표에대한 간단한 설명을 해보자 한다. 일단 컴퓨터는 기본적으로 멍청하고 이를 똑똑하게 하기위해서는 많은 컴퓨터 자원을 소모하게 되기 때문에, 컴퓨터상에 존재하는 거의 대부분의 데이터는 어떤 특정한 규격 에맞춰 작성된다. 이 규격이라는것은 대체로 이런식이다.

처음부터 4Byte는 이 데이터가 어떤 버전의 데이터 표준을 사용했는지 적어둔다.

그 다음 4Byte는 앞으로 몇 개의 문자가 적힐지에 대한 숫자를 적어둔다.

그 다음에는 위에서 밝힌 개수만큼 문자를 작성한다.

그리고 표준문서에서는 위와같은 내용과 그에대한 상세한 해설을 다 적어둔다. 하지만 위와같이 적어두면 보기 힘들고 한눈에 들어오지 않는다. 그래서 데이터에대한 표준을 작성할때 애용하는것이 바로 표 이다. 사실 정해진 규격은 없는데 대체로 다음과 같다.

크기 이름 타입 설명
4Byte 버전 int 버전에 대한 정보
4Byte 문자카운터 int 앞으로 적힐 문자열의 길이
가변적 문자열 string 문자열

위에서부터 시작해 크기만큼의 공간이 각 필드를 위해 할당되어 있으며 각 필드를 타입에 적힌 형식으로 읽어온다고 해석하면 된다.

int는 integer의 약자로 정수를 표현할때 사용되는 타입, 읽기 방식이며 string은 문자열을 표현할때 사용되는 타입이다. 타입은 int, string, char, double 처럼 관습적으로 정해진것도 있고 compactSize uint, TxIn, outpoint 처럼 비트코인 자체에서 새로 정의한 타입을 사용하는 경우도 있기 때문에 참고하고, 궁금하면 구글에 검색해보면 어떻게 구현된 타입인지 자세히 설명되어 있다.

거래가 일어나는 전체적인 흐름

상상해보자 B라는 비트코인 계좌에 현재 A로부터 입금되어 블록체인상에서 인정된 2BTC가 존재하며 B계좌의 소유주는 C계좌로 1.5BTC를 보내고 싶어한다.

graph LR

A-->|2BTC 송금완료|B_2BTC소유
B_2BTC소유-->|1.5BTC 송금예정|C

은행계좌의 경우 위를 구현하는 방법은 무지 간단하다. 일단 원래 A에 있던 2BTC를 차감하고 B에 2BTC를 추가하며, 나중에 B로부터 요청이 들어오면 B에서 1.5BTC를 빼고 C에 1.5BTC를 추가하면 된다. 이러한 방법은 일반적으로 많이 사용되는 방법이며 비트코인 다음으로 (혹은 비트코인보다)규모가 큰 이더리움 또한 이러한 방식을 채용했다. 하지만 비트코인이 선택한 방법은 이러한 방법이 아닌 송금된 돈을 입력으로 다른계좌로 출력하는 방법이다. 즉, B계좌로부터 송금을할 때 A계좌로 부터 온 돈을 입력으로 원래 송금 예정인 1.5BTC를 C로 출력하고 남은 0.5BTC를 거스름돈으로써 다시 B로 출력하는 방법이다.

graph TD

subgraph Transaction0
Tx0_in["Tx0: ...(생략)..."]-->Tx0_out[2BTC를 A로 보냄]
end
Tx0_out-.->Tx1_in
Tx1_out-.->Tx2_in


subgraph Transaction1
Tx1_in["Tx1: Tx0에서 A가 받은 돈 2BTC중"]-->Tx1_out[2BTC를 B로 보냄]
end

subgraph Transaction2
Tx2_in["Tx2: Tx1에서 B가 받은 돈 2TC중"]
Tx2_in-->Tx2_out1["1.5BTC를 C로 보냄"]
Tx2_in-->Tx2_out2["0.5BTC를 B로 보냄"]
end

즉, 위 그림에서 Tx1에는 B에 2BTC를 A로 부터 받았다는 기록이 있고, Tx2에는 Tx1에서 자신(B)에게 출력된 2BTC를 입력으로 다시 C에게 1.5BTC, B에게 0.5BTC를 출력하는 것이다. 이렇게 출력된 값은 추후 다른 Tx에서 입력값으로 사용되며, 출력은 되었으나 입력으로 사용된적이 없는 출력값 (즉 언젠간 사용 가능한 값)을 UTXO라고 한다.

UTXOUnspent Transaction Output의 약자로 번역하면 소비되지 않은 출력값정도의 의미를 가진다. 이러한 UTXO의 기억할만한 특징중 하나는 "절대로 쪼개지지 않는다."이다. 이에대해 자세히 설명하기 전에 다음 예시를 한번 보도록 하자. C주소가 B와 A주소로부터 각각 0.5BTC를 받아 1BTC가 된 상황에서 D주소로 0.8BTC를 송금하려고 한다 어떻게 해야할까?

graph LR
subgraph Transaction1
Tx1["Tx1: Tx?에서 A가 받은 돈 중"]-->C0[0.5BTC를 C로 보냄]
end
subgraph Transaction2
Tx2["Tx2: Tx?에서 B가 받은 돈 중"]-->C1[0.5BTC를 C로 보냄]
end

정답은 다음과 같다.

graph LR
subgraph Transaction3

Tx3["Tx1에서 C가 받은 돈"]-->C[0.5+0.5=1BTC 중]
Tx2["Tx2에서 C가 받은 돈"]-->C
subgraph 입력
Tx3
Tx2
end
subgraph 출력
D
E
end
C-->D[0.8BTC를 D로 보냄]
C-->E[0.2BTC를 C로 보냄]
end

Tx3가 발생하기 전 C에게는 Tx1와 Tx2로부터 각각 0.5BTC의 UTXO가 있었고 이 둘의 입력값(=1BTC)를 통해 D에게 0.8BTC를 출력하고 0.2BTC를 다시 자신의 계좌로 반환하는 상황이다. 여기서 (사실 첫 예시로도 설명 가능하지만) 알 수 있는 사실은 UTXO는 본래 그 상태로는 절대로 쪼개지지 않아 0.8BTC만 필요한 상황에서도 0.5BTC의 값을 가지는 UTXO 두개를 입력으로 받아와 1BTC로 만든 뒤에야 이를 쪼개 0.8BTC와 0.2BTC로 출력 가능하다는 것이다. 이는 바이트단위로 수수료를 매기는 비트코인 정책상 사용자 입장에서는 매우 중요한 사항인데, 만약 0.01BTC를 꾸준히 지급받은 어떤 계좌로 1BTC를 송금하는 상황이 생긴다면 100개의 0.01BTC의 값을 가지는 UTXO를 입력으로 써야되며 하나의 입력당 약 180Byte의 공간을 차지하게되어 최소 18KB이상의 크기를 가지게되어 결국 엄청난 양의 수수료를 지불하게 될것이니 이부분은 사용자입장에서 주의해야 할 사항이다.

수수료의 함정

비트코인에서는 거래가 발생할때마다 수수료를 지불하며, 해당 수수료는 채굴자가 가져가게된다. 이러한 채굴자에게의 수수료 지불은 채굴자들이 비트코인 네트워크를 계속 유지하게 하는 동기로 작용하며, 수수료를 남보다 많이 지불하면 채굴자는 남보다 먼저 블록체인에 포함시켜주려고 노력하게되니 너무 아까워 하지는 말자. 하지만 위에 보여준 과정에서 수수료를 지불하는 과정은 없었다. 그럼 이 수수료는 어떻게 지불되는 것일까?

일단 위 과정에서 입력값에서 쓰고남은 출력값은 자신의 계좌로 출력하는 과정을 확인할 수 있다. 만약 이 과정이 존재하지 않으면 어떻게 될까? 그럼 입력값이 출력값보다 큰 상황이 발생할 것이다. 첫번째의 경우 2BTC가 입력되고 1.5BTC만 출력되며 두번째의 경우 1BTC가 입력되고 0.8BTC만 출력되는 것이다. 그럼 그 차액은? 바로 이것이 수수료이다. 비트코인에서 수수료는 각 거래에서 입력값의 총합과 출력값의 총합의 차이만큼이다. 이러한 구조는 사용자로 하여끔 주의하게끔 하게 되는데 만약 10BTC 의 UTXO를 사용하여 다른 계좌로 1BTC를 지불할때 제대로 자신의 계좌로 출력되게 하지 않으면 나머지 9BTC는 그대로 채굴자에게 수수료로 지불되는 것이다! 반대로 10BTC를 입력으로 쓰고 총 출력값이 10BTC가 되면 수수료는 하나도 지불하지 않은 것이 되며, 대부분의 채굴자들이 최후의 우선순위로 둘것이기에 Tx이 블록체인에 포함되기까지 아주 오랜시간 걸리거나, 어쩌면 영원이 포함 안될수도 있다.

하지만 너무 걱정하지는 말자. 대부분의 비트코인 지갑이 수수료의 적당량까지 계산해서 알아서 지불금액과 수수료를 빼고 남은금액이 자신의 계좌로 들어올 수 있게 해준다.

거래의 생성

Transaction(Tx)의 구조

Tx데이터가 실제 어떻게 구성되어있는지 확인해 보자.

크기 이름 타입 설명
4Byte Version uint32_t Tx 표준 버전을 의미하며 2017년 기준 버전 1 을 사용하고 있다.
1~9Byte tx_in count compactSize uint 입력에 몇개의 UTXO가 오는지 표시한다. 비트코인에서 만든 compactSize uint라는 타입을 사용한다.
가변적 tx_in txIn 과거의 Tx에서 사용되지 않은 출력값(UTXO)의 정보가 담겨있다.
1~9Byte tx_out count compactSize uint 출력에 몇개의 UTXO가 오는지 표시한다.
가변적 tx_out txOut 이 Tx에 오는 입력값들을 어떤 주소로 얼만큼 출력할지에대한 정보가 담겨있다.
4Byte lock_time uint32_t 잠금시간이라 부르며 여기 정해진 시간 이후에, 혹은 여기 저정해진 몇번쨰 블록이후로 블록체인에 포함되게 할 수 있다. 일반적으로 잘 사용은 안하며 보통 0이다.

이 중 TxIn은 다음과 같은 양식을 가진다.

크기 이름 타입 설명
36Byte previous_output outpoint 입력에 사용될 Tx의 SHA256d의 값과 색인번호에 대한 정보가 담겨있다.
1~9Byte script bytes compactSize uint signature script의 크기를 Byte단위로 나타낸다. 최대 10,000까지만 입력가능
가변적 signature script char[] 입력 스크립트. 추후 설명
4Byte sequence uint32_t 이 거래의 일련번호정도로 생각하면 된다. 잠금시간이 0이 아닌 Tx가 블록체인에 포함되기전 해당 거래를 취소시키기 위해 존재한다. 안쓰는경우 0xFFFFFFFF의 값을 가진다.

비트코인은 각각의 Tx의 고유번호(지문)를 표시하기위해 해당 거래 Tx 전체를 SHA2에 넣고 두번 돌린것, 즉 SHA2(SHA2(Tx))의 값을 쓴다. 이렇게 SHA2를 두번 돌린것을 SHA256d라 한다. 다만 2017년기준 2억개를 돌파한 비트코인 Tx들을 SHA256d 해시값만으로 찾아내기에는 시간이 오래걸리니깐 (물론 해시테이블이라는 단어가 있을정도로 색인하면 충분히 빠르긴 하지만) 32Byte는 해시값을 나타내고 나머지 4Byte는 uint32 형식으로 첫 거래부터 0으로 시작해서 하나하나 번호를 붙혀 탄생한 index값에대한 정보가 담겨있다.

다음으로 TxOut은 다음과 같은 양식을 가진다.

크기 이름 타입 설명
8Byte value int64_t 지불될 비트코인 양을 사토시단위로 나타낸 값
1~9Byte pk_script bytes compactSize uint pk_script의 크기를 Byte단위로 나타낸다. 최대 10,000까지만 입력가능
가변적 pk_script char[] 출력 스크립트, 추후 설명

입력-출력 스크립트의 경우 아마 다른경로를 통해 비트코인을 공부한적이 있다면 잠금-해체 스크립트, 서명-공개키 스크립트 등의 용어를 들어본적 있을것이다. 본래 서명-공개키 스크립트가 본래 명칭이긴 하지만, 현재 많은 실시간으로 블록체인의 상태를 보여주는 사이트들이 각각을Transaction의 입력(input)부분에 존재해서 입력(input) 스크립트, 출력(output)부분에 존재해서 출력(output) 스크립트라 부르고있기에 이 책에서도 혼란을 줄이기 위해 입력 스크립트출력 스크립트의 용어를 사용하겠다.

이 입력-출력 스크립트는 간단히 말해서 전자서명과 관련해서 해당 거래가 제대로 되었음을 증명해주는 과정을 보여주는 "스크립트"란 프로그래밍 언어로 작성된 소스코드이다. 이것이 정확히 어떻게 증명을 해주는지 살펴보기전에 먼저 비트코인 내에서 그냥 "스크립트"라 불리는 이 언어가 어떤구조로 작동하는지 알아보자.

스크립트

스크립트는 아주 초기형태의 프로그래밍 언어와 작동구조가 매우 유사하다. 일단 초기 프로그래밍언어에서나 쓰던 후위 연산자(혹은 역폴란드식 표기법이라고도 함)를 사용하며 Stack기반으로 실행된다는 점에서 1970년대에 개발된 Forth라는 언어와 많이 닮았다고 한다. 다만, 이는 필자가 태어나기도 전의 일이므로 그 분류에 대해서는 자세히 다루지 않겠다. 중요한점은 이 언어가 "스택"을 적극적으로 활용하는 구조라는 것이다.

스택이란?

컴퓨터 자료구조를 배우면 항상 몇몇가는 수십년째 지치지도 않고 항상 조금도 바뀌지 않고 그대로 나오는데 그중 하나가 스택(LIFO라고도 불린다.)이란 것이다. 그 개념은 꽤나 단순하다. 프링글스를 아는가? 길다란 통속에 감자칩이 차곡차곡 쌓여있는 과자인데 그러한 길다란 통을 생각해보자. 이 프링글스 통은 위쪽으로만 집어넣을 수 있으며 꺼낼때는 항상 마지막으로 넣은것부터 꺼낼 수 있다. 이게 바로 스택이라는 자료구조이다. 어떤 공간에 데이터가 들어갈 수 있는데 꺼낼때는 마지막으로 들어간것부터 순서대로 꺼낼 수 밖에 없는 것이다. 물론 컴퓨터는 모든게 가상에서 이뤄지니 넣을떄도 마음대로 꺼낼때도 마음대로를 구현할 수 있지만 이러한 스택구조는 컴퓨터의 자원을 적게 잡아먹으며 이러한 구조를 사용하므로 이득인 상황이 꽤나 있어서 지금도 그 중요성을 인정받고 있다.

일단 다음은 "3+7==10"(3+7은 10이랑 같은가?) 라는 내용을 "스크립트"로 작성했을때 나타나는 형태이다.

3 7 ADD 10 EQUAL

이 언어는 왼쪽부터 오른쪽으로 차례대로 실행되며 아래 표는 각 데이터가 어떻게 처리되는지를 보여준다.

스택 상황 입력되는 데이터 남은데이터 설명
3 3 7 ADD 10 EQUAL 3을 그대로 넣는다
3, 7 7 ADD 10 EQUAL 7을 그대로 넣는다
10 ADD 10 EQUAL Stack으로부터 두개의 데이터를 꺼낸뒤 더하고, 더한값을 Stack에 넣는다.
10, 10 10 EQUAL 10을 그대로 넣는다.
True EQUAL Stack으로부터 두개의 데이터를 꺼낸뒤 같은지 비교한다. 같으면 True를 넣는다.

이러한 "스크립트" 언어에서 ADD나 EQUAL같이 사용가능한 명령어는 "https://en.bitcoin.in/wiki/Script"에서 확인 가능하다. 단, 이러한 사용가능한 명령어 중 반복문같은 일반적인 프로그래밍 언어에서는 필수적으로 있는 요소가 빠져있는 사실을 확인할 수 있는데, 덕분에 이 언어는 "튜링 불완전성"을 띈다. 이는 의도된 사항인데, 가장 간단한 예로 만약 누군가 무한루프가 반복되는 스크립트 언어를 Tx안에 포함시켜서 배포하게 되면 해당 Tx이 정당한건지 검증하는 컴퓨터들은 무한루프속에서 헤어나오지 못하게 될것이고, 이는 비트코인에게 있어 바람직한 현상은 아닌 것이다. 이 때문에 비트코인은 오류를 일으킬 가능성이 있는 명령어는 미리 비활성화 시켜놨다고 한다. 덕분에 비트코인의 "스크립트"를 사용해 논리오류를 일으킬수는 없다고 한다.

한편, 비트코인의 "스크립트"와 유사하게 이더리움에는 "솔리디티"가 존재한다. 솔리디티의 경우 비트코인과는 다르게 튜링 완전한 언어이며 이더리움의 고유한 특징인 "스마트 컨트랙"을 구현하기 위해 존재한다. 이 스마트 컨트랙을통해 이더리움은 블록체인을 메모리처럼 사용해 어떤 프로그램을 실행시키고 현실에서 자동이체나 수익분배같은 다양한 작업을 프로그래머의 생각대로 자동으로 실행될 수 있게 하였다. 또한 프로그램을 실행할때 한번의 명령어당 수수료를 부과하는 방식으로 무한루프의 폐해를 이겨냈지만, 자유도가 높다는것은 그만큼 취약점이 존재할 수 있다는것. 결국 2016년 중순 이러한 취약점을 이용해 이더리움에서 이더리움 자체의 버그를 이용해 부정행위가 일어났고 이 일은 이더리움 하드포크 사태까지 일어나게 하였다.

아직 이더리움과 같은 스마트 컨트랙이 과연 비트코인에 있어 적합한가 아닌가는 모른다. 다만, 필자 개인적으로 생각하기에는 은행에서 자동이체는 해주지만 돈 자체에 자동이체 기능이 있는것은 아닌것처럼, 스마트 컨트랙과 같은 기능은 신뢰할만한 제 3자가 대행해주고 비트코인은 화폐 그 자체로 남아있는게 좋지않나? 싶다.

비트코인에서는 이런식으로 마지막까지 코드가 실행 된 후 True가 남아있으면 해당 "스크립트"는 "유효한"것이라 판단한다.

표준거래

물론 "스크립트"는 모든것은 아니어도 어느정도 자유로운 프로그래밍이 가능하지만, 중요한건 이걸 검증하는 채굴자가 마음대로 작성된 코드를 받아들일지 말지에 대한 결정권을 가지고 있다는 것이다. (위와같은 3 7 ADD 10 EQUAL로 거래가 성사되버리면 심히 곤란하다!)

일반적으로 임의로 작성된 코드는 블록체인에 포함되도록 허용되지 않고 "표준거래"로 명시된 거래들만 제대로 인정되며 블록체인에 포함되고 있다. 표준거래에는 일단 가장 많이 사용되는 P2PKH(Pay to Public Key Hash, 비트코인 주소에 지불), 다중서명을 필요로하는 경우를 위한 P2SH(Pay to Script Hash), P2PKH와 P2SH에 의해 대체되어 잘 사용되지 않는 P2PK(Pay to Public Key)와 MultiSig 그리고 앞으로 추가될 가능성이 높은 P2WPKH(Pay to Witness Public Key Hash), P2WSH(Pay to Witness Script Hash) 등이 있다.

필자는 P2PKH만 알면 나머지는 비트코인 공식 문서를 확인하면 이해하는데 크게 어려움이 없을것으로 생각하므로, 이 책에서는 P2PKH가 정확히 어떻게 작동하는지, P2SH는 어떨때 사용하는지, 앞으로 추가될 P2WPKH는 이 책 후반부에서 다루도록 하겠다.

P2PKH

P2PKH란 Pay to Public Key Hash의 약자로 언어 그대로 해석하면 Public Key Hash에 지불하겠다는 의미이다. 일단 Public Key Hash란 우리가 앞에서 비트코인 주소 생성과정에서 나온 RIPEMD160(SHA2(Public Key))이와같은 함수를 사용해 나온 존재이다. 이를 Base58Check인코딩으로 표현하면 우리가 사용하는 비트코인 주소가 되는만큼 사실상 P2PKH는 비트코인 주소로 지불하겠다는 뜻으로 받아들이면 된다. 그럼 이 P2PKH는 어떻게 작동하는 것일까?

일단 P2PKH를 포함한 모든 표준거래는 크게 입력 스크립트부분과 출력 스크립트부분으로 나눠진다. 앞서 언급한 것처럼 출력 스크립트는 Transaction의 출력부에 기록되어 있으며 입력 스크립트는 Transaction의 입력부에 기록되어 있다. 이떄 P2PKH에 기록된 내용은 다음과 같다.

입력 스크립트: <sig> <Public Key>

출력 스크립트: DUP HASH160 <Public Key Hash> EQUALVERIFY CEHCKSIG

여기서 <sig>는 해당 계좌의 소유주가 비밀키로 암호화한 값이며 (Signature의 약자)

<Public Key><sig>를 복호화할 공개키이다.

비트코인에서는 입력 스크립트 를 먼저 실행한 뒤 출력 스크립트를 실행시켜 해당 거래의 유효성을 판단하며, 여기서 입력 스크립트에서 주어진 정보로 TxIn에 명시된 정보가 올바른 정보인지 검증 하며, 그 후 출력 스크립트는 주어진 공개키가 해당 비트코인 주소의 소유주인지 확인을 하게된다.

자세한 작동 순서는 다음 예시를 살펴보자. 다음 상황은 B가 A로부터 받은 2BTC를 그대로 C로 송금하는 상황이다.

graph LR
subgraph Tx2
subgraph 입력
B
end
subgraph 출력
C
end
B-->|2BTC|C
end
B_in-.-B
subgraph Tx1
subgraph 입력
A
end
subgraph 출력
B_in
end
A-->|2BTC|B_in[B]
end

먼저 Tx1은 주소A의 소유주가 작성한 부분이며 출력 스크립트부분에는 DUP HASH160 <B의 Public Key Hash> EQUALVERIFY CEHCKSIG와 같은 데이터가 담겨있어 <B의 Public Key Hash>, 즉 B의 비트코인 주소로 돈을 송금한다는 정보가 담겨있다. 그 후 주소B의 소유주가 작성한 Tx2의 입력 스크립트부분에는 <sig> <B의 Public Key>의 정보가 담겨있다.

이 두 데이터를 합치면 <sig> <B의 Public Key> DUP HASH160 <B의 Public Key Hash> EQUALVERIFY CEHCKSIG가 탄생하게 되는데 이를 실행시켜보면 다음 표와같이 나타난다.

스택 상황 입력되는 데이터 남은데이터 설명
<sig> <sig> <B의 Public Key> DUP HASH160 <B의 Public Key Hash> EQUALVERIFY CEHCKSIG <sig>를 그대로 넣는다.
<sig> <B의 Public Key> <B의 Public Key> DUP HASH160 <B의 Public Key Hash> EQUALVERIFY CEHCKSIG <B의 Public Key>를 그대로 넣는다.
<sig> <B의 Public Key> <B의 Public Key> DUP HASH160 <B의 Public Key Hash> EQUALVERIFY CEHCKSIG 맨 위의 데이터를 복제해서 그대로 넣는다. (Duplicate)
<sig> <B의 Public Key> <B의 Public Key Hash> HASH160 <B의 Public Key Hash> EQUALVERIFY CEHCKSIG 맨 위의 데이터를 RIPEMD160(SHA2(데이터)) 해준뒤 그 값을 그대로 넣는다.
<sig> <B의 Public Key> <B의 Public Key Hash> <B의 Public Key Hash> <B의 Public Key Hash> EQUALVERIFY CEHCKSIG <B의 Public Key Hash>를 그대로 넣는다.
<sig> <B의 Public Key> EQUALVERIFY CHECKSIG 맨 위의 두 데이터를 꺼내 같은지 비교한다. 같으면 계속 진행하고, 다르면 프로그램을 중단한다.
True CHECKSIG 서명이 유효한지 검사한다.

다만 여기서 생각해봐야할 점이 <sig>는 위 Tx중 어떤부분을 보증하느냐? 이다. 일단 <sig>값을 생성할 때 컴퓨터는 가장먼저 현재 Tx의 복사본 TxCopy를 만들고 TxCopy의 모든 입력스크립트 부분을 없는걸로 만든다. 그리고 보통은 TxCopy전체 데이터의 해시값을 그대로 암호화해서 <sig>값으로 등록한다. 이는 가장 많이 쓰이는 방법이며 가장 간단명료하지만 비트코인은 여기에 약간의 여지를 남겨두었다. 그것은 바로 의도적으로 몇몇부분의 데이터를 보증하지 않는 방법이다.

좀 더 기술적으로 파고들어가 보면 <sig>라는 데이터에는 <ecdsaSig>라는 실제 해시값을 암호화한 데이터와 <sigHash>라는 4Byte짜리 접미부로 구성되어있는데, 이 <sigHash>에 어떤 데이터의 해시값을 암호화 했는지에 대한 정보가 담겨있다. 현재 정해지고 비트코인에서 인정되는 방법은 다음 표와 같다.

ALL, NONE, SINGLE부분은 출력부와 관계된 내용이고 ANYONECANPAY는 입력부와 관계된 내용이며 둘이 조합하는 방식으로도 사용 가능하다. 다만 왜 이런구조를 채택한 것일까? 아쉽게도 필자도 모른다. 이 부분은 비트코인 개발 초기이후로는 크게 변화가 없던 부분이며 논의에 오른적도 별로 없기에 이러한 구조를 채택한 이유는 필자도 잘 모르겠지만 몇가지 상상은 해볼 수 있다. 예를들면 어떤사람이 고아원에 기부를 하기위해 목표 출력값이랑 제한시간인 잠금시간만 정해두고 SIGHASH_ANYONECANPAY형태로 어떤 Tx을 전파시켰다면 기부에 동참하는 사람들이 Tx에 자신의 UTXO를 마음대로 추가시킬수 있도록 해놓으면, 잠금시간이 만료되었을때 모금액을 달성하면 거래가 인정되어 사람들이 등록한 UTXO는 자동으로 소모되고, 만약 실패하면 UTXO는 소모되지않고 Tx은 자동으로 소멸하는 구조가 가능하다. 또 다른 예를 들면 팁문화가 존재하는 레스트랑과 같은 장소에서 SIGHASH_SINGLE을 설정한 Tx을 통해 손님이 레스토랑으로 가는 출력값만 확실히 한 뒤 나머지 금액은 마음대로 가져갈 수 있게 여지를 두어 해당 잔액을 웨이터가 팁으로 가져가게 할 수도 있다. 다만 이 모든것은 소프트웨어적인 구현이 필요하며, 아직 이게 구현된 비트코인 지갑 혹은 관련 프로그램은 존재하지 않아 아쉬울 뿐이다.

비트코인 개발 초기에는 지금 보여준 예시처럼 입력 스크립트출력 스크립트를 하나로 이어서 입력 + 출력 스크립트의 형태 그대로 프로그램을 실행시켰다고 한다. 하지만 나중에 이는 심각한 보안적 결함을 내포하고 있음을 알게됬는데 입력 스크립트에 이상한 값을 넣어두고 프로그램을 실행시키면 잠금 스크립트부분에서 오류가 발생해, 전혀 유효한값이 아닌데도 True가 나오는 상황이 발생할 수 있다는 것이다. 이를 확인한 비트코인 개발진은 그 후 입력 스크립트를 먼저 실행시켜 값이 유효한지 확인 한 뒤 잠금 스크립트를 따로 실행시키도록 프로그램을 변경했다고 한다.

P2SH와 MultiSig

P2SH는 Pay to Script Hash의 약자로 P2PKH가 Public Key의 해시값에 금액을 지불하도록 하는 수단이라면 P2SH는 Redeem Script라는 존재의 해시값에 금액을 지불하는 수단이라고 보면 된다. Redeem Script는 다음과같이 구성되어있는데 <최소 필요한 서명개수> <PubKey1> <PubKey2> <PubKey3> ... <총 서명개수> CHECKMULTISIG, 눈치 빠른사람은 이미 파악했다시피 이는 여러명의 비밀키 소유자들중 명시된 최소 서명에 필요한 사람수를 만족해야만 거래가 인정되는 방법이다.

Pay to Script Hash

리딤 스크립트: <최소 필요한 서명개수> <PubKey1> <PubKey2> <PubKey3> ... <총 서명개수> OP_CHECKMULTISIG

입력 스크립트: Sig1 Sig2 ... redeem_script

출력 스크립트: OP_HASH160 <Hash of redeem_script> OP_EQUAL

MultiSig

입력 스크립트: OP_0 Sig1 Sig2

출력 스크립트: <최소 필요한 서명개수> <PubKey1> <PubKey2> <PubKey3> ... <총 서명개수> OP_CHECKMULTISIG

본래 비트코인은 P2SH대신 MultiSig라는 수단을 사용해 다중서명이 필요한 거래를 처리했었지만, 기존 MultiSig는 Tx크기에 따른 수수료의 부담을 이 계좌로 입금하려는 사람에게 부담하게 하고 (그러니깐 어떤 기업에 돈을 지불하는 사람이 수수료를 더 많이 부담하게 된다!) , 어떤 사람이 해당 계좌로 송금하기 위해서는 해당 계좌에 사용되는 모든 Public Key에 다한 정보를 알고있어야해 사용하기 불편했으며 이에대한 개선판으로 나온것이 P2SH인 것이다. P2SH는 2012년 BIP16을 통해 제안되었으며 현재 다음과 같이 3으로 시작하는 비트코인 주소는 모두 P2SH를 사용하는 거래이다.

3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8

이는 실제로 존재하고 사용되는 주소임으로 궁금한 사람은 해당주소를 BlockChain.info 에 검색해보자.

거래의 전파

비트코인 네트워크

비트코인은 비트코인 네트워크에 참여하는 수많은 노드(Node)들의 기여로 유지된다. 각 노드들은 크게 다음과 같은 기능들을 포함하거나, 기기 성능이나 목적에 따라 포함하지 않을 수도 있다.

이름 설명
SIGHASH_ALL 0x00000001 모든 출력값에 대하여 보증함
SIGHASH_NONE 0x00000002 그 어떤 출력값도 보증하지 않음. 입력을 통해 주어진 금액이 어디로가던 신경쓰지 않음
SIGHASH_SINGLE 0x00000003 입력당 단 하나의 출력값만 보증함. 나머지 출력값은 어디로가던 신경쓰지 않음
SIGHASH_ANYONECANPAY 0x00000080 자신의 입력만 보증함. 다른 입력이 추가되어도 신경쓰지 않음
종류 기능
Wallet 비트코인 주소의 소유주임을 증명하는 비밀키에 대한 정보를 담고있다.
Block Chain 2009년이후로 모든 비트코인상의 거래내역을 담고있는 블록체인을 저장하고 있다. 2017년 현재 블록체인의 크기는 100GB정도 된다.
Routing Node 생성된 거래혹은 블록을 검증하고 전파하는 역할을 해준다.
Miner 생성된 거래를 모아 블록을 생성해 블록체인을 만들어준다.

비트코인상에서 거래는 대부분 지갑을 통해 생성된다. 이렇게 생성된 거래는 주변 Routing Node에 전파되고 해당 Routing Node는 또 다른 Routing Node로 전파시키고를 끝없이 반복해서 결국은 비트코인 네트워크에 존재하는 Miner에게 까지 도달하게된다. 그럼 바로 Miner에 도달한 Tx은 채굴을 기다리다가 결국 블록체인속에 포함된다.

하지만 이를 구현하는 과정은 쉽지 않다. 일단 시작부터 큰 문제가 발생하는데 TxIn에 사용할 UTXO의 정보를 어떻게 얻어올 수 있을까? 이다.

SPV 노드

스마트폰에서 비트코인을 사용하는 경우를 생각해보자. 스마트폰 용량은 최근 128GB를 넘어가는 것도 있긴 하지만 일부에 불과하며 100GB를 넘어가는 블록체인을 넣기에는 블록체인의 크기가 너무 크다. 하지만 스마트폰을 사용해 비트코인을 거래정보를 생성하려면 자신의 주소로 출력되었지만 사용된적은 없는, 즉 UTXO에 대한 정보가 필요하고 이에대한 정보는 블록체인 속에있다. 이러한 전체 블록체인은 가지고 있지 않지만 거래를 하기위해 제안되어 만들어진 개념이 SPV노드이다. SPV노드의 앞서말한 문제에대한 해결방법은 간단하다. 블록체인을 가지고 있는 노드에게 자신의 주소로 출력된 값들좀 알려달라고 요청하면 된다.

다만 여기서 또 문제가 발생한다. 첫째, 우리가 통신하는 전체 블록체인을 소유한 노드가 정직한지 모른다. 이 노드가 우리에게 실제 출력된 값보다 작은값이 출력되있다고 알려주어 우리가 더 많은 수수료를 지불하게 할수도 있다. 둘째, 우리가 통신하는 노드는 해당 비트코인 주소의 소유주가 누구의 디바이스인지 확인할 수 있다. 이는 익명성을 보장하려는 비트코인에게있어 환영할만한일은 아니다. 마지막으로 셋째, 만약 우리가 통신하는 노드가 정보를 주기를 거부한다면 우리는 거래를 생성할 수 없다.

일단 결론적으로 셋다 해결책은 나왔고 대부분의 비트코인 클라이언트에서 구현되어있다. 일단 첫번째 문제의 해결책을 살펴보자. 이부분은 이 파트의 제목인 SPV 노드와 관련되있는 사항인데 SPVSimplified payment Verification의 약자로 번역하면 간단한 지불검증 노드 정도 되는 존재이다. 이 SPV 노드는 여태껏 일어난 모든 거래에대한 정보는 알지 못하지만 어떤 거래정보(블록)이 주어져있을때 이것이 올바른지 검증할 능력이 있다. 자세한 방법은 추후 머클 트리에 대해 설명할때 언급하겠지만 간단하게 설명해보자면, SPV 노드는 블록체인에 존재하는 모든 블록의 헤더를 가지고 있다. 이 헤더의 크기는 무척 작아서 첫 블록 생성후 2017년 지금까지 모든 블록의 블록 헤더 크기의 합이 불과 40MB가 좀 안되는 크기로 스마트폰이 가지고있기 부담없는 크기이며 이 블록헤더는 각 블록에 포함되있는 거래내역을 증명할 수 있는 머클루트에 대한 정보를 가지고 있다. 이런 상황에서 SPV 노드는 상대에게 특정주소로 출력이 있는 거래데이터가 포함된 블록의 머클트리와 거래 데이터를 요청하면, SPV 노드는 받은 거래 데이터가 머클트리에 포함되있는 데이터란것을 확인하고, 해당 머클트리의 머클루트와 자신이 가지고있는 블록헤더에 기록된 머클루트를 비교하여 결국 상대방이 준 데이터가 올바른 데이터인지 불과 40MB좀 안되는 데이터로 확인 할 수 있다.

두번째 문제의 경우 블룸필터라는 방법으로 해결책을 제시하였다. 블룸필터의 원리는 간단하다. 일단 비트코인 지갑에서 잔액을 확인할 주소를 최소 2개 이상 준비한다. 그리고 각각의 주소는 0과 1로 표현 가능하다. 편의상 주소 1을 1011001100011이라 하고 주소 2를 0011010110001이라 해보자. 이제 이 둘을 OR연산 시킨다. (하나라도 1이면 1을 출력하는 연산이다.) 그럼 필터 101101110001이 탄생한다.

​ 1011001100011

OR 0011010110001

---=====----=-=-=-==

​ 1011011110011


1안

이 필터를 받은 노드는 모든 주소에대해 비교를 행하게 되는데 그 방법은 예상했다싶이 어떤 주소의 x번째 비트가 1일때 필터의 x번째 비트도 1인가? 이다. 만약 아니라면 해당 주소는 필터를 통과하지못하고 맞다면 해당 주소는 필터를 통과하게 될것이다. 이렇게 필터를 통과한 주소들은 당연히 SPV 노드가 요구로 하는것보다 많은양의 주소가 존재할텐데 이 원리를 활용해 블룸필터는 블록체인을 소유한 노드로 하여끔 어떤 비트코인 주소의 주인이 어떤 디바이스에대한 추청을 어렵게 한다.


2안

이 필터를 받은 노드는 모든 주수에대해 비교를 행하게 되는데 그 방법은 다음과 같다. 1. 필터와 비교해볼 어떤 주소와 OR연산을 해본다. 2. 그 결과값이 필터와 같은지 확인해 본다. 만약 같다면 해당 주소는 필터를 통과하게 될것이다. 이렇게 필터를 통과한 주소들은 당연히 SPV 노드가 요구로 하는것보다 많은양의 주소가 존재할텐데 이 원리를 활용해 블룸필터는 블록체인을 소유한 노드로 하여끔 어떤 비트코인 주소의 주인이 어떤 디바이스에대한 추청을 어렵게 한다.


실제 비트코인에서 블룸필터는 비트코인 주소를 그대로 사용하지 않고 출력 스크립트의 해시값을 이용하며, 단순한 작동원리를 가지고 있지만 그 단순함 덕분에 컴퓨터에서 연산속도가 매우 빨라 비트코인에 매우 적합한 방법이라 할 수 있다.

마지막으로 우리가 통신하는 노드가 정보를 주기를 거부하는 문제는 어떻게 해결할까? 사실 이 문제는 DoS, Denial of Service 라는 용어가 탄생할정도로 여기저기서 쓰이고 아직 완벽한 해결방법은 존재하지 않는다. 그래도 대안은 있는데 가능한 많은 블록체인을 소유한 노드와 통신을 시도해 확률적으로 서비스를 제공해줄 노드를 만나는 방법이다. 뭔가 해결책치고는 미온적이긴 하지만 참여를 전제로 설계된 비트코인에서 불참은 어쩔수 없는 사항이기도 하다. 일부에서는 이러한 서비스 제공에도 수수료를 지불하게하여 원활한 사용을 가능하게 하자는 말도 있었으나, 현재 서비스거부로 인한 문제가 발생한적은 없어 (적어도 필자가 듣기로는 없다.) 딱히 새로운 해결책이 나온상태는 아니다.

다른 노드와의 접촉

SPV 노드는 앞서 말한 방법들을 이용해 성공적으로 거래 생성에 필요한 정보들을 받아내고, 새로운 거래를 생성해낸다. 그 다음은 생성된 거래를 다른 노드로 전파시키기만 하면 된다. 일단 가장먼저 시작하는것은 시드노드(Seed Node) 에 접속하는 것 부터이다. 시드노드는 다른 비트코인처럼 꺼졌다 켜졌다 하지않고 네이버나 구글같은 사이트처럼 장기간 켜져있는 노드를 말하는데 2017년 기준 비트코인 클라이언트에 기본적으로 입력되어있는 시드노드의 종류는 다음과 같다.

  • seed.bitcoin.sipa.be
  • dnsseed.bluematt.me
  • dnsseed.bitcoin.dashjr.org
  • seed.bitcoinstats.com
  • seed.bitcoin.jonasschnelli.ch
  • seed.btc.petertodd.org

시드노드에 접속한 비트코인 클라이언트는 현재 비트코인 네트워크를 유지시키고 있는 다른 노드들의 IP주소를 요청하고 제공받습니다. 그후 제공받은 다른 클라이언트의 IP주소의 8333번 포트로 접속요청을 합니다. 이렇게 첫 P2P네트워크가 성립되었습니다. 이제 앞서 언급한 DoS 문제를 해결하기위에 접속한 첫 노드로부터 다른 노드의 IP주소를 요청을해 사용자 설정에따라 몇몇노드에 추가적으로 P2P네트워크를 구축합니다. 그럼 축하합니다! 여러분도 비트코인에 존재하는 하나의 노드가 되었습니다.

비상 메세지

일반적으로 잘 사용하진 않지만 비트코인 네트워크의 중대한 위험이 발견되면 비트코인 개발자들에 의해 비트코인 네트워크 전역으로 비상 메세지가 전파된다. 이 비상 메세지는 2017년 현재기준 총 12번 발생했는데 대부분의 내용은 "비트코인 규격이 업그레이드 되었으니 각자 비트코인 클라이언트를 새로운 규격에 맞게 업그레이드 해주세요"나 "소프트웨어에 중대한 보한결함이 발견되었으니 업데이트 해주세요"정도의 내용이었지만 딱 한번은 "블록체인이 지금 두갈래로 나가고 있으니 한가지를 포기해 주세요"라는 내용이 있었다. 이에관한 주제는 "블록 전파"부분에서 언급하겠지만 지금 살펴볼것은 비트코인의 긴급메세지는 어떻게 "비트코인 개발자"만 발생시킬 수 있을까? 이다.

일단 비트코인은 완벽한 분산화된 환경이고 중앙에서 통제하는 기관이 전혀 없다. 하지만 비상메세지는 정해진 몇몇사람만 발생 시킬 수 있다. 그 원리는 앞에서 지겹도록 다룬 전자서명이다. 현재 대부분의 비트코인 클라이언트에는 비트코인 개발자가 미리 정해둔 공개키가 포함되어 배포되고 있습니다. 이는 비트코인 클라이언트 종류마다 다르긴 하지만 대체로는 Bitcoin Core에 사용되는 같은 공개키가 포함되어있습니다. 비트코인에서 선택된 일부 개발자는 이 공개키에 맞는 비밀키를 가지고 있는데 자신이 보낼 메세지내용에 해당 비밀키로 서명을 하여 비상 메세지를 네트워크 전역으로 배포하게 된다.

다만 일부 채굴 프로그램은 이러한 비상메세지를 받는부분이 빠져있는경우가 가끔 있다. 이러한 비상메세지가 배포될때는 블록체인에 관련해 중대한 사건이 발생하고 자신의 채굴시스템에 변경이 꼭 필요한 경우일 수 있으니, 채굴장을 운영할경우 스마트폰에 간단한 비트코인 클라이언트를 같이 설치해 메세지를 언제 어디서든 확인할 수 있게 할것을 권장한다.

블록체인

개요

비트코인 세상에서 여러분이 발생되는 거래가 정확히 어느시점에서 승인되는지 다시한번 환기해보자. 일단 비트코인 지갑을 사용해 트랜젝션을 생성해 낸다. 그 후 이 트랜젝션을 비트코인 네트워크 전역으로 전파시키며, 채굴자는 비트코인 네트워크를 떠돌아다니는 트렌젝션들을 모아서 블록이라는 형태로 저장한다. 그 후 채굴의 과정을 거쳐 블록체인에 포함시키는 순간 여러분이 발생시킨 거래는 공식적으로 인정받게 되는 것이다. 그럼 여기서 블록체인이란 무엇일까?

사실 블록체인의 개념은 별로 복잡하지는 않아서, 그냥 딱 한마디로 표현할수도 있는데 "새로생긴 블록이 이전 블록을 증명해 주는 구조"이다. 물론 이것만으로 이해할 수 있는사람은 별로 없을것이라 생각해 좀 더 세부적으로 표현해 보자면, 일단 비트코인에서 블록은 매 10분에 하나씩 생겨난다. 그리고 새로 생긴 블록은 바로 이전에 새로생긴 블록의 해시값을 가지고 있는 형태이다. 그럼 이게 왜 대단한 것일까?

2017년기준 현재 블록체인상에는 약 50만개의 블록이 쌓여있다. 이 50만개의 블록중 필자가 100번째 블록에 있는 거래데이터를 조작하려고 한다 가정해보자. 그럼 100번째 블록의 해시값은 크게 변하게 될것이다. 그리고 그럼으로 인해 101번째 블록에 명시되어있는 100번째 블록의 해시값이 일치하지 않아 데이터가 조작되었음을 바로 확인할 수 있다. 이런 문제점을 파악하고 101번째 블록에 명시되어있는 100번째 블록의 해시값을 바꾸면 이번에는 102번째 블록에 명시된 101번쨰 블록의 해시값이 서로 달라지게 된다. 즉, 필자가 100번째 블록의 거래데이터를 조작하려면 필자는 100번째부터 가장 최근에 생긴 50만번째 블록까지 모두 조작해야된다는 것이다.

물론 이 모든것은 컴퓨터상에서 발생하는 일이니 간단한 프로그램만 짜면 단순히 N번째 블록이 N-1번째 블록의 해시값만 가지고 있는 50만개의 블록을 조작하는 일은 말그대로 순식간에 끝낼 수 있다. 이런일을 방지하기 위해 비트코인은 PoW(Proof of Work)라는 개념과 함께 채굴이란 시스템을 도입하였다.

이 파트에서는 비트코인의 블록의 구조에 대해 설명한 뒤, 비트코인의 블록체인이 어떻게 작동하는지, 채굴이란 무엇인지, 비트코인에서 운영되는 블록체인 말고 다른 블록체인은 어떻게 비트코인형태의 블록체인의 단점을 극복하려 했는지 등을 설명할 예정이다.

블록

개요

비트코인의 모든 거래데이터는 블록이란 형태로 저장된 뒤 블록체인에 포함된다. 이 블록은 크게 두가지 파트로 나뉘어 지는데 하나는 블록 헤더이고 나머지 하나는 블록 바디이다. 이름에서 예상할수 있는것 처럼 블록헤더에는 블록 그 자체에 대한 정보가 담겨있고 블록 바디에는 블록의 몸체, 즉 거래데이터가 담겨있다. 이번 파트에서는 이러한 거래데이터는 어떻게 담겨져 있는지로 시작해 블록 헤더는 어떤구조를 가져왔는지에 대해 자세히 알아보아 다음 파트에서 만날 블록체인을 이해하기 쉽게 도와줄 것이다.

다만 읽을 때 주의해야할 점이 있다. 2017년 7월 기준 블록은 언제나 약 10분에 한개씩 생성되어 왔으며 각 블록은 항상 1MB이하의 크기를 가져왔다. 이는 약속된 내용이였다. 하지만, 이러한 약속은 2009년 첫 블록이 생성될때 정해진 것이고, 2009년의 비트코인 상황과 지금의 비트코인 상황은 엄청난 차이가 있며, 현재 비트코인은 10분에 생성되는 1MB짜리 블록만 가지고는 모든 거래를 감당하기 힘든 상황에 놓여있다. 좀 더 쉬운표현으로 말하자면 처음 약속을 정할때 현재와 같은 상황을 염두하고 약속을 한 것이 아니기에 그 구조가 한계에 달했다는 것이다.

이러한 상황속에서 비트코인 개발자들은 2017년 8월 1일부터 시작해 2017년 말까지, 어쩌면 더 오랜시간에 거쳐 대규모 업그레이드를 강행할것을 예고해 왔다. 물론 상세한 업그레이드 내용은 이미 공개되어있기 때문에 그에 맞추어 글을 쓰면 되지만 더 큰 문제는 최근 거대한 3개의 비트코인 진영이 각각의 업그레이드 방안을 내놓았고 3가지 버전중 어느것이 더 많은 지지를 얻을지 필자가 이 글을 쓰는 시점에서는 파악할 수 없다는 것이다. 그래서 이 파트에서는 현재 시점으로 사용되는 블록에 대해 설명을 하고 부록형식으로 앞으로 바뀔 형식에 대해 자세히 다뤄볼 예정이니 참고바란다.

블록의 구조

블록은 다음표와 같은 데이터 구조를 가진다.

크기 이름 설명
4Byte Magic no 언제나 0xD9B4BEF9 를 가지는것으로 정해져있다.
4Byte Blocksize 블록의 총 크기가 몇바이트인지에 대한 정보가 담겨있다.
80Byte Blockheader 블록헤더
1~9Byte Transaction counter 해당 블록에 포함되는 Tx의 개수
가변적 transactions 각 사용자가 생성한 Tx들이 직렬화되어 들어있다.

그 다음으로 블록헤더는 다음과 같은 데이터 구조를 가진다.

크기 이름 설명
4Byte Version 블록 버전에 대한 정보가 담겨있다.
32Byte hashPrevBlock 이전 블록 헤더의 해시값이 담겨있다.
32Byte hashMerkleRoot 블록 바디의 머클 트리로부터 나온 머클루트값이 담겨있다.
32Byte Time 유닉스 타임스탬프를 사용한다.
4Byte nBits 이 블록헤더의 해시값이 충족해야할 조건에대한 정보가 담겨있다.
4Byte Nonce nBits를 만족시키기위해 채굴자가 마음대로 조작가능한 공간이다..

머클트리

필자가 처음 블록바디에 대해 알아보려 했을때는 C언어에서 흔히 쓰는 배열처럼 그냥 추가하려는 Tx들을 나열해 놓으면 되지 않을까?라는 생각을 했었다. 결론은 맞았다. 하지만 한가지 추가되는 내용이 있었는데 바로 머클트리의 존재였다.

머클트리는 랄프 머클(Ralph Merkle) 이라는 사람이 "Method of providing digital signatures"라는 제목으로 밝힌 특허에서 처음 공개되었다.

graph BT
Tx1-->H1["H1:Hash(Tx1)"]
Tx2-->H2["H2:Hash(Tx2)"]
Tx3-->H3["H3:Hash(Tx3)"]
Tx4-->H4["H4:Hash(Tx4)"]
H1-->H12["H12:Hash(H1+H2)"]
H2-->H12
H3-->H34["H34:Hash(H3+H4)"]
H4-->H34
H12-->H1234["H1234: Hash(H12+H34)"]
H34-->H1234

머클트리를 만들기위한 과정은 다음과 같다. 일단 가장먼저 블록에 저장된 각각의 Tx으로부터 해시값을 구한다. 여기서 사용되는 해시함수는 SHA256d로 Tx전체 데이터에대하여 SHA2를 두번돌린 값이다. 이렇게 Tx1부터 Tx4까지 각각 해시값을 구해냈으면 다음과정은 H1이라는 해시값 뒤에다가 H2를 붙혀 탄생한 새로운 데이터의 해시값 H12을 구한다. 같은과정을 H3, H4 쪽에도 행해준다. 마지막으로 H12라는 해시값 뒤에다가 H34를 붙혀 탄생한 새로운 데이터의 해시값 H1234를 구한다...... 이 과정은 최상위에 딱 하나의 노드가 남을 때까지 반복되며 이렇게 마지막으로 하나남은 노드를 머클루트라 하며, 이렇게 완성된 머클루트는 블록헤더에 블록바디 전체의 데이터를 보증해주는 역할로 저장된다.


여기서부터는 핵심만


그럼 이러한 머클트리 구조에서 머클루트존재 하나만으로도 블록 바디에 대한 무결성을 보증할 수 있다는것은 알겠지만 어떻게 SPV 노드가 이를 이용할 수 있을까? 아래 그림에서 SPV노드가 Tx4의 데이터를 받았을때, 이것이 올바른 데이터인지에 대해 증명해보려는 상황을 생각해보자.

graph BT

Tx1-->H1["H1:Hash(Tx1)"]
Tx2-->H2["H2:Hash(Tx2)"]
Tx3-->H3(("H3:Hash(Tx3)"))
Tx4-->H4("H4:Hash(Tx4)")
H1-->H12(("H12:Hash(H1+H2)"))
H2-->H12
H3-->H34["H34:Hash(H3+H4)"]
H4-->H34
H12-->H1234["H1234: Hash(H12+H34)"]
H34-->H1234

Tx5-->H5["H5:Hash(Tx5)"]
Tx6-->H6["H6:Hash(Tx6)"]
Tx7-->H7["H7:Hash(Tx7)"]
Tx8-->H8["H8:Hash(Tx8)"]
H5-->H56["H56:Hash(H5+H6)"]
H6-->H56
H7-->H78["H78:Hash(H7+H8)"]
H8-->H78
H56-->H5678(("H5678: Hash(H56+H78)"))
H78-->H5678

H1234-->H12345678
H5678-->H12345678["Merkle Root: Hash(H1234+H5678)"]

일단 SPV노드는 블록헤더에 포함되어있는 Merkle Root에 대한 정보는 알고있고 Tx4에 대한 정보는 받았으니 Tx4의 해시값인 H4도 알고있다. 그럼 여기서 Tx4에대한 정보를 추가적으로 알아내려면 H3, H12, H5678의 정보만 알면된다. 그 이유는 일단 H3와 H4를 이용해 H34를 구할 수 있으며 H34와 H12를 이용해 H1234를 구할 수 있고, 마지막으로 H1234와 H5678을 이용했더니 Merkle Root와 같은 값이 나오면 SPV노드는 완벽한 100%의 확률은 아니지만 거의 100%에 수렴하는 확률로 Tx4는 실제 블록에 포함되어있는 정보 그대로라는 것을 유추할 수 있는 것이다.

SPV노드는 이러한 머클트리의 특징을 통해 머클트리를 사용하지 않았다면 1MB에 달하는 블록을 통쨰로 받아야만했던 상황으로부터 벗어나, 받으려는 Tx 데이터 그자체와 일반적으로 블록안에 포함된 거래의 개수가 약 1000개라는 점을 생각할때 약 10개의 추가적인 32바이트짜리 해시값을 받아오는것 만으로도 자신이 원하는 Tx이 제대로된 Tx이 검증할 수 있는것이다.

일반적으로 Tx가 늘어남에따라 머클트리에서 인증을 하기위해 필요한 해시의 개수는 Log2(N)개, 2^10=1024

내용이 좀 부실....;;;; 수정 필요.

비트코인의 생성

눈치가 빠른 독자분들이라면 앞서 거래의 생성부분에 대한 설명을 읽고 있을떄 다음과 같은 한가지 의문이 들것이다.

거래의 입력으로 이전거래의 출력을 사용했다면 최초의 거래의 입력은 어디서부터 나온것인가?

이에대한 답을 알아보기위한 방법은 간단하다.

이전블록이 존재하지 않는 최초의 거래의 입력은 어디서 부터 나왔을까?

일단 비트코인상에서 최초의 거래는 2009년 1월 3일 오후 6시경에 발생했으며 BlockChain.info에서 보여주는 해당 거래 내역은 다음과 같다.

graph LR
subgraph TxId:4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
A["No Inputs (Newly Generated Coins)"] -->|50 BTC| B[1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa]
subgraph 입력
A
end
subgraph 출력
B
end
end

뭔가 이상하다. 입력값이 없고 새로 생성된 코인이라고 한다. 이게 어떻게 된 일일까?

앞서 여러번 밝혔다시피 블록은 채굴자에 의해서 생성된다. 그럼 채굴자들은 왜 채굴을 하는것일까? 당연히 비트코인을 벌기 위해서다. 그럼 채굴자들은 비트코인을 어떻게 벌 수 있을까? 이에대한 해결책으로 비트코인은 블록을 만들어낸 자에게 일정분량의 비트코인을 사용할 권리를 부여하였다. 이렇게 매 블록 생성되는 비트코인을 사용하는 거래를 Coinbase Transaction 혹은 생성거래라고 하는데 매 블록의 첫번째 거래는 생성 거래로 되어있는것으로 정해져 있으며 이 생성 거래의 데이터 구조는 다음과 같은 형태를 가진다.

크기 이름 설명
32Byte Previous Transaction hash 본래 이전거래의 TxId가 있어야 하나 없으므로 모든 비트가 0이다.
4Byte Previous Txout-index 본래 이전거래의 인덱스번호가 있어야 하나 없으므로 모든 비트가 1이다.
1~9Byte Coinbase data bytes Coinbase data의 크기를 Byte단위로 나타낸다.
가변적 Coinbase data 블록을 생성한 자가 자기가 원하는 데이터를 마음대로 집어넣을 수 있다.
4Byte sequence 무조건 0xFFFFFFFF

비트코인 채굴자는 Coinbase data부분에 자기가 원하는 메세지를 남길 수 있는데 비트코인의 개발자 사토시 나가모토가 처음으로 이곳에 남긴 메세지는 다음과 같다.

��EThe Times 03/Jan/2009 Chancellor on brink of second bailout for banks

실제 The Times라는 신문사에서 발행한 기사로, 비트코인의 개발동기를 엿볼수 있는 기사라고 한다.

지금은 이 공간을 완벽하게 개인이 자유롭게 사용할수는 없고 비트코인 개선안에대한 "투표"나 블록헤더에 추가되지 못한 블록의 추가정보, 채굴을 위한 가능성 확보등의 방법으로 사용되고 있다.

생성 거래를 통해 새로 비트코인 네트워크에 추가되는 금액은 매 블록마다 50BTC로 시작하여 매 210,000개의 블록이 생성될때 마다 (약 4년의 기간이다) 반씩 줄어들어 2012년 11월 블록당 25BTC, 2016년 7월 블록당 12.5BTC로 줄어들었으며, 그렇게 계속 줄어들어 2140년경이 되면 블록당 지불되는 비트코인이 없어져, 총 약 2,100만개의 비트코인이 블록마다 발행될 예정인데, 그럼 문제가 발생한다. 2140년 이후에는 채굴자가 받는 이득이 전혀 없는 것일까? 다행이도 그렇지 않다.

2017년 현재기준으로 새로생성되는 블록은 12.5BTC을 새로 생성한다. 하지만 생성거래부분을 보면 이보다는 확실히 많은 양의 비트코인을 받고있는것을 확인할 수 있는데 이부분이 바로 수수료를 회수하는 부분이다. 여러분도 알다시피 비트코인을 사용할때는 수수료를 지불해야하며 더 많은 수수료를 지불할수록 더 빨리 블록체인속에 포함될 수 있다. 이 수수료는 각 Tx의 입력값과 출력값의 차이만큼이 되는데 바로 이 차액이 생성거래부분에 더해지고 채굴자는 수수료를 회수할 수 있는 것이다. (당연하게도 채굴자는 더 많은금액을 받기위해 수수료가 높은 거래부터 처리한다.)

현재 통계상 매 블록마다 약 1BTC의 수수료가 채굴자에게 지불이 된다고 한다. 다만 채굴자들은 이 금액으로는 추후 기본 지급되는 비트코인이 반감되었을때, 운영되는 채굴장비의 유지비를 감당 못해 수수료를 올려야된다고 주장하고 반대로 사용자측은 지금 지불되는 수수료도 많다고 주장해 적절한 수수료의 값이 얼마인가에 대한 논의는 계속되고 있다.

비트코인 채굴의 핵심- 작업증명

개요

아이들이 가지고 놀기 좋은 정육면체 모양의 나무블록을 상상해보자. 블록A가 놓여져있다. 그 옆에 블록B를 두고 블록A와 블록B를 사슬로 엮어놓는다. 다음으로 블록 C를 블록 B옆에다 두고 블록 B와 블록 C를 사슬로 엮는다. 이제 여기서 블록 B를 들어올려보자. 블록 A와 블록 C가 같이 움직일 것이다.

비트코인의 블록체인은 위 상황과 매우 유사하다. 모든 블록은 사슬처럼 서로 묶여있으며 그중 블록 하나를 조작하려고하면 다른 블록들이 반응을 해서 블록이 조작됬다는 사실을 알려준다. 그럼 이게 데이터적으로 어떻게 구현되어있을까?

구현의 키워드는 데이터의 지문, 해시값이다. 비트코인상의 블록은 모두 이전블록의 해시값을 가지고 있다. 이렇게 다음블록이 자신의 해시값을 가지고 있는 상황에서 만약 해당블록이 조작되었다면 당연히 자기자신의 해시값이 달라져 다음블록에 적혀있는 해시값을 통해 조작된 사실을 쉽게 파악할 수 있다.

하지만 여기서 문제가 발생한다. 모든 블록의 해시값이 조작되면, 어떤 블록의 데이터가 조작되어도 파악할 수가 없다. 이런 상황에서 해시값이 조작되어도 판단할 수 있도록 비트코인에서는 PoW, Proof of Work, 작업증명 이라는 개념을 만들어 냈다. 이 작업증명은 자신이 이 블록을 만들기 위해 엄청난 노력을 했음을 증명해주는 내용이기도 하며, 현재 비트코인 채굴자들이 전세계 슈퍼컴퓨터는 아무것도 아니라는 엄청난 컴퓨팅 성능을 소모해서 하는 연산 또한 이 작업증명을 위한것이라고 보아도 된다.

이 파트에서는 이 작업증명이 무엇인지에 대해 다룬다.

블록헤더의 해시

비트코인에서 블록체인에 대한 설명에서 빠질 수없는것이 바로 블록 헤더이다. 그 이유는 위에서 말한 블록체인의 모든것이 블록 헤더에서 구현되어 있기 때문이다. 각 블록헤더는 바로 이전 블록헤더의 해시값을 가지고 있고, 각 블록의 해시값이 조작되지 않았음을 증명할 수단도 블록헤더에서 구현되어있다.

블록 헤더는 다음과 같은 정보를 가지고 있다.

크기 이름 설명
4Byte Version 블록 버전에 대한 정보가 담겨있다.
32Byte hashPrevBlock 이전 블록 헤더의 해시값이 담겨있다.
32Byte hashMerkleRoot 블록 바디의 머클 트리로부터 나온 머클루트값이 담겨있다.
32Byte Time 유닉스 타임스탬프를 사용한다.
4Byte nBits 이 블록헤더의 해시값이 충족해야할 조건에대한 정보가 담겨있다.
4Byte Nonce nBits를 만족시키기위해 채굴자가 마음대로 조작가능한 공간이다..

여기서 블록체인과 관련되어 주의깊게 살펴보아야 할 사항은 hashPrevBlock, nBits 그리고 Nonce이다. 일단 hashPrevBlock는 이전 블록의 해시값으로 블록체인의 핵심이라 할 수 있다. 하지만 nBitsNonce는 무엇일까?

이에대한 설명을 하기 앞서 다음을 살펴보자. 다음은 400,000번째 블록헤더의 해시값이다.

000000000000000004ec466ce4732fe6f1ed1cddc2ed4b328fff5224276e3f6f

뭔가 이상하다. 앞쪽에 0이 좀 많다고 생각하지 않는가?

단순히 우연일지도 모르니 바로 그 다음블록인 400,001번쨰 블록헤더의 해시값을 살펴보자.

000000000000000005421b1b2ee6d06d037557d7f5ec96852542413cfed40c22

여기에도 엄청난 0이 존재한다. 그뿐이 아니다, 그 다음블록도

0000000000000000016578099aab6d26d41c8815e9ab5f204f505ba4ac3c084d

그 다음블록도

0000000000000000053c5d6913444bcef2a5a2a6ec84cb0dbaef93e6ad3074ba

로 모두 앞에 0이 많이 존재한다는 사실을 알아낼 수 있다.

일반적으로 발생하는 해시값은

ca2099f4706a7b28c5550b304d1f51ef61389617358b45d9714de5f2699638fe

이런 형태를 가진다는 점을 생각해 볼때 위와같이 앞쪽에 0이나온다는 것은 의도되었단 것일까?

맞다.

조금만 생각해보면 어떤 데이터의 해시값이 앞부분이 저렇게 0이 많이 나올 확률은 매우 희박하다는 것을 알 수 있을것이다. 그런데 만약 실제 그러한 데이터를 찾아냈다면, 이는 엄청난 우연의 일치로 그런 데이터를 찾아냈던가, 혹은 엄청나게 많은 데이터의 해시값을 돌려본 끝에 해시값이 앞에 0이 많이 나오는 형태를 찾아냈다고 할 수 있을것이다. 비트코인에서 작업증명이란 바로 이 과정을 말한다.

자 이제 희박한 확률로 나타나는 해시값을 찾아내는게 작업증명 과정이라는 사실을 알았다. 그럼 채굴자가 찾하야 하는 해시값의 조건과 그 조건을 만족하는 해시값을 찾아내는법, 마지막으로 그러한 해시값을 찾아낼 확률이 얼마나 희박할지 알아보자.

nBits

일단 해시값이 만족해야할 조건은 nBits에 표현되어 있다.

일단 해시값을 바라보는 시점을 달리해보자. 우리가 보기에 해시값은

ca2099f4706a7b28c5550b304d1f51ef61389617358b45d9714de5f2699638fe

와 같은 이상한 문자열의 나열이다. 하지만 좀더 자세히 들여다 보면 이 표현은 64개의 16진수 숫자로 표현된 256Bits짜리 데이터임을 확인할 수 있다.

ca 20 99 f4 70 6a 7b 28 c5 55 0b 30 4d 1f 51 ef 61 38 96 17 35 8b 45 d9 71 4d e5 f2 69 96 38 fe

이말은 위 문자열은 결국 16진수로 표현된 숫자열 이라는 소리이고 이를 10진수로 바꾸면 다음과 같은 큰 숫자가 탄생한다..

91424797077149544937923234949946345081157190717769025043989719253972906555646

여기서 작업증명이 만족해야할 조건은 nBits에 표현되어있으며, 그 조건이란 nBits에 표현된 값보다 작아야 한다는 것이다.

단 nBits에 부여된 저장공간의 크기는 4Byte이며 4Byte의 저장공간으로는 32Byte크기를 가지는 숫자열을 표현하지 못하기에 다음과 같이 자연과학분야에서 많이 사용하는 지수표기법의 아이디어를 채용하였다.

Converting nBits Into A Target Threshold

지수표기법

물리학, 화학, 천문학에서는 일상적으로 사용하지 않는 엄청 큰 단위나 반대로 엄청 작은 단위를 사용할 일이 많다. 그럴때 마다 0을 많이 사용해서 해당값을 표현하는건 보기도, 쓰기도 힘들다. 그래서 생겨난 방식이 지수표기법이다. 대표적으로 지수표기법을 사용했을때 우주의 나이로 추정되는 150억년이라는 숫자는 $$1.5\times10^{10}$$년으로, CPU 공정단위를 표현할때 자주 사용되는 22나노미터라는 숫자는 $$2.2\times10^{-8}$$m로 보기쉽게 표현 가능하다. 컴퓨터 내부에서도 실수형 자료를 표기할때 이런방법을 응용한다.

위 그림대로 nBits에 저장된 4Byte중 앞의 1Byte는 나타낼려는 수의 지수값을 나타내는데 사용되고 나머지 3Byte는 유효숫자를 의미한다. 말로하는것보다 예시를 보여주는게 이해하기가 쉬우니 400,000번째 블록의 경우를 살펴보자. 400,000번째 블록의 nBits는 0x1806B99F 로 이중 0x18은 10진수로 24를 의미하고 24에서 3을 뺸 21이 nBits가 나타내려는 숫자의 지수이다. 그리고 남은 0x06BB9F를 $$256^{21}$$배, 즉 뒤에다가 00을 21개 붙혀준다. 그럼

0x6BB9F000000000000000000000000000000000000000000

라는 숫자가 탄생한다. 그럼 400,000번째 블록의 해시값은 진짜 이 수보다 작을까?

nBits: 0x000000000000000006BB9F000000000000000000000000000000000000000000

블록헤더 해시: 000000000000000004ec466ce4732fe6f1ed1cddc2ed4b328fff5224276e3f6f

보는바와 같이 가장큰 단위의 숫자가 nBits는 6인 반면 400,000블록의 해시값은 4로 nBits보다 작은 것을 확인해 볼 수 있다.

그럼 400,000번째 블록을 생성할때 nBits보다 작은 해시값이 나올 확률은 얼마나 될까? 일단 어떤 데이터의 해시값은 16진수로 표현하면

0x0000000000000000000000000000000000000000000000000000000000000000부터

0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF사이의 그 어떠한 값도 올 수 있다. 이것을 다르게 표현하면 총 $$2^{256}$$가지의 경우의 수가 존재하고 그 중 하나가 어떤 값 하나가 나올 확률은 $$1/2^{256}$$라는 것이다. 이때 위 nBits가 제시한 숫자 보다 작은값은 총

0x000000000000000006BB9F000000000000000000000000000000000000000000개, 10진수로 표현하면 약 $$6\times16^{47} = 6\times2^{188}$$개가 존재한다.

이 둘을 고려해 어떤 데이터에 대하여 해시함수를 돌렸을때 nBits보다 작게 나올 확률은

$$\dfrac{6\times2^{188}}{2^{256}} = \dfrac{6}{2^{68}} = \dfrac{6}{295,147,905,179,352,825,856}$$로 대략적으로 지수표기법으로 표현하면 $$2/10^{20}$$, 한글로 표현하면 1해분의 2, SI접두어로 표현하면 100엑사(Exa) 분의 2 정도의 확률이 된다. 이는 엄청나게 작은 확률로 이를 10분=600초에 한번씩 구해낼려면 초당 약 25경번 해시값을 탐색해 봐야한다. 물론 이정도 컴퓨터로 할수있지 않을까? 라는 생각을 가지시는분도 있겠지만 현재 시중에 판매되는 그래픽 카드의 최고사양으로 이러한 해시값을 탐색해보아도 초당 50메가(Mega)번을 탐색하지 못한다.

이렇게 각각의 블록헤더의 해시값은 nBits에 적힌 수에따라 천문학적으로 작은 확률로 탐색가능한 값을 가진다는 사실은 잘 알겠지만, 이러한 nBits의 값은 어떻게 정해지는 것일까?

참고: https://bitcoin.stackexchange.com/questions/23912/how-is-the-target-section-of-a-block-header-calculated

난이도 Difficulty

비트코인에는 난이도라는 개념이 존재한다. 위 예시의 경우 400,000번째 블록의 nBits는 1해분의 2의 확률을 가지지만 2009년 처음 비트코인이 시작할때는 지금과 같은 대규모 채굴공장도 없었고 단지 초당 5~6천번 탐색할수있는 컴퓨터 몇대가 채굴을 했을 뿐이며 당연히 매 10분마다 작업증명이 완료된 블록을 만들어 낼 수 있었을리가 없다. 그럼 nBits의 값은 계속 변해야 하는데, 그 변해야하는 정도를 정하기 위해 비트코인에서는 난이도 라는 개념이 생겼다. 이 개념은 난이도가 10% 증가하면 nBits는 10%감소라는 느낌으로 난이도 증가비율의 역수가 nBits의 증가비율이 되도록 사용된다.

먼저 난이도는 다음과 같이 측정된다. 제일 먼저 사토시 나가모토가 만든 첫번째 블록의 난이도는 "1" 이다. 그리고 2160개의 블록이 새로 생성되면 2160개의 블록이 생성되기까지 걸린 시간T를 구한다. 마지막으로 $$\dfrac{2주일}{T} = K$$의 값 난이도에 곱한다. 만약 2160개의 블록을 만드는데 1주일밖에 안걸렸으면 K=2가 되어 난이도는 두배가 되고 반대로 2160개의 블록을 만드는데 한달(4주일)이 걸렸으면 K=1/2가 되어 난이도는 반배가 되어버리는 구조이다. 2주일과 2160개의 블록이 생성되는 시점을 비교를 했는데, 여기서 2160은 2주일동안 평균적으로 10분에 블록이 하나씩 생성될생성되는 총 블록의 개수이다. ($$60분\times24시간\times14일 = 21,600$$) 즉, 평균적으로 새로운 블록이 만들어지는데 10분의 시간보다 적인 시간이 걸리면 난이도는 올라가고, 10분보다 많은시간이 걸리면 난이도가 내려가는것을 약 2주간격으로 평가를 행한다고 생각하면 된다.

400,000번째 블록의 경우 이러한 난이도는 값은 163,491,654,908.96으로, 이는 400,000번째 블록은 첫블록대비 163,491,654,908.96배 어려워지고, 400,000번째 블록의 nBits는 첫번째블록의 nBits보다 163,491,654,908.96배 작다는 의미로 해석할 수도 있다.

Nonce

이렇게 블록헤더의 해시값이 작업증명과정을 거쳐서 일반적으로 나오기 매우 힘든 값이 나온다는 사실은 알아냈으나, 어떻게 그런 해시를 탐색하는가? 어떤 데이터A의 해시값이 1/2^256의 확률로 나온다는 사실은 알아냈으나, 그 다음으로 탐색해야할 데이터B는 어디서 나오는가? 가 Nonce와 관련된 부분이다.

해시함수, 특히 비트코인에서 애용하는 SHA2 해시함수의 경우 한가지 특징을 가지는데, 그것은 바로 어떤 데이터가 단 1비트만 변질되어도 예측 불가능한 전혀 다른 해시값이 나온다는 사실이다. 이를 사소한 변화가 엄청난 변화를 가져온다해서 눈사태 효과라고도 한다. Nonce는 해시함수의 이런 효과를 적극적으로 사용한다. 즉, 블록헤더의 해시값을 구하고 nBits에서 제시한 조건에 만족하지 않으면 Nonce를 1비트만 변질시켜서 다시 시도해 보는것이다. 이를 도식화 하면 다음과 같다.

st=>start: 블록헤더를 생성한다.
op=>operation: 블록헤더의 해시값을 구한다.
cond=>condition: 해시값이 
nBits보다 작은가?
cond2=>operation: Nonce를 변질시킨다.
e=>end: 블록생성에 성공하였다.

st->op->cond
cond(yes)->e
cond(no)->cond2->op

이러면 모든게 해결된 것 같지만 아쉽게도 한가지 문제가 남는다. 그것은 바로 Nonce의 크기가 4Bytes밖에 안된다는 것이다. 이것이 왜 문제가 되냐면 Nonce가 표현할 수 있는 경우의 수가 2^32=4,294,967,296, 즉 약 40억개에 불과해 모든 경우의 수를 시도해보아도 1해분의 2의 확률로 성공하는 블록생성에 실패할 수 확률이 더 높다는 것이다. 이에대한 1차적인 해결책은 블록 헤더칸에 블록이 생성된 시간을 나타내는 TimeStamp이다. 이 값은 1990년 1월 1일 0시 0분 부터 몇초가 지났는지의 방법으로 시간을 기록하는데 약 40억개의 가능성을 시도해 보는동안 1초가 지날테고 현재 시간을 TimeStamp에다 갱신시켜 또 다른 40억개의 가능성을 시도해 볼 수 있다. 하지만 이또한 문제가 발생하는데 400,000번째 블록에 적혀있는 nBits조건에 부합하는 초당 탐색회수는 약 25경번 이다. 당연히 1초에 40억개의 가능성으로는 턱도 없다. 그래서 비트코인 개발자는 새로운 변조공간을 찾아냈는데 그것은 바로 코인베이스 거래이다. 앞서 밝힌것처럼 이 공간은 채굴자가 자유롭게 조작할 수 있으며 그 대표적인 예시로 사토시 나가모토가 적은 뉴스기사 제목이다. 이 공간을 조작하면 거래데이터 전체를 보증하는 머클트리의 각각의 해시값이 변하게 되고 블록헤더에 포함되어있는 머클루트의 값도 변하게 되어, 결국 또 다른 가능성을 탐색할 수 있는것이다. 현재 비트코인은 채굴과정에서 Nonce는 당연하고 이 공간까지 모두 이용해서 nBits에 충족하는 해시값을 구하기 위한 조작공간으로 삼고있다.

마무리

자 이제 비트코인의 채굴과정에 대해 모두 알아보았다. 이 채굴과정에 성공한 블록은 이제 다른 비트코인 네트워크로 전파되어 비트코인 전체에서 블록체인에 포함된 하나의 블록으로 인정받게 될 것이다. 이에대한 과정은 다음파트에서 알아볼것이다.

하지만 의문이 남는다. 비트코인의 작업증명방식은 확실히 그만한 연산과정을 거치지 않으면 블록을 완성할 수 없다. 이는 매우 이해하기 쉬운 상황으로 내가 연산한 만큼 연산하지 않았으면 조작 못해!라는 상황을 연출해준다. 그만큼 보안성은 인정받는다는 것이다. 다만, 그와 함께 낭비되는 자원도 엄청나다. 일단 비트코인의 경우 더 적은 전기로 더 뛰어낸 채굴성능을 자랑하기 위해 ASIC라는 비트코인 전용 채굴칩이 생겼으며 이 ASIC는 비트코인에서는 뛰어난 능력을 발휘하지만 그와 동시에 다른분야로는 전혀 써먹지 못할 아주 한정된 분야를 자랑한다. 또한 비트코인에서 해시값을 특정값보다 낮은값이 나오기위한 작업은 비트코인 외에서는 완전 쓸모가 없다. 마지막으로 이 채굴과정에서 소모되는 전기의 양은 아마 비트코인이 없었더라면 지구상에서 원전 하나쯤은 없앨 수 있지 않았을까 싶다.

이렇게 비트코인의 채굴과정을 낭비라고 본것이 필자뿐이 아닌가본지 현재 이에대한 여러가지 대안이 제시되었고 실제 구현되거나, 혹은 구현될려고 논의중인 방법들이 존재한다. 이에대해 잠깐 알아보도록 하자.

PoS (Proof Of Stake)

비트코인이 이러한 많은 연산과정을 요구하는 근본적인 이유는 "누굴 믿어야만 하는가?"에 대한 답으로 "많은 사람의 연산량 그 자체를 믿겠다!"라는 대답을 했기 때문이다. 반대로 전통적인 금융기관인 은행의 경우 "누굴 믿어야만 하는가?"에 대한 답으로 "은행 그 자체를 믿겠다!"라는 대답으로 컴퓨터가 없던 시기에도 사람의 머리와 주판으로 이 모든 과정을 구현할 수 있었다. 그럼 좀 더 구체적인 누군가를 믿으면 연산량이 적어지지 않을까? 그리고 블록체인이 붕괴되면 가장 피해를 많이보는 사람이 가장 믿을만하게 일하지 않을까? 라는 아이디어로 생긴게 PoS, Proof of Stake, 지분증명 이라는 방식이다.

이에대한 아이디어는 실로 간단하여 가상화폐의 경우 가상화폐를 가장 많이 보유한 사람이 가장 많은 지분을 가지고 있고, 지분을 가장 많이 가진사람이 블록을 생성할 권리를 가진다는 것이다. 만약 블록생성을 잘못한다면 해당 가상화폐의 신뢰도는 그 가치와 함께 급락할테니 제일 가상화폐가 붕괴되길 꺼려하는 사람일테고, 그만큼 제대로 블록을 생성할 것이라는 아이디어다.

물론 이리보면 간단해 보이기는 하지만 여러가지 현실적인 문제가 겹치는데, 지분을 가장 많이 가진사람이 항상 컴퓨터를 켜놓는다는 법은 없고 가상화폐 붕괴를 통해 이득을 볼수있는 사람이 (잘 상상하긴 힘들지만) 생겨나면 당연히 붕괴시키려 할것이다. 이를 해결하기 위해 Nxt, BlackCoin과 같은 가상화폐는 PoS와 PoW를 합쳐놨다. 즉, 개개인의 채굴자들은 채굴을 하고 채굴 결과를 내놓는데, 나온 해시값이 얼마나 작은지와 채굴자가 소유한 금액이 어느정도인지를 각 가상화폐에서 만든 특별한 함수에 따라 우선순위를 정하고 그 중 가장 높은 우선순위가 나온것을 인정한다는 것이다. 여기에 더해 PeerCoin이란 가상화폐는 금액을 얼마나 오래 보유하고 있었는지도 우선순위에 영향을 주는 형태로 PoS를 구현했다.

노트 : https://blog.ethereum.org/2015/08/01/introducing-casper-friendly-ghost/

비트코인 다음으로 유명한 이더리움에서 채용하려고하는 Casper라는 PoS기반 알고리즘에 대한 설명한 글입니다만......

제가 이해하기론 채굴자는 도박을 하고, 가장 많은 채굴자들이 배팅한 블록이 살아남는다..... 라는것 같은데, 제대로 이해했다는 확신이 없어 이에대한 글을 쓰지는 못했습니다. 저는 시간이 없어 이에대해 알아보지는 못했지만, 한번 알아보시고 쓸만한 가치가 있다 생각하시면 부디 한번 언급하는 형식으로 써주시기 바랍니다.

PBFT

PBFT는 Practical Byzantine Fault Tolerance의 약자로 이름부터가 비잔티움 장군 문제를 해결하기 위한 방법이다. 1999년에 발표된 이 아이디어는 현재 비트코인과 같은 공개적인 블록체인이 아닌 소규모나 혹은 개인적으로 사용되는 블록체인에 자주 적용되며 기본적인 작동구조는 다음과 같다. Primary 노드 가 일단 추가되는 데이터를 모두 수집한 뒤 이 데이터를 나머지 모든 노드에게 전파시킨다. 그리고 나머지 노드들은 자신을 제외한 모든 노드에게 받은걸 그대로 전파시킨다. 그 다음에 각 노드는 자기가 받은 데이터중 가장 많이 받은 데이터 종류 (즉, 이 상황은 누군가 데이터를 변조시키는 상황을 가정한다.) 를 다시 각 노드로 전파시킨다. 그렇게 각 노드가 미리 약속해둔 수 이상의 같은 데이터를 받는다면 합의가 완료된 것이다. 합의에 실패했다면 그 후는 각 프로그램의 상황에 맞춰 적절히 대응하면 된다.

img

이러한 PBFT의 경우 수만명 이상이 사용하는 것을 전재로 하는 가상화폐의 경우 통신해야하는 양이 유저수가 늘어날때마다 N^2씩 증가하여 대규모 블록체인의 상황에는 사용하지 못하지만, 반대로 기업간 거래나 개인간 채팅같은 소규모 블록체인의 상황에 사용하기에는 명쾌하고 구현하기 간단하며 비록, 블록체인의 형태는 아니었지만 이미 어느정도 사용되어 오면서 검증된 방법이기 때문에, 현재 국민은행이 도입할 예정인 FidoLedger와 IBM이 발표한 IBM BlockChain 1.0이 이 아이디어를 사용했다고 알려져 있다.

비잔티움 장군 문제

먼 옛날 비잔티움제국(동로마 제국)의 장군들은 뒤돌아보면 서로의 등 뒤에 칼을 꽂을 수 있을정도로 서로 사이가 좋지 않았다. 어느날 황제가 이 장군들 보고 어느 도시를 점령하라고 명했고, 장군들은 고생끝에 해당 도시를 포위하는데 성공하였다. 여기서 문제가 발생했는데, 도시를 둘러싸고 있는 모든 장군들이 동시에 습격하지 않으면 이 전쟁은 패할것이 불보듯 뻔한 상황이었고 이제와서 모든 장군들을 모아서 습격 타이밍에 대해서 회의하기는 너무 늦었다. 그래서 서로가 서로에게 전령을 보내서 습격 타이밍을 정하기로 했다.

비잔티움 장군 문제의 배경스토리는 위와 같다. 이 문제는 컴퓨터 업계에 신뢰성을 보장할수 없는 분산적인 체계의 프로토콜을 어떻게 구현할수 있는가?에 대한 질문으로 해석되어 꽤 오랫동안 난제로 남은 문제인데 여기서 해결해야할 사항은 다음과 같다.

  1. 장군간의 물리적 거리가 상당해서 전령을 통한 통신 딜레이가 엄청나게 크다. A장군이 "아침 먹고 9시 습격 ㄱㄱ"라고 B에게 전령을 보내는것과 동시에 B장군이 A장군에게 "적들 일어날때 7시 기습 ㅇㅋ?"라고 보내고 각 전령이 새벽 2시에 출발해 아침 6시에 도착했다면 B장군이 뭘 해야할지는 되게 애매해지는 것이다.
  2. 장군들 속에 악의적인 장군이 섞여있어 8시에 공격한다고 합의해놓고 공격을 안할 수 도 있다. 이런경우 다른장군들은 심히 곤란해진다.

이를 컴퓨터 버전으로 적용시키면 다음 문제와 같아진다.

  1. 서로의 통신시간 문제때문에 합의 사항이 엇갈릴 수 있다. 비트코인에 비유하면 서로다른 두 채굴자에 의해 서로 다른해시값을 가지지만 블록체인에 들어가는데는 문제없는 블록이 동시에 탄생하였다. (이에대한 해결법은 블록전파에서 다룬다.)
  2. 어떤 악의적인 참여자에 의해 위조된 데이터가 돌아다닐 수 있다.

비트코인은 위 두가지 문제를 완벽히 해결한 사실상 첫 프로그램이라서 그 위상이 같이 높아졌다고 할 수 있다.

이더리움 PoW

이더리움은 PoW에서 앞쪽의 블록헤더가 뒤쪽의 블록헤더를 보증하는 방식을 앞쪽의 블록이 뒤쪽의 블록 그 자체를 보증해주는 방법을 통하여, 위 다용도로 사용 불가한 ASIC의 과도생산 억제에 성공하였다. 그 원리는 실로 간단한데 ASIC는 해시연산에 특화되어있어 CPU나 GPU보다 훨씬 빠른속도로 해시연산을 할 수 있지만, 그 메모리에는 한계가 있어 특정 크기 이상의 데이터의 해시값을 구하는것이 불가능하다. 물론 대용량 메모리를 장착한 ASIC를 만드는 방법도 있지만 시중의 GPU를 사는것 대비 경제성이 떨어진다고 한다. 그럼 더 큰 데이터의 해시연산을 요구하면 ASIC 생산을 포기할테고 결국 채굴은 채굴 이외에도 다른 용도로 사용 가능한 CPU와 GPU로만 하게되고, 채굴자가 채굴을 포기할때는 해당 하드웨어를 다른용도로 사용 가능하기에 비트코인의 두 단점중 하나를 해결할 수 있다는 것이다.

물론 이러한 해결방법도 어느정도 선을 지나가면서 단점이 부각되었는데, 최근 한국에 가상화폐에 거품이 끼면서 채굴을 시도하려는 자가 늘었고, 이미 대규모 설비를 갖추고 특화 하드웨어를 소유한 기존 비트코인 채굴자를 이길수는 없으니 GPU로만 채굴이 가능하고 아직 진입장벽이 낮은 이더리움으로 신규 채굴자가 대거 나타나, 결국 그래픽카드 품귀사태와 함께 그래픽카드 가격이 크게 올라, 가상화폐와는 관계없는 일반인들에게까지 피해를 입히는 사태가 발생하였다. 무엇이든 도가 지나치면 안되는 법이다.

프라임코인, 큐어코인

위 두 가상화폐는 비트코인의 작은 해시값 찾기가 완전 무의미하다는 점을 해결한 가상화폐이다. 프라임코인은 소수를 찾는것을 채굴의 목표로, 큐어코인은 단백질 접힘이란 현상을 시뮬레이션하는것을 채굴의 목표로 정했으며, 각각의 연산 결과를 각각 수학계와 생물학계에서 활용하여 새로운 과학적 발견으로 이끌어 나가는것을 궁극적인 목표로 삼고있는 가상화폐이다. 다만 아쉽게도 이 둘 이후 이러한 시도는 보이지가 않는다.

블록의 전파

작업 증명을 위한 엄청난 연산을 거쳐 탄생한 블록을 전파하는 방법은 트랜젝션이 전파되는 방법과 똑같다. 비트코인 네트워크에서 자신과 연결되어있는 이웃노드로 전파시키고 해당 이웃노드는 전파받은 블록이 제대로된 블록인지 검사한 뒤 다음노드로 전파시키고.... 같은과정의 반복이다. 새로운 블록을 받은 채굴자는 블록이 올바르다는 검증을 완료하는 즉시 현재 작업중인 채굴을 멈추고 새로운 채굴작업을 시작하며 새로운 채굴경쟁이 시작되는 것이다.

하지만 이와같은 상황에는 두가지 예외적인 케이스가 발생한다. 한가지는 채굴에 도전하는 전세계의 채굴자들중 둘 이상의 채굴자들이 아주 우연히도 동시에 블록채굴에 성공하여 비트코인 네트워크에 두가지 버전의 블록이 떠돌아다니는 상황이고 나머지 한가지는 비트코인 프로토콜이 업데이트되면서 이전 비트코인체제에 맞는 블록버전과 업데이트된 후의 비트코인체제에 맞는 블록버전이 떠돌아다니는 상황이다.

이번파트에서는 비트코인이 이 두가지케이스를 어떻게 처리하는지 자세히 들여다보도록 하자.

서로다른 채굴자가 만든 두 블록

일반적으로 서로 다른 데이터를 가지지만 같은 부모를 가지는 블록이 거의 동시에 채굴에 성공될 확률은 그렇게 높지는 않다. 하지만 이는 분명히 발생하는 현상으로 통계적으로 한달에 3~8회정도 발생한다. 그 이유는 어떤 블록이 전 세계에 포진해있는 비트코인 네트워크 전역에 퍼지기까지는 고려할만한 시간이 소모되기 때문이다. 좀 더 구체적인 예시를 들어보자면 한국 서울에있는 채굴자가 만든 블록이 지구 정 반대편에있는 아르헨티나에 있는 비트코인 사용자에게까지 전파되는데까지 인터넷 속도 그 자체부터, 각 중간 비트코인 유저가 블록을 검증하는데 드는 시간등을 합치면 수초~수십초의 시간이 소모되고 그 시간 사이에 아르헨티나에서 블록을 생성해 배포할 수도 있다는 것이다.

이러한 사건은 통계적으로 미국에서 만든 블록과 중국에서 만든 블록이 싸우는 경우가 많은데 (중국은 인터넷이 난개발되어서 해외 통신에 딜레이가 큰편이고 전세계 채굴성능의 반정도는 중국이 차지하고 있다.) 중국 베이징의 A지점에서 100번째 블록a를 생성하고 1초도 안지나서 미국 뉴욕의 B지점에서 다른버전의 100번째 블록b을 생성해 전파시키는 상황을 예시로 이 상황을 비트코인이 어떻게 해결하는지 살펴보자.

일단 비트코인이 이 사건을 해결하기위한 1차적인 해결책은 대세를 따른다이다. 여기서 말하는 대세란 비트코인이 업데이트 되면서 기준이 바뀌어오긴 했지만 대체로는 다음과 같은 느낌이다.

  1. 블록체인의 난이도가 높은게 대세이다.
  2. 블록체인의 높이가 높은쪽이 대세이다. (100번째 블록보다 1000번째 블록의 높이가 더 높다.)

물론 여기서 다루는 상황은 위 두가지기준으로 생각해보면 우위를 가릴 수 없다. 그럼 다음 해결책은 내가 채굴중인걸 대세로 만든다이다. 한마디로 먼저 다음블록이 탄생하는 버전의 블록이 높이가 더 높아지고 더 빠르게 블록을 만들 수 있으면 더 난이도가 높아진다는 의미이기에 위 두가지 기준을 충족할 수 있기에 내가 먼저 채굴에 성공하면 그것이 대세가 되는것이다.

특별히 비트코인 채굴프로그램에 손을 대지 않는한 각 채굴 프로그램은 먼저 받는 블록에 어울리는 블록체인 채굴을 시도함으로, 한국 채굴자가 100번째 블록을 채굴하다 중국에서 만들어진 블록a를 받으면 먼저 블록a의 해시값을 가지는 101번째 블록 채굴을 개시하며 그다음으로 받는 미국에서 만들어진 블록b는 보류하는 태도를 취한다.

graph LR
99[99번째 블록]-->100a[100번째 a버전블록]
99[99번째 블록]-->100b["100번째 b버전블록(보류)"]
98[98번째 블록]-->99
100a-->mine[채굴 중]

한편 같은상황에서 미국에 있는 채굴자들은 b버전의 100번째 블록을 먼저받아 다음과 같은 상황이 연출되고 있을것이다.

graph LR
99[99번째 블록]-->100a["100번째 a버전블록(보류)"]
99[99번째 블록]-->100b["100번째 b버전블록"]
98[98번째 블록]-->99
100b-->mine[채굴 중]

이제 벌여지는것은 a버전 블록을 채굴하는 그룹과 b버전을 채굴하는 그룹의 소리없는 전쟁이다. 대체로 이 "전쟁"은 빠른시간안에 종료되는데, 전쟁의 승리조건은 앞에서 말했다시피 먼저 채굴에 성공하면 된다. 만약 a버전 블록을 이어나가는 채굴자가 먼저 채굴에 성공해 비트코인 네트워크 전역에 전파되었다면

graph LR
99[99번째 블록]-->100a[100번째 a버전블록]
99[99번째 블록]-->100b["100번째 b버전블록(Stale)"]
98[98번째 블록]-->99
100a-->101a[101번째 블록]
101a-->mine[채굴 중]

100번째 b버전 블록은 Stale Block이라 명명 되고 비트코인 네트워크 전체는 100번째 a블록을 정당한 블록체인으로 인정해 비트코인 시스템을 유지시켜 나가는 것이다.

물론 이러한 상황도 만약 a버전의 블록을 채굴하는 자와 b버전의 블록을 채굴하는자가 거의 동시에 101번째 블록 채굴에 성공하였으면, 채굴 전쟁의 연장선이 되는것이다. 대체로 이러한 상황은 두 버전의 블록이 하나 탄생할때 해당 세대에서, 좀 길어지면 바로 다음세대쯤에서 "전쟁"은 끝나게 되지만 딱 한번 이 전쟁이 엄청 길어졌던적이 있었다.

그것은 2013년 3월 11일 225430번째 블록이 생성될때 위에서 말한 상황과 같이 두가지 버전의 블록이 생성되어 "전쟁"을 했었다. 보통때라면 그냥 평범하게 해결될 문제였겠지만 전 세계적으로 비트코인 네트워크가 제대로 연결되어있지 않았는 모양인지 a버전의 블록과 b버전의 블록이 모두 비트코인 네트워크 전역에 퍼지지 않았고 a버전의 블록이 b버전을 채굴하는 채굴자에게 까지 도달하기까지 심각하게 오랜 시간이 걸려서 이 전쟁은 무려 6시간동안 24세대나 진행되었다.

사실 그냥 방치했었다면 24세대로 끝나지 않고 계속 유지되어 비트코인 자체가 두조각으로 나눠질수도 있었던 사건이었지만 다행이도 이 사건을 눈치챈 비트코인 개발자 멤버가 비상 메세지(거래의 생성밑 전파 맨 마지막부분)를 비트코인 네트워크 전역으로 배포함과 동시에 한쪽 버전의 블록을 의도적으로 제외시키는 프로그램 패치를 배포해 이 사건은 마무리가 되었다.

지금은 대다수의 비트코인 클라이언트가 이와같은 사건이 일어나지 않도록 패치된 프로그램을 사용하고 있으므로 그 후 이와같은 문제가 발생한 적은 없지만, 혹시 같은 사건이 다시 발생한다면 사라지는 버전의 블록체인에 들어있던 승인된 거래내역도 같이 사라지게되기 때문에, 큰돈이 움직이는 거래는, 거래가 블록에 포함된 후 그 위로 3~6개의 블록이 추가적으로 쌓일때까지 안심하지 말라는 이야기가 돌아다니게 되었다.

(3~6세대까지 전쟁이 지속되는 경우는 거의 없기 때문.)

서로다른 비트코인을 따르는 두 블록

그 어느 누구도 처음부터 완벽한 프로그램을 만들수는 없기에 비트코인도 계속 업그레이드 된다. 업데이트 내용은 단순히 더 효율적이거나 안전한 통신규격이나 새로운 방식의 비트코인 지갑정도가 주류이긴 하지만, 가끔씩은 블록체인에 저장되는 내용 그 자체가 업그레이드 되는경우도 종종 있다. 하지만 여기서 문제가 발생한다. 윈도우 보안업데이트를 제대로 하지않아 랜섬웨어가 전 세계의 컴퓨터를 빠른속도로 장악한것처럼, 새로운 안드로이드 버전이 나와도 기존 사용자는 기존 사용하는 안드로이드를 사용하는 것처럼, 비트코인도 업데이트를 제대로 하지 않는사람이 꽤 존재한다. 또한 업그레이드 방안이 나와도 비트코인 핵심 개발자가 만들지 않은 일반 개인이나 기업이 만든 비트코인 클라이언트에게까지 적용되려면 많은 시간이 필요하다. 물론 업그레이드하는 방법이 단순한 기능 추가로 이전버전의 블록과 새로운버전의 블록이 서로 호한되면 아무런 문제도 없지만, 만약 그렇지 않고 구조자체를 확 틀어벌이는 업그레이드가 나오면 어떻게 되는것일까?

이에대한 해결책으로 소프트포크(Soft Fork)와 하드포크(Hard Fork)가 존재한다. 이름에서 유추해볼수 있는것처럼 소프트포크는 뭔가 부드럽고 온난하게 업그레이드를 진행하며 하드포크는 과격하게 진행된다. 좀 더 상세히 알아보면 소프트포크는 기존버전과 새 버전의 블록이 동시에 호환 가능한 업그레이드의 경우에 일정 기간동안 두 버전을 모두 허용하여 진행되다가 특정 사건을 기준으로 기존 버전은 완전히 배제하고 새 버전만을 인정하는 방법을 말한다. 이 방법은 사용자로 하여끔 적응할 기간을 주고 혼란을 주지않아 안전한 방법이다. 특정 사건이란 비트코인에 소프트포크가 진행될때마다 바껴왔으며 "특정날짜" 혹은 "지지하는 사용자가 특정 비율을 넘어설때"등의 방법이 사용되어 왔다. 하지만 하드포크는 이러한 유보기간을 주지않고 어느순간부터 새버전의 블록만 인정하는 방법이다. 이 방법은 과격하고, 비트코인 네트워크에 기존버전의 블록과 새 버전의 블록이 동시에 떠돌아다니게 되어 사실상 이름만 같고 별개로 운영되는 두개의 비트코인이 탄생하는것과 마찬가지라고 생각하면 된다.

하드포크는 해당 블록체인의 신뢰성을 떨어뜨리고 가상화폐시장에 혼란을 가져오는 존재라서 사실 비트코인에서는 이 책을 쓰는 시점에서는 아직 한번도 발생한적 없는 사건이다. 하지만 이더리움의 경우 이 사건이 한번 일어났다. 이더리움이란 비트코인과 비슷한 가상화폐로 비트코인과는 다르게 스마트 컨트랙이라는 기능이 추가되어있으며, 사용자는 이 스마트 컨트랙을 이용해 수수료를 지불하는 대신 블록체인상에서 간단한 프로그램은 돌릴수 있다. 문제는 이 기능에 버그가 숨어있었다는 점이고 해커들이 이를 악용해 이더리움에 존재했던 이더(이더리움의 화폐 단위이다)의 총액의 10%가 말그대로 도난당한 사건이 일어났다. 이 도난사건은 즉시 이더리움 개발자들에게 보고되어, 즉각 가능한 2가지의 해결책을 제시하고 이용자들의 투표과정을 거쳐 3일만에 일부 블록은 없던일로 해버리고 도난당한 금액을 그대로 돌려주는 하드포크를 단행하였고 이는 성공적으로 진행되었다.

다만 문제가 발생하였는데 블록의 일부가 소실되었고, 이로인해 많은 양의 이더리움 거래가 "없던일"로 되어버린것이다. 이에 반발한 일부 유저는 해당 블록을 없애지 않고 해킹당한 금액도 그대로 유지되는 이더리움 클래식이란 새로운 가상화폐를 만들어 버렸다. 그 후 이더리움 사용자들은 누구를 사용해야 하는가?에대한 혼란때문에 이더리움이더리움 클래식의 시세는 변동을 계속하다가 지금은 각각 ETHETC란 이름으로 사실상 별개의 가상화폐로 계속 이용되고 있다.

# 부록

비트코인의 업그레이드

현재 비트코인은 크나큰 변화를 앞두고 있다. 아마 독자 여러분이 이 글을 읽을때쯤 그 이 모든 변화가 끝나있을 것이라고 생각하지만 이 변화의 핵심키워드는 "현재 비트코인이 처리할수 있는 거래의 양이 너무 적다."라는 것이다.

비트코인은 약 10분에 하나씩 블록이 생성되고 하나의 블록에는 거래 종류에따라 1000~2000건의 거래가 포함된다. 이를 초당 처리가능한 거래로 계산하면 매초 2~3건정도의 거래만 처리할 수 있다는 것이다. 비트코인이 처음 나왔을때는 이정도의 거래 처리량으로도 모든 거래를 감당할 수 있었지만 지금은 상황이 변했다. 전 세계에서 활발하게 비트코인을 사용하고 있으며, 초당 2~3건의 거래처리량으로는 모든 사용자들이 만족스럽게 사용하지 못하고 심지어는 수수료를 적게낸 거래들은 일주일이 지나도 블록속에 포함이 되지 못하는 사건도 종종 발생하고 있다. 이러한 상황을 해결하기위해 두가지 방안이 제시되었는데, 하나는 거래 하나가 차지하는 크기를 줄여 하나의 블록에 더 많은 거래가 들어가는 방법과, 나머지 하나는 블록의 크기 자체를 크게 늘려 하나의 블록에 더 많은 거래가 들어가도록 하는 방법이다.

2017년 7월 현재는 비트코인에서 어떻게 업데이트를 해서 이러한 문제를 해결할까?의 정점에 달한 시기이다. 그리고 그 핵심은 하나의 블록에 더 많은 거래를 들어가게 해주는 Segwit과 블록의 크기를 얼마나 키울까? 이다. 이제부터 필자 기준으로 실시간으로 진행되는 비트코인의 역사에대해 생생히 알아보도록 하자.

SegWit

모든 트랜젝션의 입력부분에는 이전 트랜젝션의 출력부분에 명시된 주소의 소유주가 나임을 명시하기 위해 공개키와 함께 디지털 서명이 포함된다. 이렇게 하나의 공개키와 디지털서명 세트는 264Bits의 공개키와 568Bits의 전자서명으로 하나의 입력당 트랜젝션에서 총합 104Bytes의 크기를 차지한다. 일반적으로 입력이 하나인 트랜젝션의 크기가 260Bytes정도 된다는점을 생각해보면 트랜젝션 데이터의 반정도가 전자서명에 사용된다고 보면된다. 하지만 실제 블록체인에서 아주 옛날에 발생한 거래를 증명할필요는 없는데 (증명하지 않아도 블록체인이 그 거래내역이 참임을 보여준다.)(실질적으로 증명이 필요한부분은 거래 데이터를 블록체인에 넣을 때 뿐이다.) 모든전자서명 데이터를 가지고 있을 필요가 있을까? 라는 의문에서 시작한것이 바로 Dr.Pieter Wuille 가 제시한 SegWit이란 방법이다.

SegWit은 분리를 의미하는 Segrated와 목격자(전자서명)을 의미하는 Witness의 합성어로, 거래데이터에서 목격자를 분리해냈다는 의미로 지어진 이름이다. SegWit은 이름이 가진 의미 그대로 거래의 생성및 전파 P2PKH라고 언급한 거래방식에서 <sig> <PubKey>로 구성되어있는 입력 스크립트 부분이 "이 부분은 사용하지 않겠다."라는 의미가 담긴 0으로 바뀐 P2WPKH란 거래방식을 사용한며, (P2SH도 비슷한 방법으로 P2WSH로 바뀌었다.) 이렇게 입력부분에서 빠진 전자서명과 공개키는 Witness란 이름으로 불리게 된다.

이러한 트랜젝션에서 디지털서명과 관련된 데이터가 빠진 SegWit이 적용된 비트코인에서 거래는 다음과같이 이루어진다.

  1. 비트코인 지갑에서는 P2WPKH, P2WSH에 맞게 거래데이터를 생성한뒤 그에대한 Witness Data를 따로 첨부하여 다른 블록에 전파한다.
  2. 채굴자는 이러한 거래데이터를 모아서 블록을 만들기 시작한다.
  3. 각 트랜젝션으로 머클트리를 만드는 과정처럼 각 트랜젝션별 Witness Data에 대한 머클트리를 만들어서 그 머클루트에대한 정보를 코인베이스(블록의 구조 참고)에 입력한다.
  4. 작업증명에 맞게 채굴을 한다.
  5. 완성된 블록과 Witness를 전파한다.
  6. 이 블록과 Witness를 받은 노드는 블록에대한 검증절차를 마친 후 다른 노드로 전파한다.
  7. 당신의 거래는 블록체인에 포함되었다!
  8. 특정기간이 지나 Witness가 필요없다 판단되면 삭제하여 저장공간을 확보한다.

이같은 과정을 통해 작동하는 SegWit은 두가지 장점을 지니게 되는데, 하나는 블록체인에 포함되는 데이터중 전자서명이 빠져 같은 1MB라는 제한을 가진 블록 안에 이전대비 최소 1.75배 최대 4배정도 많은 거래를 저장할 수 있어졌다는 점이고, 나머지 하나는 이중지불 문제의 가능성을 해결할 수 있어졌다는 점이다. 무슨말인가 하니, 일단 권고사항으로 입력스크립트출력스크립트부분에는 표준거래에 맞는 데이터만 삽입될 수 있지만 이는 권고사항이지 강제사항이 아니다. 문제는 스크립트부분이 변경되면 트랜젝션 전체 데이터의 해시값으로 정해진 TxID가 바뀌게 되고 TxID가 바뀌면 컴퓨터는 같은 내용의 거래라도 다른 거래로 인식하기에 만약 이러한 약점을 잘 이용해서 TxID랑 사소한 데이터만 다르지만 내용은 똑같은 서로다른 두 거래가 모두 블록체인에 포함되면 이중지불의 완성이다. 물론 이건 프로그램 버그를 잘 이용해야되서 가능성일뿐 실제 방법이 알려진것은 아니다. 다만 SegWit을 도입하면 이러한 가능성도 차단할 수 있어 더 안전할것으로 생각되어지고 있다.

소프트포크? 하드포크?

현재 이 SegWit을 도입하는 여러가지 제안이 나와있다. 하지만 그 도입방법에 대해서는 의견이 많이 갈라져서 현재 BIP91 방법과 BIP148 방법, 마지막으로 BCC가 존재한다.

일단 Segwit 2X라 불리는 BIP91은 최근 블록체인에 추가된 336개의 블록중 80%에 해당하는 269개의 블록이 SegWit을 지지한다는 표시가 있으면 그 시점을 기준으로 366블록이 생성될때 (약 2.3일에 해당하는 기간이다) 소프트포크가 발생해 그 후부터는 SegWit에 맞게 생성된 블록만 인정하고 기존 블록은 거부하는 방법이다. 원래 이 방법은 최소 95%이상의 블록이 지지해야 실행되도록 할 예정이었지만 생각보다 저조한 지지율과 함께 기 기준선을 80로 낮추었다. 다만 여기서 끝이 아니고 만약 성공시에는 11월에 블록의 최대 크기를 1MB에서 2MB로 늘리는 방안도 같이 포함되어있다. 다만 여기서 문제가 발생하는데 11월에 시행하는것은 하드포크이기에 만약 이때 모든 채굴자가 2MB상향에 대해 동의하지 않으면 비트코인은 두조각으로 나눠져 2MB블록을 생산하는 비트코인과 1MB블록을 생산하는 비트코인, 총 2개의 비트코인이 탄생하게 된다는 문제점을 가지고 있다.

그 다음으로 BIP148은 UASF로 알려져있는데, 만약 8월 1일기준으로 SegWit이 적용되어있지 않으면 하드포크를 감행해 비트코인이 Segwit을 적용한버전과 적용하지 않은 버전으로 나눠진다는 것이다. 이때는 사실 큰 문제가 발생하는데 두가지 버전의 비트코인이 Segwit을 제외하고 모든 규격이 같기때문에 이때 비트코인을 사용하면 SegWit버전의 블록체인과 기존 버전의 블록체인 양쪽다에서 비트코인을 사용한것이 되는 (혹은 한쪽은 사용하지 않은것이 되는) Replay Attack이라는 현상이 발생할 수 있다. 비트코인을 받는 입장에서는 어느쪽을 기준으로 거래가 승인되었을을 확인해야되는지 매우 까다로운 작업이 될것이다. 만약 BIP91이 성공적으로 실행되면 BIP148은 실행되지 않는다.

마지막으로 BCC는 위 사건과는 관계없이 Bitcoin Cash(BCC)라는 이더리움 클래식처럼 새로운 가상화폐를 만든다는 내용이다. 이 BCC는 비트코인과 다른 통신체계를 가지고 있어 비트코인 네트워크와 별개의 네트워크를 가지며 8월 1일에 기존 비트코인 블록체인을 복사해와 사용할 예정이므로 8월 1일전에 소유하고있는 비트코인은 BCC의 블록체인에도 똑같이 기록되어 있어 기존 비트코인 사용자는 공짜돈이 생긴다! 만약 2017년 8월 1일 이전에 소유하고 있던 비트코인이 있었다면 BCC클라이언트를 설치해봐 잔액이 있는지 한번 확인해보도록하자. 비록 비트코인만큼의 시세는 안나올것으로 예상하지만 어느정도 공짜돈이 생길것이다.

후기

이 책 전체에 걸쳐 비트코인에서 거래가 어떻게 이루어지는지 한번 살펴보았다. 비트코인에 사용된 기술들은 정말 경의롭다. 대부분의 기술은 비록 이전부터 존재해왔던 것이지만 그걸 조합해서 그 자체로 신용가능한 데이터를 생성해내는 과정은 전세계가 주목할 정도이고, 이에 영감을 받고 새로 탄생한 프로젝트는 단순한 채팅프로그램에서 공인인증서의 대안까지 날이갈수록 놀라워지고 있다. 그뿐 아니라 비트코인 그 자체도 화폐로서의 역할을 점차 찾아가 결제대행사(카드사)없는 인터넷 결제수준은 이미 그 역할을 충실히 하고있는것 같다. 하지만, 아직 한국은 비트코인의 혜택을 제대로 맛보지 못하는것 같다. 비트코인 그 자체는 거래소에서 사고팔며 주식의 대안으로서 활용할뿐이고, 비트코인에 사용된 기술들은 해외에서 응용되어 완성된 프로그램을 수입해 적용시키는 정도밖에 없는것 같다.

필자는 그 원인이 아마 제대로된 문서의 부재와 언어의 장벽이 아니었을까?라는 생각을 블로그에 "원리부터 파악하는 비트코인"을 작성한 그 순간부터 이 책의 후기를 적는 지금까지도 계속 하게된다.

이 책을 다 읽은 여러분은 무엇을 생각하게 되었는가?

그 답을 필자는 들을 수 없겠지만, 뭔가 세상을 자극할 즐거운 아이디어였으면 좋겠다는 작은 바람을 가지며 이 글을 마친다.

원리부터 파악하는 비트코인