[Bitcoin] - ch5-2. 거래 스크립트와 서명

‍허진·2023년 3월 2일
0

Blockchain

목록 보기
6/19
post-thumbnail

본 글은 '비트코인, 공개 블록체인 프로그래밍(Andreas M. Antonopoulos 저, 최은실, 김도훈, 송주한 옮김, 2018)'을 바탕으로 작성되었습니다.

> 거래 스크립트와 스크립트 언어

스크립트라고 불리는 비트코인 거래 스크립트 언어는 포스(Forth) 언어처럼 구성되고 역폴란드 표기법을 따르는 스택 기반의 실행 언어다. UTXO에 위치한 잠금 스크립트와 해제 스크립트 모두 이 스크립팅 언어로 작성된다. 거래가 유효화될 때 입력값 각각에 들어 있는 해제 스크립트는 소비 조건을 만족하는지 여부를 알아보기 위해 대응되는 잠금 스크립트와 함께 실행된다.

스크립트는 매우 간단한 언어로, 실행하는 데는 최소한의 프로세싱만 있으면 되기 때문에 현대의 프로그래밍 언어들이 할 수 있는 일들 중 많은 부분을 해내지 못한다. 하지만 이로 인해 프로그램 가능한 화폐를 유효화하기 위해 스크립트를 사용하는 데 있어 의도적인 보안을 제공해 준다.

> 튜링 불완전성

비트코인 거래의 스크립트 언어는 많은 연산자를 포함하고 있지만 한 가지 중요한 방법을 이용해서 의도적으로 기능이 제한된다. 스크립트 언어는 조건부 흐름 제어 기능 이외에는 루프나 복잡한 흐름제어 능력을 가지고 있지 않다. 이를 통해 스크립트 언어는 튜링이 완전하지(Turing Complete) 않다는 사실을 확인할 수 있다. 즉, 비트코인 거래 스크립트는 복잡성이 제한되고 실행 시간이 예측 가능하다. 이러한 제한성 때문에 스크립트 언어는 무한 루프나 '논리 폭탄(logic bomb, 네트워크에 서비스거부 공격을 야기하는 방법)' 같은 형태를 만들 수 없다. 모든 거래는 비트코인 네트워크상에 있는 모든 풀 노드에 의해서 검증된다는 사실을 명심하자. 스크림트 언어의 제한성은 거래 검증 메커니즘이 취약성으로 이용될 수 있는 가능성을 방지한다.

> 무상태형 검증

비트코인 거래의 스크립트 언어는 무상태형(stateless)이며, 스크립트 언어 내에서는 스크립트 실행 전 혹은 실행 후에 저장되는 상태가 없다. 따라서 스크립트를 실행하는 데 필요한 모든 정보는 스크립트 내에 담겨 있다. 스크립트는 어떤 시스템에서든 예측 가능하며 동일한 방식으로 실행된다. 만약 사용자의 시스템이 어떤 스크립트를 유효화한다면 비트코인 네트워크 내에 존재하는 다른 시스템 전체가 해당 스크립트를 유효화할 것이라고 확신해도 된다. 이는 곧 하나의 유효한 거래는 모두에게 유효하며, 모두가 이 사실을 알고 있다는 것을 뜻한다. 즉, 결과에 대한 예측 가능성이 비트코인 시스템의 핵심적 이점이다.

> 스크립트 구성(잠금 + 해제)

비트코인 거래 유효화 엔진은 거래를 유효화하는 두 가지 스크립트에 의존한다. 잠금 스크립트와 해제 스크립트가 그 주인공이다.

잠금 스크립트는 출력값에 위치하고 있기 때문에 향후 출력값을 소비하기 위해 충족되어야 하는 요건을 명시하고 있다. 잠금 스크립트에는 보통 공개키 혹은 비트코인 주소(공개키 해시)가 담겨 있기 때문에 scriptPubKey라고 부르기도 했다. 또한 서명 스크립트(witness script) 혹은 좀 더 일반적으로는 암호 퍼즐이라고 알려진 잠금 스크립트도 있다.

