결론부터 말하면, "한 글자 틀리면 무조건 영구 소실"은 절반만 맞는 말이에요. 대부분의 경우 그 주소는 보내기 버튼을 누르기 전에 거절돼요. 다만 걸러내는 힘이 주소 형식마다 다르고, 그 숫자가 규격 문서에 그대로 적혀 있어요. bc1q로 시작하는 주소의 bech32는 "4글자까지의 오류는 반드시 잡고, 그 이상도 검출 실패 확률이 10억분의 1 미만"이라고 규격이 스스로 적었어요. 0x 주소는 체크섬이 대소문자에 실려 있어서 평균 15비트뿐이고, 1이나 3으로 시작하는 옛 주소 방식은 같은 규격 문서가 "오류 검출 보장이 없다"고 직접 평가한 방식이에요.
그리고 이 글에서 가장 중요한 한 줄은 이거예요. 소문자로만 적힌 0x 주소에는 검사할 것이 아예 없어요. 체크섬이 대소문자에 실려 있는데 전부 소문자로 눌러 버렸으니까요.
아래 내용은 전부 규격 원문을 직접 열어 인용했고, 규격이 주장하는 성질은 계산으로 다시 재현해 봤어요.
![]()
주소를 보기 전에 먼저 갈라야 하는 네 갈래
주소 문자열은 앞 몇 글자만 봐도 어느 규격인지 갈려요. 그리고 규격이 갈리면 검사하는 방식도, 검사가 보장하는 범위도 달라져요.
| 시작 모양 | 규격 | 문자열 길이 | 대소문자 규칙 | 오류 검출 보장 |
|---|---|---|---|---|
bc1q… | bech32 (BIP-173) | 42자 또는 62자 | 전부 소문자 또는 전부 대문자 | 치환 오류 4글자까지 검출 보장 (삽입·삭제는 별개) |
bc1p… | bech32m (BIP-350) | 62자 | 전부 소문자 또는 전부 대문자 | 치환 오류 보장 유지, 삽입 약점 보완 |
1… 3… | Base58Check | 대개 34자 안팎 | 대소문자가 섞여 있는 것이 정상 | 보장 없음 (4바이트 해시 대조) |
0x… | ERC-55 | 0x 포함 42자 | 대소문자 자체가 체크섬 | 평균 15비트, 조건부 0.0247% |
표에서 이미 이상한 점이 보일 거예요. bc1로 시작하는 두 줄이 서로 다른 규격이고, 대소문자 규칙이 규격마다 정반대예요. 이 두 가지가 이 글에서 가장 자주 오해되는 자리예요.
bc1q 주소 — 규격이 스스로 적어 둔 숫자
BIP-173 원문의 해당 대목은 이래요.
This implements a BCH code that guarantees detection of any error affecting at most 4 characters and has less than a 1 in 10^9 chance of failing to detect more errors.
우리말로 옮기면 "최대 4글자에 영향을 주는 어떤 오류든 검출을 보장하고, 그보다 많은 오류를 못 잡을 확률은 10억분의 1 미만"이에요. 여기서 보장이라는 단어는 확률이 낮다는 뜻이 아니라 문자 그대로 0%라는 뜻이에요. 4글자 이하 치환 오류는 무조건 걸려요.
체크섬 자릿수를 6글자로 고른 이유도 같은 문서에 적혀 있어요. "6글자는 무작위 실패 확률을 10억분의 1 아래로 내리는 가장 작은 숫자"라서예요. 오류 개수가 많아질수록 검출 실패 확률은 2의 30제곱분의 1, 즉 10억분의 0.931로 수렴해요. 같은 문서의 부록 표를 그대로 옮기면 이래요.
| 문자열 창 | 틀린 글자 수 | 검출 실패 확률 |
|---|---|---|
| P2WPKH 주소의 데이터부(39자) | 4글자 이하 | 0 (보장) |
| P2WPKH 주소의 데이터부(39자) | 5글자 | 10억분의 0.756 |
| 19자 구간 | 5글자 | 10억분의 0.093 |
| 89자(4글자 검출을 보장하는 최대 길이) | 6글자 | 10억분의 0.933 |
표의 39자는 주소 전체 길이가 아니에요. 앞의 bc1을 뺀 데이터부만 헤아린 값이라, 실제 bc1q P2WPKH 주소는 42자예요. 위 첫 표의 42자와 어긋나는 값이 아니라 세는 구간이 다른 거예요.
문자셋 자체에도 손을 대 두었어요. bech32의 데이터 부분은 영숫자 중에서 1, b, i, o 네 글자를 뺀 32글자만 써요. 규격 각주가 밝힌 이유는 시각적으로 헷갈리는 짝을 미리 지우려는 거예요. 헷갈리는 짝이 데이터 부분에 함께 들어 있지 않아서, 헷갈려 적으면 그 자리에 올 수 없는 글자가 돼요. 오타 자체가 안 난다는 뜻이 아니라, 직접 넣어 보니 b·i·o는 체크섬을 계산하기도 전에 문자 검사에서 걸렸고 1은 구분자로 읽혀 체크섬 대조에서 걸렸어요.
규격이 주장하는 이 성질을 직접 확인해 봤어요. BIP-173 시험 벡터 주소 하나를 놓고 1~4글자를 무작위 위치에서 무작위 문자로 바꾼 문자열 20만 개를 만들어 체크섬을 대조했더니, 통과한 것이 0건이었어요. 규격이 적은 그대로였어요.
한 가지 더 짚어 둘 게 있어요. BIP-173은 오류 정정을 구현하지 말라고 못박아요. "잘못됐지만 유효한 입력을 쓰면 자금이 영구히 소실될 수 있다"는 것이 이유예요. 어디가 틀렸는지 알려주는 것까지는 되지만, 무엇으로 고치라고 제안하는 것은 해서는 안 된다고 돼 있어요.
투자 정보 안내
본 글은 암호화폐 시장에 대한 객관 데이터·정보 제공 목적이며, 특정 코인 매수·매도 권유가 아닙니다. 암호화폐는 변동성이 매우 크고 원금 전액 손실이 가능하므로 본인 판단과 책임 하에 결정하세요.
bc1p는 같은 bc1이지만 다른 규격이에요
여기서 통설이 자주 미끄러져요. 위의 "4글자 보장" 문장은 bech32에 대한 문장이고, bech32는 세그윗 버전 0 출력, 즉 bc1q로 시작하는 주소에 쓰여요. bc1p로 시작하는 탭루트 주소는 BIP-350이 정의한 bech32m이에요. "bc1로 시작하는 모든 주소"로 묶어서 같은 보장을 주장하면 틀려요.
BIP-173은 2024년에 문서 말미에 'Disclosures' 항목을 덧붙여, 이 체크섬이 "5글자 미만의 연속 삽입·삭제에 대해서는 항상 견고하지는 않다"고 스스로 적어 두었어요. 그래서 그 보장은 글자가 다른 글자로 바뀌는 치환 오류에 대한 것이고, 글자를 넣거나 빼는 오류는 별개예요. BIP-350이 왜 따로 나왔는지도 규격 원문에 적혀 있어요. bech32에 예상치 못한 약점이 발견됐거든요. 문자열의 마지막 글자가 p일 때, 그 바로 앞에 q를 몇 개 넣거나 빼도 체크섬이 깨지지 않아요.
이것도 재현해 봤어요. 체크섬 마지막 글자가 p가 되는 bech32 문자열 bc1cxpgnw305tf95zfp를 만들어 놓고 마지막 p 앞에 q를 하나씩 늘려 가며 넣었어요.
| 넣은 문자 | 결과 |
|---|---|
q 1개 | bech32 체크섬 통과 |
q 2개 | bech32 체크섬 통과 |
q 3~5개 | 전부 bech32 체크섬 통과 |
z 1개 (대조군) | 무효 |
r 1개 (대조군) | 무효 |
s 1개 (대조군) | 무효 |
같은 실험을 bech32m 상수로 다시 하면 q 삽입이 전부 무효로 잡혀요. 이게 BIP-350이 존재하는 이유예요.
다만 겁먹을 필요는 없어요. BIP-350 원문이 같은 문단에서 이렇게 덧붙여요. 이 약점은 버전 0 주소가 두 가지 길이로만 존재하기 때문에 기존 주소에는 영향이 없다고요. 세그윗 v0 프로그램은 정확히 20바이트 아니면 32바이트여야 해서, 글자가 하나 늘어난 문자열은 길이 검사에서 먼저 걸려요. 위 재현에 쓴 문자열도 실제 주소가 아니라 제가 만든 일반 bech32 문자열이에요.
버전 0에 두 규격을 모두 허용하지 않은 이유도 각주에 있어요. 둘 다 받아 주면 "체크섬이 29비트뿐인 것과 같아진다", 즉 검출 능력이 깎여요. 그래서 지갑은 버전 0이면 bech32로, 버전 1 이상이면 bech32m으로 정해진 쪽만 검사해야 해요. 같은 길이라면 유효한 bech32 문자열과 유효한 bech32m 문자열은 최소 3글자 이상 다르다고 규격이 적어 두었어요.

