Base58Check 인코딩과 디코딩 방법
인코딩하려면 다음과 같이 합니다.
- 입력 · Hex에 버전 바이트를 먼저, 그다음 페이로드를 hex로 붙여넣으세요. 공백, 콜론,
0x접두사도 받습니다. - 출력 · Base58Check에서 결과를 읽으세요. 도구가 체크섬을 계산해 인코딩 전에 덧붙입니다.
- 비트코인과 대부분의 포크에는 알파벳을 Bitcoin으로 두세요.
디코딩하려면 방향 전환에서 Base58Check → Hex를 누르고 주소나 키를 붙여넣으세요. 디코더는 변환한 뒤 체크섬을 다시 계산하고, 체크섬 4바이트가 모두 일치할 때만 페이로드(여전히 버전 바이트로 시작)를 돌려줍니다. 문자 하나만 잘못 입력해도 “체크섬이 일치하지 않습니다. 문자열에 오타가 있거나 손상되었습니다.“가 표시됩니다.
Base58Check가 Base58에 더하는 것
일반 Base58에는 오류 감지가 없습니다. 오타가 나면 다르지만 똑같이 올바른 문자열이 됩니다. Base58Check는 두 가지를 더해 이를 해결합니다.
version (1 byte) | payload | first 4 bytes of SHA-256(SHA-256(version | payload))
그런 다음 전체를 Base58로 인코딩하므로 앞쪽 0 바이트는 1이 됩니다. 버전 바이트는 네트워크와 데이터 유형을 정하며, 수의 맨 앞에 있으므로 결과의 첫 문자도 정해 줍니다.
버전 바이트와 접두사
같은 20바이트 해시 62e907b15cbf27d5425399ebf6f0fb50ebb88f18에 다른 버전 바이트를 붙이면 다음과 같습니다.
| 버전 | 의미 | 첫 문자 | 결과 |
|---|---|---|---|
00 | 비트코인 P2PKH 주소 | 1 | 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa |
05 | 비트코인 P2SH 주소 | 3 | 3Ai1JZ8pdJb2ksieUV8FsxSNVJCpoPi8W6 |
6f | 테스트넷 P2PKH 주소 | m 또는 n | mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt |
c4 | 테스트넷 P2SH 주소 | 2 | 2N2GDNJ4rEm6NxfMC9ck8VuRdheQzXWaNZv |
첫 행은 비트코인 제네시스 블록의 보상을 받은 주소입니다. 나머지 행은 버전 바이트를 보여 주기 위한 것일 뿐입니다. P2SH는 스크립트를 해시하므로, 공개 키 해시를 P2SH 버전 바이트로 감싸도 쓸 수 있는 P2SH 주소가 되지는 않습니다.
WIF 개인 키
Wallet Import Format은 버전 바이트 80과 32바이트 개인 키로 된 Base58Check입니다. 끝에 붙는 01 바이트는 공개 키를 압축 형태로 쓰는 키라는 표시입니다. 비트코인 위키에 실린 잘 알려진 예시 키로 보면 다음과 같습니다.
| Hex 입력 | Base58Check |
|---|---|
80 + 0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D | 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ |
같은 값 + 01 | KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617 |
압축되지 않은 WIF 키는 5로, 압축된 키는 K나 L로 시작합니다. 이 예시 키는 공개되어 있으니 실제 자금에는 절대 쓰지 마세요.
Python에서 Base58Check
체크섬은 표준 라이브러리의 SHA-256 호출 두 번입니다. 작은 Base58 인코더와 함께 쓰면 다음과 같습니다.
import hashlib
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
def b58encode(data: bytes) -> str:
n = int.from_bytes(data, "big")
out = ""
while n:
n, r = divmod(n, 58)
out = ALPHABET[r] + out
zeros = len(data) - len(data.lstrip(b"\0"))
return "1" * zeros + out
def b58check(payload: bytes) -> str:
checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
return b58encode(payload + checksum)
b58check(bytes.fromhex("0062e907b15cbf27d5425399ebf6f0fb50ebb88f18"))
# '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'
코드에서 문자열을 검증하려면 Base58로 디코딩하고, 마지막 4바이트를 떼어 나머지의 이중 해시와 비교하세요. Python의 바이트 처리는 Python 페이지에 더 있습니다.
자주 겪는 문제
- 체크섬이 일치하지 않습니다. 문자열에 오타가 있거나, 잘렸거나, 체크섬이 없는 일반 Base58입니다(솔라나 주소와 IPFS 해시는 일반 Base58이니 Base58 디코더를 쓰세요).
- “4바이트 체크섬을 담기에는 너무 짧습니다”. 디코딩한 값이 4바이트보다 짧으므로 Base58Check일 수 없습니다.
- 예상하지 못한 문자
"0","O","I","l". Base58 알파벳에 없는 문자입니다. 옮겨 적은 내용을 확인하세요. - 인코딩 후 첫 문자가 다릅니다. 버전 바이트를 확인하세요. 버전 바이트가 없으면 20바이트 해시는 대개
1로 시작하지 않는 문자열로 인코딩됩니다.
자주 묻는 질문
Base58Check 체크섬은 어떻게 계산하나요?
페이로드(버전 바이트 포함)를 SHA-256으로 해시하고, 그 결과를 다시 SHA-256으로 해시한 뒤 처음 4바이트를 가져옵니다. 이 4바이트를 Base58 인코딩 전에 덧붙입니다.
체크섬이 맞으면 그 주소로 보내도 안전한가요?
문자열에 오타가 없다는 뜻입니다. 무작위 오타가 통과할 확률은 약 43억분의 1입니다. 누가 그 주소를 통제하는지, 생각한 네트워크의 주소인지는 알려 주지 않습니다.
Base58Check로 bc1 주소를 디코딩할 수 있나요?
아니요. bc1로 시작하는 주소는 Bech32나 Bech32m(SegWit, Taproot)이며, 다른 알파벳과 다른 체크섬을 씁니다.
실제 개인 키를 여기에 붙여넣어도 되나요?
변환은 브라우저에서 실행되고 페이지는 Cloudflare 조회수 집계를 제외한 모든 네트워크 요청을 차단하지만, WIF 키는 자금을 통제합니다. 가치가 있는 것이라면 테스트 키를 쓰거나 오프라인 컴퓨터를 쓰세요.