검수요청.png검수요청.png

해제 스크립트

위키원
ghdrn221 (토론 | 기여)님의 2019년 9월 3일 (화) 10:29 판
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)
이동: 둘러보기, 검색

해제 스크립트(scriptSig)는 그 조건만 충족시키는 유일한 서명(signature), 잠금 해제 스크립트로 잠금 스크립트가 출력값에 걸어둔 조건을 해결해 출력값이 소비될 수 있도록 하는 스크립트이다. 열쇠의 역할로 잠금 스크립트를 풀기 위한 스크립트 시그서명 스크립트라고도 한다.

개요

거래의 입력값에 포함되어 있으며, 얼마를 보낼지 보낼 금액란에 입력하는 명령어 안에 잠금 스크립트(scriptPubkey)의 조건을 충족할 해제스크립트가 포함되어 있기 때문에 해당 비트코인(bitcoin) 주소의 UTXO에 대한 소유권을 입증하고 그 UTXO를 소비할 수 있다. 비트코인 생태계에도 스크립트라고 부르는프로그래밍 언어가 존재한다. 스크립트는 비트코인의 모든 거래를 유효화시키는 언어로, 단순하면서도 비트코인이 비트코인으로서 역할을 하게 하는 적합한 언어이다. 비트코인은 고정적인 패턴화된 형태의 시스템이 아니라 스크립트 언어를 통해 실행되기 때문에 무한대에 가까운 표현 가능한 조건들이 만들어질 수 있는데, 이것이 바로 비트코인이 화폐로서 역할을 하게 하는 힘이다. 비트코인 거래를 작동하기 위해서 두 가지 잠금 스크립트와 해제 스크립트, 두 가지 엔진이 작동한다.

블록체인상에서 기록된 비트코인의 잔액을 표현한 모든 UTXO들은 그것들을 소비하기 위한 조건이 있는데 그 조건을 잠금 스크립트라 하고 그 조건을 풀 수 있는 입력값을 해제스크립트이며, 데이터값이 복사되어 잠금 스크립트와 함께 연산 되어 실행됐을 때 결과가 TRUE 값이 나오면 그 입력값은 유효하다는 것이고, UTXO를 소비할 수 있게 된다.[1]

  1. 잠금 스크립트 : 출력값을 소비하기 위해 충족되어야 하는 요건을 스크립트로 작성한 것
  2. 해제 스크립트 : 잠금 스크립트가 출력값에 걸어둔 조건을 해결해 출력값이 소비될 수 있도록 하는 스크립트

해제 스크립트는 거래의 입력값에 포함되어 있으며, 얼마를 보낼지 보낼 금액란에 입력하는 명령어 안에 잠금 스크립트의 조건을 충족할 해제스크립트가 포함되어 있기 때문에 해당 비트코인 주소의 UTXO에 대한 소유권을 입증하고 그 UTXO를 소비할 수 있다. 해제 스크립트와 잠금 스크립트(scriptPubkey) 는 언뜻 비슷해 보이지만 이 둘은 자물쇠와 열쇠의 관계이다. 해제 스크립트는 열쇠의 역할을 하며, 트랜잭션을 발생시킨 주체의 서명과 공개키를 합쳐 잠금 스크립트를 풀기 위해 작동한다. 반면 잠금 스크립트는 자물쇠의 역할을 하며, 트랜잭션 을 검증하기 올바른지 검증하라는 키이다. 피투피 네트워크 에서 해당 트랜잭션을 받은 노드 는 이 잠금 스크립트에 해제 스크립트를 대조해서 일치하는지 확인하고 true라고 판명되면 올바른 트랜잭션이라 간주해 이웃 노드로 전달한다.[2]

활용

비트코인(bitcoin)
  • 비트코인
