Taproot script path의 control block은 첫 byte에 output key parity와 leaf version을, 다음 32바이트에 internal x-only key를, 이후에는 선택 leaf에서 root까지의 32바이트 Merkle siblings를 담습니다. 검증 node는 tapscript와 leaf version으로 TapLeaf hash를 만들고 siblings를 정렬해 TapBranch hashes를 계산한 뒤 internal key와 root로 TapTweak output point를 재구성합니다. 이 point의 x 좌표와 parity가 실제 P2TR output key와 맞아야 script 실행으로 넘어갑니다.
Witness 마지막 항목이 control block입니다
BIP341 script path에서는 annex를 제거한 witness의 끝에서 두 번째 항목을 script s, 마지막 항목을 control block c로 해석합니다. c 길이는 정확히 33+32m이어야 하고 m은 0부터 128 사이입니다. 나머지 witness items는 tapscript의 초기 stack이 됩니다.
c[0]의 최하위 bit는 output point Q의 y parity이고 c[0]&0xfe는 leaf version입니다. 현재 tapscript leaf version은 0xc0입니다. c[1:33]은 internal key P의 x 좌표이며 lift_x가 실패하면 전체 지출도 실패합니다.
Control block은 script 내용을 숨기는 열쇠가 아니라, 공개한 leaf가 원래 output key에 포함됐다는 짧은 Merkle 증명입니다.
JOBCOIN 해설

그림은 이 주제의 공통 개념을 단순화한 설명입니다. 아래 항목에서 이 글의 구체적인 조건과 예외를 함께 읽어보세요.
- Witness 마지막 항목이 control block입니다
BIP341 script path에서는 annex를 제거한 witness의 끝에서 두 번째 항목을 script s, 마지막 항목을 control block c로 해석합니다.
- TapLeaf에서 root까지 올라갑니다
먼저 k0=hashTapLeaf(v || compact_size(len(s)) || s)를 계산합니다.
- Internal key와 root로 output key를 복원합니다
t=hashTapTweak(p || k_m)를 secp256k1 order와 비교하고 Q=P+tG를 계산합니다.
AI로 제작한 개념도 · 실제 가격·거래 내역·통계가 아닙니다.
TapLeaf에서 root까지 올라갑니다
먼저 k0=hashTapLeaf(v || compact_size(len(s)) || s)를 계산합니다. Script 길이는 CompactSize로 encoding되므로 raw bytes와 length prefix가 정확해야 합니다. 사람이 읽은 opcode 문자열을 다시 조립하면 원본 byte sequence와 달라질 수 있어 witness의 raw script를 사용합니다.
각 sibling e_j에 대해 현재 k_j와 e_j를 lexicographic order로 작은 값부터 이어 TapBranch tagged hash를 만듭니다. Left·right 방향 bit를 control block에 따로 저장하지 않는 이유입니다. 모든 siblings를 처리한 k_m이 committed Merkle root가 됩니다.
| 구간 | 길이 | 의미 |
|---|---|---|
| c[0] | 1바이트 | parity + leaf version |
| c[1:33] | 32바이트 | internal x-only key |
| c[33:] | 32m바이트 | Merkle siblings |
| script s | 별도 witness 항목 | TapLeaf 대상 |
| 초기 stack | 앞선 witness 항목 | tapscript 입력 |
Internal key와 root로 output key를 복원합니다
t=hashTapTweak(p || k_m)를 secp256k1 order와 비교하고 Q=P+tG를 계산합니다. t가 curve order 이상이면 실패합니다. 계산한 x(Q)가 scriptPubKey의 32바이트 program q와 같고 y(Q) parity가 c[0] bit와 같아야 합니다. 둘 중 하나라도 다르면 다른 tree의 leaf입니다.
Merkle tree가 leaf 하나뿐이면 m=0이라 sibling이 없지만 root는 TapLeaf hash입니다. Script path가 전혀 없는 key-only output과 혼동하지 않습니다. Control block 33바이트라는 사실만으로 empty tree인 것이 아니라 단일 leaf proof일 수 있습니다.
- annex 여부를 먼저 처리합니다.
- control block 길이 33+32m을 검사합니다.
- leaf version과 raw script로 TapLeaf를 계산합니다.
- siblings를 lexicographic order로 hash합니다.
- TapTweak Q의 x와 parity를 output에 대조합니다.
- 마지막으로 tapscript를 실행합니다.
Proof는 다른 branches의 내용을 공개하지 않습니다
Sibling hashes는 선택하지 않은 scripts의 원문을 보여 주지 않습니다. Observer는 공개된 leaf와 tree depth, sibling commitments만 압니다. 같은 sibling hash나 internal key를 여러 outputs에서 재사용하면 wallet 구조를 연결하는 단서가 될 수 있어 key·policy reuse를 피합니다.
자주 쓸 leaf를 얕게 배치하면 control block이 짧아져 witness weight를 줄일 수 있습니다. 그러나 단순 balanced tree가 항상 최적은 아닙니다. 각 recovery path 사용 확률, 공개 민감도, 최악 fee를 함께 모델링하고 descriptor backup에 tree 구조를 보존합니다.
Decoder는 consensus 순서를 그대로 따라야 합니다
탐색기가 control block을 friendly fields로 보여 줘도 raw witness bytes, block height, leaf version을 기록합니다. Future leaf versions는 현재 tapscript와 다른 semantics가 적용될 수 있으므로 0xc0 규칙을 모든 version에 강제하지 않습니다. Unknown version 처리는 BIP341의 upgrade 규칙을 따라야 합니다.
테스트는 valid proof뿐 아니라 잘못된 길이, invalid internal key, sibling 순서 오류, tweak overflow, parity mismatch, script failure를 각각 포함합니다. Proof reconstruction 성공과 script execution 성공을 하나의 boolean 뒤에 숨기면 장애 원인을 찾기 어렵습니다.
자주 묻는 질문
Control block에 Merkle 방향 bit가 왜 없나요?
각 단계에서 두 hash를 lexicographic order로 정렬해 TapBranch를 계산하므로 좌우 방향을 별도 저장하지 않습니다.
33바이트 control block이면 script tree가 없나요?
아닙니다. Merkle sibling이 없는 단일 leaf script path일 수 있습니다.
Output key를 재구성하면 지출이 바로 유효한가요?
아닙니다. Proof 확인 후 초기 stack으로 tapscript 실행도 성공해야 합니다.
더 깊이 읽기
본문에서 다룬 개념과 확인 절차를 다음 글에서 이어서 살펴보세요.



