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

잠금 스크립트

해시넷
이동: 둘러보기, 검색

잠금 스크립트(scriptPubkey)는 공개키(public key)를 스크립트(scryipt)로 구성하여, 해제 조건을 입력해야 사용할 수 있도록 만든 것이다. 비트코인 생태계에서 잠금 스크립트는 트랜잭션을 검증하기 올바른지 검증는 키(key)의 역할을 한다. 스크립트퍼브키라고도 한다.

개요[편집]

비트코인 생태계에도 스크립트라고 부르는 프로그래밍 언어가 존재한다. 스크립트는 비트코인의 모든 거래를 유효화시키는 언어로, 단순하면서도 비트코인이 비트코인으로서 역할을 하게 하는 적합한 언어이다. 비트코인은 고정적인 패턴화된 형태의 시스템이 아니라 스크립트 언어를 통해 실행되기 때문에 무한대에 가까운 표현 가능한 조건들이 만들어질 수 있는데, 이것이 바로 비트코인이 화폐로서 역할을 하게 하는 힘이다. 비트코인 거래를 작동하기 위해서 두 가지 잠금 스크립트와 해제 스크립트, 두 가지 엔진이 작동한다.

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

블록체인상에서 기록되어 있는 모든 UTXO들은 그것을 소비하기 위한 조건이 있는데, 그 조건들을 스크립트로 구현한 것이 잠금 스크립트이다. 스크립트퍼브키라고도 불리는 잠금 스크립트는 UTXO를 소비하기 위한 요건을 명시하고 있으며, 공개키 또는 비트코인 주소를 포함한다. 그 이유는 UTXO가 특정 지갑에서 소유하고 있는 비트코인 덩어리기 때문에 이 소비 요건에 비트코인 주소와 공개키도 포함하기 때문이다. 따라서 해당 지갑주소를 포함하는 이 잠금 스크립트를 풀 수 있는 조건을 달성하면 해당 지갑주소에서 UTXO를 소비할 수 있게 된다.[1]

잠금 스크립트와 해제 스크립트(scriptSig)는 언뜻 비슷해보이지만 이 둘은 열쇠와 자물쇠의 관계이다. 잠금 스크립트는 자물쇠의 역할을 하며, 트랜잭션을 검증하기 올바른지 검증하라는 키이다. 반면 해제 스크립트는 열쇠의 역할을 하며, 트랜잭션을 발생시킨 주체의 서명과 공개키를 합쳐 잠금 스크립트를 풀기 위해 작동한다. 피투피 네트워크에서 해당 트랜잭션을 받은 노드는 이 잠금 스크립트에 해제 스크립트를 대조해서 일치하는지 확인하고 true라고 판명되면 올바른 트랜잭션이라 간주해 이웃노드로 전달한다.[2]

특징[편집]

트랜잭션 출력 스크립트에서는 공개키 또는 해시를 담고 있으며, 상응하는 개인 키의 소유주만이 출력된 비트코인을 얻을 수 있다. 내부적으로 비트코인 프로토콜은 잠금 스크립트를 통해 비트코인의 수신자를 식별한다. 잠금 스크립트는 비트코인 주소와 관련이 없는 것으로 보이지만 공개 키의 해시를 표시하는데, 비트코인 주소는 주소를 사용할 네트워크와 공개 키의 해시를 식별하는 버전 바이트(byte)로 구성되며, 잠금 스크립트 및 네트워크 식별자에서 비트코인 주소를 생성할 수 있다.[3]

UTXO를 기본 단위로 거래하며 출력값에 잠금 스크립트, 입력값에 해제 스크립트가 들어가고, 출력값은 잠금 스크립트로 잠겨져 있으며 받는 사람은 자신의 서명이 들어간 해제 스크립트로 잠금장치를 풀어야 받은 돈을 사용할 수 있다.[4] 잠금 스크립트는 UTXO를 소비하기 위한 요건을 명시하고 있고 그뿐 아니라 공개키 또는 비트코인 주소를 포함한다. 특정 지갑에서 소유하고 있는 비트코인 덩어리로 소비 요건에 비트코인 주소와 공개키도 포함하며, 해당 지갑 주소를 포함하는 잠금 스크립트를 풀 수 있는 조건을 달성하면 해당 지갑 주소에서 UTXO를 소비할 수 있다.[1]