비트코인(bitcoin)은 스크립트라고 하는 프로그래밍 언어가 있는데, 단순하면서도 어떻게 보면 비트코인이 비트코인으로서 역할을 하게 하는 적합한 언어라고 할 수 있고, 비트코인의 모든 거래를 유효화시키는 것이 스크립트이며, 또한 비트코인은 고정적인 패턴화된 형태의 시스템이 아니라 스크립트 언어를 통해 실행되기 때문에 무한대에 가까운 표현 가능한 조건들이 만들어질 수 있는데 이것이 비트코인이 화폐로서 역할을 하게 하는 힘이다. 해제 스크립트에는 비트코인 지갑의 소유권을 인증하는 서명이 포함되어 있는데 이 서명 값과 출력값(UTXO)의 잠금 스크립트값이 위 그림처럼 푸시 연산과 팝 연산을 거쳐 사실(TRUE) 값이 도출되면 비트코인을 소비할 수 있어 스크립트가 비트코인 거래를 작동시키는 방법이다. 스크립트는 스택(Stack)이라 불리는 데이터 구조를 사용하는데 다음과 같다.[3]
스택1.PNG
스택의 데이터 구조이고 이 스택은 푸시(push)와 팝(pop)연산을 가능하게 하며, 푸시는 데이터 최상단에 데이터를 추가하는 연산이고 팝은 데이터 최상단에서 데이터를 제거하는 연산이다.
스택2.PNG
8을 푸시 연산 하게 되면 8이 들어가고 거기에 또 3과 -1을 각각 푸시하면 쌓인 데이터의 가장 위에 데이터가 쌓여 들어가는 것이고, 그와 반대로 팝 연산을 하게 되면 최상단에 있는 데이터를 제거해주는 시스템이 스택 데이터 구조이며, 팝 연산에서는 더하기, 빼기, 곱하기, 나누기 등의 명령어를 넣으면 위의 그림처럼 그냥 가장 위의 데이터가 제거되는 것이 아닌 명령했던 더하기, 빼기, 곱하기, 나누기가 연산 과정을 거친 후 제거된다.
스택3.PNG
2+3을 했을 때 5가 나오는지 확인을 하는 과정을 스크립팅 언어로 나타낸 것인데, 만일 +3 = 5가 잠금 스크립트라면 2는 해제 스크립트인 것인데, 이 말은 +3을 했을 때 5가 나오는 입력값인 2를 찾는 것이 잠금 스크립트의 조건을 만족하는 해제 스크립트를 찾는다.가기.png 비트코인에 대해 자세히 보기
해제 스크립트는 거래의 입력값에 포함되어 있어 얼마를 보낼지 보낼 금액란에 적어 넣는다면 그 명령어에는 잠금 스크립트의 조건을 충족할 해제 스크립트가 있어 해당 비트코인 주소의 UTXO에 대한 소유권을 입증하고 그 UTXO를 소비하도록 한다. 블록체인상에서 기록되어 있는 모든 UTXO들은 그것들을 소비하기 위한 조건이 있는데 그 조건들을 스크립트로 구현한 것이 잠금 스크립트인 것이고 그 조건을 풀 수 있는 특정 입력값이 해제 스크립트인데 이 데이터가 복사되어 잠금 스크립트와 함께 연산이 실행됐을 때 결과가 사실(TRUE) 값이 나오면 그 입력값은 유효해지고 UTXO를 소비할 수 있다.[3]
  • 실행중 스택 상태변화
  1. 송금자의 비밀키로 만든 서명 데이터(<sig>)를 스택에 푸시한다.
  2. 송금자의 공개키(<punkey>)를 스택에 푸시한다.
  3. OP_HASH160 명령으로 스택 최상위에 위치한 (<punkey>)의 HASH160 해시값을 계산하고 이 값 (<punkeyhash>)을 스택에 푸시한다.
  4. OP_EQUALVERIFY 명령으로 스택 최상위에 위치한 (<punkeyhash>)을 스택에 푸시한다.
  5. OP_EQUALVERIFY 명령으로 스택 최상위에 위치한<punkeyhash>와 그 아래에 위치한 <punkeyhash>를 비교한다. 두값이 일치하면 두 값을 모두 스택에서 삭제한다.
  6. OP_CHECKSIG 명령으로 스택 최상위에 있는 송금자의 공개키 (<punkey>)와 그 아래에서 위치한 비밀키로 한서명(<sig>)을 스택에서 꺼내 서명 데이터를 검증한 다음 검증결과를 스택에 푸시한다.
마지막에 남은 스택 최상윗값이 사실(TRUE)이라면 검증에 성공한 것으로 서명을 검증하려면 송신자의 서명, 송신자의 공개키, 송신대상의 메시지가 필요한데, 송신자의 서명은, 송신자의 공개키는 <pubkey>에 해당하고 송신자의 메시지는 스크립트 에 나오지 않으며 거래가 이에 해당한다. <sig>는 거래에 송신자의 비밀키로 서명한 것으로, ECDSA 서명방식이 사용되며, 가장 간단한 서명은 거래 전체를 대상인 거래의 해시값에 대한 서명, 모든 입력과 출력, 기타 필드가 대상이 된다. 해제 스크립트의 공개키 해시를 통해 키의 소유자를 알 수 있음으로, 잠금 스크립트에서 검증에 성공할 수 있는 서명 데이터를 만들 수 있고 출력을 해제할 수 있는 것은 이 공개키와 짝이 되는 비밀키를 가진 사람뿐이라는 것을 신뢰 할 수 있다.[4]
  • 표준 거래(Standard Transactions)
  • Pay to Pubkey : 매우 단순한 스크립트를 가지며 잠금 스크립트에 공개키가 들어 있고, 해제 스크립트에 비밀키로 만든 서명을 설정한다.
