비트코인의 스크립트 이해하기

비트코인의 스크립트 이해하기

P2PK, P2SH, P2WPKH... 이런게 도대체 뭔지 궁금하신가요? 저도요..

·

5 min read

0. 들어가며

비트코인의 전송 매커니즘 ⇒ 잠금과 해제

비트코인을 전송함 ( = 트랜잭션을 일으켜 새로운 UTXO를 생성함) : 잠금 (ScriptPubKey)

비트코인을 소비함 ( = 기존 UTXO를 이용해 새로운 트랜잭션을 일으킴) : 해제 - 이때 해제를 위한 스크립트가 ScriptSig로 이것으로 해당 UTXO의 소유권을 증명가능

스크립트 : 비트코인의 스마트 계약 언어로 비트코인의 소비 조건을 기술할 수 있음

비트코인의 스크립트는 튜링불완전 언어로 반복문을 작성할 수 없음 ⇒ 무한루프 공격에 대응하기 위함 + 분석 및 디버깅에 용이

  • 이더리움에서 사용하는 솔리디티는 튜링완전언어로, 무한루프 공격을 gas 개념을 도입하여 해결

1. 스크립트란?

스크립트는 프로그래밍 언어.

명령어를 한번에 하나씩 스택 기반 처리

명령어는 두가지 종류가 있다.

  1. 원소 : 데이터 ex) signature, pubkey

  2. 연산자 : 데이터에 대한 동작 ex) OP_CHECKSIG(공개키와 서명을 가져와 검증후 T/F 리턴해 스택에 올리기) , OP_DUP(원소복사동작: 같은 원소를 복사해 스택에 올리기), OP_HASH160(암호화동작 : 기존 원소를 해싱하여 스택에 올리기)

    1. 이러한 연산자는 숫자로 식별코드 부여되어있고 이를 opcode라고 함

    2. 위의 예시 연산자 외에도 흐름제어 연산(if, else ..), 상수(0, 1 ..) 등의 연산자가 있음

    3. 대부분은 산술연산, 암호함수 기능을 수행하는 연산자

이러한 명령어 집합으로 이루어진 Script 객체는 명령어를 실행하기 위해 잠금스크립트(ScriptPubkey)와 해제 스크립트(ScriptSig)를 결합해야한다.

이 각각의 스크립트를 모아서 하나의 스크립트를 만들고(결합 스크립트) 명령어를 실행하여 암호화를 해제하고 사용할 수 있게 된다.

2. 비트코인 표준 스크립트

