[Bitcoin 5장] 지갑

Mong22·2023년 3월 20일
0
post-thumbnail

[해당 글은 '비트코인, 공개블록체인 프로그래밍(안드레아스 M. 안토노풀로스 저, 최은실 김도훈 송주한 옮김, 코인플러그 기술 감수)'을 참고했다.]

[해당 글에 https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidoc에 포함된 사진과 코드, 표들을 사용했다.]


들어가기 앞서서

  '지갑'의 정의는 넓은 의미와 좁은 의미로 나뉜다. 넓은 의미의 정의는 주요 사용자 인터페이스 역할을 하는 어플리케이션이다. 지갑은 사용자의 돈에 접근하는 것을 통제하고 키와 지갑을 관리하며 잔액을 추적하고 거래를 생성 및 서명한다. 좁은 의미의 정의는 사용자의 키를 저장하고 관리하는 데 사용되는 데이터 구조이다. 이번 장은 좁은 의미의 지갑을 살펴본다.


지갑 기술 개요

  비트코인 지갑에는 현실에서의 지갑과 달리 비트코인이 들어있는 것이 아니라, 비트코인 주소가 들어있다. 비트코인의 경우, 비트코인 네트워크 상의 블록체인 내에 기록되어 있다.

  지갑에 들어 있는 키 사이에 연관성이 있는지에 따라 지갑의 종류는 두 가지로 나뉜다.

  • 비결정적 지갑: 각각의 키가 난수생성기로부터 독립적으로 생성된다. 비결정적 지갑에 들어 있는 키들은 서로 연관성이 전혀 없다. JBOK(Just a Bunch Of Keys) 지갑이라고도 불린다.
  • 결정적 지갑: 키들이 종자(seed)에서부터 생성된다. 결정적 지갑 속 모든 키들은 연관성을 지니고, 종자 원본을 가지고 있다면 누구나 다시 지갑을 생성할 수 있다. 키 유도 방법에는 흔히 트리 형식의 계층 결정적 지갑(HD)이 자주 사용된다.

비결정적(무작위)지갑

  비결정적 지갑은 무작위로 키를 생성하여 저장하는 형태의 지갑이다. 무작위로 생성된 키들은 한 번 생성된 후에는 전부 복사본을 보관해야 한다는 단점이 있고, 이는 백업의 빈도가 높아져야 한다는 것을 의미한다.


결정적(종자)지갑

  결정적(종자)지갑에는 일방 해시 함수를 이용해 공통 종자에서 얻은 개인키들이 담겨져 있다. 종자만 있으면 추출키 전부를 복원할 수 있기 때문에 백업의 빈도가 낮아져도 되며, 다른 종류와 지갑 사이에서도 사용자들의 키 전부가 쉽게 이동할 수 있다. 아래의 그림으로 확인해보자.

종자는 개인키를 추출하기 위해 색인번호나 '체인코드' 등의 여러 데이터와 무작위로 생성된 숫자가 결합되어 있는 형태이다.


HD지갑(BIP-32/BIP-44)

  HD 지갑에는 트리 구조에서 생성된 키를 담고 있다. 이 구조에서는 부모키가 자식키 열을 만들어 낼 수 있고, 각각의 자식키는 손자키 열을 만들어 내고, 이 과정이 반복된다. 다음 그림을 통해 확인해보자.

HD 지갑은 비결정적 키에 대해 두 가지 주요한 장점을 제공한다.

  • 비트코인의 사용 방안에 따라 유기적인 의미를 표현하기 위해서 트리 구조가 사용될 수 있다.
  • 사용자들이 공개키에 대응하는 개인키에 접근하지 않고도 공개키 열을 생성할 수 있다.

종자와 연상기호 코드(BIP-39)

  연상기호는 지갑간 복사, 엑스포트, 임포트가 쉽도록 영어 단어 배열로부터 종자를 생성하는 표준화된 방법을 의미한다. 연산기호의 표준은 BIP-39가 정의하고 있다. 상호 운용되는 연상기호를 이용해 백업 및 복구용 종자를 임포트/엑스포트 할 수 있다. 아래의 예시를 통해 연상기호의 가독성을 살펴보자.