활용[편집]

비트코인 피투피 네트워크에서 해당 트랜잭션을 받은 노드는 잠금 스크립트에 해제 스크립트를 대조해서 일치하는지 확인하고 true(참)라고 판명되면 올바른 트랜잭션이라고 간주하고 이웃 노드로 전달하게 된다. input(입력) 내부에 한 쌍의 해제 스크립트와 잠금 스크립트가 존재하는데, 두 가지를 통해 트랜잭션을 검증하면 되고, 잠금 스크립트라는 자물쇠를 트랜잭션에 결과값에 같이 첨부를 하여 전달한다. 발생한 결과값을 사용하려면, 전달받은 주소 또한 자신의 해제 스크립트를 통해 해당 잠금 스크립트를 풀어야만 사용할 수 있고, 두 가지 검증이 false(실패)라면 어떤 노드에서도 유효한 트랜잭션이라 인정하지 않는다.[2] 다음은 비트코인의 트랜잭션에 관한 설명이다.

  • P2PKH 스크립트 유효성 검사(pay-to-public-key-hash)
유효성 확인 절차를 수행하려면 해제 스크립트 및 잠금 스크립트를 평가해야 한다. P2PKH 출력에서 잠금 스크립트는 다음과 같다.
OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG
지출자의 해제 스크립트가 평가되고, 스크립트 시작 부분에 접두사가 붙는다. P2PKH 트랜잭션에서 해제 스크립트에는 secp256k1 서명과 전체 공개 키(퍼브키)가 포함되어 다음과 같다.
 <Sig> <PubKey> OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG
스크립트 언어는 튜링(Turing)이 아닌 무상태(stateless)인 의도적으로 설계된 스택 기반 포스(forth) 언어이다. 무상태는 트랜잭션이 블록체인에 추가되면 영구적으로 추가 할 수 없게 하는 조건이 없음을 보장한다. 튜링의 불안정은 스크립트 언어의 유연성과 예측 가능성을 떨어뜨려 보안 모델을 크게 단순화한다. 트랜잭션이 유효한지 테스트하기 위해 해제 스크립트와 잠금 스크립트 작업이 밥(Bob)의 해제 스크립트에서 시작하여 엘리스(Alice)의 잠금 스크립트가 끝날 때까지 한 번에 하나씩 실행한다. 아래 그림은 프로세스에 대한 설명이다.
표준 P2PKH 잠금 스크립트
  1. 밥(해제 스크립트의 서명)이 빈 스택에 추가된다. 데이터이기 때문에 스택에 추가하는 것 외에는 아무것도 수행되지 않으며, 공개키는 서명의 최상부에 추가된다.
  2. 엘리스의 잠금 스크립트에서 OP_DUP 작업이 실행된다. OP_DUP은 현재 스택 상단에 있는 데이터의 복사본을 스택에 추가한다. 이 경우 밥이 제공한 공개 키의 복사본을 만든다.
  3. 다음에 실행되는 연산 OP_HASH 160은 현재 스택 상단에 있는 데이터의 해시(이 경우 밥의 공개 키)를 스택에 추가한다. 이는 밥의 공개 키 해시를 만든다.[5]
  4. 엘리스의 잠금 스크립트는 밥이 첫 번째 트랜잭션에 대해 준 잠금 퍼브키 해시를 추가한다. 이 시점에서 스택 맨 위에 밥의 퍼브키 해시 복사본이 두 개 있어야 한다.
  5. 엘리스의 잠금 스크립트는 OP_EQUALVERIFY를 실행한다. OP_EQUALVERIFY는 OP_EQUAL을 실행 한 다음 OP_VERIFY를 실행하는 것과 같다. OP_EQUAL은 스택의 맨 위에 있는 두 값을 확인한다. 이 경우, 제공된 전체 공개 키 밥에서 생성된 퍼브키 해시가 트랜잭션 # 1을 생성할 때 제공된 퍼브키 해시 엘리스와 동일한지 확인한다. OP_EQUAL은 비교한 두 개의 값을 스택 상단에서 제거하고 비교 결과로 대체한다. OP_VERIFY는 스택의 맨 위에 있는 값을 확인한다. 값이 0 (거짓)이라면 즉시 평가가 종료되고 트랜잭션 유효성 검사가 실패한다. 그렇지 않으면 스택에서 실제 값을 팝한다.
  6. 마지막으로, 앨리스의 잠금 스크립트는 OP_CHECKSIG를 실행한다. OP_CHECKSIG는 그가 제공한 서명된 현재 공개 키와 비교하여 제공한 서명을 확인한다. 서명이 공개 키와 일치하고 서명이 필요한 모든 데이터를 사용하여 생성 된 경우 OP_CHECKSIG는 true값을 스택 맨 위로 추가한다.[6]


  • P2SH 스크립트(pay-to-script-hash)