해제 스크립트는 잠금 스크립트가 출력값에 놓아 둔 조건을 '해결'하거나 충족시켜서 출력값이 소비될 수 있도록 하는 스크립트다. 해제 스크립트는 모든 거래의 입력값에 들어 있는 요소이며 대부분의 경우 사용자의 지갑이 개인키로부터 생성한 디지털 서명을 담고 있다. 해제 스크립트에는 보통 디지털 서명이 담겨 있기 때문에 ScriptSig라고 불렀다.

모든 비트코인 검증노드는 잠금 스크립트와 해제 스크립트를 함께 실행해서 거래를 유효화시킨다. 그 과정은 다음과 같다.

  1. 각 입력값에는 해제 스크립트가 들어 있고, 입력값들은 이전에 존재했던 UTXO를 참조한다.
  2. 유효화 소프트웨어는 해제 스크립트를 복사해서 입력값이 참조한 UTXO를 검색한 후에 해당 UTXO로부터 잠금 스크립트를 복사할 것이다.
  3. 해제 스크립트와 잠금 스크립트가 차례로 실행되고, 해제 스크립트가 잠금 스크립트의 조건을 충족하는 경우 해당 입력값은 유효해진다.

UTXO는 영구적으로 블록체인 내에 기록되기 때문에 새로운 거래 내에서 UTXO를 소비하려는 시도가 실패했다고 해서 변하거나 영향을 받지 않는다. 출력값의 조건을 만족하는 유효한 거래만이 '소비'되었다고 간주되는 출력값을 내 놓고 소비되지 않은 거래 출력값 세트(UTXO 세트)에서 사라지게 된다.

다음 그림은 가장 일반적인 비트코인 거래(공개키 해시 지불)를 위한 해제 스크립트와 잠금 스크립트의 예로서 스크립트가 유효화되기 전 해제 스크립트와 잠금 스크립트가 서로 연결된 상태에서 산출된 복합 스크립트를 보여준다.

[그림 - 거래 스크립트를 평가하기 위한 ScriptSig와 scriptPubKey의 조합]

> 스크립트 실행 스택

비트코인의 스크립팅 언어는 스택(stack)이라고 불리는 데이터 구조를 사용하는 스택 기반 언어이다. 스택은 데이터를 가장 위에 넣는 PUSH 연산과 가장 위에서 데이터를 빼오는 POP 연산이 가능하다. 스택에서의 작업은 가장 윗 부분에서만 가능하므로 '후입선출(Last-In-First-Out, LIPO)'이라고도 부른다.

스크립팅 언어는 각 항목을 왼쪽에서 오른쪽으로 처리하면서 스크립트를 실행한다. 숫자(데이터 상수)는 스택 상부에 기록된다. 연산자는 하나 이상의 매개변수를 스택 상부에 기록하거나 스택에서 제거하는 연산 작용을 해서 나온 결과값을 스택 상부에 기록한다. 조건부 연산자들은 조건을 평가해서 'TRUE' 혹은 'FALSE'라는 불 방식의 결과값을 생성한다.

대부분의 잠금 스크립트가 비트코인 주소나 공개키를 참조해서 소유권 증명을 요구해야만 돈을 소비할 수 있게 된다. 잠금 스크립트와 해제 스크립트의 어떠한 조합이라도 'TRUE' 값을 낼 수 있다면 유효하다.

3 OP_ADD 5 OP_EQUAL

만약 잠금 스크립트가 위와 같다면,

2

입력값에 포함되는 해제 스크립트는 다음과 같다.

유효화 소프트웨어는 잠금 스크립트와 해제 스크립트를 결합하며, 그 결과 생성된 스크립트는 다음과 같다.

2 3 OP_ADD 5 OP_EQUAL

[그림 - 비트코인 스크립트 유효화의 간단한 연산 과정]

> 해제 스크립트와 잠금 스크립트의 분리 실행