16진법으로 된 결정적 지갑의 종자
0C1E24E59177770D207E14D45F14E1A1A
12개의 단어로 구성된 연상기호로 된 결정적 지갑의 종자
army van defense carry jealous true
garbage claim echo media make crunch

비트코인 지갑의 활용

  비트코인의 지갑 기술이 발달하면서 상호 운용 가능하고 사용하기 편리하며 안전하고 유연해질 수 있도록 산업 표준이 등장했다.

  • BIP-39 기반 연상기호 코드 워드
  • BIP-32 기반 HD 지갑
  • BIP-43 기반 다용도 HD 지갑 구조
  • BIP-44 기반 복수 계좌

  사용자는 이 지갑 중 하나에서 생성되는 연상기호를 엑스포트할 수 있고 연상기호를 다른 지갑으로 임포트할 수 있게 되면서 모든 거래와 키, 주소를 복구할 수 있다.


쟈세한 지갑 기술

  비트코인 지갑에서 사용하는 주요 산업 표준에 대해 상세히 알아보자.


연상기호 코드 워드(BIP-39)

  연상기호 코드 워드는 결정적 지갑을 추출하기 위해 종자로 이용한 난수를 표현(인코딩)하는 영어 단어열이다. 단어열만 있으면 종자를 재현할 수 있고, 종자에서 지갑과 추출키 전부를 재현할 수 있다. 연상기호 코드를 이용한 결정적 지갑을 실행하는 어플리케이션은, 처음 지갑 생성시에 12-24 단어로 구성된 단어열을 사용자들에게 보여준다. 이를 통해 사용자들이 지갑을 더 쉽게 백업할 수 있도록 한다.

연상기호 코드 워드는 브레인 월렛과 혼동된다. 브레인 월렛은 사용자가 원하는 단어로 종자를 표현한다.

연상기호 워드 생성하기

  연상기호 워드는 BIP-39가 규정한 표준화된 과정을 이용해 지갑을 자동적으로 생성한다.

  1. 128-256 비트의 무작위열(엔트로피)을 생성한다.
  2. 생성된 열의 SHA256 해시 중 첫 몇 비트(엔트로피 길이/32)를 따서 무작위열의 검사합을 생성한다.
  3. 생성된 검사합을 무작위열의 끝부분에 붙인다.
  4. 무작위열을 11비트씩 나눈다.
  5. 미리 정해진 단어 2,048개로 구성된 사전에 있는 단어와 11비트 크기의 값을 연결시킨다.
  6. 연상기호 코드가 단어열이 된다.

  다음 그림과 위의 단계를 비교하며 이해해보자.

아래의 표는 엔트로피 데이터의 크기와 단어의 연상기호 코드의 길이 간 관계를 보여준다.

연상기호에서 종자에 이르기까지의 과정

  연상기호 워드는 128-256비트를 나타내며 키스트레칭 함수인 PBKDF2를 사용해서 좀 더 길이가 긴(512비트) 종자를 추출하는 데 사용된다.

  키스트레칭 함수는 두 개의 변수를 취한다. 하나는 연상기호, 나머지 하나는 솔트다. 솔트를 통해 브루트 포싱을 가능하게 하는 탐색표의 구축을 어렵게 하고, 추가 보안 인수 역할을 하는 패스프레이즈 도입을 가능하게 한다.

  1. PBKDF2 키스트레칭에 대한 첫 번째 변수는 6단계에서 산출된 연상기호다.
  2. PBKDF2 키스트레칭에 대한 두 번째 변수는 솔트다. 솔트에서는 'mnemonic'이라고 하는 문자열 상수와 사용자가 제공하는 선택적 패스프레이즈열이 연결되어 있다.
  3. PBKDF2HMAC-SHA512 알고리즘으로 2,048회 해싱해서 연상기호와 솔트를 늘인다. 그 결과 512비트의 값이 최종 출력값으로 생산된다. 이것이 바로 종자다.

  다음 그림과 위의 단계를 비교하며 이해해보자.

