비트코인 스크립트 설명
목차
들어가며
비트코인은 어떻게 작동하나요?
비트코인 스택 설명
Pay-to-Pubkey (P2PK)
Pay-to-Pubkey-Hash (P2PKH)
Pay-to-Script-Hash (P2SH)
세그윗 트랜잭션 (P2WPKH & P2WSH)
마치며
비트코인 스크립트 설명
아티클
비트코인 스크립트 설명

비트코인 스크립트 설명

고급
Published Jul 10, 2020Updated Apr 29, 2021
13m

들어가며

비트코인을 가리켜 종종 프로그래밍 가능한 돈이라 하기도 합니다. 비트코인의 디지털 특성 때문에, 사용자는 상당히 유연한 방식으로 자금 사용 조건을 설정할 수 있습니다. 
비트코인에 대해 논의할 때, 우리는 지갑코인에 대해 이야기 합니다. 그러나 우리는 지갑을 키로, 코인을 수표로, 블록체인을 줄지어 늘어선 금고로 생각할 수 있습니다. 각 금고에는 작은 틈이 존재하여, 누구나 수표를 입금하거나 얼마나 많은 금액이 보관되어 있는지 들여다볼 수 있습니다. 그러나 키를 보유한 이만 금고 내부에 접근할 수 있습니다.

키를 보유한 이가 누군가에게 자금을 전달하고자 한다면, 자신의 금고의 잠금을 해제합니다. 이들은 이전의 수표를 참조하는 새로운 수표를 생성하고(이전의 수표는 파기), 수신자가 열 수 있는 금고에 이를 넣고 잠급니다. 새로운 수신자가 이를 사용하고자 한다면, 동일한 과정을 반복합니다.

이번 아티클에서 우리는 스크립트에 대해 자세히 살펴볼 것이며, 이는 블록체인 네트워크상의 노드에 의해 해석되는 프로그래밍 언어입니다. 스크립트는 언급된 금고의 잠금 및 해제 메커니즘을 관리하는 것입니다.


비트코인은 어떻게 작동하나요?

위의 비유를 계속해서 살펴보자면, 모든 트랜잭션에는 (여러분의 금고 잠금을 해제하는)와 잠금장치(lock)가 존재한다고 할 수 있습니다. 여러분은 사용하고자 하는 수표가 들어 있는 금고를 열기 위해 키를 사용하며, 새로운 수표를 새로운 금고에 다른 잠금장치와 함께 넣습니다. 새로운 금고를 사용하기 위해서는, 다른 키가 필요합니다.
무척 간단합니다. 여러분은 또한 해당 시스템 내 잠금장치에 약간의 변화를 줄 수도 있습니다. 일부 금고에서는 다중서명 키가 필요할 것이며, 다른 금고에서는 여러분이 비밀을 알고 있음을 증명해야 할 수도 있습니다. 사용자들이 설정할 수 있는 많은 조건들이 존재합니다. 
우리의 키를 scriptSig라 합니다. 잠금장치는 scriptPubKey입니다. 우리가 그 구성 요소를 조금 더 자세히 살펴본다면, 이들은 데이터 비트와 코드 블록으로 이뤄져 있음을 알 수 있습니다. 이들을 결합하여, 그들은 작은 프로그램을 만듭니다.

트랜잭션을 생성할 때, 여러분은 해당 조합을 네트워크에 전송합니다. 이를 수신하는 각 노드는 트랜잭션의 유효성 여부를 말해주는 프로그램을 확인할 것입니다. 트랜잭션이 유효하지 않다면 이는 폐기될 것이며, 동결된 자금을 사용할 수 없게 됩니다.

여러분이 보유하고 있는 수표(코인)를 UTXOs(Unspent Transaction Outputs)라 합니다. 이 자금은 해당 잠금장치에 해당하는 키를 제시하는 누구나 사용할 수 있습니다. 보다 구체적으로 말하자면, 해당 키는 scriptSig, 잠금 장치는 scriptPubKey입니다.
여러분의 지갑에 UTXOs가 있을 경우, 이는 이 공개 키의 소유권을 증명할 수 있는 이만 자금 동결을 해제할 수 있음이라고 말하는 상황일 것입니다. 잠금을 해제하려면 디지털 서명을 포함하는 scriptSig를 제공하고, scriptPubKey에 명시된 공개 키와 연관된 개인 키를 사용해야 합니다. 다음의 설명을 통해 이를 보다 분명하게 이해할 수 있을 것입니다.


비트코인 스택 설명