수신자는 스크립트 조건에 주의를 기울이고 원하는 경우 지출자에게 잠금 스크립트 사용을 요청할 수 있고, 짧은 비트코인 주소보다 덜 편리하며 BIP70 지불 프로토콜을 광범위하게 구현하기 전에 프로그램 간에 이를 통신하는 표준 방법이 없어 P2SH 트랜잭션을 작성하여 스크립트 해시가 포함된 잠금 스크립트인 리딤(redeem) 스크립트를 만들었다. P2SH 워크 플로는 P2PKH 워크 플로와 거의 동일하고, 밥은 원하는 스크립트로 리딤 스크립트를 생성하고 사용 스크립트를 해시하며 엘리스에 사용 스크립트 해시를 제공하며, 엘리스는 밥의 상환 스크립트 해시가 포함된 P2SH 스타일 출력을 만든다.[7]
P2sh1.PNG
밥은 출력을 보내려고 할 때 해제 스크립트의 전체 직렬화된 사용 스크립트와 함께 자신의 서명을 제공합니다. 피투피 네트워크는 엘리스가 출력에 넣은 스크립트 해시와 동일한 값으로 전체 회수 스크립트 해시를 보장하며, 기본 잠금 스크립트인 것처럼 보충 스크립트를 정확하게 처리하여 검색 스크립트가 거짓을 반환하지 않으면 밥에게 출력을 보낸다.
P2sh2.PNG
사용 스크립트의 해시는 잠금 해시와 동일한 속성을 갖기 때문에 표준 주소와 구분하기 위해 하나의 작은 변경만으로 표준 비트코인 주소 형식으로 변환 할 수 있어 P2PH 스타일 주소를 수집하는 것처럼 간단하게 P2SH 스타일 주소를 수집 할 수 있다. 해시는 사용 스크립트의 공개 키를 난독 화하여, P2SH 스크립트는 P2PKH 잠금 해시만큼 안전하다.[8]
  • 표준 거래(Standard Transactions)
  • P2PKH : P2PKH는 하나 또는 여러 개의 비트코인 주소로 트랜잭션을 보내는 데 사용되는 가장 일반적인 잠금 스크립트 형식이다.
잠금 스크립트 : OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
해제 스크립트 : <sig> <pubkey>
  • P2SH : P2SH는 트랜잭션 해시에 트랜잭션을 보내는 데 사용된다. 각 표준 잠금 스크립트는 P2SH 리딤 스크립트로 사용할 수 있지만, 실제로는 더 많은 트랜잭션 유형이 표준화될 때까지 다중서명 잠금 스크립트만 이해할 수 있다.
잠금 스크립트 : OP_HASH160 <Hash160 (redeemScript)> OP_EQUAL
해제 스크립트 : <sig> [sig] [sig ...] <redeemScript>
  • 다중서명 : 현재 P2SH 다중서명은 일반적으로 다중서명 트랜잭션에 사용되지만 이 기본 스크립트는 UTXO를 사용하기 전에 여러 서명을 요구하는 데 사용할 수 있다. M-of-N이라고 하는 다중서명 잠금 스크립트에서 M은 공개 키와 일치해야 한느 최소 서명 수이고, N은 제공된 공개 키의 수이다, M과 N은 모두 원한느 번호에 해당하는 OP_1 ~ OP_16의 opcode여야한다. 호환성을 위해 유지되어야 하는 원리 비트코인의 구현이 off-by-one 오류로 인해 OP_CHECKMULTISIG는 m으로 표시된 것보다 스택에서 하나 더 많은 값을 소비하므로 해제 스크립트의 secp256k1 서명 목록에 추가로 끝나야 한다. 해제 스크립트는 해당 공개 키가 잠금 스크립트 또는 리딤 스크립트에 나타나는 것과 동일한 순서로 서명을 제공해야 한다.[9]