BIP-39에서 선택적 패스프레이즈 사용하기

  패스프레이즈 사용은 선택적이다. 패스프레이즈를 사용하지 않는 경우, 연상기호는 'mnemonic'이라는 상수 문자열로 구성되어 있는 솔트를 붙여 길이를 늘리며 512비트 크기의 종자를 만들어 낸다. 패스프레이즈를 사용하는 경우, 스트레치 함수를 통해 동일한 연상기호에서 다른 종자가 생성된다. 종자의 생성가능 범위(2^512)가 너무 크기 때문에 브루트 포싱에 안전하다고 할 수 있다.

  선택적 패스프레이즈는 두 가지 중요한 기능을 만들어 낸다.

  • 도둑이 제시하는 타협안으로부터 연상기호 백업본을 보호하기 위해 연상기호 단독으로는 쓸모가 없게 만드는 두 번째 인수
  • 설득력 있는 부인의 형태, 즉 '협박 지갑', 선택된 패스프레이즈는 자금의 대부분이 들어 있는 '진짜' 지갑을 공격자로부터 따돌리기 위해 사용되는 소액 지갑으로 연결된다.

  패스프레이즈를 사용할 때, 분실 위험도 존재한다.

  • 해당 지갑의 소유주가 정상적인 생활을 하지 못하게 되거나 사망해서 패스프레이즈를 알고 있는 사람이 없는 경우, 종자는 지갑에 저장되어 돈을 영영 잃게 된다.
  • 패스프레이즈를 종자와 동일한 장소에 백업하게 되면 두 번째 인수의 역할이 사라진다.

  패스프레이즈는 유용하다. 하지만 소유주보다 오래 생존하는 소유주의 가족들이 백업 및 복구를 위해 신중하게 계획된 과정 속에서 사용되어야 한다.

연상기호 코드로 작업하기

  BIP-39는 여러 다른 프로그래밍 언어에서 라이브러리로 구현된다.

  • 파이선 연상기호: 파이썬에서 BIP-39 구현
  • bitcoinjs/bip39: 자바스크립트 하에서 BIP-39 구현
  • libbitcoin/연상기호: C++ 하에서의 BIP-39 구현

  독립형 웹페이지에서 구현되는 BIP-39 생성기도 있으며, 테스팅 및 실험에 매우 유용하다. 한번 활용해보자.


종자로부터 HD 지갑 생성하기

  HD 지갑은 무작위 숫자인 근원종자 한 개로부터 생성된다. 이 종자는 앞서 본 것처럼 연상기호에서 생성된다. HD 지갑에 담겨 있는 모든 키들은 이 근원종자로부터 결정적으로 추출되며, 이 근원종자 덕분에 수천 개 혹은 수백만 개의 키를 담고 있는 HD 지갑이라도 근원 종자만 전송하면 백업이나 복원, 엑스포트와 임포트가 가능하다.

  위의 사진은 HD 지갑에서 마스터 키와 마스터 체인코드를 생성하는 과정이다. 근원종자는 HMAC-SHA512 알고리즘에 입력되고, 그 결과로 나온 해시값이 마스터 개인키(m)마스터 체인코드(c)를 생성한다.

  그 후, 타원곡선 곱셈법 m*G를 이용해 마스터 개인키(m)가 마스터 공개키(M)을 생성한다. 체인코드의 경우 자식키를 생성하는 함수 내에 엔트로피를 도입하기 위한 것으로, 다음 섹션에서 다룬다.

