해제 스크립트
해제 스크립트(scriptSig)는 그조건만 충족시키는 유일한 서명(signature), 잠금 해제 스크립트로 잠금 스크립트가 출력값에 걸어둔 조건을 해결해 출력값이 소비뒬수 있도록 하는 스크립트이며, 열쇠의 역할로 잠금스크립트를 풀기위한스크립트 시그나 서명 스크립트라고도 한다.
개요
거래의 입력값에 포함되어 있으며, 얼마를 보낼지 보낼금액란에 입력하는 명령어 안에 잠금 스크립트의 조건을 충족할 해제스크립트가 포함되어 있기 때문에 해당 비트코인 주소의 UTXO에 대한 소유권을 입증하고 그 UTXO를 소비할수 있다.비트코인 생태계에도 스크립트라고 부르는 프로그래밍 언어가 존재한다. 스크립트는 비트코인의 모든 거래를 유효화시키는 언어로, 단순하면서도 비트코인이 비트코인으로서 역할을 하게 하는 적합한 언어이다. 비트코인은 고정적인 패턴화된 형태의 시스템이 아니라 스크립트 언어를 통해 실행되기 때문에 무한대에 가까운 표현 가능한 조건들이 만들어질 수 있는데, 이것이 바로 비트코인이 화폐로서 역할을 하게 하는 힘이다. 비트코인 거래를 작동하기 위해서 두 가지 잠금 스크립트와 해제 스크립트, 두 가지 엔진이 작동한다.
- 잠금 스크립트 : 출력값을 소비하기 위해 충족되어야 하는 요건을 스크립트로 작성한 것
- 해제 스크립트 : 잠금 스크립트가 출력값에 걸어둔 조건을 해결해 출력값이 소비될 수 있도록 하는 스크립트
블록체인 상에서 기록된 비트코인의 잔액을 표현한 모든 UTXO들은 그것들을 소비하기 위한 조건이 있는데 그조건을 잠금 스크립트라 하고 그조건을 풀수 있는 입력값을 해제스크립트 이며, 데이터 값이 복사되어 잠금 스크립트와 함께 연산 되어 실행됐을 때결과가 TRUE값이 나오면 그 입력값은 유효하다는 것이고, UTXO를 소비할수 있게 된다.[1]
해제 스크립트는 거래의 입력값에 포함되어 있으며, 얼마를 보낼지 보낼금액란에 입력하는 명령어 안에 잠금 스크립트의 조건을 충족할 해제스크립트가 포함되어 있기 때문에 해당 비트코인 주소의 UTXO에 대한 소유권을 입증하고 그 UTXO를 소비할수 있다. 해제 스크립트와 잠금 스크립트(scriptPubkey) 는 언뜻 비슷해보이지만 이 둘은 자물쇠와 열쇠의 관계이다. 해제 스크립트는 열쇠의 역할을 하며, 트랜잭션을 발생시킨 주체의 서명과 공개키를 합쳐 잠금 스크립트를 풀기 위해 작동한다. 반면 잠금 스크립트는 자물쇠의 역할을 하며, 트랜잭션을 검증하기 올바른지 검증하라는 키이다. 피투피 네트워크에서 해당 트랜잭션을 받은 노드는 이 잠금 스크립트에 해제 스크립트를 대조해서 일치하는지 확인하고 true라고 판명되면 올바른 트랜잭션이라 간주해 이웃노드로 전달한다.[2]
특징
해제 스클비트에는 시그(sig) 및 퍼브키(PubK) 또는 디지털 서명 및 공개 키가 포함되어 있으며 잠금 스크립트를 충족시키기 위해 제공되며, 해제 스크립트 및 잠금 스크립트(scriptPubKey)가 순서대로 결합 및 실행되고 해제 스크립트가 먼저 실행되도록 작동한다. 예를 들어, 밥(Bob)이 엘리스(Alice)로부터받은 1비트 코인을 사용하기로 결정한 경우 먼저 출력을 잠금 해제 해야 하고 수신자가 1비트 코인을 수신하면 잠금 이 해제 된다.[3] 해제 스크립트는 트랜잭션을 발생시킨 주체의 서명 + publicKey , 열쇠의 역할을 하고, 잠금스크립트를 풀기위한 해제 스크립트라고도 불리며, 인위적으로 만들어 낼 수 없다. 트랜잭션 발생자의 개인키가 필요한 서명이 존재하기 때문이며, 잠금 스크립트를 통해 트랜잭션을 검증하고 서명을 확인한다.[4]
해제 스크립트는 거래의 입력값에 포함 되어 있어 얼마를 보낼지 보낼 금액란에 적어 넣는다면 그 명령어에는 잠금 스크립트의 조건을 충족할 해제 스크립트가 있어 해당 비트코인 주소의 UTXO에 대한 소유권을 입증하고 그 UTXO를 소비하도록 한다. 블록체인상에서 기록되어 있는 모든 UTXO들은 그것들을 소비하기 위한 조건이 있는데 그 조건들을 스크립트로 구현한 것이 잠금 스크립트인 것이고 그 조건을 풀 수 있는 특정 입력값이 해제 스크립트인데 이 데이터가 복사되어 잠금 스크립트와 함께 연산이 실행됐을때 결과가 TRUE 값이 나오면 그 입력값은 유효해지고 UTXO를 소비할 수 있다.[5]
- 실행중 스택 상태변화
- 송금자의 비밀키로 만든 서명 데이터(<sig>)를 스택에 푸시한다.
- 송금자의 공개키(<punkey>)를 스택에 푸시한다.
- OP_HASH160 명령으로 스택 최상위에 위치한 (<punkey>)의 HASH160 해시값을 계산하고 이 값 (<punkeyhash>)을 스택에 푸시한다.
- OP_EQUALVERIFY 명령으로 스택 최상위에 위치한 (<punkeyhash>)을 스택에 푸시한다.
- OP_EQUALVERIFY 명령으로 스택 최상위에 위치한<punkeyhash>와 그 아래에 위치한 <punkeyhash>를 비교한다. 두값이 일치하면 두 값을 모두 스택에서 삭제한다.
- OP_CHECKSIG 명령으로 스택 최상위에 있는 송금자의 공개키 (<punkey>)와 그 아래에서 위치한 비밀키로 한서명(<sig>)을 스택에서 꺼내 서명 데이터를 검증한 다음 검증결과를 스택에 푸시한다.
- 마지막에 남은 스택 최상위값이 사실(TRUE)이라면 검증에 성공한것으로 서명을 검증하려면 송신자의 서명, 송신자의 공개키, 송신대상의 메시지가 필요한데, 송신자의 서명은<sig>, 송신자의 공개키는 <pubkey>에 해당하고 송신자의 메시지는 스크립트에 나오지 않으며 거래가 이에 해당한다. <sig>는 거래에 송신자의 비밀키로 서명한 것으로, ECDSA 서명 방식이 사용되며, 가장 간단한 서명은 거래 전체를 대상인 거래의 해시값에 대한 서명, 모든입력과 출력, 기타 필드가 대상이 된다. 해제 스크립트의 공개키 해시를 통해 키의 소유자를 알 수 있으므로, 잠금 스크립트에서 검증에 성공할 수있는 서명 데이터를 만들수 있고 출력을 해제할 수 있는 것은 이 공개키와 짝이 되는 비밀키를 가진 사람뿐이라는 것을 신뢰 할 수 있다.[6]
- 표준 거래(Standard Transactions)
- Pay to Pubkey : 매우 단순한 스크립트를 가지며 잠금 스크립트에 공개키가 들어 있고, 해제 스크립트에 비밀키로 만든 서명을 설정한다.
잠금 스크립트 : <pubkey> OP_CHECKSIG 해제 스크립트 : <sig>
- 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 스킴을 적용하려면 <m> 은 2, <n>은 3으로 설정하면 된다. 그리고 <n>개의 공개키가 포함된다. 해제 스크립트의 <sig>에는 서명이 들어가야 하는데, 2-of-3 스킴이라면 <sig>에 2개의 서명이 들어가야 한다.
잠금 스크립트 : <m> <pubkey> [<pubkey> ...] <n> OP_CHEXKMULTISIG 해제 스크립트 : OP_0 [<sig> ... <sig>]
- * Pay to Script Hash : 잠금 스크립트에 스크립트의 해시값을 포함하는 유형으로, 멀티시그에도 사용할 수 있다. 여기서는 P2SH(pay-to-script-hash)를 적용한 멀티시그를 기준으로 설명된다. P2M(pay to multiSig)에서는 잠금 스크립트에 n개의 공개키를 포함시켜야 하므로, 거래의 크기가 커지고 그만큼 수수료가 비싸지는데 수수료는 거래 크기에 의해 결정된다. 이때문에 P2M를 지원하는 어드레스에 송금하려면 송금자가 비싼 수수료를 물어야 한다는 단점이 있고, 거래를 생성할 때도 P2PKH에 비해 복잡한 값을 잠금 스크립트에 포함시켜야 하므로 송금하는 쪽의 부담이 크다. 문제를 해결하기 위해 P2SH에서는 길이가 긴 스크립트 설정을 송금자가 아닌 송금받는 쪽에 맡긴다. P2M에서는 다음과 같은 잠금 스크립트를 사용했었다.
<m> <pubkey> [<pubkey> ...] <n> OP_CHECKMULTISIG
- P2SH는 이 스크립트의 해시값(HASH160)을 잠금 스크립트에 포함시킨다. HASH160으로 생성한 해시값은 20바이트 길이이므로, 공개키를 나열한 형태인 원래의 스크립트보다 길이가 많이 줄어든다. 그리고 해제 스크립트에 해시를 계산한 원래의 스크립트를 포함 시킨다.
잠금 스크립트 : OP_HASH160 <redeemScriptHash> OP_EQUAL 해제 스크립트 : [<sig> ...<sig>] <redeemScript>
- OP_RETURN : 이 유형의 거래는 지불 목적이 아니라 어떤 데이터를 분산장부에 저장하기 위해 사용되고, 비트코인 네트워크에서는 장부 수정이 실질적으로 불가능하므로, 분산 장부에 데이터를 기록해두면 어떤 시점에 이 데이터가 존재했는지 증명할 수 있으며 전자 공증 서비스처럼 이용할 수 있다. 지불에 쓰이는 거래가 아니므로 출력은 0BTC로 설정 된다.
잠금 스크립트 : OP_RETURN 해제 스크립트 : 지불 용도가 아니므로 해제 거래가 만들어 지지 않는다.
활용
- 비트코인
- 비트코인(Bitcoin)은 스크립트라고 하는 프로그래밍 언어가 있는데, 단순하면서도 어떻게 보면 비트코인이 비트코인으로서 역할을 하게 하는 적합한 언어라고 할 수 있고, 비트코인의 모든 거래를 유효화 시키는 것이 스크립트이며, 또한 비트코인은 고정적인 패턴화된 형태의 시스템이 아니라 스크립트 언어를 통해 실행되기 때문에 무한대에 가까운 표현 가능한 조건들이 만들어질 수 있는데 이것이 비트코인이 화폐로서 역할을 하게하는 힘이다. 해제 스크립트에는 비트코인 지갑의 소유권을 인증하는 서명이 포함되어 있는데 이 서명 값과 출력값(UTXO)의 잠금 스크립트 값이 위 그림처럼 푸시연산과 팝연산을 거쳐 TRUE값이 도출되면 비트코인을 소비할 수 있어 스크립트가 비트코인 거래를 작동시키는 방법이다. 스크립트는 스택(Stack)이라 불리는 데이터 구조를 사용하는데 다음과 같다.[5]
- 스택의 데이터 구조이고 이 스택은 푸시(push)와 팝(pop)연산을 가능하게 하며, 푸시는 데이터 최상단에 데이터를 추가하는 연산이고 팝은 데이터 최상단에서 데이터를 제거하는 연산이다.
- 8을 푸시연산 하게되면 8이 들어가고 거기에 또 3과 -1을 각각 푸시하면 쌓인 데이터의 가장 위에 데이터가 쌓여 들어가는 것이고, 그와 반대로 팝 연산을 하게되면 최상단에 있는 데이터를 제거해주는 시스템이 스택 데이터 구조이며, 팝 연산에서는 더하기, 빼기, 곱하기, 나누기 등의 명령어를 넣으면 위의 그림처럼 그냥 가장 위의 데이터가 제거되는 것이 아닌 명령했던 더하기, 빼기, 곱하기, 나누기가 연산 과정을 거친 후 제거된다.
- 2+3을 했을때 5가 나오는지 확인을 하는 과정을 스크립팅 언어로 나타낸 것인데, 만일 +3 = 5가 잠금 스크립트 라면 2는 해제 스크립트인 것인데, 이 말은 +3을 했을때 5가 나오는 입력값인 2를 찾는 것이 잠금 스크립트의 조건을 만족하는 해제 스크립트를 찾는다. 비트코인에 대해 자세히 보기
과정
- 거래검증
- 해제 스크립트는 위와같이 임의로 블럭정보를 기반으로 생성을 할수없고, 생성후 코드기반으로 확인을 할수가 없어 개인키(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>
- PUSHDATA <sig > : 서명(signature)을 스택(stack)에 푸시(push) 하라는 명령어
- SIGHASH_ALL : 거래에 대한 모든 것이 서명되어 있음을 나타낸다.
- PUSHDATA <pubKey> : 공개키(public-key)를 스택에 푸시하라는 명령어
각주
- ↑ easyblockchain, 〈쉽게 설명하는 블록체인:비트코인의 언너 '스크립트 Script)'〉, 《뱅크샐러드》, 2018-07-02
- ↑ niipoong, 〈비트코인 스크립트와 디지털 서명, 검증 (scriptSig, scriptPubKey )〉, 《스팀잇》
- ↑ 〈scriptPubKey 및 scriptSig 설명〉, 《MYCRYPTOPEDIA》, 2018-10-30
- ↑ niipoong, 〈비트코인 스크립트와 디지털 서명, 검증 (scriptSig, scriptPubKey )〉, 《스팀잇》
- ↑ 5.0 5.1 jsralph, 〈쉽게 설명하는 블록체인, 스크립트란 뭔가요?〉, 《스팀잇》
- ↑ 블록체인 프로그래밍 백서 - http://a.to/198i4Aw
- ↑ 니르바나, 〈트랜잭션 검증을 위한 scriptPubKey와 scriptSig 생성하기〉, 《티스토리》
참고자료
- 비트코인 개발자가이드 공식 홈페이지 - https://wikidocs.net/14505
- niipoong, 〈비트코인 스크립트와 디지털 서명, 검증 (scriptSig, scriptPubKey )〉, 《스팀잇》
- easyblockchain, 〈쉽게 설명하는 블록체인:비트코인의 언너 '스크립트 Script)'〉, 《뱅크샐러드》, 2018-07-02
- 〈scriptPubKey 및 scriptSig 설명〉, 《MYCRYPTOPEDIA》, 2018-10-30
- 니르바나, 〈트랜잭션 검증을 위한 scriptPubKey와 scriptSig 생성하기〉, 《티스토리》
- jsralph, 〈쉽게 설명하는 블록체인, 스크립트란 뭔가요?〉, 《스팀잇》
- AEP코리아네트, 〈비트코인 시스템에서 사용하는 암호 기술(II) - 거래 검증〉, 《네이버 블로그》, 2017-12-21
- 블록체인 프로그래밍 백서 - http://a.to/198i4Aw
같이 보기