명칭의미주소ScriptPubKey(잠금) 구조ScriptSig(해제) 구조Witness 필드특징문제점
P2PKpay-to-pubkey공개키 OP_CHECKSIG (*이 잠금스크립트가 공개키를 포함하고 있기때문에 잠금스크립트를 ScriptPubKey라는 이름으로 부르게 됨)서명 (*이 해제스크립트가 서명을 포함하고 있기때문에 해제스크립트를 ScriptSig라고하게됨)비트코인 초기 스크립트 방식1. ScriptPubKey에 포함된 공개키의 길이가 너무 길다. 비압축방식 주소를 사용하면 너무 길어서 인간이 이용하기 불편하며 UTXO내에 포함되어야 하므로 사이즈가 너무 커져 노드에 부담 (추후 압축SEC형식 사용으로 줄어들었으나 이 역시 김) 2. 잠금스크립트는 누구나 볼 수 있는데 여기에 공개키가 그대로 포함되어 암호방식이 깨지게되면(양자컴퓨터 등) 해킹위험 높아짐
P2PKHpay-to-pubkey-hash1 p2pk에서 사용하는 압축SEC형식 공개키 → hash160 해싱 : 20바이트 16진수 나옴 → Base58 부호화 → 주소 나옴. (1로 시작한다)OP_DUP OP_HASH160 공개키 해시값 OP_EQUALVERIFY OP_CHECKSIG서명 공개키 유효성 검증을 2번에 걸쳐서 함(공개키 일치하는지, 서명이 유효한지)p2pk의 대안 1. 짧은 주소(잠금 스크립트 크기가 25바이트로 작아짐) 2. 해싱함수 추가 사용으로 보안성 높임 비트코인 초기부터 많이 사용은 안됐지만 있긴 했었음하나의 비밀키로 자산을 보관해야하기에 단일 실패 지점 문제
OP_m 공개키1 … 공개키n OP_n OP_CHECKMULTISIG 위의 스크립트가 리딤스크립트OP_0 서명1 … 서명m
P2SHpay-to-script-hash3 P2PKH 주소 방식과 유사 리딤스크립트를 Hash160 해싱 후 접두부바이트(부호화하면 3)와 체크섬 → Base58 부호화 (*P2PKH에서는 공개키를 Hash160 해싱)OP_HASH160 기존 멀티시그 스크립트(리딤스크립트)의 해시 OP_EQUAL 가 되고 리딤스크립트의 해시값을 구함 이 해시값이 잠금 스크립트를 대신하여 들어OP_0 (CHECKMULTISIG 버그때문에 항상 포함 필요) 서명1 … 서명m 리딤스크립트 기존의 리딤스크립트를 해제시 제시 ⇒ 즉, 리딤스크립트를 사용자가 보관하고 있어야 함!! 리딤스크립트 분실, 혹은 재작성 불가하면 해당 UTXO 사용이 불가능함기존 Multisig(다중서명) 방식의 긴 주소/잠금스크립트 문제를 해결하기 위해 제안 기존의 긴 스크립트 대신 그 스크립트의 짧은 해시값을 제시 리딤스크립트 길이가 최대 520바이트(단일 원소가 가질수 있는 최대길이)까지 가능 리딤스크립트 보관의 부담을 사용자에게 부여하며 UTXO 풀의 크기를 줄이는 방식 ————P2SH 특별 규칙—————- 리딤스크립트 OP_HASH160 위 스크립트의 해시 OP_EQUAL 이런 패턴의 명령어가 명령어집합(스택들어가기전)에 남아있을 때 P2SH 특별 규칙이 실행됨 ⇒ 리딤스크립트 해싱 후 잠금스크립트 내의 해시와 비교하여 일치하면 리딤스크립트를 파싱하여 스크립트 명령집합에 삽입하는 동작
P2WPKHpay-to-witness-pubkey-hashbc1q Bech32 주소형식 사용 (예전 지갑은 지원 안됨)OP_0 ← 세그윗버전 20바이트 해시(P2PKH에서 사용하는 공개키 해시값, hash160)(비어있음)서명 공개키P2PKH와 유사하게 동작하지만 해제스크립트 데이터가 Witness 필드에 분리되었다는 차이 P2SH 특별 규칙과 유사하게 세그윗 특별 규칙 이 있음 ————세그윗 특별 규칙1—————- 스택에서 <20바이트해시 + 0>의 패턴을 만나면 증인 필드에서 값을 가지고와 아래 순서로 스크립트 명령집합에 추가하는 방식으로 동작 (세그윗 노드에서만) 👇 서명 (witness에서 가져옴) 공개키 (witness에서 가져옴) OP_DUP OP_HASH160 20바이트 해시 OP_EQUALVERIFY OP_CHECKSIG (P2PKH의 스크립트와 동일하게 동작)예전노드에서는 세그윗 특별규칙을 알지 못한채 P2PKH 방식의 스크립트를 가지고 오지 않고 20바이트 해시값에서 종료 따라서 추가검증을 따로 하지 않는 셈이지만 이미 많은 다른 노드에서 검증되어왔을 것이기 때문에 해당 노드는 직접 검증하지 않고 서명이 유효하다고 믿을 수 있음 * 이는 세그윗 버전 0에 대한 설명임! 세그윗은 20바이트 해시 이후의 원소로 버전을 명시하는 세그윗버전방식을 사용하고 있어 업그레이드가 용이함
P2SH-P2WPKH네스티드 세그윗 (세그윗 스크립트(OP_0 + 20바이트해시)가 P2SH 리딤 스크립트 안에 들어있음) 일반적인 P2SH 주소 사용3 P2SH형식을 사용해 기존 지갑에서 P2WPKH 잠금스크립트를 사용할 수 있게 구현한 방식OP_HASH160 해시 OP_EQUAL (P2SH 잠금스크립트와 동일)리딤스크립트 <파싱된 리딤스크립트> OP_0 ← 세그윗버전 20바이트 해시(P2PKH에서 사용하는 공개키 해시값)P2SH 특별규칙 실행 패턴과 일치 리딤스크립트 해싱 후 잠금스크립트 내 해시와 비교 일치한다면 리딤스크립트 파싱 파싱 후에는 세그윗 특별규칙 실행 패턴의 결과값 나옴 세그윗노드에서는 해당 규칙 실행하며 검증
P2WSHpay-to-witness-script-hashbc1q 다중서명 트랜잭션에 대한 세그윗 스크립트OP_0 32바이트 해시(sha256)(비어있음)<파싱된 증인필드> witness수 OP_0 signaturex signaturey witnessScript (증인스크립트) ⇒ 이 값의 sha256해싱 결과와 잠금스크립트의 32바이트 해시와 비교해 검증P2SH와 차이점 : 모든 해제스크립트 데이터가 witness 필드에 있음 라이트닝 네트워크를 위한 양방향 결제 채널에서 특히 중요! (가변성 문제가 없는 다중서명 트랜잭션이 필요해서) ————세그윗 특별 규칙2—————- 스택에서 <32바이트해시 + 0>의 패턴을 만나면 증인필드에서 값을 가지고 와 파싱 <파싱된 증인필드> witness수 OP_0 signaturex signaturey witnessScript (증인스크립트) ⇒ 이 값의 sha256해싱 결과와 잠금스크립트의 32바이트 해시와 비교해 검증 검증이 된 후 증인스크립트는 스크립트명령어로 파싱되어 명령집합에 추가 <파싱된 증인스크립트> OP_0 서명1 … 서명m OP_m 공개키1 … 공개키n OP_n OP_CHECKMULTISIG (기본적인 다중서명 리딤스크립트 구조)
P2SH-P2WSH3 P2SH형식을 사용해 기존 지갑에서 P2WSH 잠금스크립트를 사용할 수 있게 구현한 방식OP_HASH160 해시 OP_EQUAL (P2SH 잠금스크립트와 동일)리딤스크립트 <파싱된 리딤스크립트> OP_0 ← 세그윗버전 32바이트 해시(P2WSH에서 사용하는 잠금스크립트)P2SH 특별규칙 실행 후 세그윗 특별 규칙 실행
P2TRpay-to-Taprootbc1pOP_1 (세그윗 버전 1) 32바이트 공개키 (세그윗방식의 잠금스크립트)(비어있음)서명잠금스크립트 내의 공개키가 여러 공개키를 합친 공개키(p = p1 + p2 + …)라면 증인 필드에도 다중 서명을 위한 전체서명(s = s1 + s2 + ….) 포함시키면 됨 이런 식으로 하나의 서명을 이용해 여러개의 공개키를 검증 가능하도록 하는 것이 슈노르 서명…