스크립트는 스택 기반 언어로 알려져 있습니다. 이것이 의미하는 바는 우리가 일련의 지시 사항을 읽을 때, 이를 하나의 세로 줄이라 생각할 수 있는 장소에 배치한다는 것입니다. 예를 들어, 목록 A, B, C는 A가 가장 아래에, C가 가장 위에 있는 스택이 됩니다. 지시 사항이 무언가를 지시한다면, 우리는 가장 위에 있는 스택에서부터 하나 혹은 그 이상의 구성 요소를 조작합니다.


요소 A, B, C가 추가되고, 스택에서 “추출되는” 과정.


우리는 이러한 데이터(서명, 해시, 공개 키와 같은 것들)와 지시 사항(<0>또는 옵코드)을 구분할 수 있습니다. 지시 사항은 데이터를 제거하고 이를 통해 작업을 수행합니다. 다음은 스크립트가 무엇인지 보여주는 아주 간단한 예시입니다.
<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <check if equal>
빨간색 안에는 데이터가 존재하며, 파란색 안에는 옵코드가 존재합니다. 우리는 왼쪽에서 오른쪽으로 이를 읽으며, 가장 먼저 스택에 문자 <xyz>를 놓습니다. 다음은 <md5 hasher> 옵코드 입니다. 이는 비트코인에는 존재하지 않는 것이지만, 스택의 최상단 요소(<xyz>)를 제거하고 MD5 알고리즘을 사용해 해시화 한다고 해보겠습니다. 이후, 출력값이 다시 스택에 추가됩니다. 여기서 출력값은 d16fb36f0911f878998c136191af705e일 것입니다.
이런 우연이 있을까요! 다음으로 추가할 요소는 <d16fb36f0911f878998c136191af705e>이며, 현재 스택에는 두 개의 동일한 요소가 존재합니다. 마지막으로, <check if equal>은 상단에서 두 개의 요소를 제거하고, 그 값이 일치하는지 확인합니다. 값이 일치할 경우, <1> 스택 추가됩니다. 그렇지 않을 경우, <0>이 추가됩니다. 
우리는 지시 사항의 마지막 부분에 도달했습니다. 우리의 스크립트는 나머지 요소가 0이거나 연사자 중 하나가 일부 조건을 충족되지 않는 오류를 일으키는 경우 스크립트 작동이 실패할 수 있습니다. 이 예시에서는 어떠한 연산자도 없었지만, 0이 아닌 요소(<1>) 스크립트는 유효했습니다. 이러한 규칙은 비트코인 트랜잭션에도 적용됩니다.

이는 가상의 프로그램이었습니다. 이제 실제 경우를 살펴보도록 하겠습니다.


Pay-to-Pubkey (P2PK)

Pay-to-Pubkey (P2PK)는 무척이나 직관적입니다. 이는 특정 공개 키를 통해 자금을 동결합니다. 이 방법으로 자금을 전송받고자 한다면, 전송자에게 비트코인 주소가 아닌 여러분의 공개 키를 제공해야 합니다.

2009년 사토시 나카모토와 할 핀니 사이에서 이뤄진 최초의 트랜잭션은 P2PK 방식이었습니다. 해당 구조는 초창기 비트코인에서 많이 사용되었지만, 오늘날에는 Pay-to-Pubkey-Hash (P2PKH) 가 이를 대부분 대체했습니다. 
P2PK 트랜잭션 잠금 스크립트는 <public key> OP_CHECKSIG 형식을 따릅니다. 무척 간단합니다. 여러분은 아마도 OP_CHECKSIG가 제공된 공개 키에 대한 서명을 확인한다고 추측하셨을 것입니다. 이처럼 우리의 scriptSig는 간단한 <signature>이 됩니다. scriptSIg가 잠금을 해제는 키라는 것을 기억하시기 바랍니다.



이보다 더 간단할 수는 없습니다. 서명이 스택에 추가되고, 공개 키가 이어서 추가 됩니다. OP_CHECKSIG는 이 둘을 추출하여 공개 키에 대한 서명을 검증합니다. 만약 일치한다면, <1>을 스택에 추가합니다. 그렇지 않다면, <0>를 추가합니다.

우리는 다음 섹션에서 P2PK가 실제로는 더 이상 사용되지 않는 이유에 대해 자세히 설명할 것입니다.


Pay-to-Pubkey-Hash (P2PKH)

Pay-to-Pubkey-Hash (P2PKH)는 오늘날 가장 일반적인 트랜잭션 유형입니다. 여러분이 오래된 소프트웨어 버전을 받으려고 노력하지 않는 이상, 여러분의 지갑은 이를 기본으로 사용합니다.