0x 주소 — 체크섬이 대소문자에 실려 있어요
이더리움 계열의 0x 주소는 사정이 완전히 달라요. 주소 자체는 16진수 40자인데, 여기에 체크섬을 덧붙일 자리가 없어요. ERC-55가 택한 방법은 글자의 대소문자에 정보를 숨기는 거예요.
방법은 짧아요. 소문자 16진 주소 문자열을 keccak256으로 해시한 뒤, i번째 글자가 a부터 f 사이의 글자라면 해시의 i번째 자리가 8 이상일 때 대문자로, 아니면 소문자로 적어요. 숫자 0부터 9까지는 대문자가 없으니 그냥 둬요.
ERC-55 원문의 검출력 문장은 이래요.
On average there will be 15 check bits per address, and the net probability that a randomly generated address if mistyped will accidentally pass a check is 0.0247%.
이 문장은 조건을 떼면 오독돼요. 0.0247%는 "무작위로 생성된 주소를 오타냈을 때 우연히 검사를 통과할 확률"이에요. 특정 주소 하나에 대한 값도 아니고, 오타가 났을 때 자금이 사라질 확률도 아니에요.
숫자가 어디서 나오는지도 계산으로 확인했어요. 검사 비트는 곧 주소에 든 a부터 f 글자의 개수예요. 16진수 한 자리가 글자일 확률은 16분의 6이니 40자 주소에 평균 15개가 들어요. 글자가 L개인 주소를 오타냈을 때 우연히 통과할 확률은 2의 L제곱분의 1이고, 이걸 L의 분포로 평균 내면 16분의 13을 40번 곱한 값, 즉 0.0247%가 나와요. 규격이 적은 숫자와 정확히 일치했어요.
그리고 여기가 두 규격의 대소문자 규칙이 정반대로 갈리는 자리예요. bech32는 대소문자가 섞인 문자열을 디코더가 받아들이면 안 된다고 못박아요. 반대로 ERC-55는 대소문자가 섞인 것 자체가 체크섬이에요. 같은 눈으로 보면 정반대 판정이 나오니, 주소 형식을 먼저 가르고 나서 봐야 해요.
검사 비트는 주소마다 달라요 — 여기서 통설이 갈려요
"평균 15비트"라는 말에서 평균이 진짜 평균이에요. 어떤 주소는 글자가 21개라 21비트지만, 어떤 주소는 글자가 6개뿐이라 6비트예요.
이게 얼마나 벌어지는지 직접 세어 봤어요. ERC-55 규격에 실린 시험 벡터 주소들을 놓고, 40자리 각 자리마다 다른 글자로 바꾼 한 글자 오타를 전부 만들어 넣었어요(대문자 변형까지 포함해 주소당 819~834가지). 그리고 그 결과가 그 자체로 유효한 ERC-55 체크섬 형태가 되는지를 셌어요.
| 시험 벡터 주소 | 글자(a~f) 개수 | 한 글자 오타가 검사를 통과한 비율 |
|---|---|---|
0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB | 21 | 0 / 819 |
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed | 18 | 0 / 822 |
0x8617E340B3D01FA5F11F306F4090FD50E238070D | 12 | 0 / 828 |
0x52908400098527886E0F7030069857D2E4169EE7 | 6 | 13 / 834 = 1.559% |
0xde709f2102306220921060314715629080e2fb77 | 6 | 12 / 834 = 1.439% |
같은 규격, 같은 검사인데 결과가 이렇게 갈려요. 글자가 12개 이상인 주소에서는 820가지 오타 중 하나도 통과하지 못했지만, 글자가 6개뿐인 두 주소에서는 100번 중 1.5번꼴로 그냥 통과했어요. 규격이 적은 0.0247%와 견주면 60배 가까이 나쁜 값이에요. 그리고 저 6글자짜리 두 개는 제가 고른 극단값이 아니라 ERC-55 규격 문서에 시험 벡터로 실려 있는 주소예요.
여기서 알 수 있는 건 이래요. 0.0247%는 주소를 무작위로 뽑았을 때의 평균이고, 눈앞의 주소 하나에 대해서는 그 주소가 몇 글자를 갖고 있느냐가 검사 강도를 정해요. 그리고 그 값은 주소를 보면 셀 수 있지만, 실무에서 이걸 세고 있을 사람은 없어요. 그래서 결론은 하나예요. 0x 주소에서 체크섬은 보조 장치이지 최종 방어선이 아니에요.
그래서 소문자 주소에는 검사할 것이 없어요
여기가 이 글의 결론 자리예요.
ERC-55는 근거 항목에서 이 방식의 이점을 이렇게 적어요. "대소문자를 받아 주는 기존 16진수 파서들과 호환되므로 시간을 두고 쉽게 도입할 수 있다." 뒤집어 말하면 소문자로만 적힌 주소도 계속 받아 줘야 도입이 된다는 뜻이에요. 그래서 소문자 주소는 대개 그대로 통과해요.
그런데 그 소문자 주소를 보고 무엇을 알 수 있을까요. 규격 시험 벡터 0xde709f2102306220921060314715629080e2fb77은 전부 소문자인데도 정상적인 체크섬 형태예요. 우연히 모든 글자의 해시 자리가 8 미만이라 전부 소문자가 된 거예요. 반대로 0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB를 전부 소문자로 눌러 놓으면 체크섬 형태와 어긋나요.
즉 소문자로만 적힌 0x 주소를 보고 체크섬이 붙어 있는 것인지 벗겨진 것인지 겉으로는 구분할 수 없어요. 그리고 그 주소를 받는 쪽 지갑도 대개 구분하지 않고 받아 줘요. 검사할 것이 없다는 말은 이런 뜻이에요.
레거시 1·3 주소 — "보장이 없다"의 정확한 뜻
1이나 3으로 시작하는 옛 비트코인 주소는 Base58Check라는 방식을 써요. BIP-173은 새 방식을 제안하면서 옛 방식의 한계를 항목으로 나열했는데, 그중 한 줄이 이거예요.
The double SHA256 checksum is slow and has no error-detection guarantees.
여기서 "보장이 없다"는 말을 검출 확률이 나쁘다는 뜻으로 읽으면 틀려요. Base58Check는 데이터 뒤에 4바이트 체크섬을 붙이고 디코딩할 때 다시 계산해 대조해요. 비트코인 코어 소스의 해당 함수에도 "포함된 4바이트 체크섬과 일치하는지 확인한다"는 주석이 그대로 달려 있어요. 4바이트면 32비트라 무작위로 틀린 문자열이 통과할 확률은 대략 43억분의 1이에요. 숫자만 보면 오히려 bech32의 수렴값보다 작아요.
차이는 다른 데 있어요. BIP-350은 해시 기반 체크섬을 이렇게 설명해요. Base58Check 같은 방식은 모든 유형의 오류를 균일하게 검출하지만, 실제로 사람이 내는 오타는 유형별로 발생 빈도가 다르다고요. bech32는 사람이 자주 내는 치환 오류에 대해 "몇 글자까지는 반드시"라는 하한선을 만들어 뒀고, Base58Check에는 그 하한선이 없어요. 그래서 "보장이 없다"예요. 평균이 나쁜 게 아니라, 최악의 경우를 막아 주는 선이 없다는 뜻이에요.
Base58도 눈으로 헷갈리는 글자는 미리 지워 두었어요. 비트코인 코어의 문자셋 상수를 열어 보면 58글자 안에 숫자 0, 대문자 O, 대문자 I, 소문자 l이 빠져 있어요. 다만 BIP-173이 지적한 대로 대소문자가 섞여 있어서 받아 적거나 모바일에서 입력하기 불편하고, QR 코드에서도 자리를 많이 먹어요.

