파이썬으로 배우는 블록체인 구조와 이론 — 3장 지갑(Wallet)

Minjoo
Quantum Ant
Published in
11 min readJul 28, 2019

01. 비트코인 지갑 주소

지갑은 잔액을 사용할 수 있는 권한이 부여된 키와 주소를 관리한다.

비트코인 지갑은 자신만의 고유한 주소를 갖는다.

노드들은 지갑 주소를 통해 코인을 주고받는다.

지갑 주소는 개인 키와 공개키로 만들어진다.

키와 지갑 주소

<지갑 주소가 생성되는 과정>

(1) 개인키로 공개키 생성한다.

개인키(256 bit) : 특정 범위의 수에서 한 개를 랜덤하게 선택한다.

공개키(512 bit) : 개인키와 타원곡선 암호로 만들어진다.

(2) 공개키 해시(160 bit) 계산한다.

공개키에 SHA — 256 해시 알고리즘을 두 번 적용한 후 RIPEMD 160 해시 알고리즘을 적용한 것이다.

(3) 지갑 주소(160bit) 생성한다.

공개키 해시 값을 ‘Base58Check’로 인코딩 한 것이다.

  • 지갑 주소로 공개키 해시는 만들 수 있지만 공개키 해시로 공캐키를 만들 수 없고 공개키로 개인키를 만들 수는 없다.

*해시 함수 : 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수를 의미합니다.

**SHA? 안전한 해시 함수의 약자로 해시함수의 종류 중 하나이다.

02. 개인키(Private Key)

개인키 : 주소 생성의 시작점이며 비트코인의 소유권을 보증하는 등 가장 중요한 역할

타원곡선 암호의 표준 문서

타원곡선암호의 표준 문서 : http://www.secg.org/sec2-v2.pdf

비트코인은 이 문서의 p9에 정의된 secp256k1규격을 따르는 데 비트코인의 모든 애플리케이션도 이 규격에 따라 키를 만든다.

랜덤 넘버 생성기(Random Number Generator:RNG)

<난수 생성 방법>

TRNG (True Random Number Generators)

: 실제 물리적인 행위를 기반으로 난수를 생성하는 방식

예를 들어 동전이나 주사위 던지기, 마우스의 움직임 등이 있다. 난수에는 패턴이 없어 완전 무작위적이라 할 수 있다.

PRNG (Pseudo-random Number Generators)

: 시드(seed)값을 이용해 시계열로 난수를 생성한다. 시드 값은 주로 클럭을 사용한다.

일반적인 프로그래밍 언어는 이 방식을 사용한다. (예시 : 파이썬의 random.random() 함수)

하지만 이 방식은 시계열 간의 연관성이 있을 수 있고, 이후 시계열의 추측 가능성이 있으므로 보안상 안전하지 못한 것으로 알려져 있다.

*시계열 :확률적 현상을 시간적으로 관측하여 얻은 값의 계열로 시간 수열이라 할 수 있다.

*시드값 : 컴퓨터 프로그램에서 발생하는 무작위 수는 사실 엄격한 의미의 무작위 수가 아니다. 어떤 특정한 시작 숫자를 정해 주면 컴퓨터가 정해진 알고리즘에 의해 마치 난수처럼 보이는 수열을 생성하는데 어떤 특정한 시작 숫자를 시드 값이라고 한다.

CSPRNG (Cryptographically Secure Pseudo-random Number Generators)

: 암호학적으로 안전한 PRNG방식으로 OS 디바이스 등 하드웨어 장치에서 발생하는 노이즈들을 모아서 랜덤 시드로 사용하는 방식이다.

Base58Check 인코딩

Base58Check 인코딩 : 숫자나 문자열을 읽기 쉬운 형태의 문자열로 변환하는 알고리즘이다.

개인키, 공개키 지갑 주소에도 사용되며 숫자나 문자열을 아래의 58개 문자로 표현한다.

문자열 : “123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz”

<예시>

