Jason Dev
About
비트코인 주소와 지갑
published: 2023-11-05
bitcoin
address
hd wallet
mnemonic

비트코인 주소는 사용자 편의를 위해 만들어진 개념이다. 보통은 비트코인을 특정 주소로 보낼 때 트랜잭션의 출력에 해당 주소가 직접적으로 기록되지는 않는다.

비트코인 초창기에는 공개키가 곧 주소였고, 해당 주소가 직접적으로 트랜잭션의 출력에 기록됐다. 하지만 이제는 몇 가지 표준화된 비트코인 주소를 사용하게 되면서 각 비트코인 주소가 가리키는 스크립트 유형으로 처리된다.

각 스크립트 유형의 비트코인 주소에 대해 알아보자.

스크립트 유형별 비트코인 주소

P2PKH 주소

공개키로부터 P2PKH 주소를 만드는 과정은 다음과 같다.

  1. result1 = RIPEMD160(SHA256(pubkey))
  2. result2 = result1 앞에 0x00 버전 바이트 추가
  3. result3 = result2 뒤에 SHA256(SHA256(result2)) 결과의 처음 4바이트를 추가
  4. address = Base58check(result3)

Base58check 결과값이 주소가 된다.

초기에는 공개키를 해싱하지 않고 그대로 사용했으며 주소라는 개념도 없었다(주소를 만드는 과정 자체가 없었다). P2PKH부터 주소라는 개념이 등장했고 공개키를 해싱해서 사용하기 시작했다. 공개키 해싱은 다음의 장점이 있다.

  • 보안성 강화: 공개키와 관련된 암호학적 취약점이 발견되더라도 공개키가 직접 노출되지 않아서 일정 수준의 보호를 받게 된다. 예를 들어, 공개키로부터 개인키를 계산하려는 시도 자체를 막을 수 있다.
  • 공간 절약: 공개키 크기(ECDSA 비압축 65바이트, 압축 33바이트)에 비해 해싱된 공개키 크기(RIPEMD160 20바이트, SHA256 32바이트)가 더 작다. 이는 트랜잭션 크기 및 블록 크기를 줄여주는 효과가 있다.

P2SH 주소

주소를 만드는 과정은 P2PKH와 거의 같으며 입력으로 리딤 스크립트(RedeemScript)를 사용한다는 점과 버전 바이트만 다르다. 리딤 스크립트로부터 P2SH 주소를 만드는 과정은 다음과 같다.

  1. result1 = RIPEMD160(SHA256(redeemScript))
  2. result2 = result1 앞에 0x05 버전 바이트 추가
  3. result3 = result2 뒤에 SHA256(SHA256(result2)) 결과의 처음 4바이트를 추가
  4. address = Base58check(result3)

P2WPKH 주소

공개키로부터 P2WPKH 주소를 만드는 과정은 다음과 같다.

  1. result1 = RIPEMD160(SHA256(pubkey))
  2. result2 = 8bit 배열인 result1을 5bit 배열로 변환 (result1.length=20 => result2.length=32)
  3. result3 = result2 앞에 00000(5개의 비트) 버전 정보 추가 (result3.length=33)
  4. checksum = result3와 HRP(Human Readable Part, =bc)를 이용해서 체크섬 계산 (코드)
  5. result4 = result3 뒤에 checksum 추가 (result4.length=39)
  6. result5 = result4 배열의 각 요소를 Bech32 문자로 매핑
  7. address = result5 앞에 'bc1' 추가 (address.length=42)

P2WSH

주소를 만드는 과정은 P2WPKH와 거의 같으며 입력으로 리딤 스크립트(RedeemScript)를 사용한다는 점과 result1 계산 시 SHA256만 사용하고 RIPEMD160는 사용하지 않는다는 점이 다르다. 따라서 result1.length는 32가 되고 5bit 배열로 변환 시 result2.length는 P2WPKH 보다 20 만큼 더 커진다. 결과적으로 P2WSH 주소는 P2WPKH의 42 문자보다 20 더 많은 62 문자가 된다.

P2TR 주소

주소를 만드는 과정은 P2WPKH와 거의 같으며 버전 정보로 0이 아니라 1을 사용한다는 점과 인코딩 시 Bech32 대신 Bech32m를 사용한다는 점이 다르다. Bech32m은 Bech32 체크섬 계산의 약점을 보완했다. 그리고 P2TR에서는 서명 알고리즘으로 Schnorr를 사용하면서 변형된 공개키를 사용하게 된다.

니모닉(Mnemonic)