P2PKH 내 scriptPubKey는 다음과 같습니다.

OP_DUP OP_HASH160 <public key hash> OP_EQUALVERIFY OP_CHECKSIG

ScriptSig에 대해 설명하기 전에, 새로운 옵코드를 자세히 살펴보도록 하겠습니다.


OP_DUP

OP_DUP는 첫 번째 요소를 추출하며, 이를 복제합니다. 이후, 두 요소를 스택에 추가합니다. 일반적으로 해당 작업은 기존 요소에 영향을 주지 않고, 복제본에서 작업할 수 있도록 진행합니다.


OP_HASH160

이는 첫 번째 요소를 추출하고 이를 두 번 해시화합니다. 첫 번째 단계에서는 SHA-256 알고리즘으로 해시화합니다. SHA-256 결괏값은 RIPEMD-160 알고리즘으로 해시화됩니다. 해당 결괏값은 다시 스택에 추가됩니다.


OP_EQUALVERIFY

OP_EQUALVERIFY는 OP_EQUAL과 OP_VERIFY라는 두 가지 연산자를 조합합니다. OP_EQUAL은 두 요소를 추출하여, 그것이 동일한지 확인합니다. 만약 동일하다면 1을 스택에 추가합니다. 그렇지 않다면, 0을 추가합니다. OP_VERIFY는 최상단 요소를 추출하여 그것의 진위를 확인(예를 들면, 0이 아닌)합니다. 진위 확인을 실패한다면, 트랜잭션도 진행되지 않습니다. OP_EQUALVERIFY를 결합하면, 최상단의 두 요소가 일치하지 않을 경우 트랜잭션이 진행되지 않게 됩니다.

여기서 scriptSig는 다음과 같습니다.

<signature> <public key>

여러분은 P2PKH 결괏값을 해제하기 위해 서명과 함께 이에 상응하는 공개 키를 제공해야 합니다.



여러분은 위의 GIF에서 진행되는 일을 살펴보실 수 있습니다. 이는 P2PK 스크립트와 크게 다르지 않습니다. 우리는 공개 키가 스크립트 내의 해시와 일치하는지 확인하기 위해 부가적인 단계를 추가했을 뿐입니다.

그러나 한 가지 알아둘 것이 있습니다. P2PKH 잠금 스크립트와 공개 키는 가시적이지 않으며, 그 해시만을 볼 수 있다는 것입니다. 우리가 블록체인 탐색기로 이동하여 사용되지 않은 P2PKH 결괏값을 살펴봐서는 공개 키를 결정지을 수 없습니다. 이는 수신자가 자금을 이동시키기로 결정할 때만 공개됩니다.
여기에는 몇 가지 장점이 존재합니다. 첫 번째 장점은 공개 키 해시가 전체 공개 키보다 쉽게 전달될 수 있다는 것입니다. 사토시는 2009년 이러한 이유로 이를 출시했습니다. 공개 키 해시는 오늘날 우리가 비트코인 주소로 알고 있는 것입니다.
두 번째 장점은 공개 키 해시가 양자 컴퓨터에 대한 추가적인 보안 계층을 제공할 수 있다는 점입니다. 우리가 자금을 사용하기 전까지는 공개 키를 알 수 없기 때문에, 다른 이가 개인 키를 연산하는 것이 훨씬 더 어려워집니다. 이들이 개인 키를 얻으려면, 두 단계의 해싱(RIPEMD-160과 SHA-256)을 되돌려야 합니다.



Pay-to-Script-Hash (P2SH)

Pay-to-Script-Hash (P2SH)는 비트코인을 위한 무척이나 흥미로운 개발 사항입니다. 이는 사용자가 스크립트의 해시에 자금을 동결시킬 수 있게 하여, 스크립트가 실제로 어떤 기능을 하는지 알 필요가 없습니다. SHA-256 해시를 예로 들어보겠습니다.

e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0dbfb6583f1

여러분은 자금 동결을 해제하기 위해 해시 입력값을 알 필요가 없습니다. 그러나 자금을 사용하는 이는 이를 해시화하는 데 사용된 스크립트를 제시해야 하며, 해당 스크립트의 조건을 충족해야 합니다.

위의 해시는 다음과 같은 스크립트에서 생성되었습니다.

<multiply by 2> <4> <check if equal>