잠금 스크립트 : <m> <A pubkey> [B pubkey] [C pubkey ...] <n> OP_CHECKMULTISIG
해제 스크립트 : OP_0 <A sig> [B sig] [C sig ...]
  • 퍼브키(Pubkey) : 퍼브키의 출력은 P2PKH 잠금 스크립트의 단순화된 형식이지만 P2PKH만큼 안전하지 않으므로 일반적으로 더이상 새 트랜잭션에서 사용되지 않는다.
잠금 스크립트 : <pubkey> OP_CHECKSIG
해제 스크립트 : <sig>
  • 널 데이터(Null date) : 전체 노드가 자신의 UTXO 데이터베이스에 저장할 필요가 없는 입증할 수 없는 잠금 스크립트에 임의의 데이터를 추가하는 비트코인 코어 0.9.0 이상에서 기본적으로 릴레이되고 채워지는 트랜잭션 유형이다. UTXO 데이터베이스를 자동으로 제거할 수 없기 때문에 UTXO 데이터베이스를 확장하는 트랜잭션에 널데이터 트랜잭션을 사용하는 것이 바람직하다. 그러나 가능한 겨웅 트랜잭션 외부에 데이터를 저장하는 것이 더 좋다. 합의 규칙에 따라 최대 데이터 바이트 수는 520바이트를 초과하지 ㅇ낳는 등 다른 모든 합의 규칙을 따르는 경우 허용되는 최대 잠금 스크립트 크기인 10,000바이트까지 널 데이터 출력이 허용된다. 비트코인 코어 0.9.x에서 0.10.x는 기본적으로 단일 데이터 푸시데이터에서 최대 40바이트의 널 데이터 트랜잭션과 정확히 0을 지불하는 하나의 널 데이터 출력을 릴레이 및 채굴한다.[9]
잠금 스크립트 : OP_RETURN <0 ~ 40 바이트의 데이터>
널데이터 스크립트는 사용할 수 없으므로 해제 스크립트는 없다.

과정[편집]

  • 거래 검증
