336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이전 포스팅에서 트랜잭션의 Input/Output의 자료구조와 UTXO 모델에 대해 설명하였습니다.


Output에는 누가(scriptPubKey) 얼마(nValue)를 받았는지 표시되고, 어떤 Input은 이 Output을 가리켜 해당 nValue만큼의 비트코인을 쓸 수 있다고 하였습니다. 그리고 아직 소비되지 않은 Output을 UTXO(Unspent Transaction Outputs)이라 한다고 하였습니다.


트랜잭션 Input 검증

트랜잭션 검증에서 중요한 일 중 하나는 트랜잭션 Input을 검증하는 일입니다. 예를 들어 A가 채굴에 성공해서 50 비트코인의 Output을 가지고 있었는데, 이를 A가 아닌 다른 사람이 쓰면 안되기 때문에 scriptPubKey라는 A만 풀 수 있는 잠금 장치를 걸어두고, 이를 A가 쓸 때에는 scriptSig라는 일종의 잠금해제 장치를 제공해야 합니다.


이전 포스트에서 트랜잭션 Input은 prevout과 scriptSig로 구성된다고 하였습니다. prevout이 가리키는 트랜잭션 Output에는 scriptPubKey가 있습습니다. scriptSig와 scriptPubKey 두 개 스크립트 쌍이 맞아야 합니다. 개념적으로는 scriptPubKey는 공개키이고 scriptSig는 비밀키 서명입니다. 그러나 실제로는 명령어 코드(OPCODE)와 데이터로 구성된 스크립트이고 이 명령어를 수행한 결과에 의해 Input 검증 성공/실패가 결정됩니다.


비트코인 스크립트 실행 방법

비트코인 스크립트 실행은 스택이 빈 상태에서 input의 scriptSig를 먼저 실행하고, 그 다음 scriptPubKey를 실행시킵니다. 실행 결과 스택의 맨 위 값이 FALSE이면 실패, TRUE(0이 아닌 값)이면 성공한 것입니다. 성공할 경우에만 해당 input 검증을 통과한 것으로 처리합니다.


스크립트는 후위연산식으로 생각할 수 있습니다. 아래는 후위연산식 실행의 간단한 예제입니다.


4 5 +


위의 후위연산식을 실행하면 아래 결과가 나옵니다.


9


조금 더 복잡한 후위연산식


4 5 * 2 +


결과


22


아래와 같이 scriptPubKey가 있다고 가정해 봅시다.


4 + 10 ==


== 연산자는 2개 값을 읽어 같으면 TRUE, 같지 않으면 FALSE를 반환하는 연산자입니다.

+ 연산자는 2개 피연산자를 요구하는데, 그 앞에 4 밖에 없어서 위의 스크립트는 무효합니다. 4 앞에 어떤 하나의 숫자를 제시하면 유효한 스크립트를 만들 수 있습니다.

위의 scriptPubKey를 풀기 위해서는 scriptSig를 제공해야 합니다.


scriptPubKey: 4 + 10 ==

scriptSig: x


여기서 scriptSig와 scriptPubKey를 차례대로 실행시키면 아래 스크립트를 실행시키는 것과 같은 효과입니다.


x 4 + 10 ==

위의 스크립트는 x가 6이면 실행 결과가 TRUE이고, 아닐 경우 FALSE입니다.


즉, "4 + 10 =="는 풀어야 할 문제이고, "6"은 그 해답입니다.



scriptPubKey: 문제

scriptSig: 해답



표준 스크립트

비트코인은 비밀키 서명을 검증할 수 있는 OP_CHECKSIG 명령어를 제공합니다. "x y OP_CHECKSIG" 스크립트는 x를 비밀키 서명, y를 공개키로 취급하여 유효한 서명이면 TRUE, 아닐 경우 FALSE를 반환합니다. OP 코드의 목록은 비트코인 위키에서 확인할 수 있습니다.