Base58Check 인코딩으로 ‘12548’->‘4jM’ 변환 과정

숫자 12548 / 58 => 몫 = 216, 나머지 = 20

->나머지에 해당하는 문자(20번째 문자) :‘M’

216 / 58 => 몫 = 3, 나머지 = 42 ->‘j’

3 / 58 => 몫 = 0, 나머지 = 3 ->‘4’

숫자 12548 ->’4jM’

Wallet Import Format(WIF)

WIF 포맷 : 개인키는 키는 숫자로 이뤄져 있어 읽기가 어려운데 이를 읽기 쉬운 형태로 변환한 것으로 체크섬(Checksum) 값이 포함돼 있어 오류를 검출할 수도 있다.

<개인키 WIF 변환 절차>

* ‘+’는 연산이 아니라 이어붙임을 의미한다.

* 체크섬(checksum)? 중복 검사의 한 형태로, 오류 정정을 통해, 공간(전자 통신)이나 시간(기억 장치) 속에서 송신된 자료의 무결성을 보호하는 단순한 방법이다.

03. 공개키(Public Key)

공개키 = 개인키 + 타원곡선암호

공개키: 트랜잭션 입력부에 전자서명과 함께 기록, 다른 사람들은 기록된 공개키로 전자서명 검증한다.

공개키 유형

비압축 포맷 : (x, y) 좌표 모두 사용한다.

비압축 포맷임을 표시하기 위해 앞에 0x04를 붙인다.

‘0x04 + x좌표 + y좌표’ 형태이다.

비압축 포맷의 공개키 길이 => 8 bit(0x04)+ 256 bit(x좌표) +256 bit(y좌표) = 520 bit

압축 포맷 : x좌표만 사용한다.

압축 포맷임을 표시하기 위해 앞에 0x02 나 0x03을 붙인다.

y좌표가 짝수이면 ‘0x02 + x좌표’, y좌표가 홀수이면 ‘0x03 + x좌표’

압축포맷의 공개키 길이 => 8 bit(0x02 or 0x03) + 256 bit(x좌표) = 264 bit

공개키는 전자서명과 함께 트랜잭션 입력부에 기록한다.

비압축 포맷을 기록하면 트랜잭션의 크기가 커지므로 채굴자에게 더 많은 수수료 지급해야 하기 때문에 압축 포맷의 공개키를 사용하는 게 좋다.

공개키 포맷 변환

압축 포맷의 공개키를 비압축 포맷으로 변환하려면 주어진 함수식에 x값을 대입해서 y값을 계산하면 된다.

  • 타원곡선은 x축에 대칭이므로 y값이 2개 존재하기 때문에 y가 짝수인 경우와 홀수인 경우를 구분한다.

04. 지갑 주소(Address)

지갑 주소는 비트코인을 주고받을 때, 지갑 애플리케이션에서 잔액과 거래 내역을 관리할 때 사용된다.

지갑 주소 생성과정

‘01. 비트코인 지갑 주소’ 부분에서 설명하여 생략한다.

메인넷(Mainnet)과 테스트넷(Testnet)

메인넷 : 실제로 운영되는 비트코인 네트워크

테스트넷 : 비트코인을 개발할 때 시험용으로 사용하는 네트워크

버전 프리픽스(Version pretix)

버전 프리픽스 : 지갑이 어떤 용도로 사용되는지 구분하기 위해 사용한다.

0x00 : 메인넷에서 사용되는 일반 지갑 주소 버전 프리픽스

0x6f : 테스트넷에서 사용되는 시험용 지갑 주소의 버전 프리픽스

0x05 : P2SH용 지갑 주소의 버전 프리픽스

<예시>

‘공개키 해시’ + ‘버전 프리픽스’ 인코딩을 수행하면

메인넷의 지갑 주소는 ‘1’ 으로 시작

(예시 : 182mocjYj7PjCnJxUTSrVCK9dNkbjNqarA)

테스트넷의 지갑 주소는 ‘m’, ‘n’으로 시작