투자 정보 안내
본 글은 암호화폐 시장에 대한 객관 데이터·정보 제공 목적이며, 특정 코인 매수·매도 권유가 아닙니다. 암호화폐는 변동성이 매우 크고 원금 전액 손실이 가능하므로 본인 판단과 책임 하에 결정하세요.
검출된다는 것과 되돌릴 수 있다는 것은 다른 층이에요
지금까지 적은 숫자는 전부 보내기 전에 소프트웨어가 그 문자열을 거절할 수 있느냐에 관한 이야기예요. 이미 네트워크에 퍼진 트랜잭션을 되돌리는 것과는 아무 관계가 없어요. 이 층을 섞어 읽으면 정확히 반대 결론이 나와요.
세 가지를 갈라 둘게요.
- 체크섬은 문자열이 망가졌는지만 봐요. 그 주소가 실제로 존재하는지, 잔액이 있는지, 누구 것인지는 전혀 검사하지 않아요.
- 공격자의 주소도 체크섬은 완벽히 유효해요. 클립보드를 바꿔치기하는 악성코드는 자기 주소를 넣는 것이지 남의 주소를 망가뜨리는 게 아니에요. 그래서 체크섬은 이 공격을 전혀 막지 못해요.
- 체크섬을 통과한 뒤 보낸 것은 되돌릴 수 없어요. BIP-173이 오류 정정을 구현하지 말라고 한 이유가 바로 이거예요. 잘못 고쳐서 유효해진 주소로 보내면 자금이 영구히 소실될 수 있다고 규격이 직접 적었어요.
네트워크를 잘못 골라 보낸 경우처럼 이미 보낸 뒤의 상황은 규격이 아니라 개별 서비스의 처리 문제로 넘어가요. 그 갈래는 코인 출금 네트워크 선택 가이드에 상황별로 정리해 두었고, 태그나 메모를 빠뜨린 경우는 데스티네이션 태그·메모 누락 복구 절차가 따로 있어요.
한 가지는 분명히 갈라 둘게요. "거래소가 주소 형식 검증 단계에서 막아 준다"는 말은 자주 쓰이지만, 거래소가 무엇을 막아 주는지는 규격이 정하는 것이 아니에요. 규격이 정하는 것은 "이 문자열이 이 형식의 유효한 주소인가"까지고, 출금 화면에서 실제로 어떤 검사를 거는지는 거래소별 구현이에요. 이 글을 쓰면서 업비트와 빗썸의 공개 개발자 문서를 직접 열어 봤는데, 주소 문자열의 형식이나 체크섬을 어떻게 검사하는지는 적혀 있지 않았어요. 대신 두 곳 모두 사전에 등록한 주소로만 출금된다고 문서에 적어 두었어요. 업비트 '디지털 자산 출금' 문서는 "업비트에서 타 거래소 혹은 지갑으로 디지털 자산을 출금하기 위해서는 사전에 출금 주소를 등록해야 합니다"라고 적었고, 빗썸 '가상 자산 출금 요청' 문서는 address 항목을 "출금 가능 주소에 등록된 출금 주소"로 설명해요. 즉 공개 문서로 확인되는 방어선은 문자열 형식 검사가 아니라 주소 등록제예요. 출금 화면이 형식을 어디까지 걸러 주는지는 여전히 공개 문서로는 확인되지 않으니, 그 부분을 전제로 두지 않는 편이 안전해요.
보내기 전에 스스로 판정하는 순서
체크섬이 걸러 주는 범위와 못 걸러 주는 범위가 갈렸으니, 순서도 그에 맞춰 짜면 돼요.
- 접두어로 규격부터 가른다.
bc1q인지bc1p인지1·3인지0x인지 확인해요. 받는 쪽이 알려 준 네트워크와 접두어가 맞물리는지도 같이 봐요. - 대소문자가 섞였는지 본다.
bc1로 시작하는데 대소문자가 섞여 있다면 규격상 무효한 문자열이라 정상적인 지갑이라면 거절해야 해요. 반대로0x인데 전부 소문자라면 검사할 것이 없다는 뜻이니, 체크섬이 걸러 줄 거라는 기대를 접어야 해요. - 앞뒤 4자만 대조하지 않는다. 체크섬은 문자열 전체에 걸려 있지만, 사람의 눈 대조는 대개 앞뒤 몇 글자에서 끝나요. 주소를 통째로 바꿔치기하는 쪽은 그 습관을 노려요. 대조할 거면 가운데 구간도 한 번은 봐야 해요.
- 붙여넣은 뒤 지갑 화면에 다시 표시된 문자열과 원본을 대조한다. 붙여넣기와 전송 사이에서 바뀌는 경우를 잡는 유일한 단계예요. 지갑이 대소문자까지 그대로 다시 보여 주는지도 이때 확인돼요.
- 금액이 크면 최소 수량으로 한 번 먼저 보낸다. 수수료를 한 번 더 내지만, 위 네 단계가 못 잡는 것까지 실제로 확인되는 유일한 방법이에요. 도착 확인은 블록체인 익스플로러로 거래·지갑 조회하기에서 하면 돼요.
오해와 규격 원문을 한 표로
| 흔한 말 | 규격 원문에서 확인된 것 |
|---|---|
| 한 글자만 틀려도 무조건 코인이 사라진다 | 대부분 보내기 전에 거절돼요. bech32는 4글자 이하 치환 오류의 검출을 보장한다고 규격이 적었어요 |
bc1로 시작하면 다 같은 규격이다 | bc1q는 bech32(BIP-173), bc1p는 bech32m(BIP-350)이에요. 지갑도 둘을 갈라서 검사해야 해요 |
| 이더리움 주소 체크섬은 0.0247%로 안전하다 | 그 값은 무작위로 생성된 주소를 오타냈을 때 우연히 통과할 확률이에요. 조건을 떼면 오독돼요 |
| 검사 비트 15개는 모든 주소에 해당한다 | 평균이에요. 실제 검사 비트는 그 주소에 든 a~f 글자 수라, 6글자짜리 주소에서는 한 글자 오타가 1.5%쯤 그냥 통과했어요 |
| 소문자 주소도 체크섬이 걸러 준다 | 체크섬이 대소문자에 실려 있어서 검사할 것이 없어요. ERC-55는 소문자 호환을 이점으로 적어 두었어요 |
옛날 1 주소는 체크섬이 허술하다 | 4바이트(32비트) 대조라 확률만 보면 낮지 않아요. 없는 것은 "몇 글자까지는 반드시"라는 하한선이에요 |
| 거래소가 다 걸러 준다 | 규격이 정하는 범위가 아니라 거래소별 구현이에요. 공개 문서로 확인되는 것은 형식 검사가 아니라 사전 등록한 주소로만 출금된다는 주소 등록제예요 |
| 체크섬을 통과했으니 안전한 주소다 | 체크섬은 문자열이 망가졌는지만 봐요. 공격자의 주소도 체크섬은 유효해요 |
자주 묻는 질문 (FAQ)
Q. bc1으로 시작하는 주소는 4글자까지 틀려도 무조건 잡히나요?
bc1q로 시작하는 주소, 즉 세그윗 버전 0 주소에 한해서 그래요. BIP-173 원문이 "최대 4글자에 영향을 주는 어떤 오류든 검출을 보장한다"고 적었고, 저도 시험 벡터 주소에 1~4글자 무작위 치환 20만 건을 넣어 봤을 때 통과한 것이 0건이었어요. 다만 bc1p로 시작하는 탭루트 주소는 BIP-350이 정의한 bech32m이라 규격이 다르니, 같은 문장을 bc1로 시작하는 모든 주소로 넓히면 안 돼요. 그리고 이 보장은 글자가 다른 글자로 바뀌는 치환 오류에 대한 것이고, 글자를 넣거나 빼는 오류는 별개예요.
Q. 이더리움 주소 체크섬이 0.0247%라는데 그만큼 안전한 건가요?
그 숫자에는 조건이 붙어 있어요. ERC-55 원문은 "무작위로 생성된 주소를 오타냈을 때 우연히 검사를 통과할 확률이 0.0247%"라고 적었어요. 특정 주소 하나에 대한 값이 아니고, 오타가 났을 때 자금이 사라질 확률도 아니에요. 실제 검사 강도는 그 주소에 든 a부터 f 사이 글자의 개수로 정해져요. 규격의 시험 벡터 중 글자가 6개뿐인 주소 두 개를 놓고 한 글자 오타를 전부 만들어 넣었더니 각각 1.559%, 1.439%가 그냥 통과했어요. 평균값을 개별 주소의 안전도로 읽으면 안 돼요.
Q. 0x 주소를 전부 소문자로 적으면 어떻게 되나요?
ERC-55의 체크섬은 대소문자에 실려 있어서, 전부 소문자로 만들면 검사할 정보가 사라져요. 그리고 소문자 주소를 보고 그것이 원래 체크섬이 붙은 주소인지 대소문자를 눌러 버린 주소인지 겉으로 구분할 수 없어요. 규격 시험 벡터 중에는 전부 소문자인데도 정상적인 체크섬 형태인 주소가 실제로 들어 있어요. ERC-55가 근거 항목에서 소문자 호환을 이점으로 적어 둔 만큼 받는 쪽 소프트웨어도 대개 그대로 받아 주고요. 소문자로만 된 0x 주소를 다룰 때는 체크섬이 걸러 줄 거라는 기대를 접고 다른 단계로 확인해야 해요.
Q. 오타가 검출되면 보낸 코인을 되찾을 수 있다는 뜻인가요?
아니에요. 이 둘은 다른 층이에요. 체크섬은 보내기 버튼을 누르기 전에 소프트웨어가 그 문자열을 거절하게 해 주는 장치일 뿐이고, 이미 네트워크에 퍼진 트랜잭션을 되돌리는 것과는 관계가 없어요. BIP-173이 오류 정정 기능을 구현하지 말라고 한 이유도 같아요. 잘못 고쳐서 유효해진 주소로 보내면 자금이 영구히 소실될 수 있다고 규격이 직접 적었어요.
Q. 체크섬을 통과했으면 안전한 주소인가요?
체크섬은 문자열이 망가졌는지만 검사해요. 그 주소가 내가 보내려던 상대의 주소인지는 전혀 보지 않아요. 클립보드를 바꿔치기하는 악성코드는 남의 주소를 망가뜨리는 게 아니라 자기 주소로 통째로 갈아 끼우기 때문에, 바뀐 주소도 체크섬은 완벽히 유효해요. 그래서 붙여넣은 뒤 지갑 화면에 다시 표시된 문자열을 원본과 대조하는 단계가 따로 필요하고, 이때 앞뒤 몇 글자만 보지 말고 가운데 구간도 봐야 해요.
Q. 거래소가 잘못된 주소를 알아서 막아 주지 않나요?
규격이 정하는 것은 "이 문자열이 이 형식의 유효한 주소인가"까지고, 출금 화면에서 실제로 어떤 검사를 거는지는 거래소별 구현이에요. 업비트와 빗썸의 공개 개발자 문서를 직접 열어 보면 주소 문자열의 형식이나 체크섬을 어떻게 검사하는지는 적혀 있지 않아요. 대신 두 곳 모두 사전에 등록한 주소로만 출금된다고 적어 두었어요. 업비트 '디지털 자산 출금' 문서는 "사전에 출금 주소를 등록해야 합니다"라고 적었고, 빗썸 '가상 자산 출금 요청' 문서는 address 항목을 "출금 가능 주소에 등록된 출금 주소"로 설명해요. 즉 공개 문서로 확인되는 방어선은 문자열 형식 검사가 아니라 주소 등록제예요. 출금 화면이 형식을 어디까지 걸러 주는지는 공개 문서로 확인되지 않으니, 그 부분을 전제로 두는 대신 위에 적은 다섯 단계를 본인이 직접 밟는 편이 안전해요.
Q. 옛날 1이나 3으로 시작하는 주소는 위험한가요?
"보장이 없다"는 규격의 표현을 확률이 나쁘다는 뜻으로 읽으면 오해예요. Base58Check는 4바이트, 즉 32비트 체크섬을 대조하기 때문에 무작위로 틀린 문자열이 통과할 확률 자체는 낮아요. 없는 것은 "몇 글자까지는 반드시 잡는다"는 하한선이에요. 대신 이 방식은 대소문자가 섞여 있어 받아 적거나 모바일에서 입력할 때 불편하고, 문자셋에서 숫자 0과 대문자 O, 대문자 I와 소문자 l은 이미 빠져 있어요.
정리
- "한 글자 틀리면 무조건 소실"은 절반만 맞아요. 대부분은 보내기 전에 거절되고, 걸러내는 힘은 주소 형식마다 규격 문서에 다르게 적혀 있어요.
bc1q주소의 bech32는 4글자 이하 치환 오류의 검출을 보장한다고 BIP-173이 스스로 적었어요. 20만 건 재현에서도 통과 0건이었어요.bc1p는 같은bc1이지만 bech32m(BIP-350) 이에요. bech32의q삽입 약점을 재현해 보면 bech32에서는 통과하고 bech32m에서는 전부 무효로 잡혀요.0x주소의 ERC-55는 체크섬이 대소문자에 실려 있고, 규격이 적은 0.0247%는 무작위로 생성된 주소를 오타냈을 때 우연히 통과할 확률이라는 조건이 붙은 값이에요.- 검사 비트는 주소마다 달라요. 규격 시험 벡터 중 글자가 6개뿐인 주소에서는 한 글자 오타가 1.5%쯤 그냥 통과했어요.
- 그래서 결론은 하나예요. 소문자로만 적힌
0x주소에는 검사할 것이 없어요. - 검출된다는 것과 되돌릴 수 있다는 것은 다른 층이에요. 체크섬은 문자열이 망가졌는지만 보고, 공격자의 주소도 체크섬은 유효해요.
주소 검증에서 제일 자주 어긋나는 지점은 규격이 허술해서가 아니라, 어느 규격이 적용되는 주소인지를 안 가르고 한 문장으로 뭉뚱그리기 때문이에요. 접두어 네 글자만 먼저 보고 갈래를 정하면, 그다음에 무엇을 믿고 무엇을 직접 확인해야 하는지가 갈려요.
이 글은 공개된 규격 문서와 오픈소스 구현을 직접 열어 정리한 정보 제공 글이며 매매를 권유하는 글이 아니에요. 가상자산은 변동성이 크고 원금 손실 위험이 있으며, 전송과 지갑 사용의 판단과 책임은 본인에게 있어요. 본문의 주소 문자열은 모두 규격 문서에 실린 시험용 예시이니 실제 전송에 쓰지 마세요.
확인한 자료: BIP-173 원문(bitcoin/bips 저장소 bip-0173.mediawiki, 20,803바이트), BIP-350 원문(같은 저장소 bip-0350.mediawiki, 26,836바이트), ERC-55 원문(ethereum/ERCs 저장소 ERCS/erc-55.md, 3,674바이트 · 옛 ethereum/EIPS 경로는 128바이트짜리 이전 안내 스텁만 돌아와 옮겨진 주소를 따라갔어요), eips.ethereum.org의 EIP-55 페이지, 비트코인 코어 소스 src/base58.cpp. 업비트 개발자 문서 '디지털 자산 출금'(docs.upbit.com/kr/docs/digital-asset-withdrawal)과 빗썸 '가상 자산 출금 요청'(apidocs.bithumb.com/reference/가상-자산-출금-요청)도 직접 열어 봤어요. 두 문서 모두 주소 등록제는 명시하지만, 주소 형식·체크섬 검증에 관한 서술은 없었어요. 검출력 재현 계산(bech32 치환 20만 건, bech32 q 삽입, ERC-55 한 글자 오타 전수 열거, keccak256 자체 구현으로 시험 벡터 8건 전부 재현)은 직접 작성한 코드로 돌렸어요. 모두 2026년 8월 12일에 조회했어요.