여러분이 scriptPubKey에 연동된 코인을 사용하고자 한다면, 이러한 명령어만을 제공할 수는 없습니다. 완료된 스크립트를 참(Ture)으로 평가하는 scriptSig도 필요합니다. 해당 예시에서 이는 <4>의 결괏값을 위한 <multiply by 2> 기본 요소입니다. 물론, 이는 우리의 scriptSig는 단순히 <2>라는 의미입니다.

실제 환경에서는 P2SH 출력값을 위한 scriptPubKey는 다음과 같습니다.

OP_HASH160 <redeemScript hash> OP_EQUAL

여기서는 새로운 운영자가 존재하지 않습니다. 그러나 우리는 <redeemScript hash>새로운 요소를 갖게 됩니다. 이름에서 알 수 있듯, 이는 자금을 상환하기 위해 제공해야 하는 스크립트의 해시입니다(redeemScript라 함). scriptSig는 redeemScript에 무엇이 들어있느냐에 따라 달라집니다. 그럼에도 불구하고, 여러분은 이것이 일반적으로 (필수적인) redeemScript에 이어지는 서명과 연결된 공개 키의 조합이라는 것을 알게 될 것입니다.

<signature> <public key> <redeemScript>

값을 구하는 과정은 이제까지 우리가 살펴 본 스택 실행과는 약간 다릅니다. 이는 두 부분으로 나눠서 진행됩니다. 먼저, 여러분이 정확한 해시를 제공했는지 확인합니다.



한 가지 알아둘 것은 redeemScript 앞에 있는 요소에 대해서는 아무런 작업도 수행하지 않는다는 것입니다. 이는 현재 시점에서는 사용되지 않습니다. 우리는 이 작은 프로그램의 마지막에 도달했으며, 최상위 요소는 0이 아닙니다. 이는 이것이 유효하다는 의미입니다.

그러나 아직 끝나지 않았습니다. 네트워크 노드는 이러한 구조를 P2SH로 인식하며, 이는 실제로 다른 스택에서 대기 중인 scriptSig의 요소를 갖고 있습니다. 서명과 공개 키가 사용되는 지점입니다.
이제까지 우리는 redeemScript를 하나의 요소로 취급했습니다. 그러나 이제는 하나의 지시 사항으로 해석할 것이며, 이는 무엇이든 될 수 있습니다. <redeemScript>내의 <public key hash>와 일치하는 <signature><public key>를 반드시 제공해야 하는 P2PKH 잠금 스크립트를 예로 들어보겠습니다.



여러분의 redeemScript가 확장되면, 일반 P2PKH 트랜잭션에서와 똑같아 보이는 상황을 보게 됩니다. 여기서부터는 이를 보통의 것처럼 실행하면 됩니다.

우리는 P2SH(P2PKH) 스크립트라 하는 것을 시연해 봤지만, 실제에서 이러한 스크립트는 찾을 수 없을 것입니다. 이를 만드는 데 여러분을 방해하는 것은 아무것도 없지만, 이로 인해 블록 공간을 더 많이 차지하게 됩니다(따라서 더 많은 비용이 듦).

P2SH는 일반적으로 다중서명 또는 세그윗(SegWit) 호환 트랜잭션에 유용합니다. 다중서명 트랜잭션은 크기가 매우 클 수 있는데, 여러 키가 필요할 수 있기 때문입니다. Pay-to-Script-Hash를 구현하기 전에, 전송자는 자신의 잠금 스크립트 내에서 가능한 모든 공개 키를 나열해야 합니다. 

그러나 Ps2H에서는 지불 조건이 얼마나 복잡한지가 문제가 되지 않습니다 redeemScript의 해시는 언제나 고정된 크기를 갖습니다. 따라서 수수료는 잠금 스크립트를 해제하고자 하는 사용자(들)에게 이전됩니다.

세그윗 호환은 P2SH를 유용하게 사용하는 또 다른 경우입니다(우리는 다음 섹션에서 트랜잭션 구조가 어떻게 다른지에 대해 자세히 살펴볼 것입니다). 세그윗은 블록/트랜잭션 형식을 변경하는 소프트 포크였습니다. 이는 사전 동의를 거친 선별적인 업그레이드였기 때문에, 모든 지갑 소프트웨어가 이러한 변화를 승인하지는 않았습니다.

클라이언트가 P2SH 내에서 SegWit 스크립트를 감싸도 문제가 되지 않습니다. 이러한 유형의 모든 트랜잭션은 잠금 해제 redeemScript가 무엇이 될지 알지 않아도 됩니다.


세그윗 트랜잭션 (P2WPKH & P2WSH)

