본문으로 바로가기

비트코인 트랜잭션에서는 Input UTXO의 유효성 검증을 위한 스크립트 연산에서 다음과 같이 scriptSig와 scriptPubKey가 사용됩니다.




이번 글에서는 다음의 글을 참고로 scriptPubKey와 scriptSig가 어떻게 만들어지는지 알아보도록 하겠습니다. 

https://klmoney.wordpress.com/bitcoin-dissecting-transactions-part-2-building-a-transaction-by-hand/



1. scriptPubKey 생성


예제를 위해 https://blockchain.info/block-height/499118?format=json 정보를 사용하도록 하겠습니다.


"hash":"503e4e9824282eb06f1a328484e2b367b5f4f93a405d6e7b97261bafabfb53d5",

   "vout_sz":2,

   "relayed_by":"0.0.0.0",

   "out":[

      {

         "spent":true,

         "tx_index":311962649,

         "type":0,

         "addr":"3FfQGY7jqsADC7uTVqF3vKQzeNPiBPTqt4",

         "value":34676070,

         "n":0,

         "script":"a914994394dbd20b7752e272458c738ae9b7666271b787"

      },

      {

         "spent":true,

         "tx_index":311962649,

         "type":0,

         "addr":"1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD",

         "value":31129454,

         "n":1,

         "script":"76a914ed5600751fea259a0f8c8bec09a626e7e4450e7a88ac"

      }

   ] 



1. DUP + HASH160 + <pubKeyHash> + EQUALVERIFY + CHECKSIG

2. 비트코인 OPCODE 값을 확인하여 위의 OPCODE에 해당하는 Hex값으로 변환

   :  76 + a9 + length + pubKeyHash + 88 + ac

3. 비트코인 주소를 기반으로 pubKeyHash값을 계산

   : pubKeyHash = Base58Decode((1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD))

   : 00ED5600751FEA259A0F8C8BEC09A626E7E4450E7A2F6DA14A

   : 디코딩된 hex값에서 1바이트 버전 prefix와 4바이트 checksum을 제외한 순수 pubKeyHash값을 가져옴

4. pubKeyHash값을 사용하여 재구성

   : 76 + a9 + 14 + ED5600751FEA259A0F8C8BEC09A626E7E4450E7A + 88 + ac

5, 최종 scriptPubKey hex값 생성

   : 76a914ED5600751FEA259A0F8C8BEC09A626E7E4450E7A88ac


이렇게 생성한 scriptPubKey 는 위의 블록정보에서 확인한  script값과 동일합니다.


"script":"76a914ed5600751fea259a0f8c8bec09a626e7e4450e7a88ac"


2, scriptSig 생성


scriptSig는 위와같이 임의로 블럭정보를 기반으로 생성을 할수없고, 생성후 코드기반으로 확인을 할수가 없습니다.

개인키(Private key)를 사용하여 signature를 생성해야 하고, 동일한 private key를 사용해서 signature를 생성해도 시간변화에 따라 매번 다른 signature가 생성이 됩니다. 따라서 특정 private key를 하나 할당해서 그것을 사용하여 생성하는 과정을 위주로 설명을 하도록 하겠습니다.


1. 먼저 scriptSig를 제외한 트랜잭션 템플릿을 작성합니다.




2. 위의 템플릿에서 비어있는 scriptSig 부분에는 입력에 사용하기위한 UTXO의 이전출력 scriptPubKey를 추가합니다.

   위의 템플릿에 추가로 마지막에 sigHash Code가 01 00 00 00  붙어있는것에 유의하시기 바랍니다.



3. 위의 16진수 트랜잭션 메시지와 private key를 사용하여 ECC 알고리즘을 통해 signature를 생성합니다.


import hashlib, ecdsa, binascii
from ecdsa import SigningKey, SECP256k1
mhex = ‘0100000001416e9b4555180aaa0c417067a46607bc58c96f0131b2f41f7d0fb665eab03a7e000000001976a91499b1ebcfc11a13df5161aba8160460fe1601d54188acffffffff01204e0000000000001976a914e81d742e2c3c7acd4c29de090fc2c4d4120b2bf888ac0000000001000000’
txHash = hashlib.sha256(hashlib.sha256(mhex.decode('hex')).digest()).hexdigest()
privkey = '3cd0560f5b27591916c643a0b7aa69d03839380a738d2e912990dcc573715d2c'
signingkey = ecdsa.SigningKey.from_string(privkey.decode('hex'), curve=ecdsa.SECP256k1)
SIG = signingkey.sign_digest(txhash, sigencode=ecdsa.util.sigencode_der_canonize)
binascii.hexlify(SIG)


4. 이 과정을 통해 생성된 signature 는 다음과 같습니다.

   : 304402201c3be71e1794621cbe3a7adec1af25f818f238f5796d47152137eba710f2174a02204f8fe667b696e30012ef4e56ac96afb830bddffee3b15d2e474066ab3aa39bad


5. 생성된 signature와 public key를 사용하여 DER포맷으로 scriptSig를 구성합니다. R, S 데이타는 32, 33바이트가 될수있기 때문에 PUSHDATA Opcode 값은 47, 48, 49가 될수있습니다.



6. scriptSig 부분을 위에서 최종 생성한 signature로 교체하면 최종 트랜잭션이 완성됩니다.