비트코인 니모닉(mnemonic)은 종종 시드 문구(seed phrase) 또는 복구 문구(recovery phrase)로 불리며 비트코인 지갑을 생성하기 위한 초기 데이터를 사람이 읽을 수 있는 단어들의 연속으로 표현한 것이다.

복잡한 문자열로 이루어진 개인키를 사람이 관리하는 것은 실수의 여지가 있기 때문에 사용자 친화적인 니모닉을 사용하는 게 좋다. 현재 거의 모든 지갑 앱이 니모닉을 통해 지갑을 생성하는 프로세스를 채택하고 있다. 이때 니모닉을 프린트하거나 클립보드에 복사해서 메모장에 붙여넣는 등의 행동은 위험하다(라고 개인적으로 생각한다). 아날로그 방식으로 니모닉을 백업할 것을 추천한다.

니모닉 만들기

니모닉은 BIP-39에서 제안되었으며 니모닉을 만드는 과정은 다음과 같다.

  1. 엔트로피 선택: 무작위 데이터(엔트로피)를 생성한다. 이 엔트로피의 크기는 128비트에서 256비트 사이이며, 니모닉의 길이(12, 15, 18, 21, 24단어)를 결정한다.
  2. 체크섬 추가: 엔트로피 길이의 1/32 만큼이 체크섬 크기이다. SHA256(엔트로피) 결과에서 (앞쪽부터) 체크섬 크기 만큼을 엔트로피 뒤에 붙인다. 예를 들어, 256비트 엔트로피에는 8비트 체크섬이 추가되어 총 264비트가 된다.
  3. 니모닉 문구 생성: 이제 엔트로피와 체크섬을 합쳐서 11비트 단위로 나눈다. 각 11비트 단위는 2048개 단어로 이루어진 BIP-39 단어 리스트 중 하나와 대응된다. (264/11=24단어)
  4. 필요한 경우 선택적으로 패스워드를 설정할 수 있다. (BIP-39 스펙에 있는 내용이며 대부분의 지갑이 지원한다)

체크섬이 존재하므로 단순히 니모닉 문구 24개를 선택하는 것으로는 유효하지 않은 니모닉이 생성될 확률이 높다. 23개의 단어를 선택했다면 마지막 1개의 단어로 들어갈 수 있는 단어는 2048개 중에 보통 10개 미만이다. 단어를 직접 선택하는 것은 무작위 생성이 아니므로 위험하다. 사람이 직접 선택하는 단어는 편향될 위험이 있기 때문에 비교적 쉽게 타인에게 노출될 수 있다.

니모닉을 생성할 때는 주사위 등의 무작위 생성 방식을 사용하는 게 좋다. 이미 많은 지갑 앱에서 주사위나 오디오/비디오 등의 무작위 데이터를 통한 니모닉 생성 기능을 제공하고 있다. 필요한 경우 필자가 만든 니모닉 생성 사이트를 이용하자.

12단어 vs 24단어

12단어는 128비트 엔트로피로 이루어져 있으며 2^128 가지의 가능한 조합을 의미한다. 이는 엄청난 수치로, 현재의 컴퓨팅 기술로는 단순 대입(brute force) 공격으로 이를 깨트리기가 실질적으로 불가능하다. 단순 계산을 통해 초당 수조번의 시도를 할 수 있는 고성능 컴퓨터로도 10^25년 이상이 걸린다. 따라서 12단어도 충분히 안정적이라고 할 수 있다.

HD 지갑

HD 지갑 (Hierarchical Deterministic Wallet)은 트리 구조를 사용하여 하나의 시드(보통 니모닉)에서 무한히 많은 개인키와 공개키를 파생시킬 수 있는 비트코인 지갑이다. HD 지갑의 주요 특징 및 장점은 다음과 같다.

  1. 계층적 구조: HD 지갑은 계층적 트리 구조를 가지고 있어, 여러 계층에 걸쳐 다양한 개인키와 공개키를 생성할 수 있다. 이를 통해 사용자는 다양한 목적으로 주소를 구분하여 사용할 수 있다.
  2. 결정성: 동일한 니모닉을 사용하면 언제든지 동일한 키와 계층 구조를 복구할 수 있다.
  3. 보안성: HD 지갑은 트랜잭션마다 새로운 주소를 생성하므로, 사용자의 거래 행위를 추적하기 어렵게 만들어 개인정보 보호에 기여한다.
  4. 확장성: BIP-32, BIP-44, BIP-49, BIP-84 등의 프로토콜은 HD 지갑의 다양한 사용 사례와 기능을 정의하고 있다. 예를 들면, BIP-44는 여러 암호화폐와 여러 계정을 지원하는 HD 지갑의 구조를 정의한다.