세그윗에 대한 보다 전반적인 설명은, 초보자를 위한 세그윗 설명을 확인해보시기 바랍니다.
세그윗 내의 트랜잭션 형식을 이해하려면, scriptSig와 scriptPubKey만을 가지고서는 안된다는 것만 아시면 됩니다. 이제 우리에게는 증명이라 하는 새로운 분야도 존재합니다. 우리가 scriptSig 내에 보관하던 데이터는 증명으로 이동되며, scriptSig는 이제 비어있습니다.

여러분이 ‘bc1’으로 시작하는 주소와 마주쳤다면, 이것이 세그윗 네이티브(SegWit-native)입니다. 이는 P2SH 주소기 때문에 ‘3’으로 시작하는 세그윗-컴패터블(Segwit-compatible) 주소와 대조되는 것입니다.


Pay-to-Witness-Pubkey-Hash (P2WPKH)

Pay-to-Witness-Pubkey-Hash(P2WPKH)는 P2PKH의 세그윗 버전입니다. 우리의 증명은 다음과 같습니다.

<signature> <public key>

여러분은 이것이 P2PKH scriptSig와 동일하다는 것을 아실 것입니다.여기서 scriptSig는 비어있습니다. 한편, scriptPubKey는 다음과 유사합니다.

<OP_0> <public key hash>

이것이 좀 이상하게 보이지 않나요? 서명, 공개 키 및 해시를 비교할 수 있는 옵코드는 어디 있을까요?

여기서는 추가적인 연산자를 표시하지 않는데, 트랜잭션을 수신하는 노드는 <public key hash>의 길이에 따라 무엇을 해야 할지 알고 있기 때문입니다. 이들은 길이를 계산하고, 반드시 적절한 P2PKH 트랜잭션과 동일한 방식으로 실행되어야 함을 이해합니다.
업그레이드되지 않은 노드는 이러한 방식으로 트랜잭션을 해석하는 방법을 알지 못하지만, 문제가 되지는 않습니다. 기존 규칙에서는 증명이 없으므로, 이들은 빈 scriptSig와 일부 데이터를 읽습니다. 이들은 이를 평가하고 유효한 것으로 표시합니다. 누구나 이들의 출력값을 사용할 수 있습니다. 이것이 바로 세그윗이 이전 버전과 호환되는 소프트 포크인 이유입니다.


Pay-to-Witness-Script-Hash (P2WSH)

Pay-to-Witness-Script Hash (P2WSH)는 새로운 P2SH입니다. 여러분이 여기까지 왔다면 이것이 어떤 모습일지 이해할 수 있을 것이지만, 어쨌거나 살펴보도록 하겠습니다. 우리의 증명은 우리가 보통 scriptSig에 넣었던 것입니다. P2PKH 트랜잭션을 감싸는 P2WSH에서는 이는 다음과 같이 보일 수 있습니다.

<signature 1> <public key>

다음은 우리의 scriptPubKey입니다.

<OP_0> <script hash>

동일한 규칙이 적용됩니다. SegWit 노드는 스크립트 해시 길이를 읽고 이것이 P2WSH 출력값임을 결정하며, 이는 P2SH와 비슷하게 평가됩니다. 한편, 이전 노드는 이를 단지 누구나 사용할 수 있는 출력값으로 봅니다.


마치며

이번 아티클에서 우리는 비트코인의 구성 요소에 대해 조금 알아봤습니다. 이를 빠르게 요약해보겠습니다.


스크립트 유형설명

Pay-to-Pubkey (P2PK)

자금을 특정 공개 키에 동결

Pay-to-Pubkey-Hash (P2PKH)

자금을 특정 공개 키 해시(예를 들면, 주소)에 동결

Pay-to-Script-Hash (P2SH)

수신자가 증명할 수 있는 스크립트 해시에 자금을 동결

Pay-to-Witness-Pubkey-Hash (P2WPKH)

P2PK의 세그윗 버전

Pay-to-Witness-Script-Hash (P2WSH)

P2SH의 세그윗 버전


여러분이 비트코인에 대해 더 깊게 파고든다면, 비트코인에 그토록 많은 잠재력이 존재하는 이유를 이해하게 될 것입니다. 트랜잭션은 다양한 구성 요소로 이뤄질 수 있습니다. 이러한 구성 요소를 조작함으로써, 사용자는 자금을 어떻게 사용하고, 언제 사용하는지에 대한 조건을 설정함에 있어 상당한 유연성을 갖게 됩니다.