ERC-5564 스텔스 주소 (Stealth Addresses)

Final · 계정·지갑 · 2022-08-13 작성

보내는 사람이 받는 사람과 미리 연락하지 않고도, 받는 사람만 열 수 있는 비공개 주소를 만들어 자산을 보낼 수 있게 합니다. 체인마다 하나뿐인 알림 컨트랙트가 수신 사실을 알려 줍니다.

왜 필요한가

이더리움에서 거래는 모두 공개됩니다. 어떤 주소가 어떤 토큰을 받았는지 누구나 볼 수 있어서 주소가 누구 것인지 알려지면 그 사람의 자산 내역이 그대로 드러납니다. 특정 단체나 국가에 기부하고 싶지만 자신과 받는 쪽의 연결은 밝히고 싶지 않은 경우가 그렇습니다. 받는 사람이 거래마다 새 주소를 만들어 알려 주면 추적을 피할 수 있지만 그러려면 보내기 전에 매번 연락을 주고받아야 합니다. 보내는 사람이 혼자서 받는 사람 전용 주소를 만드는 방법이 표준으로 정해져 있지 않으면 지갑과 앱마다 방식이 달라지고 받는 사람은 자기에게 온 자산이 어디에 있는지 놓치기 쉽습니다. 이런 프라이버시 기능은 표준이 있어야 널리 쓰일 수 있습니다.

구현해야 하는 것

심층 설명

세 가지 키와 메타 주소 길이 규칙

스텔스 메타 주소는 받는 사람의 스텔스 주소를 계산하는 데 쓰는 공개키 한 개 또는 두 개의 묶음입니다. 지출 키(spending key)는 스텔스 주소로 온 자금을 쓰는 개인키이고 열람 키(viewing key)는 어떤 스텔스 주소가 자기 것인지 판별만 할 수 있는 개인키입니다. 각각 대응하는 지출 공개키와 열람 공개키가 있습니다. 공개키 길이가 n바이트인 스킴에서 메타 주소 길이가 n이면 지출 공개키와 열람 공개키로 같은 키를 쓰고 길이가 2n이면 앞 n바이트가 지출 공개키, 뒤 n바이트가 열람 공개키입니다. 이 규칙은 MUST로, 모든 스킴이 따라야 합니다.

모든 스킴이 구현해야 하는 함수 세 개

보내는 사람은 generateStealthAddress로 메타 주소에서 스텔스 주소, 임시 공개키(ephemeralPubKey), 뷰 태그(viewTag)를 얻을 수 있어야 합니다. 받는 사람은 checkStealthAddress로 어떤 스텔스 주소가 자기 것인지 확인하고 computeStealthKey로 그 주소의 개인키를 계산할 수 있어야 합니다. computeStealthKey의 stealthAddress 인자는 계산에 꼭 필요하지는 않지만 도출한 개인키가 올바른지 검증하려고 받습니다. 세 함수의 구현은 스킴마다 다르며 새 스킴을 제안하는 ERC는 각 함수의 구현을 명시해야 합니다. 인터페이스는 Solidity로 적혀 있지만 반드시 Solidity로 구현할 필요는 없습니다. 다만 이 표준을 따르는 라이브러리나 SDK는 호환되는 함수 인터페이스로 구현해야 합니다.

schemeId와 스킴 1(SECP256k1 + 뷰 태그)

스킴은 256비트 정수 schemeId로 구분합니다. 새 스킴을 표준화하는 ERC는 schemeId와 명세의 대응을 선언해야 하며 단순하게 1씩 늘어나는 정수를 쓰는 것이 권장(RECOMMENDED)되지만 임의의 값이나 의미 있는 값도 허용됩니다. 이 ERC는 schemeId 1을 정의합니다. 스킴 1에서는 뷰 태그를 알림 이벤트에 반드시 포함해 받는 사람의 파싱 시간을 줄이고 SECP256k1 곡선으로 메타 주소(지출 공개키와 열람 공개키)를 bytes로 인코딩하고 다시 키 타입으로 디코딩합니다. generateStealthAddress, checkStealthAddress, computeStealthKey 모두 뷰 태그가 있는 SECP256k1 방식을 씁니다.

ERC5564Announcer 싱글턴과 metadata 규칙