최초의 비트코인 클라이언트에서는 해제 스크립트와 잠금 스크립트가 서로 연결되어 있고 순서대로 실행되었다. 하지만 보안상의 이유로 2010년 변경되었다. 왜냐하면 기형적 해제 스크립트가 데이터를 스택으로 밀어 넣고 잠금 스크립트에 오류를 초래하게끔 만들었던 취약성 때문이었다. 현재 실행되는 구현에서는 두 개의 실행 결과 사이를 이동하는 스택을 이용해서 잠금 스크립트와 해제 스크립트가 따로 실행된다.

> Pay-to-Public-Key-Hash(P2PKH)

비트코인 네트워크상에서 진행되는 거래 대부분은 Pay-to-Public-Key-Hash 스크립트, 즉 P2PKH 스크립트로 잠겨 있는 출력값을 소비한다. 이 거래에는 공개키 해시(비트코인 주소)를 이용해 출력값을 잠그는 잠금 스크립트가 포함되어 있다. P2PKH 스크립트로 잠겨 있는 출력값은 공개키와 공개키에 대응하는 개인키가 생성한 디지털 서명을 사용하여야만 해제가 가능하다.

P2PKH 스크립트에서의 잠금 스크립트는 다음과 같다.

OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

Cafe Public Key Hash는 16진수로 인코딩 되어 있는 공개키 해시에 해당한다.

아래의 해제 스크립트를 이용하면 앞의 잠금 스크립트이 조건을 만족시킬 수 있다.

<Cafe Signature> <Cafe Public Key>

위 두 가지 스크립트를 사용하여 다음과 같은 복합 유효성 검사 스크립트를 생성할 수 있다.

<Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160
<Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

이 복합 스크립트가 일단 시행되면 잠금 스크립트가 설정한 조건을 해제 스크립트가 만족할 때에만 TRUE 판정을 내릴 것이다. 즉, 예상 지출로 설정되어 있는 공개키 해시에 대응하는 개인키에서 생성된 유효 서명을 해제 스크립트가 보유하고 있는 경우에 결과 값은 TRUE가 된다. 이 과정을 그림으로 보면 다음과 같다.

[그림 - P2PKH 거래에 대한 스크립트 평가(파트1)] [그림 - P2PKH 거래에 대한 스크립트 평가(파트 2)]

> 디지털 서명 (ECDSA)

비트코인에서 사용하는 디지털 서명 알고리즘은 타원곡선 디지털 서명 알고리즘(Eliptic Curve Digital Signature Algorithm), 즉 ECDSA다. ECDSA는 스크립트 함수인 OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY에서 사용된다. 잠금 스크립트 내에서 이러한 함수들이 보인다면 해제 스크립트에는 반드시 ECDSA 서명이 포함되어야 한다.

디지털 서명은 비트코인에서 세 가지 역할을 담당한다.

  1. 디지털 서명은 개인키 소유자(암묵적으로 돈의 소유자라고 판단)가 해당 금액에 대한 소비를 허가하는 것을 증명한다
  2. 허가 증명은 부인할 수 없다(부인방지).
  3. 디지털 서명은 해당 거래(혹은 해당 거래의 특정 부분)가 서명이 되고 난 후에는 그 누구에 의해서도 수정되지 않거나 수정될 수 없다는 사실을 증명한다.

디지털 서명(ECDSA)와 관련된 추가적인 사항은 다음을 참고하도록 하자.
디지털 서명 참고 사항

> 비트코인 주소, 잔액, 추상화


[그림 - Bob에게 지불하는 Alice의 거래]