(예시 : mnYj6fpXX8pyytnaC2REK7XUVNMJhs8AKL)

P2SH용 주소는 ‘3’으로 시작

(예시 : 3H1FfAYW5sDYRqJCxUTSrVCK9dNkbjNqarA)

05. 지갑 주소 관리

지갑 애플리케이션들은 개인키와 지갑 주소를 하나만 운영하는 것이 아니라, 보안 상 안전을 위해 여러 개의 개인키를 운용하기도 한다.

거래할 때마다 새로운 개인키로 지갑 주소를 만든다.

예를 들어 일회용 암호(One Time Password: OTP)처럼 한번 쓰고 버리는 개념이다.

06 .지갑 백업 관리

백업 방식

웜 스토리지(Warm Storage) : 개인키를 usb등의 전자장치에 백업하는 방식

장치가 고장나거나 사용자가 실수로 삭제할 가능성이 존재해 장기간 보관 용도로는 비적합하다.

콜드 스토리지(Cold Storage) : 개인키를 물리적(오프라인에 저장)으로 기록해 두는 것

바로 출금은 하지 못한다.

페이퍼 월렛(Paper wallet) : 개인키를 종이에 기록해 두는 것

http://bitaddress.org 에서 제공하는 서비스로 개인키를 화폐나 증권처럼 만들어서 장기간 보관할 수 있다.

페이퍼 월렛도 분실이나 도난, 화재 등의 위험은 존재할 수 있지만 페이퍼월렛이 완벽한 방식은 아니더라도 가장 안전한 방식이라고 할 수 있다.

개인키 유실

개인키 분실 시 블록체인에 기록된 해당 지갑의 UTXO는 영원히 아무도 사용할 수 없다.

또, 비트코인을 보유한 사람이 불의의 사고로 더 이상 개인키를 사용할 수 없는 경우에 비트코인은 관리 주체가 없기 때문에 개인 키를 전달해주지 않으면 상속이 이뤄질 수 없다.

이런 경우를 대비하려면 페이퍼 월렛에 개인키를 기록해 가족끼리 공유할 필요도 있다.

브레인 월렛(Brain Wallet)

개인키를 랜덤하게 생성하지 않고 단어 목록이나 특정문장을 사용해서 개인키를 만드는 방식

특정 문장에 double-SHA-256 해시 알고리즘을 적용하면 해시 값의 크기는 256bit로 개인키의 크기와 동일하기 때문에 개인키로 사용이 가능하다.

이 경우 개인키를 만들 때 사용한 단어 목록이나 문장만 기억하고 있으면 언제든지 개인키를 다시 만들 수 있으며 개인키 자체를 보관할 필요가 없다.

베니티 월렛(Vanity Wallet)

지갑 주소의 특정 위치에 사용자가 원하는 문자열이 나타나게 한 것

베니티 월렛 사용시 사용자 자신이나 다른 사람들이 지갑 주소를 알아보기 쉽다.

예를 들어 인터넷 상점이나 사업체 등에서 회사명을 주소에 표시하면 고객들이 알아보기 쉬울 것이다.

단, 원하는 문자열이 나타날 때까지 개인키를 반복적으로 생성해야 하므로 문자열이 길면 시간이 오래 걸릴 수 있다.

*문자열은 Base58Check 인코딩에 사용되는 문자열만 가능하다.

07 지갑의 유형과 키 관리

비결정적 방식의 지갑(Non-deterministic Wallet)

여러 개의 키를 랜덤하게 만드는 방식이다. ( Type-0형 지갑)

키들은 서로 아무런 연관성이 없어 안전한 방식일 수 있으나 빈번히 바뀌는 키들을 자주 백업해야 하는 번거로움 존재한다.

결정적 방식의 지갑(Deterministic Wallet)

*결정적? 같은 상태라면 똑같은 입력을 주었을 때 항상 같은 결과가 나온다는 의미이다.

시드 값과 해시함수를 이용해서 연쇄적으로 키를 만드는 것이다.

