블록체인: 지갑과 니모닉(Mnemonic)
1. 블록체인 지갑 기본 개념 블록체인 지갑 : 디지털 자산을 담는 소프트웨어 : 개인키 또는 니모닉을 소유하고 있는 사람만이 접근 가능 : 수많은 DApp들과 상호작용할 수 있음 : 자료형이 허용하는 한도까지 디지털 자산을 보관할 수 있음 => 지갑은 체인에서 허용
1. 블록체인 지갑 🎯

블록체인에서 지갑은, 디지털 자산을 관리하는 소프트웨어입니다. 개인키(Private Key)를 소유한 사람만이 블록체인 지갑에 접근할 수 있습니다.

그런데 왜 체인별로 다른 지갑을 사용할까요? 이에 앞서 체인이 의미하는 바가 무엇일까요?
블록체인은 블록이 체인으로 연결된 형태의 네트워크를 의미합니다. 각 체인은 자신만의 규칙, 합의 방식, 데이터 구조를 갖고 있습니다. 지갑은 결국 블록체인과 사용자를 연결하는 소프트웨어이기 때문에, 각 체인이 제공하는 고유한 API와 프로토콜을 사용해야 합니다.
그래서 이더리움 체인에서는 이더리움의 API 규격에 맞춰 개발된 Metamask를 사용하고, 솔라나 체인에서는 솔라나의 API 규격에 맞춰 개발된 Phantom을 사용하도록 생태계가 분화된 것으로 이해할 수 있습니다.
2. 니모닉(Mnemonic) 🎯
블록체인 지갑의 핵심은 개인키입니다. 하지만 개인키는 e9873d79c6d87dc0fb6a5778633389f4453213303da61f20bd67fc233aa33262와 같이 64자리의 16진수로 이루어져 있어, 사람이 기억하거나 안전하게 백업하기에는 너무 복잡합니다.
이 문제를 해결하기 위해 BIP-39 표준에서 니모닉(Mnemonic)이 도입되었습니다. 니모닉은 복잡한 개인키를 12~24개의 일반적인 영어 단어로 변환하여, 인간이 읽고 기억하기 쉬운 형태로 만든 것입니다.
2-1. 엔트로피 생성 ✅
엔트로피는 무작위로 생성된 난수입니다.
import secrets
# Define strength (in bits) for the entropy
strength = 128 # You can set this to 128, 160, 192, 224, or 256
strength_bytes = strength // 8
# Generate entropy using the secrets module
entropy = secrets.token_bytes(strength_bytes)
# Print the generated entropy in hexadecimal format
print(f'Created entropy: {entropy.hex()} ({len(entropy)} bytes, len(hex): {len(entropy.hex())})')위 코드에서는 strength를 128비트로 설정했습니다. 비트가 클수록 더 안전하지만 니모닉 단어 개수가 늘어날 것입니다. 우선 128로 가정하시죠.
strength_bytes는 strength를 8비트, 즉 1바이트 단위로 나눈 값입니다. 컴퓨터는 바이트 단위를 다루기 때문에 그에 맞게 값을 변형한 것이죠.
엔트로피라는 용어는 원래 무작위성 또는 예측 불가능성을 의미합니다. 암호학에서는 아무도 추측할 수 없는 완전한 랜덤 데이터를 뜻합니다.
secret 모듈로 16바이트(128비트)의 랜덤 데이터를 생성합니다. 이것이 바로 엔트로피입니다. 8비트 덩어리가 16개 있는 형태죠.
생성된 엔트로피를 hex 함수를 통해 16진수 형태로 출력하여 확인해 보면 다음과 같은 임의의 값이 도출됩니다. 8비트는 256가지 값을 표현할 수 있고 이는 16진수 두 자리(00~FF)로 표현할 수 있으니 length가 32가 되는 것은 쉽게 이해할 수 있습니다.
Created entropy: 010c462be9c6477a25aed634e3249823 (16 bytes, len(hex): 32)복잡한 개인키를 인간이 읽기 쉬운 니모닉으로 변환하는 첫 번째 단계를 완료했습니다. 예측 불가능한 128비트 랜덤 데이터(엔트로피)를 생성했고, 이것이 최종적으로 12개의 영어 단어로 변환될 것입니다.
2-2. 엔트로피에 체크섬 추가 ✅
import hashlib
entropy_hash = hashlib.sha256(entropy).hexdigest()
print(f'Calculated sha256 hash of entropy: {entropy_hash}')Calculated sha256 hash of entropy: cb83363eb76b651c3c465f8bed6546d39e8eccfba0a25ad989be172e74a3a983엔트로피, 즉 예측 불가능한 128비트 랜덤 데이터를 SHA-256 해시 함수에 전달합니다. 체크섬이란, 데이터 전송 중 오류가 발생했는지 확인하기 위해 사용되는 값입니다.
해시는 임의의 길이의 데이터를 고정된 길의의 데이터로 변환하는 과정을 의미합니다. 단 한 글자라도 변경되면 전혀 다른 데이터가 도출됩니다. 엔트로피의 일부에 변형이 생겼다면, SHA-256 해시 함수를 거친 값은 전혀 다른 데이터가 되겠죠?
# Compute the SHA-256 hash of the entropy, which is used to derive the checksum.
# The hash is assumed to be in hexadecimal format, so it's converted to binary.
entropy_hash_bits = bin(int(entropy_hash,16))[2:].zfill(256)
print(f'Entropy hash bits: {entropy_hash_bits} ({len(entropy_hash_bits)} bits)')만약 해시값이 "7"이었다고 가정해 봅시다.
int("7", 16) → 숫자 7이 됨.
bin(7) → "0b111"이 됨. (이진수 111)
[2:] → "111"이 됨. (파이썬에서 이진수임을 표시하는 0b 제거)
.zfill(8) → "00000111"이 됨. (8자리로 꽉 채움)entropy_hash_bits는 16진수로 된 해시값을 컴퓨터가 쓰기 좋게 256자리 이진수(0 또는 1) 덩어리로 변환한 결과입니다.
# Extract the first (entropy length / 32) bits of the hash to use as the checksum.
# This ensures the checksum length is proportional to the entropy length.
first_bits = len(entropy) * 8 // 32
print(f'Calculate checksum bits... | len_entropy(bits): {len(entropy) * 8}, len_entropy // 32: {first_bits}')
checksum_bits = entropy_hash_bits[:first_bits]
print(f'Checksum bits: {checksum_bits} (len: {len(checksum_bits)})')체크섬은 데이터 전송 중 오류가 발생했는지 확인하기 위해 사용되는 값인데 전체를 다 체크섬으로 사용하는 것은 본질에 맞지 않겠죠. 후술하겠지만, BIP-39 표준에는 엔트로피 32비트당 체크섬 1비트를 붙인다는 법칙이 있습니다.
first_bits는 우리가 128비트를 엔트로피로 사용했기 때문에 앞에 4글자가 될 것입니다.
checksum_bits는 계산된 길이만큼 실제로 맨 처음부터 4개만큼 잘라내는 작업입니다.
# Convert the entropy to binary bits.
# The entropy is converted from bytes to an integer, then to a binary string.
# The length is padded to match the number of bits in the entropy.
entropy_bits = b = bin(int.from_bytes(entropy, byteorder="big"))[2:].zfill(len(entropy) * 8)
print(f'Entroy bits: {entropy_bits} (len: {len(entropy_bits)})')우리의 최종 목표는 엔트로피 비트에 체크섬(위에서 구한 네 자리)를 붙이는 것입니다. 이를 위해서는 엔트로피 역시 비트 형태여야겠죠?
int.from_bytes(entropy, ...)는 바이트를 숫자로 변경하라는 코드입니다. 15와 같은 일반적인 숫자로 변경되었다면 bin 함수를 통해 해당 숫자를 이진수로 변경합니다.
entropy_bits는 말 그대로 엔트로피를 비트 형태로 변환한 값입니다.
# Concatenate the entropy bits with the checksum bits.
# This forms the final bit sequence that will be used to generate the mnemonic words.
bits = entropy_bits + checksum_bits
print(f'[entropy_bits|checksum_bits]: {bits} (len: {len(bits)})')bits는 엔트로피 비트 값에 체크섬 비트 값을 결합한 형태의 값입니다.
2-3. 엔트로피 + 체크섬을 11비트 단위로 분할 ✅
result = []
for i in range(len(bits) // 11):
idx = int(bits[i * 11 : (i + 1) * 11], 2)
print(f'Calculated idx: {idx}')
word = wordlist[idx]
print(f'Word at {idx}: {word}')
result.append(word)
print(f'Successfully created mnemonic: {result} ({len(result)} words, {len(result)*11} bits)')엔트로피가 128비트였고 체크섬 4비트를 추가했으니 bits는 132비트겠죠?
이를 11비트씩 떼어냅니다. 그런데 왜 하필 11비트로 나눌까요? 비트코인 니모닉 단어 목록에 들어있는 단어 개수가 정확히 2의 11승, 즉 2048개이기 때문입니다. 그리고 각 숫자를 인덱스로 활용하여 단어로 교환하게 됩니다.
2-4. Wordlist의 인덱스로 사용하여 단어 매핑 ✅
wordlist = []
with open("english.txt", "r", encoding="utf-8") as f:
wordlist = [w.strip() for w in f.readlines()]
print('Successfully loaded wordlist')
wordlistSuccessfully loaded wordlist
['abandon',
'ability',
'able',
'about',
'above',
'absent',
'absorb',
'abstract',
...]BIP-39는 Bitcoin Improvement Proposal 39(비트코인 개선 제안서 39번)입니다. 비트코인을 개선하기 위한 39번째 제안서라고 볼 수 있고, 해당 제안서에서는 복잡한 암호화폐 지갑 비밀번호를 사람이 외우기 쉬운 단어로 만들자는 표준을 제안했습니다.
이제 우리가 얻어낸 인덱스로 12개의 단어 리스트를 도출할 수 있게 되었습니다. 다음과 같은 값이 나오겠네요.
mnemonic = [
"witch", "collapse", "practice", "feed", "shame", "open",
"despair", "creek", "road", "again", "ice", "least"
]3. 복습 🎯
디지털 시대의 검열로부터 자유를 지키기 위해 블록체인이라는 개념이 고안되었습니다. 비잔틴 장군 문제라는 난제를 공개키 암호화와 합의 알고리즘으로 풀어내며, 메세지의 위변조 방지와 무결성을 보장할 수 있게 된 것입니다.
블록체인 지갑은 이러한 디지털 자산을 관리하는 도구이며, 그 소유권은 오직 개인키(Private Key)로 증명됩니다. 하지만 64자리 16진수로 된 개인키는 인간이 다루기에 너무 가혹했습니다. 그래서 BIP-39 표준은 이 복잡한 키를 사람이 기억할 수 있는 니모닉(Mnemonic)으로 변환하는 방법을 제시했습니다.
엔트로피에 체크섬을 더해 11비트로 나누고, 이를 단어 사전에 매핑하여 니모닉을 만드는 과정. 이 일련의 과정을 통해 우리는 비로소 블록체인 지갑을 안전하고 쉽게 관리할 수 있게 되었습니다.
확실히 자유는 공짜가 아니네요. 기술적 이해가 마냥 쉽진 않습니다. 하지만 되뇌어보죠. 어려운 게 아니라, 낯선 것일 뿐입니다.
More to read
Amazon VPC Architecture 이해하기
새로운 프로젝트를 기획하며, 개발에서 무엇을 가장 먼저 고민해야 하는지 다시 돌아보게 되었습니다.한때는 프론트엔드가 모든 설계의 출발점이라고 믿었습니다. 유저가 무엇을 보고, 어떤 흐름에서 머무르고 이탈하는지에 대한 이해 없이 서비스를 만든다는 건 불가능하다고 생각했기
'원사이트'프론트엔드 관점으로 알고리즘 이해하기
오랜만에 방법론에 관한 글을 쓰게 되었습니다. 최근 상황은 이렇습니다. SSAFY에서는 하루에 엄청난 양의 알고리즘 문제들을 과제로 수행하게 됩니다. 그 과정에서, '구현력'이 매우 떨어진다는 생각이 들었습니다. 완전히 어려운 문제라면 '아쉬움'이라는 감정조차 느끼지
SubnetVPC 설계의 시작: IP와 Subnet
반복되는 루틴 속에서 얻은 안정감을 발판 삼아, 이제는 기술적 스펙트럼을 넓히기 위한 개인 프로젝트에 착수하고자 합니다.이번 프로젝트의 목표는 단순한 포트폴리오 구축을 넘어, 실제 서비스 수준의 블로그 시스템 구현과 다국어 처리 적용 등 실무에 가까운 역량을 한 단계