잠금 스크립트 : <pubkey> OP_CHECKSIG
해제 스크립트 : <sig>
  • P2M (pay to multisig) : 멀티시그(multisig)는 잠금 스크립트를 해제하기 위해 하나 이상의 비밀키를 이용한 서명이 필요한데 잠금 스크립트를 풀기 위해 최소한 M개의 서명이 필요하고, 서명 가능한 N개일 경우를 M-of-N 스킴이라고 부르기도 한다. 예를 들어 2-of -3 이라면 잠금 스크립트 공개키 3개가 들어 있으며, 이 중 2개 이상의 비밀키로 된 서명이 해제 스크립트에 포함되어야 해제할 수 있다. 멀티 시그는 에스크로 결제 등에 사용할 수 있다는 것 외에 보안에도 이점이 있는데 P2PKH(pay-to-public-key-hash)는 비밀키 하나로 된 서명만 있으면 되므로 비밀키가 유출되면 부정 송금이 발생할 수 있고, 예를 들어 2-of -3 멀티시그는 이와달리 비밀키 하나가 유출되어도 안전이 유지된다. 또한 키 하나를 분실해도 나머지 2개의 키만으로 출력을 해제할 수 있다는 이점도 있다. 잠금 스크립트의 <m>은 M-of-N에 해당한다. 2-of -3 스킴을 적용하려면 은 2, <n>은 3으로 설정하면 된다. 그리고 <n>개의 공개키가 포함된다. 해제 스크립트의 <sig>에는 서명이 들어가야 하는데, 2-of -3 스킴이라면 <sig>에 2개의 서명이 들어가야 한다.[4]
잠금 스크립트 : <m> <pubkey> [<pubkey> ...] <n> OP_CHEXKMULTISIG
해제 스크립트 : OP_0 [<sig> ... <sig>]
  • P2SH(Pay to script hash) : 잠금 스크립트에 스크립트의 해시값을 포함하는 유형으로, 멀티시그에도 사용할 수 있다. 여기서는 P2SH(pay-to-script-hash)를 적용한 멀티시그를 기준으로 설명된다. P2M(pay to multiSig)에서는 잠금 스크립트에 n개의 공개키를 포함해야 하므로, 거래의 크기가 커지고 그만큼 수수료가 비싸지는데 수수료는 거래 크기에 의해 결정된다. 이 때문에 P2M를 지원하는 어드레스에 송금하려면 송금자가 비싼 수수료를 물어야 한다는 단점이 있고, 거래를 생성할 때도 P2PKH보다 복잡한 값을 잠금 스크립트에 포함해야 하므로 송금하는 쪽의 부담이 크다. 문제를 해결하기 위해 P2SH에서는 길이가 긴 스크립트 설정을 송금자가 아닌 송금받는 쪽에 맡긴다. P2M에서는 다음과 같은 잠금 스크립트를 사용했었다.[4]
<m> <pubkey> [<pubkey> ...] <n> OP_CHECKMULTISIG
P2SH는 이 스크립트의 해시값(HASH160)을 잠금 스크립트에 포함시킨다. HASH160으로 생성한 해시값은 20바이트 길이이므로, 공개키를 나열한 형태인 원래의 스크립트보다 길이가 많이 줄어든다. 그리고 해제 스크립트에 해시를 계산한 원래의 스크립트를 포함 시킨다.
잠금 스크립트 : OP_HASH160 <redeemScriptHash> OP_EQUAL
해제 스크립트 : [<sig> ...<sig>] <redeemScript>  
  • OP_RETURN : 이 유형의 거래는 지불 목적이 아니라 어떤 데이터를 분산 장부에 저장하기 위해 사용되고, 비트코인 네트워크에서는 장부 수정이 실질적으로 불가능하므로, 분산 장부에 데이터를 기록해두면 어떤 시점에 이 데이터가 존재했는지 증명할 수 있으며 전자 공증 서비스처럼 이용할 수 있다. 지불에 쓰이는 거래가 아니므로 출력은 0BTC로 설정된다.[4]