개인 자식키 유도하기

  HD 지갑은 부모키로부터 자식키를 얻기 위해 자식키 유도(CKD) 함수를 사용한다. 이 함수는 일방 해시 함수를 기반으로 하며 다음 항목들을 포함한다.

  • 부모 개인키 혹은 부모 공개키(ECDSA 비압축키)
  • 체인코드라는 이름의 종자(256비트)
  • 색인번호(32비트)

  결정적 무작위 데이터 프로세스에 도입하기 위해 체인코드가 사용되기 때문에 색인번호만으론 다른 자식키를 생성할 수 없다. 즉, 체인코드가 없으면 자식키만으로는 또 다른 자식키를 생성할 수 없다. 최초의 체인 코드는 무작위 데이터에서 만들어지며, 그 이후의 체인코드는 각각의 부모 체인코드에서 얻어진다.

  위의 사진은 자식키 생성 과정이다. 부모 공개키, 체인코드, 색인번호를 이용해서 HMAC-SHA512 알고리즘을 통해 해싱 작업을 거치면, 512비트 크기의 해시가 만들어진다. 해시 출력값 중 오른쪽 반의 256비트는 자식키를 생성을 위한 체인코드가 되고, 왼쪽 반의 256비트는 자식 개인키를 생성하기 위해 부모 개인키에 더해진다.

  색인번호를 변경하면 부모키를 확장해서 동일한 열 내에 다른 자식키를 생성할 수 있다. 각 부모키는 2^31개의 자식키를 가질 수 있다.(나머지 2^31은 이후의 유도라는 특별한 유형을 위해 비축되어 있음.) 이런 과정이 무한 반복되어 부모키가 자식키를 생성한다.

확장키

  키 유도 함수에서 중요한 것이 키와 체인코드다. 확장키는 이 둘을 결합한 것을 의미한다. 확장키는 256비트 크기의 키와 256비트 크기의 체인코드를 512비트 크기의 열로 결합해서 단순하게 표현되고 저장된다. 확장키에는 두 가지 형태가 있다.

  • 확장 개인키: 개인키와 체인코드의 결합으로 자식 개인키를 또는 자식 공개키를 얻는 데 쓰인다.
  • 확장 공개키: 확장 공개키는 공개키와 체인코드의 결합으로, 오직 자식 공개키를 생성하는 데 사용될 수 있다.

  확장 개인키를 가지고 있으면 브랜치의 나머지를 구할 수 있는 반면, 확장 공개키를 가지고 있으면 오직 공개키로 이루어진 브랜치만을 생성할 수 있다.

  확장키는 Base58Check를 이용해서 인코딩된다. 인코딩될 때 쉽게 인지되기 위해서 'xprv'와 'xpub'라는 접두부가 붙는 특수 버전 번호를 사용한다. 아래의 사진이 차례대로 확장 개인키, 확장 공개키다.

xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaYAL9CAWrUE9i6GoNMKUga5biW6Hx4tws2six3b9c
xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeMVKZBPLrtJunSDMstweyLXhRgPxdp14sk9tJPW9

공개 자식 키 유도하기

  HD 지갑은 개인키가 없이도 공개 부모키로부터 공개 자식키를 얻을 수 있다. 따라서 HD 지갑 구조의 해당 브랜치 내에서 공개키만을 전부 얻기 위해 확장 공개키를 사용할 수 있다. 이 방법을 이용하면 개인키들을 외부에 노출시키지 않으면서 확장 공개키의 복사본만으로도 매우 안전한 서버나 어플리케이션을 만들 수 있다.

  흔히 사용되는 어플리케이션 중 하나는 전자상거래 어플리케이션을 제공하는 웹서버상에 확장 공개키를 설치하는 것이다. 해당 웹서버는 모든 거래에 대한 새로운 비트코인 주소를 생성하기 위해 공개키 유도 함수를 사용할 수 있으며, 웹서버가 도난에 취약한 어떠한 개인키도 보유하고 있지 않기 때문이 안전하다.

  또 다른 어플리케이션으로는 오프라인 보관이나 하드웨어 지갑을 이용하는 것이다. 확장 개인키는 비트코인 종이 지갑이나 하드웨어 장치에 저장하고, 확장 공개키는 온라인 상에 보관된다. 사용자는 임의로 수신 주소를 생성할 수 있지만, 개인키는 오프라인에 안전하게 저장된다.