현재 비트코인 네트워크에서는 표준 스크립트만 허용되고 있습니다. (https://bitcoin.org/en/developer-guide#standard-transactions)


- P2PKH

- P2SH

- P2PK

- Multisig

- Null Data


가장 간단한 표준 스크립트는 P2PK 스크립트입니다.

P2PK (Pay to Public Key)

scriptPubKey

<pubkey> OP_CHECKSIG

scriptSig

<sig>



잘 아시다시피 비트코인 거래 내역은 공개되어 누구나 볼 수 있습니다. 즉 풀어야 할 문제가 미리 공개되어 있고, 누군가 그 문제를 푼다면 해답 역시 공개됩니다. 미리 공개되어 있는 문제는 충분히 어려워야 하고, 제시된 해답은 다른 UTXO를 공격할 힌트가 되지 않도록 조심해야 합니다.


위의 P2PK 스크립트는 내가 비트코인을 받는 시점에서 공개키가 드러나게 됩니다. 만약 ECDSA가 공격당할 경우 P2PK로 만든 UTXO 모두 공격당하게 됩니다. 따라서 더 안전한 표준 스크립트인 P2PKH 스크립트를 쓰는 것이 보안상 권장됩니다.


P2PKH(Pay to Public Key Hash)

scriptPubKey

OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

scriptSig

<sig> <pubkey>


P2PKH의 scriptPubKey에는 공개키의 해시값만 있습니다. scriptSig를 제시할 때 공개키를 내가 직접 제공해야 합니다. scriptPubKey의 OP_DUP부터 OP_EQUALVERIFY는 공개키 해시를 검증하는 부분이고, 이게 사라지면 "<sig> <pubkey> OP_CHECKSIG"로 P2PK와 같은 형태가 됩니다.


중요한 점은 scriptPubKey에는 공개키의 해시만 있다는 점입니다. 만약 ECDSA 알고리즘이 완전히 뚫리더라도 scriptPubKey에 있는 공개키 해시만 보고 비밀키를 알아내기 위해서는 ECDSA뿐만 아니라 해시 함수까지 공격해야 합니다. 해당 UTXO를 사용하는 순간 scriptSig에 공개키가 드러나면 비밀키를 공격할 수 있습니다. 하지만 이는 매번 새로운 공개키를 사용하면 문제가 되지 않습니다.


P2PKH는 블록 익스플로러나 지갑 앱에서 보여주는 1로 시작하는 주소(예: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2)에 해당됩니다. 공개키 해시에 네트워크 ID와 체크섬을 붙이고 Base58로 변환한 값입니다.

Multisig

scriptPubKey

<m> <A pubkey> [B pubkey] [C pubkey...] <n> OP_CHECKMULTISIG

scriptSig

OP_0 <A sig> [B sig] [C sig...]


OP_CHECKMULTISIG는 n개 중에 m개의 서명을 받으면 TRUE를 반환하는 OP코드입니다. 이는 다양한 응용에 쓰일 수 있습니다. 예를 들면 두 명이 공동으로 자산을 관리하는데, 돈을 쓰기 위해선 2명의 서명을 모두 필요로 할 수 있고, 한 명의 서명만을 필요로 하게 할 수도 있습니다. 변호사같은 중립적인 역할을 두어 3개 중 2개 서명이 필요하도록 할 수도 있습니다.


여기에선 기본적으로 공개키가 2개 이상이기 때문에 주소를 효율적으로 만들기가 까다롭습니다. 주소라는 것은 결국 저 scriptPubKey를 특정할 수 있어야 합니다. 예를 들면 A가 B에게 돈을 주기 위해서 B에게 주소를 물어보면, B가 n이 10인 Multisig로 받기 위해서는 공개키 10개를 모두 전달해야한다는 의미가 됩니다. 이는 비효율적이고 공개키가 모두 공개되는 문제가 있습니다. Multisig로 돈을 받기 위해서는 P2SH 표준 스크립트를 사용하는 것이 권장됩니다.

P2SH(Pay to Script Hash)

scriptPubKey

OP_HASH160 <Hash160(redeemScript)> OP_EQUAL

scriptSig

<sig> [sig...] <redeemScript>


P2SH에선 scriptSig에 있는 redeemScript가 실제 "문제" 역할을 담당합니다. scriptSig에는 문제와 해답(<sig>)이 동시에 존재하는 셈입니다. 임의의 공격자가 스스로 자기가 풀 수 있는 문제를 제시하고 혼자 푸는 상황을 방지하기 위해, 문제지의 해시를 scriptPubKey에 기록합니다. 


아래는 Multisig를 redeepScript로 사용하는 예입니다.

scriptPubKey

OP_HASH160 <Hash160(redeemScript)> OP_EQUAL

redeemScript

<OP_2> <A pubkey> <B pubkey> <C pubkey> <OP_3> OP_CHECKMULTISIG

scriptSig

OP_0 <A sig> <C sig> <redeemScript>


P2SH가 지갑 앱에서 보여주는 3으로 시작하는 주소(예: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy)에 해당됩니다. 3으로 시작하는 주소는 Multisig일 가능성이 있습니다. 그러나 3으로 시작하는 주소가 실제로 어떤 redeemScript를 쓰는지는 scriptSig가 제시되기 전까진 알 수 없습니다. P2PKH 일 수도 있습니다.


그렇다고 P2SH를 쓰는 것이 항상 좋은 것만은 아닙니다. 스크립트의 크기가 커지면 트랜잭션이 커지고, 이는 수수료가 비싸지는 것을 의미합니다. 최근에 비트코인 수수료가 매우 비싸지면서 P2PK를 쓰는 UTXO도 많이 보이고 있습니다. 통상적인 P2PKH Input 1개 + Output 2개 트랜잭션이 약 226 바이트인데, 주는 사람이 P2PK를 쓸 경우 126 바이트로 공간 비용을 절약할 수 있습니다.

'비트코인 Technical Background' 카테고리의 다른 글

비트코인 주소에 대한 이해 (1) - UTXO 모델  (0) 2018.01.26
비트코인 SPV  (2) 2018.01.17

+ Recent posts