잠금 스크립트 : OP_RETURN 
해제 스크립트 : 지불 용도가 아니므로 해제 거래가 만들어 지지 않는다. 
  • 입출력
해제 스클비트에는 시그(sig) 및 퍼브키(PubK) 또는 디지털 서명 및 공개 키가 포함되어 있으며 잠금 스크립트를 충족시키기 위해 제공되며, 해제 스크립트 및 잠금 스크립트(scriptPubKey)가 순서대로 결합 및 실행되고 해제 스크립트가 먼저 실행되도록 작동한다. 예를 들어, 밥(Bob)이 엘리스(Alice)로부터 받은 1비트 코인을 사용하기로 결정한 경우 먼저 출력을 잠금 해제해야 하고 수신자가 1비트 코인을 수신하면 잠금 이 해제 된다.[5]
  • 구조와 생성
해제 스크립트는 트랜잭션을 발생시킨 주체의 서명 + publicKey, 열쇠의 역할을 하고, 잠금 스크립트를 풀기 위한 해제 스크립트라고도 불리며, 인위적으로 만들어 낼 수 없다. 트랜잭션 발생자의 개인키가 필요한 서명이 존재하기 때문이며, 잠금 스크립트를 통해 트랜잭션을 검증하고 서명을 확인한다.[6]

과정

  • 거래검증
해제 스크립트는 위와같이 임의로 블럭정보를 기반으로 생성을 할 수 없고, 생성 후 코드 기반으로 확인을 할 수가 없어 개인 키(Private key)를 사용하여 서명(signature)을 생성해야 하고, 동일한 개인 키를 사용해서 서명을 생성해도 시간 변화에 따라 매번 다른 서명이 생성되며, 특정 개인 키를 하나 할당해서 그것을 사용하여 생성하는 과정은 다음과 같다.[7]
1. 먼저 해제 스크립트를 제외한 트랜잭션 템플릿을 작성한다.
분홍색 : 입력 세그먼트, 노란색 : 출력 세그먼트
Version : 01 00 00 00
Number of Inputs : 01
Previous Tx Hash(reversed) : 41 6e 9b 45 55 18 0a aa 0c 41 70 67 a4 66 07 bc 58 c9 6f 01 31 v2 f4 1f 7d 0f b6 65 ea b0 3a 7e
Previous Output Index : 00 00 00 00
ScriptLength
ScriptSig(Unlocking script)
Sequence : ff ff ff ff
Number of Outputs 01
Value : 20 4e 00 00 00 00 00 00
Script Length : 19
ScriptPubKey(Locking Script) : 76 a9 14 e8 1d 74 2e 2c 3c 7a cd 4c 29 de 09 0f c2 c4 d4 12 0b 2b f8 88 ac
Locktime : 00 00 00 00
2. 위의 템플릿에서 비어있는 해제 스크립트 부분에는 입력에 사용하기위한 UTXO의 이전출력 잠금 스크립트를 추가하고, 템플릿에 추가로 마지막에 sigHash Code가 01 00 00 00 붙어있는것에 유의 하여야 한다.
분홍색 : 입력 세그먼트, 노란색 : 출력 세그먼트
Version : 01 00 00 00
Number of Inputs : 01
Previous Tx Hash(reversed) : 41 6e 9b 45 55 18 0a aa 0c 41 70 67 a4 66 07 bc 58 c9 6f 01 31 v2 f4 1f 7d 0f b6 65 ea b0 3a 7e
Previous Output Index : 00 00 00 00
ScriptLength : 19
ScriptPubKey of Previous Output(Pkaceholder for final scriptSig) : 76 a9 14 99 b1 eb cf c1 1a 13 df 51 61 ab a8 16 04 60 fe 16 01 d5 41 88 ac
Sequence : ff ff ff ff
Number of Outputs 01
Value : 20 4e 00 00 00 00 00 00
Script Length : 19
ScriptPubKey(Loking Script) : 76 a9 14 99 b1 eb cf c1 1a 13 df 51 61 ab a8 16 04 60 fe 16 01 d5 41 88 ac
Lokingtime : 00 00 00 00
SigHash Code : 01 00 00 00
3. 위의 16진수 트랜잭션 메시지와 개인키를 사용하여 ECC 알고리즘을 통해 서명을 생성한다.
import hash1ib, ecdsa, binascii
from ecdsa import Signingky, SECP256k1

