받는 사람도 코인을 낸다
블록체인 분석은 한 거래의 입력이 모두 한 사람의 것이라고 가정한다. 페이조인(Payjoin)은 결제를 받는 사람이 자기 코인을 입력으로 보태 이 가정을 틀리게 만든다. 숫자 예시로 결제 금액이 어떻게 사라지는지 보고, 보내는 쪽과 받는 쪽이 서로를 믿지 않고도 거래를 만드는 장치, 평범해 보이기가 왜 어려운지, 그리고 수신 서버라는 장벽을 BIP-77이 어떻게 치웠는지를 정리한다.
비트코인 백서 10절 「프라이버시」는 한 가지 한계를 스스로 인정하고 끝난다.
Some linking is still unavoidable with multi-input transactions, which necessarily reveal that their inputs were owned by the same owner.
입력이 여러 개인 거래에서는 어느 정도의 연결을 피할 수 없다. 그런 거래는 입력들이 같은 주인의 것임을 드러낼 수밖에 없기 때문이다. 블록체인 분석 업계는 이 문장을 규칙으로 삼았다. 한 거래의 입력은 모두 한 사람의 것이라고 가정하고, 그 가정으로 주소들을 한 사람의 묶음으로 엮는다. 공통 입력 소유 휴리스틱이라고 부른다.
페이조인(Payjoin)은 이 문장의 'necessarily'를 겨냥한다. 결제를 받는 사람이 자기 코인 하나를 그 결제 거래의 입력으로 보탠다. 그러면 입력이 여러 개인데 주인은 둘이다. 겉으로는 평범한 결제 한 건이고, 분석가의 가정은 조용히 틀린다.
평범한 결제가 남기는 것
UTXO 지갑에서 결제는 대개 이렇게 생긴다. 앨리스가 밥에게 0.05 BTC를 보내는데, 앨리스 지갑에는 0.08 BTC짜리 코인이 있다. 거래는 입력 하나(0.08)와 출력 둘을 갖는다. 하나는 밥에게 가는 0.05, 하나는 앨리스에게 돌아오는 거스름돈 0.03이다. 이 글의 숫자는 계산을 쉽게 하려고 수수료를 뺐다.
이 거래를 보는 분석가는 몇 가지를 추정할 수 있다. BIP-78은 그중 셋을 이름 붙여 적어 두었다. 첫째는 앞서 말한 공통 입력 소유. 둘째는 주소 형식이다. 입력이 모두 어떤 형식의 주소에서 왔다면 같은 형식의 출력이 거스름돈일 가능성이 높다. 셋째는 둥근 금액이다. 0.05처럼 딱 떨어지는 출력은 결제이고, 남는 쪽이 거스름돈일 가능성이 높다. 위 거래는 셋째 추정만으로도 결제 금액과 거스름돈이 갈린다.
받는 사람이 입력을 하나 보탠다
같은 결제를 페이조인으로 하면 밥이 자기 지갑의 0.04 BTC 코인을 입력에 보탠다. 거래는 이렇게 바뀐다.
- 입력: 앨리스의 0.08, 밥의 0.04
- 출력: 밥에게 0.09, 앨리스에게 0.03
밥은 0.05를 받았고 자기 코인 0.04를 합쳐 0.09짜리 코인 하나를 새로 갖게 됐다. 앨리스는 0.03을 거스름돈으로 받았다. 실제로 일어난 일은 처음과 똑같다.
분석가에게는 전혀 다르게 보인다. 공통 입력 소유를 적용하면 0.12 BTC를 가진 한 사람이 지출한 거래다. 거스름돈을 찾으려 하면 지갑이 필요 이상의 코인을 고르지 않는다는 추정이 작동한다. 결제가 0.03이었다면 0.08 하나로 충분했으니 0.04를 더 넣을 까닭이 없다. 그러니 결제는 0.09이고 0.03이 거스름돈이라는 결론이 나온다. 결론은 둘 다 틀렸다. 입력은 두 사람의 것이고, 실제 결제 금액 0.05는 블록체인 어디에도 적혀 있지 않다.
밥이 다른 코인을 골랐다면 사정이 달라진다. 0.01 BTC 코인을 보탰다면 출력은 밥 0.06, 앨리스 0.03이 된다. 이번에는 어느 쪽이 결제든 앨리스의 0.08 하나로 충분했다. 0.01이라는 입력은 아무 이유 없이 들어간 것처럼 보이고, 평범한 지갑은 그런 선택을 하지 않는다. 이 거래는 오히려 '누군가 코인을 보탰다'는 표시가 된다. 이 점은 아래에서 다시 다룬다.
밥에게도 얻는 것이 있다. 상점처럼 결제를 많이 받는 쪽은 작은 코인이 수백, 수천 개 쌓인다. 언젠가 이것들을 합치는 통합 거래를 따로 해야 하고, 그 거래는 수수료를 내면서 자기 주소들을 한 사람의 것으로 묶어 버린다. 페이조인으로 받으면 결제를 받을 때마다 코인 하나씩을 합쳐 두는 셈이고, 그 비용의 대부분은 어차피 나가는 결제 거래에 얹힌다. BIP-78이 제안의 동기로 가장 먼저 꼽은 것이 이 통합 기회다.
원본 거래라는 담보
두 사람이 한 거래를 같이 만들려면 서로 정보를 주고받아야 한다. BIP-78의 흐름은 네 단계다.
- 밥이 결제 요청 주소(BIP-21 URI)에
pj=파라미터로 페이조인 접수 주소를 붙여 보여 준다. - 앨리스는 평소처럼 밥에게 보내는 거래를 만들고 서명까지 끝낸다. 이것을 원본(Original) PSBT라 부르고, 접수 주소로 보낸다.
- 밥은 원본에 자기 입력을 넣고 자기 출력을 고친 뒤 자기 입력에만 서명해서 돌려준다. 이것이 제안(Proposal) PSBT다.
- 앨리스는 제안을 검사하고 자기 입력에 다시 서명해 내보낸다.
여기서 중요한 장치는 2단계다. 앨리스가 처음 보내는 원본은 그대로 네트워크에 내보내도 되는 완성된 거래여야 한다. 밥이 받는 상점이라면 이 원본을 받은 순간 결제는 확보된 것이다. 앨리스가 3단계 이후에 사라지면 밥은 원본을 그냥 내보내면 된다. 원본과 최종 거래는 같은 코인을 쓰므로 둘 중 하나만 블록에 들어간다.
이 담보는 밥 쪽의 다른 위험도 막는다. 상점의 접수 주소는 누구에게나 열려 있다. 나쁜 의도를 가진 사람이 원본을 보내 놓고 마지막 서명을 안 하면, 밥은 제안을 만들 때마다 자기 코인 하나를 보여 주게 된다. 이를 되풀이하면 상점의 지갑 내용을 하나씩 캐낼 수 있다. BIP-78은 이를 UTXO 탐색 공격이라 부른다. 원본이 실제로 유효한 거래라면 공격자는 탐색 한 번마다 진짜 결제를 하나씩 걸어야 하고, 밥은 그것을 내보내 돈을 받는다. 그래서 BIP-78은 자동으로 결제를 받는 수신자에게 원본이 실제로 내보낼 수 있는 거래인지 확인하고, 이미 본 적 있는 입력이 들어 있으면 거절하라고 요구한다. 노출된 코인은 다음 페이조인에 우선 다시 쓰도록 권한다. 이 장치의 뿌리는 2018년 라이언 하바(Ryan Havar)가 쓴 버스타페이(Bustapay, BIP-79)다. 그 문서는 '공짜 염탐과 서비스 거부를 막기 위해' 보내는 쪽에 바로 전파할 수 있는 유효한 거래를 먼저 요구했다.
앨리스 쪽의 검사도 길다. 밥이 돌려준 제안에서 앨리스는 자기 입력이 모두 남아 있는지, 자기 출력의 금액이 줄지 않았는지, 수수료 총액이 원본보다 줄지 않았는지, 거래 버전과 nLockTime, 자기 입력의 sequence 값이 그대로인지를 확인한다. 그리고 원본에 있던 자기 입력에만 서명한다. 반대로 밥은 자기 몫의 출력을 마음대로 바꿀 수 있다. 금액을 줄이거나 주소를 바꾸는 것도 허용된다(출력 치환). 앨리스의 주소가 네이티브 세그윗인데 밥의 요청 주소가 옛 형식이면 밥이 같은 형식으로 바꿔 둘째 추정까지 흐릴 수 있게 하려는 것이다. 접수 서버를 결제 서버보다 덜 믿을 수 있는 곳에 두었다면 밥은 pjos=0을 붙여 치환을 금지한다. 그러면 서버가 털려도 결제를 가로챌 수 없다.
BIP-78이 스스로 적어 둔 약점도 있다. 하드웨어 지갑은 원본과 최종 거래가 같은 결제의 두 판본인지 판단하지 못한다. 연결된 컴퓨터의 지갑 소프트웨어가 오염됐다면 하드웨어 지갑은 서로 다른 두 거래에 서명하게 된다. 페이조인이 아니면 오염된 소프트웨어가 빼돌릴 수 있는 최대치는 결제 한 건이지만, 페이조인에서는 두 건이다.
평범해 보이는 것이 가장 어렵다
페이조인의 가치는 전부 '평범해 보인다'는 데 달려 있다. 평범한 결제와 구별되지 않아야 분석가가 모든 다중 입력 거래를 의심해야 한다. 그런데 평범해 보이는 일은 생각보다 어렵다.
앞의 0.01 사례가 대표적이다. 2021년 시민 게스마티(Simin Ghesmati) 등은 필요 없어 보이는 입력이 든 거래를 걸러 내는 불필요 입력 휴리스틱(Unnecessary Input Heuristic)으로 페이조인이 드러날 수 있음을 보였다. 받는 쪽이 아무 코인이나 집어넣으면 페이조인이 오히려 표시가 된다는 것이다. 널리 쓰이는 구현인 rust-payjoin은 이를 피하는 선택 함수를 둔다. 출력이 둘인 거래에서, 보탠 뒤 가장 작은 입력이 가장 작은 출력보다 커지는 코인을 고른다. 그러면 가장 작은 출력이 평범한 거스름돈처럼 보인다. 앞의 0.04가 바로 이 조건을 만족하는 선택이었다.
수수료율도 흔적이 된다. 지갑들은 보통 2 sat/vB처럼 둥근 수수료율을 쓴다. 받는 쪽이 입력을 보태고 수수료를 그대로 두면 거래가 커진 만큼 수수료율이 1.87 같은 어정쩡한 값으로 떨어진다. 입력 하나를 빼고 다시 계산했을 때 둥근 값이 나오면 의심은 확신이 된다. BIP-78은 보내는 쪽이 늘어난 수수료를 얼마까지 낼지 미리 알려 주는 파라미터를 두어, 받는 쪽이 수수료율을 원래 값으로 맞출 수 있게 했다.
구현 사이의 작은 차이도 지문이 된다. 2025년 9월 Sparrow 사용자가 Cake Wallet으로 페이조인을 보내다 'The proposal PSBT changed the nLocktime'라는 오류를 받았다는 보고가 올라왔다. Sparrow는 BIP-78의 검사 목록대로 nLockTime이 바뀐 제안을 거절한 것이다. 반대로 Cake Wallet은 모든 비트코인 거래의 nLockTime을 0으로 두고 있었다. Bitcoin Core나 Electrum은 현재 블록 높이 근처 값을 넣기 때문에, 0이라는 값은 그 자체로 어느 지갑에서 만든 거래인지 알려 주는 흔적이었다. Cake Wallet은 2026년 8월 이를 Core 방식으로 고쳤다. 같은 지갑의 수신 쪽은 한동안 후보 코인 중 첫 번째를 무조건 보태서 위의 선택 함수를 건너뛰고 있었고, 이것도 2026년 6월에 고쳐졌다.
페이조인은 평범한 거래를 흉내 내는 기술이다. 그러니 그 평범함의 기준은 결국 다른 지갑들이 실제로 만드는 거래다.
막힌 것은 서버였다
페이조인이라는 생각은 오래됐다. 2018년 8월 블록스트림 블로그에 매슈 헤이우드(Matthew Haywood)가 한 커뮤니티 워크숍의 결론을 P2EP(Pay-to-EndPoint)라는 이름으로 정리했고, 10월에 버스타페이가 BIP-79 번호를 받았다. 2019년 5월 BTCPay Server의 니콜라 도리에(Nicolas Dorier)가 쓴 BIP-78이 번호를 받아 버스타페이를 대체했다. BIP-78은 버스타페이가 PSBT를 쓰지 않아 수수료를 올리려면 받는 쪽이 UTXO 집합 전체를 알아야 했다는 점 등을 대체 이유로 들었다. 2020년 4월 16일 BTCPay Server 1.0.4.0이 상점의 페이조인 수신과 내장 지갑의 송신을 넣었다. BIP-78의 상태는 지금 'Deployed'다.
그런데도 페이조인은 널리 쓰이지 않았다. 이유는 수학이 아니라 서버였다. BIP-78의 받는 쪽은 인증된 암호화(TLS 또는 .onion)로 보호된 공개 HTTP 접수 주소를 운영해야 하고, 보내는 쪽과 동시에 온라인이어야 한다. 상점 서버에는 어렵지 않지만 휴대폰 지갑에는 사실상 불가능하다. 2020년 6월 Bitcoin Core에 '페이조인을 구현하자'는 이슈가 열렸을 때 제안자 스스로 서버와 통신하려면 OpenSSL이 필요할 수 있어 BIP-70과 같은 반대에 부딪힐 것이라고 적었다. Core는 결제 프로토콜 BIP-70을 TLS 의존 등의 문제로 이미 걷어 낸 참이었다.
BIP-77(Async Payjoin)은 이 장벽을 겨냥한다. 2023년 8월 번호를 받았고, 저자는 댄 굴드(Dan Gould)와 유발 코그먼(Yuval Kogman)이다. 받는 쪽이 서버를 운영하는 대신, 믿을 필요 없는 제3자 디렉터리 서버에 임시 우편함을 연다. 보내는 쪽은 원본을 그 우편함에 넣고, 받는 쪽은 나중에 와서 꺼내 제안을 다른 우편함에 넣는다. 두 사람이 동시에 온라인일 필요가 없다. 내용은 양쪽 끝에서 암호화되어 디렉터리는 거래를 읽지 못한다. 요청은 오블리비어스 HTTP(OHTTP, RFC 9458) 중계를 거쳐 디렉터리가 누구의 IP에서 온 요청인지도 모르게 한다. 암호 재료는 secp256k1 키 교환과 ChaCha20-Poly1305로, Core가 BIP-324 암호화 통신을 위해 이미 갖고 있는 것들이다. TLS가 필요 없다.
2020년의 Core 이슈는 2025년 10월 22일에 닫혔다. 같은 날 PSBT 규격 BIP-174의 저자인 에이바 차우(Ava Chow)가 BIP-77을 Core 지갑에 넣기 위한 추적 이슈를 새로 열었다. 2026년 10월 현재 그 이슈는 열려 있고, Core 지갑에는 아직 페이조인이 없다. BIP-77의 상태도 아직 'Draft'다. 지갑 쪽에서는 Bull Bitcoin 모바일 지갑이 2024년 12월 27일 0.4.0에서 BIP-77 송수신을 넣었고, Cake Wallet이 2025년 5월 15일 4.28.0에서 뒤따랐다. Sparrow는 BIP-78 송신을 지원하고, BIP-77 지원 요청은 2026년 3월에 열려 있다.
쓰지 않는 사람에게도
페이조인이 노리는 효과는 쓰는 사람에게만 머물지 않는다. BIP-78은 이 제안의 존재 자체가 공통 입력 소유 휴리스틱을 네트워크 전체에서 믿기 어렵게 만들어, 쓰지 않는 사람의 프라이버시도 높인다고 적었다. 분석가가 다중 입력 거래 중 일부가 두 사람의 것일 수 있다고 의심해야 하는 순간, 모든 다중 입력 거래의 묶음이 흔들린다.
다만 이 효과는 조건부다. 페이조인이 드물면 분석가는 그 가능성을 무시해도 대부분 맞는다. 그리고 앞에서 본 것처럼 구현이 흔적을 남기면 페이조인은 숨지 못하고 골라내진다. 코인조인은 같은 금액의 출력이 줄지어 있어 누가 봐도 코인조인이지만 대신 많은 사람이 섞인다. 페이조인은 두 사람만 섞이지만 겉모습이 평범하다. 앞의 것은 숨기는 군중의 크기가, 뒤의 것은 의심하게 만드는 거래의 수가 힘이다.
BIP-77은 프라이버시 말고도 다른 쓰임을 내세운다. 거래소로 들어오는 입금이 같은 거래 안에서 다른 고객의 출금을 채우는 식으로, 받자마자 내보낼 돈을 한 거래로 처리하면 블록 공간과 수수료가 준다. 거래소들이 이미 하는 출력 묶음에 입력 묶음을 더하는 셈이다.
지금 해 볼 수 있는 것
받는 쪽이 BTCPay Server를 쓰는 상점이라면 페이조인 수신을 켤 수 있다. 결제 요청 URI에 pj=가 보이면 그 상점은 페이조인을 받는다. 보내는 쪽은 Sparrow처럼 BIP-78 송신을 지원하는 지갑에서 그 URI를 그대로 붙여 넣으면 된다. 개인끼리 주고받으려면 양쪽 모두 BIP-77을 지원하는 지갑(Bull Bitcoin, Cake Wallet)이 필요하다. 페이조인을 모르는 지갑은 pj 파라미터를 무시하고 평범한 송금을 하므로, 받는 쪽이 페이조인을 켜 두어서 손해 볼 일은 없다.
하드웨어 지갑으로 보낸다면 앞에서 말한 두 건 서명의 위험을 기억해 둔다. 받는 쪽이라면 보탤 코인을 지갑이 어떻게 고르는지도 본다. 아무 코인이나 보태는 지갑은 페이조인을 숨기지 못하고 드러낸다.
백서는 다중 입력 거래가 입력의 주인이 같다는 것을 드러낼 '수밖에 없다'고 적었다. 페이조인 거래에서 그 문장은 틀린다. 그리고 그 기록이 사실과 다르다는 것을 아는 사람은 거래한 두 사람뿐이다.