BIP48 설명: SSP 아래의 파생 경로

·8분 읽기·작성자: SSP Editorial Team
남색 SSP 커버, 어두운 그라데이션 위 키·방패·CPU 아이콘, Multisig Deep Dive 시리즈의 BIP48 장

이 시리즈에서 지금까지 multisig가 무엇인지어떤 임계값을 선택할지를 다뤘다. 두 글 모두 multisig 지갑의 행동을 묘사했다 — n개의 키 중 m개가 서명하고, 체인이 임계값을 확인하고, 돈이 움직인다. 두 글 모두 지갑이 실제로 그 아래에서 어떻게 조립되는지에 대해서는 별로 말하지 않았다. 이 글이 그것이다.

짧은 버전: SSP가 너에게 지갑을 만들 때, 그저 두 개의 랜덤한 키를 생성하고 끝내지 않는다. **BIP48**이라는 문서화된 표준을 따르는 방식으로 생성하므로, 그 결과 나오는 지갑은 상호 운용 가능하고, SSP 외의 소프트웨어에서도 복구 가능하며, 체인에서 예측 가능하게 검사 가능하다. 이것이 BIP48이 무엇인지, 왜 존재하는지, 그리고 왜 "이 지갑은 BIP48을 쓴다"가 multisig에서 가장 지루하면서도 가장 중요한 문장 중 하나인지를 설명하는 글이다.

TL;DR

  • 파생 경로는 하나의 seed phrase에서 지갑 내 특정 키(및 주소)로 가는 길이다. BIP44 / BIP48 같은 표준화된 경로는 서로 다른 지갑 소프트웨어가 같은 seed에서 같은 키에 도달하도록 한다.
  • BIP48은 multisig 지갑을 위한 spec이다. 그것은 말한다: 여기 주요 출력 스크립트 유형 전반에 걸쳐 2-of-3, 3-of-5 등의 지갑을 구성하는 m개 키의 정규 파생 경로가 있다.
  • SSP는 BIP48을 쓴다. 즉, 너의 SSP 지갑이 생성한 두 seed는 다른 어떤 BIP48 호환 지갑(Sparrow, Electrum, Bitcoin Core의 descriptors)에서도 사용할 수 있다 — SSP 자체뿐 아니라.
  • BIP48은 이전 multisig spec(BIP45)이 가지고 있던 문제를 해결한다: 다른 스크립트 유형들(legacy, P2SH-wrapped SegWit, native SegWit, Taproot)을 위한 키를 깨끗하게 분리하여, 하나의 seed phrase가 충돌 없이 그 모두를 보유할 수 있게 한다.
  • SSP를 쓰기 위해 파생 경로를 수동으로 다룰 필요는 없다. 하지만 그것들이 존재한다는 것은 알아두어야 "지갑 복구"가 마법처럼 느껴지지 않고 — 너의 seed가 실제로 무엇에 매핑되는지 이해할 수 있다.

파생 경로의 30초 투어

BIP48이 어떤 의미를 갖기 전에, 그 아래의 기계가 존재해야 했다. 그 기계는 BIP32: hierarchical deterministic(HD) 지갑이다. 핵심 아이디어는 seed phrase에서 파생된 하나의 마스터 키가, 무한한 자식 키의 나무를 결정론적으로 생성할 수 있다는 것이다. 나무에서 특정 경로를 따라가면 항상 같은 자식 키에 도착한다. 다른 경로를 따라가면 다른 키에 도착한다.

경로는 이렇게 생겼다:

m / purpose' / coin_type' / account' / change / index

예를 들어 BIP44 경로 m / 44' / 0' / 0' / 0 / 0BIP44 규칙 하의 Bitcoin 첫 번째 계정의 첫 번째 수신 주소에 도달한다. coin_type60'으로 바꾸면 Ethereum 공간에 있고; purpose84'로 바꾸면 BIP84(native SegWit) 공간에 있다; 등등. 작은따옴표(')는 hardened 파생이다 — 자식은 부모로 역변환될 수 없다. 마스터 이후의 각 세그먼트는 관례에 따라 분할된 32-bit 수다.

이 부분은 보통 휙 넘어가곤 한다: 경로는 메타데이터이지 비밀이 아니다. 너의 경로 그리고 너의 개인 키(또는 확장 키)를 아는 사람은 누구나 같은 주소를 파생할 수 있다. 경로는 지갑에게 어디를 봐야 하는지 말한다. Seed는 거기에 무엇이 있는지 말한다.

