비트코인 스크립트: 화폐의 프로그래밍 언어
비트코인 스크립트 심층 기술 가이드 — 스택 기반 프로그래밍 언어의 작동 원리, 옵코드, 표준 스크립트 유형(P2PKH, P2SH, P2WPKH, P2TR), 실행 추적, 타임락, 다중서명, 탭스크립트까지 상세히 다룹니다.
존재하는 모든 비트코인은 프로그램에 의해 잠겨 있다. 은행에 의해서도, 비밀번호에 의해서도, 사용자명에 의해서도 아니다 — 비트코인 스크립트라는 언어로 작성된 작고 결정론적인 프로그램에 의해 잠겨 있다. 그 비트코인을 지출하려면, 프로그램이 TRUE를 반환하게 하는 입력을 제공해야 한다. 프로그램이 FALSE를 반환하거나 실행이 실패하면, 비트코인은 지출될 수 없다. 이것이 비트코인이 소유권을 집행하는 근본적 메커니즘이다: 신원이 아닌, 계산을 통해.
비트코인 스크립트는 역사상 가장 중요한 프로그래밍 언어 중 하나이면서도 놀라울 정도로 단순하다. 루프도, 재귀도, 부동소수점 연산도, 외부 상태 접근도 없다. 의도적으로 튜링 완전하지 않다. 이 제한들은 버그가 아니다 — 비트코인의 1조 달러 이상의 가치를 가능하게 하는 핵심 보안 속성이다.
스택 기반 실행 모델
비트코인 스크립트는 Forth와 PostScript와 유사한 철학의 스택 기반 언어다. 변수도, 명명된 함수도, 객체도 없다. 오직 스택 — 후입선출(LIFO) 데이터 구조 — 과 데이터를 스택에 넣고, 빼고, 계산을 수행하는 연산(옵코드)의 시퀀스만 있다.
실행은 스크립트를 왼쪽에서 오른쪽으로 진행한다. 데이터 요소는 스택에 푸시된다. 옵코드는 스택에서 인수를 팝하고, 연산을 수행하고, 결과를 다시 스택에 푸시한다.
간단한 스크립트를 살펴보자:
스크립트: 2 3 OP_ADD 5 OP_EQUAL
실행 추적:
| 단계 | 연산 | 스택 (상단 → 하단) | 비고 |
|---|---|---|---|
| 1 | 2 | [2] | 2를 푸시 |
| 2 | 3 | [3, 2] | 3을 푸시 |
| 3 | OP_ADD | [5] | 3과 2를 팝하고, 2+3=5를 푸시 |
| 4 | 5 | [5, 5] | 5를 푸시 |
| 5 | OP_EQUAL | [TRUE] | 5와 5를 팝하고, TRUE를 푸시 (동일) |
스택 상단이 TRUE이므로 스크립트는 성공한다.
이중 스크립트 시스템
비트코인 트랜잭션은 단일 스크립트가 아니라 함께 실행되는 두 개의 상보적 스크립트를 포함한다:
ScriptPubKey (잠금 스크립트): 트랜잭션 출력에 배치되며, 비트코인을 지출하기 위해 충족해야 하는 조건을 정의한다. “퍼즐”이라고도 한다.
ScriptSig (해제 스크립트): 출력을 지출하는 트랜잭션 입력에 배치되며, 잠금 스크립트를 만족시키는 데이터를 제공한다. 퍼즐의 “해답”이다.
노드가 트랜잭션을 검증할 때, 해제 스크립트와 잠금 스크립트를 연결하여 결합된 스크립트를 실행한다. 실행이 성공하면(스택 상단이 참) 지출이 유효하다.
핵심 옵코드
스택 연산
- OP_DUP — 스택 상단 요소를 복제
- OP_DROP — 스택 상단 요소를 제거
- OP_SWAP — 상위 두 요소를 교환
암호화 연산
- OP_HASH160 — SHA-256 후 RIPEMD-160을 적용 (20바이트 해시 생성)
- OP_HASH256 — SHA-256을 두 번 적용
- OP_CHECKSIG — 공개 키와 서명을 팝하고, 트랜잭션에 대해 서명을 검증하고, TRUE 또는 FALSE를 푸시
- OP_CHECKMULTISIG — m-of-n 서명을 트랜잭션에 대해 검증
비교 연산
- OP_EQUAL — 두 요소를 팝하고, 같으면 TRUE, 아니면 FALSE를 푸시
- OP_EQUALVERIFY — OP_EQUAL과 같지만 FALSE이면 즉시 스크립트를 실패시킴
흐름 제어
- OP_IF / OP_ELSE / OP_ENDIF — 조건부 실행
- OP_RETURN — 즉시 스크립트를 실패시킴 (증명 가능한 지출 불가 출력과 데이터 임베딩에 사용)
타임락 연산
- OP_CHECKLOCKTIMEVERIFY (OP_CLTV) — 트랜잭션의 잠금시간이 지정된 값 미만이면 실패
- OP_CHECKSEQUENCEVERIFY (OP_CSV) — 입력의 시퀀스 번호가 지정된 값 미만이면 실패
표준 스크립트 유형
P2PKH (Pay-to-Public-Key-Hash)
P2PKH는 원래의 표준 스크립트 유형으로, 1로 시작하는 주소에 사용된다.
잠금 스크립트 (ScriptPubKey):
OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
해제 스크립트 (ScriptSig):
<signature> <publicKey>
실행 추적:
| 단계 | 연산 | 스택 | 비고 |
|---|---|---|---|
| 1 | <sig> | [sig] | 서명 푸시 |
| 2 | <pubKey> | [pubKey, sig] | 공개 키 푸시 |
| 3 | OP_DUP | [pubKey, pubKey, sig] | 공개 키 복제 |
| 4 | OP_HASH160 | [hash, pubKey, sig] | 복제된 키를 해시 |
| 5 | <pubKeyHash> | [expected, hash, pubKey, sig] | 예상 해시 푸시 |
| 6 | OP_EQUALVERIFY | [pubKey, sig] | 해시 일치 확인; 불일치 시 실패 |
| 7 | OP_CHECKSIG | [TRUE] | 공개 키로 서명 검증 |
논리가 우아하다: 먼저 주소로 해시되는 공개 키를 알고 있음을 증명하고(3-6단계), 그 다음 유효한 서명을 제공하여 대응하는 개인 키를 소유하고 있음을 증명한다(7단계).
왜 공개 키를 해시하는가? 추가적인 보안 레이어를 제공한다. ECDSA(서명 알고리즘)가 깨지더라도, 공개 키를 모르는 공격자는 자금을 지출할 수 없다 — HASH160 연산도 역전시켜야 한다.
P2SH (Pay-to-Script-Hash)
BIP-16(2012)에서 도입된 P2SH는 특정 공개 키 해시가 아닌 임의 스크립트의 해시로 비트코인을 보낼 수 있게 한다. 실제 스크립트(“리딤 스크립트”)는 비트코인이 지출될 때만 드러난다.
잠금 스크립트:
OP_HASH160 <scriptHash> OP_EQUAL
P2SH의 중요성: 복잡성을 발신자에서 수신자로 전환한다. P2SH 출력을 만드는 발신자는 20바이트 해시만 필요하다 — 단순 서명 요구 사항인지, 3-of-5 다중서명인지, 복잡한 타임락인지 알 필요가 없다. P2SH 주소는 3으로 시작한다.
P2WPKH (Pay-to-Witness-Public-Key-Hash)
P2WPKH는 BIP-141(2017)에서 도입된 P2PKH의 세그윗 버전이다. 서명 데이터(“증인”)를 전통적 ScriptSig 밖으로 옮겨 별도의 증인 구조에 넣는다.
잠금 스크립트:
OP_0 <20-byte pubKeyHash>
장점:
- 트랜잭션 가변성 해결. 레거시 트랜잭션에서 ScriptSig는 트랜잭션 ID 계산의 일부다. 서명은 여러 동등한 형태로 유효할 수 있으므로, 제3자가 유효한 서명을 다른 유효한 형태로 변경하여 트랜잭션을 무효화하지 않고 트랜잭션 ID를 변경할 수 있었다. 세그윗은 서명을 트랜잭션 ID 계산에서 제외시켜 이 공격 벡터를 제거한다. 이 수정은 라이트닝 네트워크에 필수적이었다.
- 블록 공간 효율성. 증인 데이터는 가중치 할인을 받아, 1MB 기본 블록 크기 제한을 유지하면서 블록 용량을 효과적으로 약 2-4MB로 확장한다.
P2WPKH 주소는 Bech32 인코딩을 사용하며 bc1q로 시작한다.
P2TR (Pay-to-Taproot)
BIP-341(2021년 11월 활성화)로 도입된 P2TR은 P2SH 이래 비트코인 스크립트의 가장 중요한 진화를 나타낸다. 슈노르 서명(BIP-340)과 MAST(Merkleized Abstract Syntax Trees)를 사용한다.
잠금 스크립트:
OP_1 <32-byte tweaked public key>
두 가지 지출 경로:
키 경로 (일반적 경우): 소유자가 조정된 공개 키에 대한 슈노르 서명을 제공한다. 다른 어떤 스크립트 조건이 존재하든 간에, 이것은 단순한 단일 서명 지출과 동일하게 보인다. 블록체인에서 키 경로 지출은 다른 키 경로 지출과 구별할 수 없다.
스크립트 경로 (대체 수단): 키 경로 지출이 불가능한 경우, 지출자가 MAST 트리에서 특정 스크립트를 공개하고 만족시킨다. 사용된 스크립트 분기만 공개되고, 다른 가능한 스크립트는 모두 숨겨진다.
탭루트가 혁명적인 이유:
균일성을 통한 프라이버시. 키 경로의 경우 모든 탭루트 출력이 블록체인에서 동일하게 보인다. 단일 서명, 다중서명, 복잡한 스마트 컨트랙트 트랜잭션이 모두 OP_1 <32-byte key>로 나타난다.
MAST를 통한 효율성. 실행된 스크립트 경로만 공개된다. 10개의 가능한 조건을 가진 스크립트가 있다면, 실제로 사용하는 1개의 조건만 공개한다.
슈노르 서명. 키 집합 — 여러 당사자가 공개 키를 단일 집합 키로 결합하고 단일 집합 서명을 생성할 수 있다. 3-of-3 다중서명이 솔로 서명과 구별할 수 없는 단일 서명을 생성할 수 있다.
P2TR 주소는 Bech32m 인코딩을 사용하며 bc1p로 시작한다.
타임락 스크립트
타임락은 비트코인 스크립트의 가장 강력한 기능 중 하나로, 라이트닝 네트워크 채널, 상속 계획, 고급 스마트 컨트랙트에 필수적인 시간 의존적 지출 조건을 가능하게 한다.
OP_CHECKLOCKTIMEVERIFY (OP_CLTV)
OP_CLTV(BIP-65)는 절대적 타임락을 강제한다 — 특정 블록 높이나 유닉스 타임스탬프에 도달할 때까지 비트코인을 지출할 수 없다.
예시: 블록 900,000까지 잠긴 자금
잠금 스크립트:
900000 OP_CHECKLOCKTIMEVERIFY OP_DROP <pubKeyHash> OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
활용: 상속. 앨리스가 1년의 CLTV 잠금으로 UTXO를 생성한다. 앨리스가 1년 내에 자금을 이동하지 않으면 상속인이 상속인의 키로 청구할 수 있다.
OP_CHECKSEQUENCEVERIFY (OP_CSV)
OP_CSV(BIP-112)는 상대적 타임락을 강제한다 — UTXO가 확인된 후 지정된 수의 블록이 경과할 때까지 비트코인을 지출할 수 없다.
활용: 라이트닝 네트워크. 결제 채널은 OP_CSV를 사용하여 “분쟁 기간”을 강제한다. 한 당사자가 채널 상태를 브로드캐스트하면, 다른 당사자가 오래된 상태였을 경우 페널티 트랜잭션을 브로드캐스트할 수 있는 기간을 갖는다.
결합 타임락
OP_IF
<alicePubKey> OP_CHECKSIG
OP_ELSE
144 OP_CHECKSEQUENCEVERIFY OP_DROP
<bobPubKey> OP_CHECKSIG
OP_ENDIF
이 스크립트는 “앨리스는 자신의 서명으로 즉시 지출할 수 있고, 또는 밥은 144블록 후에 자신의 서명으로 지출할 수 있다”를 의미한다. 이 패턴이 결제 채널의 빌딩 블록이다.
다중서명 스크립트
레거시 다중서명 (OP_CHECKMULTISIG)
잠금 스크립트:
OP_2 <pubKey1> <pubKey2> <pubKey3> OP_3 OP_CHECKMULTISIG
해제 스크립트:
OP_0 <sig1> <sig2>
OP_0 주의: OP_CHECKMULTISIG의 오래된 버그에 대한 해결책이다. 옵코드가 필요한 것보다 하나 더 많은 요소를 스택에서 팝한다. 이 버그는 초기에 발견되었지만 수정이 하드 포크가 되므로 절대 수정할 수 없었다. 모든 다중서명 해제는 처음에 더미 OP_0을 포함해야 한다.
탭루트 다중서명 (키 집합)
탭루트에서는 슈노르 키 집합(MuSig2 프로토콜)을 사용하여 n개 당사자가 개별 공개 키를 단일 집합 공개 키로 결합하고 단일 집합 서명을 생성할 수 있다. 결과적으로 3-of-3 탭루트 다중서명은 32바이트 공개 키와 64바이트 서명을 생성한다 — 단일 키 지출과 같은 크기다.
탭스크립트: 비트코인 프로그래밍 가능성의 미래
탭스크립트(BIP-342)는 탭루트 스크립트 경로 지출에 사용되는 업데이트된 스크립트 시스템이다.
OP_CHECKSIGADD. OP_CHECKMULTISIG를 더 효율적인 메커니즘으로 대체한다. 더미 요소 버그를 제거한다.
OP_SUCCESS 옵코드. 탭스크립트는 이전에 비활성화되거나 정의되지 않은 옵코드를 무조건 성공하는 OP_SUCCESS로 재정의한다. 이것은 깔끔한 업그레이드 경로를 만든다: 미래의 소프트 포크가 새 기능을 추가하기 위해 OP_SUCCESS 옵코드를 재정의할 수 있다. OP_CTV, OP_CAT, OP_VAULT 같은 미래의 코버넌트 제안이 이렇게 활성화될 것이다.
왜 튜링 불완전성이 기능인가
이더리움의 솔리디티에 익숙한 개발자들의 가장 흔한 비판은 튜링 완전성의 부재다. 하지만 이것은 비트코인 스크립트의 가장 중요한 보안 속성 중 하나다.
보장된 종료. 모든 비트코인 스크립트는 유한한 단계에서 성공하거나 실패한다. 무한 루프의 가능성이 없다.
정적 분석. 비트코인 스크립트는 튜링 완전하지 않으므로, 실행하지 않고도 스크립트가 정확히 무엇을 하는지 결정할 수 있다.
“가스” 불필요. 이더리움은 무한 루프를 방지하기 위해 “가스” 메커니즘이 필요하다. 비트코인의 유한 실행은 이 전체 범주의 복잡성을 제거한다.
더 작은 공격 표면. 언어가 단순할수록 악용할 수 있는 방법이 적다. 이더리움 EVM의 복잡성은 수많은 익스플로잇을 야기했다 — DAO 해킹(6천만 달러, 2016), 패리티 다중서명 버그(2억 8천만 달러 동결, 2017), 무수한 재진입 공격.
실질적 함의
비트코인 스크립트를 이해하는 것은 비트코인을 사용하는 모든 사람에게 실질적 함의를 갖는다:
주소 유형 선택. P2TR(탭루트) 주소가 최고의 프라이버시와 효율성을 제공한다. 레거시 P2PKH 주소는 더 크고 지출 비용이 더 비싸다.
수수료 추정. 트랜잭션 수수료는 사용된 스크립트 유형에 의해 직접 결정되는 트랜잭션의 가중치(크기)에 기반한다.
보안 모델 인식. 비트코인이 회사의 보안 팀이나 정부의 법률 시스템이 아니라 암호화 프로그램에 의해 보호된다는 것을 아는 것은 수탁, 백업, 상속에 대한 사고방식을 근본적으로 바꾼다.
관련 주제는 비트코인 트랜잭션 읽기, 탭루트, 세그윗 가이드를 참조하라.