각각의 키들은 시드 값을 시작으로 키 체인을 이루는데 이 키들은 서로 독립적이지 않고 어떤 관계를 갖는다.

그러나 해시함수의 확산 과정 때문에 그 관계가 드러나지 않는다.

초기 시드 값만 보관하면 나머지 키들은 어제든지 다시 만들 수 있다.

(Type-1형 지갑)

08. 계층 구조의 결정적 방식(Hierarchical Deterministic Wallets: HD Wallets, BIP-32)

HD지갑은 계층구조로 키와 지갑 주소를 관리, 마스터 시드로 마스터 개인키와 공개키를 만들고, 마스터키로 하위 계층의 키와 주소 생성

시드와 마스터키를 사용(Type-1유형)하고 여기에 계층구조 적용하여 Type-2로 발전함

개인키 없어도 지갑 주소를 만들 수 있다. 또한 시드 값만 보관하면 하위 계층의 기와 주소들은 모두 원래 상태로 복원할 수 있어 백업 관리 용이

HD 지갑의 구조

HD 지갑은 계층적 구조로 이뤄져 있다

-마스터 시드로 마스터 키를 만든다

-마스터키로 하위 계층의 확장 키를 만든다(하위 계층의 키를 만들때는 CKD(Child Key Derivation) 함수를 이용한다.

*HMAC — SHA512는 메시지 인증코드 알고리즘이다.

**HMAC ? 무결성을 검증하고 메시지를 인증하는 메시지 인증코드인 MAC에 패딩이 추가된 것입니다.

<HD 지갑>

출처 : https://github.com/sipa/bips/blob/bip32update/bip-0032/derivation.png

이 구조의 특징은 하위 계층의 공개키를 만들 때 해당 계층의 개인키를 사용하는 것아니라 상위 계층의 공개키를 사용한다는 것이다.

상위 계층의 공개키는 하위 계층으로 상속된다.

이렇게 만든 공개키는 자기 계층의 개인키로 만든 공개키와 같다.

특정 계층의 개인키-공개키 쌍은 암호학적 특징을 모두 갖추고 있으므로 전자 서명과 검증에 사용될 수 있다.

하위 계층의 지갑 주소를 만들 때도 마찬가지로 상위 계층의 공개키를 사용한다.

활용 케이스

HD지갑을 사용하면 계층 트리 브랜치별로 지갑의 용도를 다르게 활용할 수 있다.

예시

1. 개인

브랜치(A)에 속한 지갑들은 수신전용으로 사용

브랜치(B)에 속한 지갑들은 송금 후 남은 잔돈을 수신할 목적으로 사용

2. 기업에 적용

부서별로 사용권한이 다른 지갑을 운용할 수 있고 감사(audit)도 쉽게 할 수 있다.

3. 인터넷 쇼핑몰에서도 활용

외부 호스팅 서버에 상품을 진열하고 결제를 위한 지갑 주소를 올려놓으면서 지갑 주소를 자주 바꾸는 경우 유용하게 사용할 수 있다.

외부 호스팅 서버에서 개인키를 생성하지 않고 상위 서버에서 받은 공개키로 지갑 주소를 생성할 수 있어 개인키가 외부 호스팅 서버에 노출될 위험이 없다.

09. 니모닉 코드(Mnemonic Code:BIP-39)

브레인 월렛 : 사용자가 임의로 문장이나 단어 목록을 지정

니모닉 코드 월렛 : 사전에 단어 목록을 랜덤하게 선택

사용자가 임의로 지정하는 방식보다 사전에 랜덤하게 선택하는 방법이 훨씬 안전하다.

HD 지갑(BIP-32)의 시드 값을 니모닉 코드(BIP-39)로 생성하면 효과가 더 커진다.

최근 대부분 지갑 애플리케이션들은 니모닉 코드(BIP-39)와 HD지갑(BIP-32)을 지원하고 , 시드 값의 백업, 복업 기능을 지원하고 있다.

--

--