Seed 자체가 무엇인지에 대한 친절한 복습으로, seed phrase best practices 글이 선행 읽기다.

BIP48이 명시하는 것

BIP48은 m / 48' / coin_type' / account' / script_type' / change / index에 산다. 흥미로운 추가는 script_type' — 끝에서 두 번째 세그먼트다.

그 세그먼트는 그 경로가 어떤 종류의 multisig 출력을 위한 것인지를 인코딩한다:

  • 0' → P2SH(legacy multisig)
  • 1' → P2SH-wrapped SegWit(P2WSH-in-P2SH)
  • 2' → native SegWit(P2WSH)
  • 3' → Taproot-등가 multisig(BIP48 수정에 따라)

이것이 중요한 이유는 실제로 같은 m-of-n cosigner 집합이 어느 출력 스크립트가 사용되는가에 따라 체인에서 다른 주소들을 생성하기 때문이다. BIP48 없이는, 한 지갑이 조용히 한 종류를 쓸 수 있고, 복구 소프트웨어가 다른 종류를 가정할 수 있으며, 결과적으로 같은 코인을 파생해야 하는 것처럼 보이는 두 지갑이 — 그러나 다른 주소를 계산하기 때문에 그렇지 않은 — 나오게 된다.

BIP48은 또한 purpose' 세그먼트를 48'로 고정하여, multisig 경로가 single-sig BIP44/BIP49/BIP84 경로와 충돌할 수 없게 한다. 하나의 seed가 BIP84의 single-sig 지갑 그리고 BIP48의 2-of-2 multisig 지갑을 간섭 없이 보유할 수 있다. 각각은 자신의 부분 나무에 산다.

경로 자체를 넘어, BIP48은 cosigner 공개 키("xpubs")가 multisig 출력을 구성할 때 어떻게 정렬되어야 하는지 명시한다. 정규 규칙은 공개 키가 redeem script에 들어가기 전 사전식 정렬이다. 그것이 모호함을 제거한다 — 같은 xpubs에서 빌드하는 모든 BIP48 준수 지갑은 같은 주소를 계산한다. 그 규칙 없이는 두 지갑이 같은 키를 다른 순서로 결합하고 같은 redeem 규칙으로 다른 주소에서 끝날 수 있다.

spec을 글자 그대로 읽고 싶다면, Bitcoin BIPs repo에 산다(bips/bip-0048.mediawiki).

SSP가 실제로 BIP48을 어떻게 쓰는가

SSP 지갑을 설정할 때, 두 개의 seed phrase가 생성된다 — 하나는 브라우저 확장에, 하나는 SSP Key 모바일 앱에. 각 seed phrase는 마스터 개인 키에 해당한다. 각 마스터에서, SSP는 관련 체인(Bitcoin, Ethereum, Flux 및 SSP가 지원하는 나머지 집합)을 위한 BIP48 경로를 script_type' = 2'에서 파생한다(Bitcoin에서는 native SegWit; 적용 가능한 다른 체인에서는 동등한 정규 형태).

두 서명자의 xpubs는 그 후 교환된다. 각 측은 이제 BIP48에 따라 사전식으로 정렬된 같은 두 개의 xpubs 집합을 가진다. 그 쌍으로부터, 각 측은 독립적으로 같은 주소를 계산한다. 두 반쪽은 절대 개인 키를 공유하지 않는다 — 공개 키만 기기 간에 이동한다.

돈을 받을 때, 너에게 보이는 주소는 두 xpubs로부터 계산된 BIP48-파생 주소다. 지출할 때, 각 기기는 같은 거래를 자신의 개인 키로 서명한다. 체인의 redeem script는 두 공개 키를 참조한다; 네트워크가 두 서명을 확인한다. 그것이 전체 프로토콜이다.

이것이 복구 시나리오에서 중요한 이유: 만약 SSP가 제품으로서 내일 사라진다면, 너는 여전히 BIP48 준수의 seed phrase 두 개를 가지고 있을 것이다. 둘 다 Sparrow(또는 SSP가 쓰는 BIP48 경로를 지원하는 다른 어떤 multisig 가능 지갑)에 로드하면 같은 지갑이, 같은 주소에서, 전체 지출 능력을 갖고 재구성된다. 지갑은 SSP 안에 살지 않는다 — 체인에 살고, seed와 BIP48 spec이면 어디에서든 그것에 닿기에 충분하다.

