주소 하나를 평생 공개해도 추적당하지 않는 방법
사일런트 페이먼트(BIP-352)는 정적 주소 하나로 매번 새로운 출력을 받는 프로토콜이다. 발신자가 주소를 계산해내는 원리, 수신자가 대신 치르는 스캔 비용, 라벨 기능, 2026년 8월 기준 지갑 지원 현황까지 정리했다.
후원 페이지에 비트코인 주소를 하나 걸어둔 사람이 있다고 하자. bc1q로 시작하는 그 주소는 6개월 뒤에 무엇이 되어 있을까. 후원자 명단이자, 실시간 잔고 공시이자, 후원 금액과 시각의 전체 기록이다. 블록 익스플로러 주소창에 그 문자열을 붙여넣기만 하면 누구나 볼 수 있다. 후원한 사람들의 지갑까지 함께 노출된다는 점이 더 곤란하다. 후원자의 UTXO가 그 주소로 흘러들어간 순간, 그 사람이 어디서 코인을 받았고 얼마를 남겼는지가 같은 화면에 딸려 나온다.
주소를 재사용하지 마라는 원칙은 비트코인 프라이버시의 첫 번째 계명이다. 문제는 이 원칙이 "매번 새 주소를 상대에게 건네줄 수 있는 사람"에게만 적용된다는 것이다. 후원을 받는 단체, 인터넷에 결제 정보를 게시하는 판매자, 명함에 주소를 인쇄한 개발자, 매달 같은 곳에서 급여를 받는 사람은 그럴 수가 없다. 한 번 공개해서 여러 번 받아야 하는 주소는, 지금까지 프라이버시를 포기하는 대가로만 존재할 수 있었다.
사일런트 페이먼트(Silent Payments, BIP-352)는 이 딜레마를 없앤다. 정적 주소 하나를 평생 공개해두되, 그 주소로 들어온 결제는 블록체인 어디에도 그 주소와 연결된 흔적을 남기지 않는다. 온체인에 기록되는 것은 매번 다른, 평범해 보이는 탭루트 출력뿐이다.
이전 해법들이 멈춘 자리
정적 주소 문제를 푸는 시도는 사일런트 페이먼트가 처음이 아니다.
대화형 주소 교환. 결제할 때마다 수신자가 새 주소를 만들어 발신자에게 전달하는 방식이다. 프라이버시는 완벽하지만 양쪽이 동시에 온라인이어야 하고, 주소를 전달할 별도의 채널이 필요하다. 후원자 한 명 한 명과 메시지를 주고받는 후원 페이지는 존재할 수 없다. BTCPay Server 같은 결제 서버는 이 과정을 자동화해주지만, 서버를 운영해야 하고 방문자에게 주소를 발급하는 그 서버가 모든 결제를 알게 된다.
BIP-47 재사용 가능 결제 코드. 한 번 공개한 결제 코드로부터 결제마다 새 주소를 파생하는 방식이다. 개념은 사일런트 페이먼트와 같지만, 발신자가 처음 결제하기 전에 온체인에 알림 트랜잭션(notification transaction)을 한 건 보내야 한다. 이 트랜잭션이 문제다. 수수료가 들고, 무엇보다 "누가 이 결제 코드에 관심을 보였는가"가 영구히 체인에 남는다. 후원자 명단을 지우려다 후원 의사 표명 명단을 만든 셈이다. BIP-47을 주력으로 밀던 지갑 생태계가 2024년 이후 크게 위축된 것도 채택이 정체된 이유 중 하나다.
사일런트 페이먼트는 알림 트랜잭션을 없앤다. 발신자가 수신자에게 아무것도 알리지 않고, 어떤 사전 접촉도 없이, 트랜잭션 한 건만으로 결제가 끝난다. 이름이 "조용한 결제"인 이유다.
발신자가 주소를 계산해낸다
핵심 아이디어는 순서를 뒤집는 것이다. 보통은 수신자가 주소를 만들어서 발신자에게 준다. 사일런트 페이먼트에서는 발신자가 주소를 직접 계산해서 만들어낸다. 재료는 두 가지다. 수신자가 공개한 sp 주소, 그리고 발신자가 지금 쓰려는 입력들의 개인 키.
sp 주소 안에 든 것
사일런트 페이먼트 주소는 sp1q로 시작하는 bech32m 문자열이다(테스트넷은 tsp1). 최소 117자로, 우리가 아는 bc1q 주소보다 훨씬 길다. 길이의 이유는 안에 33바이트 압축 공개키가 두 개 들어 있기 때문이다.
- 스캔 키(B_scan): 나에게 온 결제를 찾아내는 데 쓰는 키. 대응하는 개인 키는 상시 온라인 상태여야 한다.
- 지출 키(B_spend): 찾아낸 코인을 실제로 쓸 때 필요한 키. 하드웨어 지갑에 격리해 둘 수 있다.
이 분리가 실용적으로 중요하다. 스캔에는 스캔 개인 키만 있으면 되므로, 항상 켜져 있는 노드에 스캔 키만 두고 지출 키는 콜드 상태로 유지할 수 있다. 감시 전용 지갑이 잔고를 보는 것과 같은 구도다.
발신자가 하는 계산
발신자의 지갑은 대략 이런 순서로 출력을 만든다.
- 이 트랜잭션에서 쓸 적격 입력들의 개인 키를 모두 더한다. 그 합을
a라 하고, 대응하는 공개키를A = a·G라 한다. - 입력들의 아웃포인트 중 사전순으로 가장 작은 것을 골라
input_hash = hash(outpoint_L || A)를 계산한다. - 수신자의 스캔 키와 ECDH로 공유 비밀을 만든다.
공유비밀 = input_hash · a · B_scan - 출력 하나마다 트윅을 뽑는다.
t_k = hash(공유비밀 || k)(k는 0부터 시작) - 최종 출력 키를 만든다.
P_k = B_spend + t_k·G
P_k는 그대로 BIP341 탭루트 출력이 된다. 즉 체인에 기록되는 것은 bc1p로 시작하는 평범한 탭루트 출력이며, 다른 탭루트 결제와 구별할 방법이 없다. 사일런트 페이먼트를 쓴다는 사실 자체가 온체인에 드러나지 않는다는 뜻이다.
3단계에 왜 input_hash가 곱해져 있는지가 이 설계의 미묘한 부분이다. 같은 발신자가 같은 수신자에게 두 번 보낼 때, 만약 공유 비밀이 입력과 무관하다면 같은 출력 키가 두 번 나와서 결국 주소 재사용이 된다. 아웃포인트는 세상에 한 번만 존재하므로, 입력 집합이 다르면 공유 비밀이 반드시 달라진다. 트랜잭션마다 새 출력이 나오는 것이 우연이 아니라 보장이다.
수신자는 같은 계산을 반대편에서 한다
수신자는 발신자의 개인 키를 모른다. 대신 트랜잭션에 공개된 입력 공개키들의 합 A를 볼 수 있다. 타원곡선의 성질상 input_hash · b_scan · A는 발신자가 계산한 input_hash · a · B_scan과 정확히 같은 값이다. 양쪽이 서로 다른 재료로 같은 비밀에 도달한다.
공유 비밀을 얻으면 t_k를 뽑고 P_k를 계산해서, 그 트랜잭션의 탭루트 출력 키들과 대조한다. 일치하는 것이 있으면 나에게 온 결제다. 일치하는 출력을 찾으면 k를 올려 한 번 더 확인한다. 한 트랜잭션이 나에게 여러 출력을 보낼 수 있기 때문이다.
수신자가 대신 치르는 값: 스캔
여기까지가 좋은 소식이다. 대가는 수신 쪽에 몰려 있다.
발신자가 아무 통보 없이 출력을 만들기 때문에, 수신자는 내게 온 결제가 있는지 스스로 찾아내야 한다. 새 블록이 올 때마다 그 안의 트랜잭션들을 하나씩 검사하는 수밖에 없다. 기존 지갑처럼 "내 주소 목록에 해당하는 출력이 있나"를 문자열로 대조하는 것이 아니라, 트랜잭션마다 타원곡선 연산을 돌려야 한다.
비용이 폭발하지 않는 이유는 연산이 출력당이 아니라 트랜잭션당 한 번이기 때문이다. 트랜잭션 하나에 대해 ECDH를 한 번 계산하고, 거기서 나온 값으로 출력들을 비교한다. 그럼에도 노트북에서 몇 초 만에 끝나는 작업은 아니고, 휴대폰 지갑이 혼자 감당하기는 더 어렵다.
검사 대상은 생각보다 적다
BIP-352는 스캔 대상을 좁히는 조건을 명시한다. 다음을 모두 만족하는 트랜잭션만 후보다.
- 탭루트 출력이 하나 이상 있을 것
- 적격 입력이 하나 이상 있을 것: P2TR, P2WPKH, P2SH-P2WPKH, P2PKH
- SegWit 버전 1을 넘는 출력을 쓰는 입력이 없을 것
적격 입력에서 빠지는 것들도 분명하다. 조건 분기가 있는 스크립트, 여러 공개키를 쓰는 다중서명 스크립트, 비압축 공개키를 쓰는 옛 입력은 제외된다. 발신자가 "이 입력의 개인 키를 확실히 알고 있다"고 단정할 수 있는 형태만 남기는 규칙이다. 탭루트 스크립트 경로 지출은 포함되지만, 내부 키로 NUMS 포인트를 쓴 경우는 제외된다. 지출할 수 있는 내부 키가 애초에 없기 때문이다.
스캔을 어디에 맡기느냐가 갈림길
프라이버시가 실제로 어디까지 지켜지는지는 이 선택에서 결정된다.
풀노드 직접 스캔. 자기 노드가 모든 블록을 받아서 직접 검사한다. 외부에 아무것도 묻지 않으므로 프라이버시가 완전하다. 대신 노드를 돌려야 하고, 인덱싱 부담을 자기가 진다.
SP 지원 인덱서/서버. 서버가 미리 트윅 데이터를 계산해두고 지갑에 넘긴다. Sparrow 2.5.0이 이 방식으로 수신 기능을 붙였고, frigate.2140.dev라는 SP 지원 Electrum 서버를 필수로 자동 선택한다. 접속한 서버는 최소한 "이 사람이 사일런트 페이먼트를 스캔하고 있다"는 사실을 알게 된다.
필터 기반 라이트 클라이언트. BlindBit 계열은 서버가 블록별 트윅과 필터만 배포하고, 매칭 판정은 클라이언트에서 한다. 서버는 누가 무엇을 받았는지 알 수 없다. 다운로드 부담과 프라이버시 사이의 절충안이다.
복구는 확실히 느려진다
시드 문구로 지갑을 복구하는 상황을 생각해보자. 일반 HD 지갑은 주소를 순서대로 파생해서 조회하면 끝난다. 사일런트 페이먼트 지갑은 지갑이 만들어진 시점부터 현재까지의 블록을 다시 스캔해야 잔고를 재구성할 수 있다. 지갑 생성 높이(birth height)를 시드와 함께 적어두는 습관이 여기서 실질적인 차이를 만든다. 백업 봉투에 "2026-08-20, 블록 912000" 한 줄을 더 적어두는 것만으로 복구 시간이 크게 줄어든다.
라벨: 주소 하나로 후원자를 구분하기
정적 주소의 반대급부는 "누가 보냈는지 모른다"는 점이다. 후원 페이지 하나만 운영한다면 상관없지만, 여러 경로에서 들어오는 돈을 구분해야 하는 경우가 있다.
BIP-352의 라벨(label)이 이 문제를 푼다. 지출 키에 라벨 정수 m으로 만든 값을 더해서 B_m = B_spend + hash(b_scan || m)·G를 만들고, 이것을 지출 키 자리에 넣은 sp 주소를 발급한다. 스캔 키는 그대로이므로 스캔은 한 번에 끝나고, 매칭된 출력에서 뺄셈을 해보면 어느 라벨로 들어온 돈인지 알 수 있다. 실질적으로 "채널별 계좌번호"를 무한히 찍어낼 수 있는 셈이다.
두 가지 주의사항이 있다.
m=0은 예약되어 있다. 자기 잔돈을 인식하는 데 쓰는 라벨이므로, 이 주소는 절대 공개하면 안 된다.
라벨 주소들은 서로 연결된다. 모든 라벨 주소가 같은 스캔 키를 공유하기 때문에, 두 개의 라벨 주소를 공개적으로 게시하면 관찰자는 둘이 같은 사람 것임을 즉시 알 수 있다. 라벨은 내가 들어온 돈을 분류하는 도구이지, 서로 다른 신원을 만드는 도구가 아니다. 신원을 분리하려면 지갑을 분리해야 한다.
2026년 8월 기준, 실제로 쓸 수 있나
BIP-352 명세는 2024년 5월 BIP 저장소에 병합되었고, 2026년 들어 수신 구현이 본격적으로 나오기 시작했다. 현재 상황을 정리하면 이렇다.
| 지갑 | 보내기 | 받기 |
|---|---|---|
| Cake Wallet | 지원 | 지원 |
| Sparrow Wallet | 지원 | 지원 (2.5.0, 2026년 5월) |
| Dana Wallet | 지원 | 지원 |
| BlindBit Desktop | 지원 | 지원 |
| BlueWallet | 지원 | 미지원 |
| BitBox | 지원 | 미지원 |
| Nunchuk | 지원 | 미지원 |
| Wasabi Wallet | 지원 | 미지원 |
| Bitcoin Core | 개발 중 | 개발 중 |
하드웨어 서명 장치는 상황이 낫다. BitBox02, Coldcard, Krux, SeedSigner가 소프트웨어 지갑과 짝을 이루었을 때 사일런트 페이먼트 트랜잭션 서명을 지원한다. Sparrow 2.5.0은 에어갭 하드웨어 서명기까지 포함해서 수신 지갑을 구성할 수 있다.
주목할 부분은 비트코인 코어에 아직 릴리스된 지갑 기능이 없다는 점이다. 수신 기능 PR은 열려 있지만, 송신 PR과 SP 인덱스 PR은 병합되지 못하고 닫혔다. 명세의 참조 구현 위치에 있는 소프트웨어가 마지막에 도착하는 형국이고, 이것이 채택 속도를 가장 크게 좌우한다.
정리하면, 보내는 쪽은 이미 널리 지원되고 받는 쪽은 아직 선택지가 좁다. sp 주소를 공개해도 상당수의 지갑 사용자가 보낼 수 있지만, 그 주소를 운영하려면 지갑을 몇 개 안 되는 후보 중에서 골라야 한다.
실전: 후원 주소를 바꾼다면
지금 당장 적용하려는 사람을 위한 현실적인 순서다.
-
수신 지갑을 먼저 정한다. 데스크톱 중심이고 하드웨어 지갑을 쓴다면 Sparrow, 모바일 중심이면 Cake Wallet이 현재 가장 무난한 조합이다. 프라이버시를 끝까지 챙기려면 자기 노드와 SP 인덱스를 붙이는 구성을 택한다.
-
폴백 주소를 반드시 함께 게시한다. 아직 대다수 거래소는 sp 주소로 출금할 수 없다. "거래소에서 바로 보낼 분은 아래 주소를, 지원 지갑을 쓰시는 분은 sp 주소를"처럼 두 줄로 안내하는 것이 현실적이다. 폴백 주소는 어차피 재사용될 것이므로, 그쪽으로 들어온 돈은 처음부터 별도 UTXO로 분류해 관리한다.
-
지갑 생성 높이를 백업에 함께 적는다. 위에서 말한 복구 문제 때문이다.
-
라벨을 쓸지 미리 정한다. 후원, 상품 판매, 급여를 구분해야 한다면 라벨을 발급한다. 다만 각 라벨 주소를 같은 웹페이지에 나란히 게시하면 연결된다는 점을 잊지 않는다.
사일런트 페이먼트가 해결하지 못하는 것
과대평가를 막기 위해 경계선을 분명히 해두는 편이 낫다.
발신자는 여전히 자기가 보낸 출력을 안다. 사일런트 페이먼트는 제3자 관찰자와 다른 후원자들로부터 수신자를 보호한다. 나에게 돈을 보낸 사람이 그 출력을 계속 추적하는 것은 막지 못한다. 다만 발신자가 볼 수 있는 것은 자기가 보낸 그 출력 하나뿐이고, 수신자의 다른 수입은 보이지 않는다. 공개 주소가 전부를 노출하던 것과 비교하면 결정적인 차이다.
발신자 쪽 프라이버시는 별개 문제다. KYC 거래소에서 갓 출금한 UTXO로 결제하면, 그 결제는 여전히 내 신원과 연결된 코인에서 나왔다. 사일런트 페이먼트는 수신 주소의 재사용 문제를 풀 뿐, 입력의 이력을 세탁하지 않는다.
코인조인의 대체재가 아니다. 둘은 다른 층위의 문제를 다룬다. 코인조인은 이미 가진 UTXO의 과거 연결을 끊고, 사일런트 페이먼트는 앞으로 받을 UTXO가 처음부터 연결되지 않게 한다. 병행할 수 있고, 병행하는 것이 낫다.
UTXO 관리를 대신해주지 않는다. 서로 다른 발신자에게서 받은 사일런트 페이먼트 출력들을 한 트랜잭션에 입력으로 몰아넣으면, 공동 입력 소유권 휴리스틱으로 그 출력들이 한 사람 것임이 드러난다. 받을 때 분리된 것을 쓸 때 합쳐버리면 원점이다.
정리
사일런트 페이먼트는 비트코인 프라이버시에서 오래 비어 있던 칸을 채운다. "한 번 공개하고 여러 번 받는다"는 요구는 지금까지 프라이버시와 양립할 수 없었고, 그래서 후원 단체와 공개 판매자는 재사용 주소를 감수하거나 결제 서버를 운영하는 두 갈래 중 하나를 골라야 했다. BIP-352는 세 번째 선택지를 만들었다.
대가는 정직하게 표시되어 있다. 받는 쪽이 스캔 부담을 지고, 복구가 느려지고, 아직은 지갑 선택지가 좁다. 탭루트가 그랬듯 이런 프로토콜은 활성화된 날이 아니라 지갑들이 조용히 지원을 붙여나가는 몇 년 동안 실제 효과를 낸다. 비트코인 코어에 수신 기능이 들어가는 시점이 그 곡선의 변곡점이 될 가능성이 높다.
지금 할 수 있는 일은 두 가지다. 공개 주소를 운영하고 있다면 sp 주소를 폴백과 함께 병기해보는 것, 그리고 누군가에게 보낼 때 sp 주소가 제시되면 그것을 쓰는 것이다. 보내는 쪽 지원은 이미 충분히 넓다.
관련 글: