2️⃣

탭 스크립트

Key-path와 Script-path

Key-path
별도의 스크립트가 없이 온전히 서명으로만 쓰인다.
스크립트의 존재 여부가 드러나지 않아 받는 상대는 key-path인지 알 수 없다.
MuSig 을 활용해 다중서명에서도 사용이 가능하다.
x좌표만 있는 공개키를 사용하여 주소를 추출한다.
Script-path
스크립트의 조건으로 지출하는 방식이다.
보통은 key-path에 조건부 지출(분쟁상황, 타입락, 백업 키, 조건부 지출)로 활용된다.
복잡한 조건 처리가 가능하다.
Internal key & Output key
Internal key는 소유권을 의미한다.
key-path 에서는 공개되지 않는다.
script-path 에서 적용된 실제 스크립트가 소유자가 작성한 것이 맞는지 확인할 때 쓰인다.
Output key는 장부에 기록하기 위한 키이다.
Internal key는 소유자가 직접 제공하는 원래 키이고, Output key 는 internal key에 tweak을 적용하여 UTXO나 주소에 사용하는 키이다.
key-path와 script-path를 구분할 수 없게 하기 위해 나뉘었다.
P2TR 주소 추출 방법
TapTweak 계산
t=taggedHash("TapTweak",PinternalxScriptmerkleroot)t=taggedHash("TapTweak",P_{internal_x}||Script_{merkleroot})
Output public key 계산
Q=Pinternal+tGQ=P_{internal}+t\cdot G
주소생성
Witness program version(01)과 Q의 x좌표(32바이트)로 bech32m인코딩한다. (bc1p…)
Bech32 인코딩 과정
[01][751e76e8199196d454941c45d1b3a323f1433bd6]
8비트를 5비트로 전환
01110101 00011110 01110110 ... ↓ 01110 10100 01111 00111 01100 ...
[01][14, 20, 15, 7, 12, ...]
polymod 연산(나머지를 맞추는 방식)으로 체크섬 계산
문자 치환 (0부터 차례로)
qpzry9x8gf2tvdw0s3jn54khce6mua7l
네트워크 정보를 앞에 붙임(’bc’ or ‘tb’)
Base58 vs Bech32
관점
Base58
Bech32
설계 목표
사람이 읽기 쉬운 문자열
사람의 오타 검출
철학
“짧고 간단하게”
“명확하고 안전하게”
시대성
초기 인터넷/암호화폐 스타일
현대적 프로토콜 설계
장점
길이가 짧다.
대소문자 구분이 없다. 더 강력한 체크섬
단점
일부 오타 허용
가시성이 떨어짐
비트코인 적용
짧고 간결한 표현을 위해
구조적 표현 (네트워크, 버전, 공개키 분리)

Script-path

P2WSH의 한계
P2WSH는 모든 스크립트가 공개되어 프라이버시가 위배될 수 있다.
머클트리
Script-path는 전체 스크립트를 공개하지 않고, 사용된 부분만 공개된다.
스크립트를 조건별로 머클트리를 구성하고, 실제로 사용한 스크립트 1개를 제출할 수 있다.
탭루트에서 사용되는 용어들
Tapscript : 실제 지출 조건으로 실행되는 코드
Tapleaf : Tapscript의 해시 값
Tapbranch : 두 개의 해시를 결합하는 규칙
tapbranch = taggedHash(“TapBranch”,  min(a, b) || max(a, b) )
항상 사전순으로 (min/max) 후 결합함
Merkle root : 모든 leaf를 branch 규칙으로 묶은 최종 결과
Merkle proof : 특정 leaf의 경로 증명을 위한 해시 목록
Control block : path의 정당성 증명을 위한 데이터 묶음
스크립트를 검증하기 위해 경로 정보를 담은 데이터 구조

Script-path 예시

평소에는 key-path로 사용하고 아래 조건에 따라 지출을 가능하게 한다.
(A AND B) ← 평상시 (key-path) OR (time ≥ T1 AND BackupKey) ← Leaf 1 OR (2-of-3 Guardian) ← Leaf 2 OR (hash preimage AND ServiceKey) ← Leaf 3 OR (time ≥ T2 AND AuditorKey) ← Leaf 4
Python
복사
leaf 1 : <T1> 블록 이후 일정 시간 후에는 무조건 <Backup_pub> 으로 백업 회수를 한다.
<T1> OP_CHECKSEQUENCEVERIFY OP_DROP <Backup_pub> OP_CHECKSIG
Python
복사
leaf 2 : 위기 시 2-of-3 (<G1_pub>, <G2_pub>, <G3_pub>)로 회수한다.
OP_0 <G1_pub> OP_CHECKSIGADD <G2_pub> OP_CHECKSIGADD <G3_pub> OP_CHECKSIGADD OP_2 OP_NUMEQUAL
Python
복사
leaf 3 : 특정 스크립트 <hash32> 를 통해 <Service_pub>으로 지급을 한다.
OP_SHA256 <hash32> OP_EQUALVERIFY <Service_pub> OP_CHECKSIG
Python
복사
leaf 4 : <T2> 이후에는 <Auditor_pub> 로 회수한다.
<T2> OP_CHECKLOCKTIMEVERIFY OP_DROP <Auditor_pub> OP_CHECKSIG
Python
복사
Merkle root 구성
root / \ hAB hCD / \ / \ hA hB hC hD hAB = TapBranch(hA, hB) hCD = TapBranch(hC, hD) root = TapBranch(hAB, hCD)
Python
복사
Output key를 만들어 주소 생성
평소 지출 시
scriptSig: (empty) witness: [ sig ]
Python
복사
예외 지출 시
scriptSig: (empty) witness: [ <script satisfaction data> , <tapscript> , <control block> ]
Python
복사
Control block 구성 (leaf 4번 지출 시)
leaf version(+parity bit): 0xc0 internal key: <32-byte x-only> //output key 검증용 merkle proof: <32-byte merkle proof of hC> <32-byte merkle proof of hAB>
Python
복사
노드들의 검증 (leaf 4번 지출 시)
UTXO의 주소를 디코딩하여 output key를 추출한다.
머클루트를 추출한다. (tap script 와 merkle proof의 조합으로)
internal key와 머클루트를 통해 output key와 동일 여부를 검증한다.
tap script를 실행한다.
세그윗 버전 0(P2WSH) 와 비교
같은 내용을 P2WSH로 구성해보자
P2WSH는 조건 관계가 매우 명확하다. (4번 조건은 3이 아니어야 한다.)
탭루트는 조건의 순서가 관계 없다. (특정 시점에 3이 맞느냐만 검증한다.)
OP_IF 2 <A_pub> <B_pub> 2 OP_CHECKMULTISIG OP_ELSE OP_IF <T1> OP_CHECKSEQUENCEVERIFY OP_DROP <Backup_pub> OP_CHECKSIG OP_ELSE OP_IF 2 <G1_pub> <G2_pub> <G3_pub> 3 OP_CHECKMULTISIG OP_ELSE OP_IF OP_SHA256 <hash32> OP_EQUALVERIFY <Service_pub> OP_CHECKSIG OP_ELSE <T2> OP_CHECKLOCKTIMEVERIFY OP_DROP <Auditor_pub> OP_CHECKSIG OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF
Python
복사