"hadh":"503e4e9824284eb06f1a328484e2b367b5f4f93a405d6e7b97261bafabfb53d5", 
"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" 〈
 }, 
 { 
"sepent":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 = Base58Decode((1NdvAyRJLdK5EXs7DV3ebYb5wffdCZk1pD))
 : 00ED5600751FEA259A0F8C8BEC09A626E7E4450E7A2F6DA14A
 : 디코딩된 hex값에서 1바이트 버전 prefix와 4바이트 checksum을 제외한 순수 퍼브키 해시값을 가져온다.
4. 퍼브키 해시값을 사용하여 재구성한다.
 : 76 + a9 + 14 + ED5600751FEA259A0F8C8BEC09A626E7E4450E7A + 88 + ac
5. 최종 잠금스크립트 해시값 생성한다.
 : 76a914ED5600751FEA259A0F8C8BEC09A626E7E4450E7A88ac 생성한 잠금 스크립트는 위의 블록정보에서 확인한 스크립트값과 동일하다.[10]
  • 거래 생성 및 디지털 서명
생성된 거래, 트랜잭션 데이터에는 거래 수신자의 퍼블릭 - 키 해시값을 포함한 스크립트인 잠금 스크립트가 들어 있으며, 디지털 서명 후, 서명 값은 해제 스크립트(서명 값 포함) 속에 들어간다. 비트코인에서의 시스템은 먼저 거래, 트랜잭션을 생성한다. unsigned raw Transaction data를 만든다고 하면, 일반적인(input:1 & qutput:1) 거래, 트랜잭션 데이터를 보면 다음과 같다.
파란글씨는 서명후 변경되는 부분이고, 트랜잭션 데이터 와 비교하면, 해제스크립트 위치에 잠금 스크립트가 들어갔다.
01000000
01
eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2
01000000
19
76a914010966776006953d5567439e5e39f86a0d273bee88ac
ffffffff
01
605af40500000000
19
76a914097072524438d003d23a2f23edb65aae1bb3e46988ac
00000000
01000000
Sign(서명) 전에는 이전 거래에 있던 잠금 스크립트값이 들어가고, 마지막에 four-byte hash type인 01000000(0x00000001)가 붙어 있다. (SIGHASH_ALL 값)
이 값을 SHA-256 해시 함수로 계산한 다음, 한 번 더 SHA-256 해시 함수로 계산하여 최종 해시값을 만들면, 더블해싱(double hashing) 이라고 하며 아래와 같은 수식으로 표현하기도 한다.
dhash(m) = sha256(sha256(m))
해시값을 개인 키(private-key)로 서명하여 DER 형식으로 된 서명 값을 생성하고, 개인 키로부터 공개키(public-key) 값을 생성하고, 관련 정보를 추가하여 해제 스크립트값을 완성한다. "unsigned raw Transaction data" 에 있던 첫 번째 잠금 스트립트 값을 해제 스트립트 값으로 바꾸고(replace), 스크립트 길이(script length) 값도 바꾼다. 그리고 마지막에 있던 4바이트-해시 유형인 01000000을 제거하면, 서명 값이 들어간 거래, 트랜잭션 데이터가 완성된다.
ECC 암호 알고리즘에서는 공개키를 2개(X값, Y값) 사용하며, 서명 값도 2개(X값, Y값 ==> R 값, S값) 만들어지는데 특징으로 인해, 개인 키는 256-비트이지만, 서명 값과 공개키는 각각 512-비트라고 한다. 서명 값과 공개키 값은 해제 스크립트 안에 들어 있고, 공개키는 비압축(Uncompressed) 형식과 압축(Compressed) 형식 2가지로 표현할 수 있다. [11]
Uncompressed Form :  04 <X> <Y>
Compressed Form     :  02 <X>   When <Y> is even
Compressed Form     :  03 <X>   When <Y> is odd

가기.png 비트코인에 대해 자세히 보기

명령어[편집]

  • 스크립트 코드 : 해제 스크립트에 의해 데이터를 스택에 푸시하고 나서, 잠금 스크립트를 실행하여 검증한다.
  1. OP_DUP : duplicate(복사)하는 명령어
  2. OP_HASH160 : 160-bit Hash 값을 연산하는 명령어
  3. OP_EQUALVERIFY : stack에 들어 있는 2개의 값이 동일한지 검증 하는 명령어
  4. OP_CHECKSIG : signature를 검증 하는 명령어

각주[편집]

  1. 1.0 1.1 jsralph, 〈쉽게 설명하는 블록체인, 스크립트란 뭔가요? (비트코인의 언어)〉, 《스팀잇》
  2. 2.0 2.1 niipoong, 〈비트코인 스크립트와 디지털 서명, 검증 (scriptSig, scriptPubKey )〉, 《스팀잇》
  3. knocte, 〈ScriptPubKey {# payment-script}〉, 《깃허브》
  4. feyee95, 〈비트코인 스크립트 언어의 장점과 한계〉, 《스팀잇》
  5. KIM JUN YONG , 〈블록체인을 알기 전에 알아야 할 "암호학"〉, 《미디엄》, 2018-11-14
  6. 2-01 P2PKH 스크립트 유효성 검사(P2PKH Script Validation〉, 《비트코인 개발자 가이드》
  7. 안성주지몬, 〈(Mastering Bitcoin) 마스터링 비트코인 내 맘대로 정리 - Ch07〉, 《티스토리》, 2019-01-28
  8. 2-02 P2SH 스크립트(P2SH Scripts)〉, 《비트코인 개발자 가이드》
  9. 9.0 9.1 2-03 표준 거래(Standard Transactions)〉, 《비트코인 개발자 가이드》
  10. 니르바나, 〈트랜잭션 검증을 위한 scriptPubKey와 scriptSig 생성하기〉, 《티스토리》
  11. AEP코리아네트, 〈비트코인 시스템에서 사용하는 암호 기술(II) - 거래 검증〉, 《네이버 블로그》, 2017-12-21

참고자료[편집]

같이 보기[편집]


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