‘Mastering Bitcoin 2nd’ 세미나 6, 5장. Wallets
이번 장은 지갑에 대해 매우 깊이 있고 자세한 설명을 합니다. 비트코인 지갑을 개발해야 한다면 많은 도움을 받을 수 있는 장입니다.
책 내용 설명을 잘 따라 간다면 크게 어려운 부분은 없습니다. 지갑 개발에 큰 관심이 없으신 분들은 후반부로 갈 수록 집중도가 떨어질 수 있습니다. Hardened child key derivation에서 한 번 끊고 읽으시는 것을 권합니다.
번역서에는 그림이 잘못된 부분이 있으니 원문 그림과 비교해 보시기 바랍니다.
책 내용을 다 읽으신 후 아래 정리한 부분에 주의를 기울여 다시 한 번 읽어봅니다.
Chapter 5. Wallets
Bitcoin wallets contain keys, not coins. Each user has a wallet containing keys. Wallets are really keychains containing pairs of private/public keys. Users sign transactions with the keys, thereby proving they own the transaction outputs (their coins). The coins are stored on the blockchain in the form of transaction outputs (often noted as vout or txout).
지갑의 기본 기능은 키를 생성하고 관리하는 것입니다. 대부분의 지갑 사용자는 키를 관리하기 위해 지갑을 사용한다기 보다는 코인 전송을 위해 지갑을 사용합니다. 따라서 지갑은 사용자(주소)가 사용할 수 있는 트랜잭션 출력들로 부터 잔고를 계산하고, 트랜잭션을 생성하고 서명하고 네트워크에 전송할 수 있어야 합니다.
Wallet Technology Overview
두 종류의 지갑이 있습니다. 하나는 비결정 지갑(a nondeterministic wallet)이라 불리는 지갑입니다. 이름 그대로 키가 결정되어 있지 않은(랜덤한) 지갑으로, 지갑에서 생성한 키들은 서로 아무런 관련도 없습니다. 다른 하나는 결정 지갑(a deterministic wallet)이라 불리는 지갑으로, 시드인 단일 마스터 키로 부터 모든 키들을 생성합니다.
Nondeterministic (Random) Wallets
비결정 지갑은 지금은 거의 사용되지 않고, 사용을 권하지도 않기 때문에 이런 것이 있다는 정도만 이해하고 넘어가면 됩니다.
Deterministic (Seeded) Wallets
그림 2와 같이 결정 지갑은 시드를 갖는 지갑입니다. 시드를 사용해서 마스터 키를 생성하고, 마스터 키로 부터 모든 키들을 생성합니다.
결정 지갑은 시드만 관리하면 됩니다. 시드만 알고 있으면 모든 키를 다시 생성해 낼 수 있기 때문입니다. 시드만 백업 받아 놓으면 되고, 시드만 가져오기나 내보내기 하면 됩니다. 키들을 별도 관리할 필요가 없습니다.
HD Wallets (BIP-32/BIP-44) – 시드로 부터 어떻게 키들을 생성해 낼 것인가?
결정 지갑의 가장 발전된 형태는 BIP-32 표준에 정의된 HD 지갑입니다. HD 지갑은 그림 3과 같이 키들이 트로 구조로 계층을 형성합니다. 시드로 부터 마스터키를 생성하고 마스터키로 자식키들을 생성하고 자식키들로 부터 손자키들을 생성해 내고 계속적으로 자손키들을 생성해 냅니다.
HD 지갑은 조직 구조와 유사한 트리 구조를 갖기 때문에 조직 구조를 반영한 키 관리를 가능하게 합니다. 또한 부모 공개키 만으로 자식 공개키들을 만들 수 있기 때문에, 개인키를 노출하지 않고도 필요한 주소들을 생성할 수 있습니다. 이러한 특징들을 잘 이용하면 유용한 다양한 사용사례를 만들어낼 수 있습니다.
Seeds and Mnemonic Codes (BIP-39) – 시드를 어떻게 관리할 것인가?
의미 없는 랜덤 수 보다는 사람이 알기 쉬운 단어로 이루어진 시드를 표현할 수 있다면, 적어두기도 쉽고 지갑들 사이에 내보내기나 가져오기도 쉬울 것입니다. 일련의 단어들로 이루어진 시드를 니모닉이라고 합니다. BIP-39는 니모닉 표준을 정의합니다. 니모닉은 초기에는 영어 단어만 지원했으나 지금은 한국어를 포함한 다수의 언어들을 지원합니다.
Wallet Best Practices
지갑을 개발을 개발하다면 BIP-39, BIP-32, BIP-43을 지원하도록 해야 합니다. 다양한 종류의 코인들과 다수의 계정을 지원하는 지갑을 개발하려면 여기에 BIP-44 또한 지원해야 합니다.
Wallet Technology Details
지갑 기술에 대해서 좀 더 상세하게 설명합니다.
Mnemonic Code Words (BIP-39)
Generating mnemonic words
그림 6은 엔트로피를 생성하고 니모닉 단어들로 인코딩하는 과정을 설명합니다.
- 128비트 랜덤 수를 생성합니다.
- 시드는 랜덤하게 생성해야 합니다. 얼마나 랜덤한가는 얼마나 무질서(엔트로피)한가를 의미합니다. 비트 수가 더 크다는 것은 더 높은 엔트로피를 사용한다는 것을 의미합니다.
- 대부분의 지갑들은 128비트 엔트로피를 사용합니다. 표22는 다양한 엔트로피와 그에 따른 니모닉 단어 수가 어떻게 달라지는지를 보여줍니다.
- 시드는 랜덤하게 생성해야 합니다. 얼마나 랜덤한가는 얼마나 무질서(엔트로피)한가를 의미합니다. 비트 수가 더 크다는 것은 더 높은 엔트로피를 사용한다는 것을 의미합니다.
- SHA256 함수로 1에서 생성한 랜덤수의 해시 값을 구합니다.
- 해시 값의 첫 번째 4비트를 1에서 생성한 랜덤수에 덧붙입니다. 결과는 132비트가 됩니다.
- 3의 결과를 11비트 씩 나눕니다. 12개의 부분으로 나눠집니다.
- BIP-39에 정의된 대로 12개 부분으로 나눠진 수들에 매핑되는 단어들을 구합니다.
- 12개의 순서가 있는 단어 목록을 구할 수 있습니다.
From mnemonic to seed
그림 7은 니모닉에서 시드를 생성하는 과정을 설명합니다.
- 키 확장 함수 PBKDF2를 사용해서 512비트 길이의 시드를 생성합니다.
- 니모닉이 나타내는 엔트로피(위의 예에서는 132비트 값)와 추가적인 문구(salt)를 입력으로 사용합니다.
- 추가적인 문구는 “mnemonic” 문자열 상수에 사용자가 정한 비밀구절(passphrase)를 더해서 만듭니다. 비밀구절은 선택적으로 사용할 수 있습니다.
- PBKDF2는 엔트로피와 추가 문구로 이루어진 입력으로 사용해서 HMAC-SHA512 알고리즘으로 2048번 반복해서 해시 값을 구합니다. 결과는 512비트로 확장된 시드입니다.
- 니모닉이 나타내는 엔트로피(위의 예에서는 132비트 값)와 추가적인 문구(salt)를 입력으로 사용합니다.
Working with mnemonic codes
그림 8은 니모닉을 생성할 수 있는 웹페이지를 보여줍니다.
Creating an HD Wallet from the Seed
그림 9는 시드로부터 마스터 키와 체인 코드를 생성하는 과정을 설명합니다.
512비트 시드를 둘 로 나누어서 왼쪽 256비트는 마스터 개인 키로, 오른쪽 256비트는 마스터 체인 코드로 사용합니다. 마스터 개인 키로 마스터 공개 키를 생성합니다.
Private child key derivation
그림 10은 부모 개인 키로 부터 자식 개인 키를 생성하는 과정을 설명합니다.
- 부모 공개키, 부모 체인 코드, 부모 인덱스를 입력으로 HMAC-SHA512로 512비트 해시 값을 생성합니다.
- 512비트를 두 부분으로 나눕니다. 부모의 개인 키와 왼쪽 256비트와 자식 인덱스로 자식 개인 키를 생성합니다. 오른쪽 256비트는 자식의 체인 코드로 사용합니다.
Extended keys
자식 키를 생성하려면 부모 키와 부모 체인 코드를 알아야 합니다. 키와 체인 코드가 하나로 관리된다면 키 파생이 좀 더 쉬울 것입니다. 이러한 요구로 키와 체인 코드가 결합된 확장 키가 등장합니다.
확장 키는 체인 코드가 어떤 키와 결합하느냐에 따라 확장 개인 키와 확장 공개 키로 구분됩니다. 확장 개인 키는 개인 키가 확장 공개 키는 공개키가 체인 코드에 결합됩니다.
확장 키는 Base58Check으로 인코딩됩니다. 확장 키는 일반 키와 구분하기 위해 특별한 버전을 사용합니다. 버전에 따라 확장 개인 키는 ‘xprv’로, 확장 공개 키’xpub’로 인코딩됩니다.
Public child key derivation
HD 지갑은 자식의 개인 키 없이 부모의 공개 키로 자식 공개 키를 생성할 수 있습니다. 이 특징 또한 잘 사용하면 다양한 유용한 사례들을 만들어 낼 수 있습니다.
그림 11은 확장 부모 공개 키로 부터 자식 공개 키를 생성하는 과정을 설명합니다.
- 부모 공개키, 부모 체인 코드, 부모 인덱스를 입력으로 HMAC-SHA512로 512비트 해시 값을 생성합니다.
- 512비트를 두 부분으로 나눕니다. 부모의 공개 키와 왼쪽 256비트와 자식 인덱스로 자식 공개 키를 생성합니다. 오른쪽 256비트는 자식의 체인 코드로 사용합니다.
여기 까지 진행한 내용을 다시 정리해 보면, “자식 개인 키로 생성한 자식 공개 키와 확장 부모 공개 키로 부터 파생한 자식 공개 키가 같다”는 결론을 얻을 수 있습니다. 본문에서는 어떻게 그렇게 되는지는 설명해 주지 않고 있지만 수학적으로 증명 가능합니다. 좀 더 자세한 내용이 궁금하신 분들은 비트코인 개발자 가이드 관련 부분을 참고합니다.
Hardened child key derivation
The ability to derive a branch of public keys from an xpub is very useful, but it comes with a potential risk. Access to an xpub does not give access to child private keys. However, because the xpub contains the chain code, if a child private key is known, or somehow leaked, it can be used with the chain code to derive all the other child private keys. A single leaked child private key, together with a parent chain code, reveals all the private keys of all the children.
확장 공개 키는 체인 코드를 포함하고 있기 때문에 자식 개인 키를 알게 된다면 자식 키로 부터 파생되는 모든 키들을 알 수 있다는 위험이 있습니다. HD 지갑은 이러한 위험에 대응하기 위해 hardened child key derivation 방법을 사용할 수 있도록 합니다.
그림 13은 자식 키를 hardened derivation 방법으로 생성하는 것을 설명합니다.
hardened derivation 방법으로 자식 키를 생성해야 한다면 부모 공개키 대신 부모 개인키를 HMAC-SHA256 입력으로 사용합니다.
HD 지갑은 일반 파생 방식과 hardened derivation 방식을 모두 사용합니다. 32비트 자식 인덱스에서 231 과 232–1 사이 값에 해당하는 인덱스(0x80000000에서 0xFFFFFFFF)는 hardened derivation을 사용합니다.
hardened derivation을 사용할 때 자식 인덱스를 좀 더 쉽게 표시하고 읽기 위해서, 일반 방식 처럼 0부터 시작합니다. 단 숫자 위에 0’와 같이 prime symbol을 작성합니다.
마스터 키의 첫 번째 레벨 자식들은 항상 hardened derivation을 통해 생성하는 것을 추천합니다.
HD wallet key identifier (path)
HD 지갑에서 키는 계층 레벨과 인덱스를 갖기 때문에 이것을 사용해서 키를 식별할 수 있습니다. 계층 구분은 /를 사용합니다.
개인키와 공개키를 구분하기 위해 개인키에는 m을 공개키에는 M을 사용합니다. 마스터 키는 루트니까 m, M. 마스터 키의 첫 번째 자식은 m/0, M/0과 같이 나타냅니다.
표 6의 경로를 보고 경로가 의미하는 바를 설명해 봅니다.
Navigating the HD wallet tree structure
BIP-43은 첫 번째 자식은 hardened 인덱스를 사용하도록 하고, 각각의 인덱스는 목적을 갖도록 정의하고 있습니다.
BIP-44는 미리 정의된 5개의 레벨을 정의하고 있습니다. 3번째 레벨까지는 hardened 인덱스입니다. purpose’는 44’로 정해져 있습니다.
두 번째 레벨에 coin_type’을 정의할 수 있게 함으로 비트코인 외에도 다수의 코인 타입을 사용할 수 있도록 합니다. 비트코인은 m/44’/0′, 비트코인 테스트넷은 m/44’/1′, 라이트코인은 m/44’/2’로 정의되어 있습니다.
세 번째 레벨은 계정으로 회계나 조직의 목적에 따라 하위 계정을 분리해서 사용할 수 있도록 합니다.
네 번째 레벨부터는 일반 방식의 인덱스를 갖기 때문에 확장 공개키의 장점을 활용하는 영역에 사용할 수 있습니다. HD 지갑은 네 번째 레벨로 두 계층을 갖습니다. 하나는 받는 주소를 만들어내기 위한 것이고 다른 하나는 잔돈 주소를 위한 것입니다.
표 7의 경로를 보고 경로가 의미하는 바를 설명해 봅니다.