BIP-44

BIP-44BIP-32를 확장하여 여러 암호화폐와 여러 계정을 지원하도록 정의한 프로토콜이다. BIP-44는 경로를 표준화하여 다양한 암호화폐와 계정을 구분하고 관리할 수 있게 해준다.

BIP-44는 다음과 같이 경로 구조를 정의한다.

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

여기서 각 섹션은 다음을 의미한다.

  • m: master node
  • purpose': 항상 44' (BIP-44의 번호)로 고정
  • coin_type': 각 암호화폐에 할당된 고유 번호 (Bitcoin은 0, Ethereum은 60)
  • account': 사용자 지갑 내부의 계정 번호. 이를 통해 사용자는 지갑 안에 여러 개의 독립된 계정을 생성할 수 있다.
  • change: 0은 외부에 공개하는 주소용(수신 주소), 1은 내부 주소용(거스름돈 주소)
  • address_index: 주소의 인덱스 번호. 각 계정 내에서 주소를 생성할 때마다 증가

예를 들어, m/44'/0'/0'은 BIP-44 프로토콜을 따르고 비트코인을 관리하며 첫 번째 계정이라는 것을 의미한다. 만약 같은 니모닉으로 부모님의 비트코인 계정도 관리하고 싶다면 m/44'/0'/1'을 활용할 수 있다.

BIP-49

BIP-49는 P2SH를 사용하여 SegWit 트랜잭션을 지원하는 주소를 생성하기 위한 방법을 제시한다. SegWit의 이점을 누리고 기존 시스템과의 호환성도 유지할 수 있도록 설계되었다. 이는 특히 레거시 시스템이나 지갑이 SegWit을 직접 지원하지 않는 경우에 유용하다. 다만 현재는 대부분의 지갑이 SegWit을 지원하므로 이 방식을 선택할 필요는 없어보인다.

BIP-49의 경로는 purpose' 부분에 49'가 들어간다.

BIP-84

BIP-84는 BIP-44를 확장하여 SegWit 주소(P2WPKH) 생성을 지원하는 프로토콜이다. 현재 시점에 HD 지갑을 생성한다면 보통 이 프로토콜을 선택하게 된다.

BIP-84의 경로는 purpose' 부분에 84'가 들어간다.

BIP-86

BIP-86은 BIP-44를 확장하여 Taproot 주소(P2TR) 생성을 지원하는 프로토콜이다. 현재 시점에는 이 프로토콜을 지원하는 지갑이 많지 않다.

BIP-86의 경로는 purpose' 부분에 86'이 들어간다.

xpub

xpub은 확장 공개키(Extended Public Key)를 의미한다. 에어갭(air-gap) 방식의 하드웨어 지갑을 사용한다면 잔고 확인 및 수신 주소 확인을 위해 xpub를 추출해서 소프트웨어 지갑에 입력하게 된다.

xpub의 주요 구성요소는 다음과 같다.

  • Depth: 마스터 키에서 해당 키까지의 계층적 수준을 표현한다. 예를 들어, m/84'/0'/0'은 마스터 키에서 3단계 아래에 있으므로 Depth는 3이다. (m => 84 => 0 => 0)
  • Fingerprint: RIPEMD-160(SHA256(부모 공개키)) 해시의 앞 4바이트다. 예를 들어, m/84'/0'/0'의 Fingerprint는 m/84'/0'의 공개키를 기반으로 계산된다.
  • Public Key: 실제 33바이트 압축 공개키

xpub을 사용하는 주된 이점 중 하나는 개인키를 노출하지 않고도 HD 구조를 통해 여러 공개키를 생성할 수 있다는 점이다. 예를 들어, 거래소나 지갑 서비스는 사용자의 개인키를 알 필요 없이 사용자의 각 입금마다 고유한 주소를 생성할 수 있다.

xpub이 주어지면, 해당 xpub에서 파생된 어떤 주소에도 입금할 수 있지만, 자금을 출금하거나 지출하기 위해서는 해당 주소의 개인키(xpriv)가 필요하다. 그러므로 xpub은 안전하게 공유될 수 있으며, 이를 통해 외부 서비스나 애플리케이션에서 해당 경로의 모든 주소에 대한 잔액을 모니터링할 수 있다.

댓글 삭제 시 메일 주소가 필요합니다