그 속성은 self-custody-without-cold-storage 글이 2-of-2 SSP 지갑을 custodial 풍미의 호기심이 아닌 진지한 지갑으로 다루는 큰 이유다. 그것은 열린 표준으로부터 복구 가능하다.

BIP45 대신 BIP48인 이유(그리고 BIP44가 아닌 이유)

이전의 multisig spec은 BIP45였다. 정직한 첫 시도였다: m / 45' / cosigner_index' / change / index, cosigner_index'가 너가 지갑에서 어떤 cosigner인지를 인코딩한다. 돌이켜보면 두 가지 문제가 있었다.

첫째, cosigner_index'가 순서를 경로 자체에 구워 넣었다. 그것은 서명자가 추가되는 순서가 파생에 영향을 미친다는 것을 의미했고, 이는 공동 설정을 취약하게 만들었다 — 순서를 잘못 잡으면 cosigner와 다른 주소를 파생한다. BIP48은 cosigner 인덱스를 경로에서 완전히 제거하고 공개 키의 사전식 정렬이 그것을 처리하게 함으로써 이를 해결한다.

둘째, BIP45는 스크립트 유형으로 분리하지 않았다. 지갑이 legacy P2SH multisig를 쓰든 SegWit-wrapped multisig를 쓰든 같은 경로가 재사용되곤 했다. 그것은 위에서 설명한 같은 주소-충돌-그러나-같은-코인이-아닌 문제를 만들었다.

더 일반적인 HD spec인 BIP44는 multisig을 다룬다고 주장한 적이 없다. BIP44에 multisig 경로를 과적재하려는 시도는 자체적인 충돌을 만들었다. BIP48이 명시적 수정이었다: 전용 purpose 번호, 명시적 script-type 슬롯, 결정론적 키 정렬. 오늘날 대부분의 현대 multisig 지갑이 그것으로 수렴한다; 사실상의 표준이다.

이것이 multisig의 다음 장 — 여러 서명이 하나로 압축되는 Schnorr 집계 — 으로 어떻게 이어지는지에 대한 더 깊은 역사는, 이 시리즈의 다음 글 Schnorr signatures and multisig aggregation이 그 실을 이어받는다.

이것이 상호 운용성에 의미하는 것

"이 multisig 지갑이 정말 self-custodial인가?"의 가장 깨끗한 테스트는: 지갑의 소프트웨어 없이 그것을 복구할 수 있는가? 답이 그렇다 — 문서화된 seed, 문서화된 파생 경로, 표준 도구를 사용하여 — 라면 지갑은 진짜로 너의 것이다. 답이 그렇지 않다면, 지갑에는 숨겨진 custodial 요소가 있다.

SSP의 BIP48 준수는 우리가 그렇다고 답할 수 있게 하는 것이다. Seed phrase는 BIP39(표준 mnemonic), 파생은 BIP48, 주소 구성은 BIP48-정규. 같은 표준을 말하는 어떤 지갑도 지갑을 재구성할 수 있다.

그래서 도입 글 Meet SSP Wallet이 SSP를 관리 서비스가 아니라 "2-of-2 multisig를 갖춘 self-custody"로 프레임한다. 아래의 표준들이 그 프레임이 정직한 이유다.

이것이 너에게 의미하는 것

세 가지 결론:

  1. SSP를 쓰기 위해 경로를 외울 필요는 없다. m/48'/0'/0'/2'/0/0이라는 숫자는 일반 사용자가 절대 입력할 필요가 없는 것이다. 하지만 그것이 존재한다는 것을 아는 것이 "나는 SSP 없이도 이 지갑을 복구할 수 있다"를 마케팅이 아닌 실제 주장으로 만든다.
  2. 너의 두 seed는 상호 운용 가능하다. 언젠가 제3자 multisig 지갑으로 복구해야 한다면, BIP48 + 너의 두 BIP39 seed + 체인의 coin_type이 레시피다. self-custody 체크리스트가 이것을 리허설 단계로 이름하는 데는 이유가 있다.
  3. BIP48(또는 유사한 것)을 쓰지 않는 multisig 지갑은 의심해볼 만하다. 제품이 너의 키에서 주소가 어떻게 파생되는지를 정확히 말해줄 수 없다면, 그것은 self-custody가 아니다 — 추가 단계가 있는 custody다. 표준 준수가 "너의 키, 너의 코인"이라는 주장을 검증 가능하게 만드는 것이다.

이 글 공유하기

관련 글