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 계산
◦
Output public key 계산
◦
주소생성
▪
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
복사
