[Bitcoin] Descriptor
Descriptor는 월렛간 'import' 'export' 처리를 위한 형태를 제공한다. 백업과 derivationPath를 통한 주소를 생성하는 목적으로도 사용한다고 한다.
function([derivationPath]key)checksum 형태로 되어있다.
Descriptor에 들어갈 수 있는 정보는 Script, Key, MultiSig 정보가 있다. 개인적으로 다중서명지갑에서 주소가 결정된 형태로 들어가는 형태만 알고 있었는데, derivationPath로 파생되는 자식을 범위로 묶을 수 있다는 것이 신기했다.
다중서명지갑 1 of 2, 고정된 키를 사용하는 경우
- multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc) describes a bare 1-of-2 multisig output with keys in the specified order.
다중서명지갑 1 of 2, 고정된 키를 사용하지 않는 경우(공개키에서 파생된 자식 주소로 서명할 수 있다)
- wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*)) describes a set of 1-of-2 P2WSH multisig outputs where the first multisig key is the 1/0/i child of the first specified xpub and the second multisig key is the 0/0/i child of the second specified xpub, and i is any number in a configurable range (0-1000 by default).
[] 안에 fingerprint, derivationPath 정보가 추가적으로 명시될 수도 있다(Optional)
- pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*) describes a set of P2PKH outputs, but additionally specifies that the specified xpub is a child of a master with fingerprint d34db33f, and derived using path 44'/0'/0'.
스크립트 형태가 어떤 식으로 되어 있는지도 한번 살펴보자.
SCRIPT expressions:
- sh(SCRIPT) (top level only): P2SH embed the argument.
- wsh(SCRIPT) (top level or inside sh only): P2WSH embed the argument.
- pk(KEY) (anywhere): P2PK output for the given public key.
- pkh(KEY) (not inside tr): P2PKH output for the given public key (use addr if you only know the pubkey hash).
- wpkh(KEY) (top level or inside sh only): P2WPKH output for the given compressed pubkey.
- combo(KEY) (top level only): an alias for the collection of pk(KEY) and pkh(KEY). If the key is compressed, it also includes wpkh(KEY) and sh(wpkh(KEY)).
- multi(k,KEY_1,KEY_2,...,KEY_n) (not inside tr): k-of-n multisig script using OP_CHECKMULTISIG.
- sortedmulti(k,KEY_1,KEY_2,...,KEY_n) (not inside tr): k-of-n multisig script with keys sorted lexicographically in the resulting script.
- multi_a(k,KEY_1,KEY_2,...,KEY_N) (only inside tr): k-of-n multisig script using OP_CHECKSIG, OP_CHECKSIGADD, and OP_NUMEQUAL.
- sortedmulti_a(k,KEY_1,KEY_2,...,KEY_N) (only inside tr): similar to multi_a, but the (x-only) public keys in it will be sorted lexicographically.
- tr(KEY) or tr(KEY,TREE) (top level only): P2TR output with the specified key as internal key, and optionally a tree of script paths.
- addr(ADDR) (top level only): the script which ADDR expands to.
- raw(HEX) (top level only): the script whose hex encoding is HEX.
- rawtr(KEY) (top level only): P2TR output with the specified key as output key. NOTE: while it's possible to use this to construct wallets, it has several downsides, like being unable to prove no hidden script path exists. Use at your own risk.
key Origin 정보는 옵셔널하게 제공할 수 있다. (fingerprint, hardened or unhardened derivation 정보가 들어갈 수 있음)
KEY expressions:
- Optionally, key origin information, consisting of:
- An open bracket [
- Exactly 8 hex characters for the fingerprint of the key where the derivation starts (see BIP32 for details)
- Followed by zero or more /NUM or /NUM' path elements to indicate unhardened or hardened derivation steps between the fingerprint and the key or xpub/xprv root that follows
- A closing bracket ]
16진수 공개키, WIP로 인코딩된 개인키, xpub으로 인코딩된 확장 공개키 or xprv로 인코딩된 확장 개인키로 Key를 표현한다.
- Followed by the actual key, which is either:
- Hex encoded public keys (either 66 characters starting with 02 or 03 for a compressed pubkey, or 130 characters starting with 04 for an uncompressed pubkey).
- Inside wpkh and wsh, only compressed public keys are permitted.
- Inside tr and rawtr, x-only pubkeys are also permitted (64 hex characters).
- WIF encoded private keys may be specified instead of the corresponding public key, with the same meaning.
- xpub encoded extended public key or xprv encoded extended private key (as defined in BIP 32).
- Followed by zero or more /NUM unhardened and /NUM' hardened BIP32 derivation steps.
- No more than one of these derivation steps may be of the form <NUM;NUM;...;NUM> (including hardened indicators with either or both NUM). If such specifiers are included, the descriptor will be parsed as multiple descriptors where the first descriptor uses all of the first NUM in the pair, and the second descriptor uses the second NUM in the pair for all KEY expressions, and so on.
- Optionally followed by a single /* or /*' final step to denote all (direct) unhardened or hardened children.
- The usage of hardened derivation steps requires providing the private key.
- Followed by zero or more /NUM unhardened and /NUM' hardened BIP32 derivation steps.
- Hex encoded public keys (either 66 characters starting with 02 or 03 for a compressed pubkey, or 130 characters starting with 04 for an uncompressed pubkey).
(Anywhere a ' suffix is permitted to denote hardened derivation, the suffix h can be used instead.)
출처:
https://medium.com/@nagasha/understanding-output-script-descriptors-in-bitcoin-8af8f20e0008
https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
회사에서 Descriptor 관련해서 외부 지갑 정보를 import하는 상황이라 관련 문서를 읽어봤다. 외부 지갑 추가시 기존에 사용하고 있던 월렛간의 호환성을 생각해야 하는데, 그 과정에서 추가적으로 생성하는 정보가 있기 때문이다. 아마 기존 WalletBase쪽에서 사용하던 descriptor를 계속 사용하면서 xpub 정보에 다른 고정값을 넣어서 임의로 descriptor를 만들 것으로 예상된다. 또한 외부 월렛과 내부 월렛을 구분하기 위한 스키마를 하나 더 생성할 것 같다.
다만, 기존의 경우에는 앱을 통한 월렛 추가 밖에 없는지라 '외부 월렛을 통한 싱글 or 멀티서명 지갑'이라는 개념이 없었다. 앱 내에서 멀티서명 지갑인 경우에는 WalletBase, MultiSigWallet 정보를 같이 저장해주고 있다. 여기에 외부 지갑인 경우에는 ExternalWallet 정보까지 추가로 관리하는 식으로 처리될 것 같다. 기존 어플에서 개발된 상태에서 호환성을 생각하면 생각보다 신경쓸 부분이 많아보였다(비트코인 입문인 내가 작업해도 되는건가..?!)
이번 학습을 통해 Descriptor가 어떤 형태인지, 어떤 정보가 포함되어 있는지 알 수 있었다. 아무튼 일을 받으니까 필요한 도메인 지식도 학습하고 나쁘지 않은 것 같다.