mhex = '0100000001416e9b4555180aaa0c417067a46607bc58c96f0131b2f41f7d0fb665eab03a7e000000001976a9145

txHash = hadh1ib.sha256(hadh1ib.sha256(mhex.decode('hex')).degest()).hexdigest()
privkey = '3cd0560f5b27591916c643a0b7aa69d3839380a728d2e912990dc573715ㅇ2c'

signingkey = ecdsa.Signingkey.from_string(privey.decide('hex'), curve=ecdsa.SECP256k1)
SIG = signingkey.sign_digest(txhash, sigencode=ecdsa.util.sige.util.sige,code_ca,ize)

binascii.hexlify(SIG)
4. 이 과정을 통해 생성된 서명은 다음과 같다.
 : 304402201c3be71e1794621cbe3a7adec1af25f818f238f5796d47152137eba710f2174a02204f8fe667b696e30012ef4e56ac96
5. 생성된 서명과 개인 키를 사용하여 DER 포맷으로 해제 스크립트를 구성하며, R, S 데이터는 32, 33바이트가 될 수 있기 때문에 PUSHDATA Opcode 값은 47, 48, 49가 된다.
PUSHDATA Opcode 47
Header 30
Sig Length 44
Integer 02
R Length 20
R 1c 3b e7 1e 17 94 62 1c de 3a 7a de 3a 7a de c1 af 25 f8 18 f2 38 f5 79 6d 47 15 21 37 eb a7 10 f2 17 4a
Inedger 02
S Length 20
S 4f 8f e6 67 b6 96 e3 00 12 ef 4e 56 ac 96 af b8 30 db df fe e3 b1 5d 2e 47 40 66 ab 34 a3 9b ad
SigHash Code 01
PUSHDATA Opcode 21
Public Key(compressed with 03 prefix) 03 bf 35 0d 28 21 37 51 58 a6 08 b5 1e 3e 89 8e 50 7f e4 7f 2d 2e 8c 77 4d e4 a9 a7 ed ec f7 4e da
Header, Sig Length, Integer, R Length, R, Inedger, S Length, S ->Signature(DERencoded)
6. 해제 스크립트 부분을 위에서 최종 생성한 서명으로 교체하면 최종 트랜잭션이 완성된다.
분홍색 : 입력 세그먼트, 노란색 : 출력 세그먼트
Version : 01 00 00 00
Number of Inputs : 01
Previous Tx Hash(reversed) : 41 6e 9b 45 55 18 0a aa 0c 41 70 67 a4 66 07 bc 58 c9 6f 01 31 v2 f4 1f 7d 0f b6 65 ea b0 3a 7e
Previous Output Index : 00 00 00 00
ScriptLength : 6a
ScriptSig(Unlocking script) : 47 30 44 02 20 1c 3d e7 1e 17 94 62 1c de 3a 7a de c1 af 25 f8 18 f2 38 f5 79 6d 47 15 21 37 eb a7 10 fe 17 4a 02 20 4f 8f e6 67 b6 96 e3 00 12 ef 4e 56 ac 96 af b8 30 bd df fe e3 b1 5d 2e 47 40 66 ab 3a a3 9b ad 01 21 03 bf 35 0d 28 21 37 51 58 a6 08 b5 1e 3e 89 8e 50 7f e4 7f 2d 2e 8c 77 4d e4 a9 a7 ed ec f7 4e da
Sequence : ff ff ff ff
Number of Outputs 01
Value : 20 4e 00 00 00 00 00 00
Script Length : 19
ScriptPubKey(Loking Script) : 76 a9 14 99 b1 eb cf c1 1a 13 df 51 61 ab a8 16 04 60 fe 16 01 d5 41 88 ac
Lokingtime : 00 00 00 00

명령어

  • 스크립트 코드: PUSHDATA <sig> SIGHASH_ALL PUSHDATA <pubKey>
  1. PUSHDATA <sig > : 서명(signature)을 스택(stack)에 푸시(push) 하라는 명령어
  2. SIGHASH_ALL : 거래에 대한 모든 것이 서명되어 있음을 나타낸다.
  3. PUSHDATA <pubKey> : 공개키(public-key)를 스택에 푸시하라는 명령어

각주

참고자료

같이 보기


  검수요청.png검수요청.png 이 해제 스크립트 문서는 블록체인 기술에 관한 글로서 검토가 필요합니다. 위키 문서는 누구든지 자유롭게 편집할 수 있습니다. [편집]을 눌러 문서 내용을 검토·수정해 주세요.