위의 그림을 보면서 Alice(송신자)와 Bob(수신자)의 거래가 어떻게 이루어지는지 다시 살펴보자.
거래의 왼쪽 부분을 보면, 블록체인 익스플로러에는 Alice의 비트코인 주소가 송신인으로 나와 있다. 사실 이 정보는 거래 자체를 나타내는 것은 아니다. 블록체인 익스플로러가 해당 거래를 검색할 때 입력값이 참조한 이전 거래도 검색해서 첫 번째 출력값을 추출해 낸다. 그 과정 내에서 출력값은 Alice의 공개키 해시(P2PKH 해시)를 추출한 후 Base58Check 인코딩을 이용해 해당 공개키 해시를 인코딩해서 공개키에 나타나는 비트코인 주소를 생성하고 보여 준다.

이와 유사하게 거래의 오른쪽 부분을 보면 블록체인 익스플로러는 두 개의 출력값을 보여 준다. 하나는 Bob의 비트코인 주소로 가는 것이고 다른 하나는 Alice의 주소로(잔액으로) 가는 것이다. 다시 한 번 이 비트코인 주소를 생성하기 위해 블록체인 익스플로러는 각 출력값으로부터 잠금 스크립트를 추출하고 이 스크립트를 P2PKH 스크립트로 인지해서 공개키 해시를 추출한다. 마지막으로 블록체인 익스플로러에서 이 공개키 해시를 다시 인코딩해서 비트코인 주소를 생성해 보여 준다.

우리가 Bob의 비트코인 주소를 클릭하게 되면 다음과 같은 화면이 나타날 것이다.

[그림 - Bob의 비트코인 주소에 나와 있는 잔액]

'Total Received'에 나와 있는 금액을 구성하기 위해서는 우선 블록체인 익스플로러가 비트코인 주소의 Base58Check 인코딩을 디코딩해서 이 주소 내에서 인코딩된 Bob의 공개키에 대한 160 비트 크기의 해시를 검색한다. 그 후, 블록체인 익스플로러는 거래의 데이터베이스를 검색해서 Bob의 공개키 해시가 담겨 있는 P2PKH 잠금 스크립트를 가지고 있는 출력값을 찾을 것이다. 모든 출력값의 값을 다 더해서 받아야 할 총액을 제시하게 된다.

현재 잔액('Final Balance')을 구성하기 위해서는 좀 더 많은 작업이 필요하다. 블록체인 익스플로러는 현재 소비되지 않은 출력값에 대한 개별 데이터베이스, 즉 UTXO 세트를 보관하고 있다. 이 데이터베이스를 유지하기 위해 블록체인 익스플로러는 실시간으로 비트코인 네트워크를 모니터해서 비승인 거래에 UTXO가 등장하면 새롭게 생성된 UTXO를 더하고 소비된 UTXO를 제거한다. 이는 거래가 전파되면서 계속 전파를 추적하고 정확한 체인이 따라 오는지를 확인하기 위해 비트코인 네트워크와의 합의를 유지해야 하는 복잡한 과정이다. 때로는 블록체인 익스플로러가 비동기화되어 UTXO 세트에 대한 시각이 불완전하거나 정확하지 않게 된다.
블록체인 익스플로러는 UTXO 세트에서 Bob의 공개키 해시를 참조하는 소비되지 않은 모든 출력값을 합하고 사용자에게 보여지는 'Final Balance'를 만들어 낸다.

이 두 가지 '잔액'이 들어있는 하나의 이미지를 만들기 위해 블록체인 익스플로러는 수십 혹은 수백 개 어쩌면 수십만 개의 거래를 색인하고 검색해야 한다.

요약하자면 지갑 어플리케이션, 블록페인 익스플로러, 기타 비트코인 사용자 인터페이스를 통해 사용자에게 제시되는 정보는 많은 거래를 검색하고 내용을 조사해서 그곳에 담겨 있는 데이터를 처리를 통해 얻을 수 있는 고차원의 추상화 작업으로 구성되어 있다. 한 명의 송신인이 한 명의 수신인에게 전송하는 은행 수표와 비슷한 비트코인 거래를 가장 간단한 방법으로 제시함으로써 비트코인 어플리케이션들은 많은 세부사항들을 추상화한다.

profile
매일 공부하기 목표 👨‍💻 

0개의 댓글