단절된 자식키 유도하기

  앞선 확장 공개키에서 공개키 브랜치를 생성하는 기능은 리스크가 따른다. 확장 공개키가 체인코드를 포함하고 있기 때문에 자식 개인키를 알게 되거나 어떤 방법을 통해 자식 개인키가 유출되는 경우, 다른 자식 개인키 전부를 얻을 수 있다.

  이런 위험성에 대응하기 위해 HD 지갑은 단절 유도법이라고 불리는 대안 유도 함수를 사용한다. 부모 공개키를 사용하지 않고 부모 개인키를 사용해서 자식 체인키를 만든다. 이를 통해 부모/자식 열에 '방화벽'이 생기며 체인코드는 부모 개인키나 다른 자식 개인키를 위험에 빠뜨리지 못한다.
?????????????????????

단절 유도와 단절 유도의 색인번호

  유도 함수에서 사용하는 색인번호는 32비트의 정수다. 정규 유도 함수를 통해 얻은 키와 단절 유도법을 통해 얻은 키를 구분하기 위해 색인번호는 두 영역으로 나뉜다. 0~2^31-1 까지의 색인번호는 정규 유도법, 2^31부터 2^32-1 까지의 색인번호는 단절 유도법에만 사용된다.

  색인번호를 좀 더 쉽게 읽고 나열하기 위해서 단절 자식 키에 대한 색인번호는 0부터 시작하지만 프라임이 붙는다. 따라서 첫 번째 정규 자식 키는 0으로 표시되는 반면 첫 번째 단절 자식(0x80000000)은 0'으로 표현된다. HD지갑에서 i'라는 색인번호를 보게 된다면 그것이 의미하는 바는 2^31+i이다.


HD 지갑키 식별자(경로)

  HD 지갑에 들어 있는 키는 명명 규칙인 '경로'를 통해 식별되며, 트리 구조의 각 단계는 슬래시로 구분된다. 마스터 개인키에서 나온 개인키들은 'm'으로 시작한다. ㅏㅁ스터 공개키에서 나온 공개키들은 'M'으로 시작한다. 표를 통해 이해해보자.

  m/x/y/z의 경우, m의 x번째 자식의 y번째 자식의 z번째 자식이라는 뜻이다.


HD 지갑 트리 구조 탐색하기

  HD 지갑의 트리 구조는 엄청나게 유연하여 무한 확장 가능하기에 탐색하기 아주 어려워진다. 따라서 두 개의 BIP가 HD 지갑 트리의 구조에 대한 표준을 제안했다. BIP-43은 첫 번째 단절 자식 색인번호를 트리 구조의 '용도'를 나타낸다. 이 같은 경우, 트리의 1세대 브랜치 하나만 사용해야 한다. 예를 들어, m/i'만을 사용하는 HD 지갑은 특정한 용도를 나타내며, 용도는 색인번호에 의해 정해진다.

  이 사양을 확장한 BIP-44는 '용도' 번호를 44로 제시한다. BIP-44 구조에 대해 자세히 알아보자.

m / purpose' / coin_type' / account' / change / address_index

  첫 단계인 'purpose'는 항상 44이다. 두 번째 단계인 'coin_type'은 암호화폐 동전의 유형이다.. 비트코인은 0', 라이트코인은 2'를 사용한다. 세 번째 단계인 'account'는 하위 계좌로 세분화할 수 있도록 한다. 네 번째 단계인 'change'에서는 HD 지갑이 두 개의 서브트리를 보유하고 있다. 하나는 수신 주소를 생성하기 위한 것이고, 하나는 잔액 주소를 생성하기 위한 것이다. 트리의 세 번째 단계가 단절 유도법을 사용하는 반면, 네 번째부터는 정규 유도법을 사용한다. 마지막, 다섯번째는 주소 색인번호를 의미한다. 예를 들어, 첫 번째 계좌에서 비트코인 지불에 대한 세 번째 수신 주소는 m/44'/0'/0'/0/2가 될 것이다.


  이번 장에선 지갑의 종류와 결정적 지갑에서 종자 생성 및 자식키 유도 방식에 대해 알아봤다. 다음 장에선 거래에 대하여 자세히 다룰 예정이다.

profile
Wah!

0개의 댓글