체인마다 하나만 존재하는 ERC5564Announcer 컨트랙트가 Announcement 이벤트를 냅니다. 이벤트는 schemeId, stealthAddress, caller가 indexed이고 ephemeralPubKey와 metadata를 담습니다. announce 함수는 호출자(msg.sender)를 caller에 넣어 이벤트를 발생시킵니다. metadata의 첫 바이트는 반드시 뷰 태그여야 하고 나머지는 자유롭게 쓸 수 있지만 다음 구조가 권장됩니다. 네이티브 토큰(ETH)을 보낼 때는 2~5바이트에 0xeeeeeeee, 6~25바이트에 주소 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, 26~57바이트에 보내는 ETH 양을 넣습니다. ERC-20, ERC-721 같은 토큰이면 2~5바이트에 함수 식별자(함수 선택자가 있으면 반드시 그것), 6~25바이트에 토큰 컨트랙트 주소, 26~57바이트에 수량 또는 토큰 ID를 넣습니다. 컨트랙트는 0x55649E01B5Df198D18D95b5cc5051630cfD45564에 배포되어 있으며 결정적 배포자 0x4e59b44847b379578588920ca78fbf26c0b4956c를 통해 CREATE2로, salt 0xd0103a290d760f027c9ca72675f5121d725397fb2f618f05b6c44958b25b4447을 써서 배포했습니다.

메타 주소 표기 형식 st:eth:

스텔스 메타 주소는 체인별 주소 형식 앞에 st:(stealth) 접두사를 붙입니다. 이더리움에서는 st:eth:0x<spendingPubKey><viewingPubKey> 형태입니다. 이 형식은 일반 주소와 구분하기 위한 것일 뿐이며 계산할 때는 접두사를 떼고 씁니다. 메타 주소는 사용자가 직접 관리해도 되고 ERC-6538에 정의된 공개 Registry 컨트랙트에 등록해도 됩니다. 레지스트리를 쓰면 다른 사람의 메타 주소를 한곳에서 찾을 수 있고 받는 사람은 스텔스 주소로 거래할 의사가 있음을 알릴 수 있습니다.

스킴 1의 주소 생성 계산

SECP256k1 곡선은 y^2 = x^3 + 7 (mod p), p = 2^256 - 2^32 - 977로 정의되고 G는 생성점입니다. 받는 사람은 개인키 p_spend, p_view와 그에 대응하는 공개키 P_spend, P_view를 갖고 메타 주소를 공개해 둡니다. generateStealthAddress는 다음 순서로 계산합니다. 32바이트 무작위 임시 개인키 p_ephemeral을 만들고 임시 공개키 P_ephemeral을 구합니다. 메타 주소에서 P_spend와 P_view를 파싱합니다. 공유 비밀 s = p_ephemeral · P_view를 계산하고 해시해 s_h = h(s)를 얻습니다. 뷰 태그 v는 s_h의 최상위 바이트 s_h[0]입니다. S_h = s_h · G를 구하고 스텔스 공개키 P_stealth = P_spend + S_h를 계산합니다. 스텔스 주소 a_stealth는 pubkeyToAddress(P_stealth)입니다. 함수는 a_stealth, P_ephemeral, v를 반환합니다.

스킴 1의 알림 확인과 개인키 도출

checkStealthAddress는 열람 개인키 p_view와 지출 공개키 P_spend만으로 동작합니다. 알림의 임시 공개키와 곱해 공유 비밀 s = p_view · P_ephemeral을 구하고 s_h = h(s)를 계산합니다. s_h[0]을 알림의 뷰 태그와 비교해 다르면 자기 것이 아니므로 나머지 계산을 건너뜁니다. 같으면 S_h = s_h · G, P_stealth = P_spend + S_h, a_stealth = pubkeyToAddress(P_stealth)를 구해 알림의 스텔스 주소와 일치하면 true를 반환합니다. computeStealthKey는 열람 개인키와 지출 개인키 p_spend를 모두 씁니다. 같은 방식으로 s_h를 구한 뒤 스텔스 개인키를 p_stealth = p_spend + s_h로 계산합니다. 개인키 도출에 지출 개인키가 필요하므로, 열람 키만으로는 수신 여부 확인까지만 할 수 있습니다.

뷰 태그가 파싱 비용을 줄이는 원리

뷰 태그가 없으면 받는 사람은 알림 하나를 확인할 때마다 타원곡선 곱셈(ecMUL) 2회, 해시 2회, 타원곡선 덧셈(ecADD) 1회를 수행해야 합니다. 뷰 태그를 쓰면 공유 비밀을 해시한 뒤 첫 바이트만 비교해 대부분의 알림을 걸러내므로 ecMUL 1회와 해시 1회만 하면 되고 파싱 시간이 약 6배 줄어듭니다. 뷰 태그가 1바이트이므로 자기 것이 아닌 알림에서 나머지 계산을 건너뛸 확률은 255/256입니다. 대신 공유 비밀의 1바이트가 드러나기 때문에 보안 여유(security margin)는 128비트에서 124비트로 줄어듭니다. 이 감소는 프라이버시에만 영향을 주며 스텔스 주소 생성 자체의 안전성에는 영향이 없습니다. 저자들은 뷰 태그가 체인 밖 효율을 높이는 대신 알림 이벤트를 복잡하게 만드는 절충이라고 설명합니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs