Skip to content

Instantly share code, notes, and snippets.

@chappjc
Last active June 24, 2020 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chappjc/26d74d30e44007dec2bc7359d6594b55 to your computer and use it in GitHub Desktop.
Save chappjc/26d74d30e44007dec2bc7359d6594b55 to your computer and use it in GitHub Desktop.
Script size and structure

Script Size and Structure

Redeem script execution: signature script prefixed to beginning of pkScript

Items in angle brackets (<like this>) represent data pushes, so if like this is 20 bytes, <like this> is 21 bytes with the OP_DATA_20 to make it a data push instead of interpreting it as Script itself.

Pubkey (P2PK)

Pubkey script: <pubkey> OP_CHECKSIG // 35 byte p2pk pkScript

i.e. OP_DATA_33 (33-byte pubkey) OP_CHECKSIG // 1 + 33 + 1

Signature script: <sig> // 74

Pubkey Hash (P2PKH)

Pubkey script: OP_DUP OP_HASH160 <20-byte pubkey hash> OP_EQUALVERIFY OP_CHECKSIG // 25 byte p2pkh pkScript

Signature script: <sig> <pubkey> // 74+34=108

Note that in execution, <sig> OP_CHECKSIG is the final operation as the pubkey is hashed and verified first.

"hex":

47 (71)
304402203a4bf63fc02419c77d7d0c404a9a6a646df6d1317714229df880cb257987a1d2022059aa08bbe8b515f9bae5cbb39d4ee73f163e2e42b70694fe0b1c214bc155db9601
21 (33)
028456d9594574f7efb179b0a2d2a10d7b39b3d750784329d25871ea0efdc10b83

"asm":

304402203a4bf63fc02419c77d7d0c404a9a6a646df6d1317714229df880cb257987a1d2022059aa08bbe8b515f9bae5cbb39d4ee73f163e2e42b70694fe0b1c214bc155db9601 // 71 bytes
028456d9594574f7efb179b0a2d2a10d7b39b3d750784329d25871ea0efdc10b83 // 33 bytes

Script Hash (P2SH)

Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL

Signature script: <...signatures...> <redeemScript> <= only push data ops!

  1. Normal stack valiation, then 2) take sigScript, pop <redeemScript>, then execute <...signatures...> redeemScript (no longer just a data push, but a pkScript).

P2SH with pubkey redeem script input stack

OP_DATA_73 (73-byte sig) OP_DATA_35        -- 1 + 73 + 1 = 75
||
{OP_DATA_33 (33-byte pubkey) OP_CHECKSIG}    -- 1 + 33 + 1 = 35 redeem script (p2pk pkScript)
||
OP_HASH160 [OP_DATA_20 + 20 bytes redeem script hash] OP_EQUAL     -- 23 p2sh pkScript

1 + 73 + 1 + 1 + 33 + 1 + 23 = 75 + 35 + 23 = 110 + 23 = 133

P2SH with pubkey hash redeem script (but why?)

<sig> <pubkey> <redeemScript / p2pkh pkScript>
OP_DATA_73 (73-byte sig) OP_DATA_33 (33-byte pubkey) OP_DATA_25
||
{OP_DUP OP_HASH160 <20-byte pubkey hash> OP_EQUALVERIFY OP_CHECKSIG}

1 + 73 + 1 + 33 + 1 + 1 + 1 + 1 + 20 + 1 + 1 + 23 = 134 + 23 = 157

P2SH with multisig redeem script

M-of-N multisig pkScript (the redeem script) contains N pubkeys:

OP_M [pubkey 1] [...] [pubkey N] OP_N OP_CHECKMULTISIG

signature script contains M signatures:

OP_0 [signature 1] [...] [signature M] [serialized redeem script (op_data_#/op_pushdata{1,2}+len, script bytes)]

NOTE: The OP_0 is omitted in Decred as it was ony required because of an off-by-1 bug in Bitcoin's original P2MS implementation.

e.g. 2-of-3 multisig P2SH input stack (sigs must be in order of pubkeys):

OP_0 [OP_DATA_73 (73-byte sig A/B)] [OP_DATA_73 (73-byte sig B/C)] OP_DATA_#/OP_PUSHDATA#+(1-2 bytes)             -- 1 + M*74 + 3(1)
||
{OP_2 [OP_DATA_33 (33b pubkey A)] [OP_DATA_33 (33b pubkey B)] [OP_DATA_33 (33b pubkey C)] OP_3 OP_CHECKMULTISIG}  -- 1 + N*34 + 1 + 1
||
OP_HASH160 [OP_DATA_20 + 20 bytes redeem script hash] OP_EQUAL     -- 23 pkScript

NOTE: max scripts/pubkeys is 15, so largest sigScript (bitcoin) is 1 + 15*74 + 3 + 1 + 15*34 + 1 + 1 = 1 + 1110 + 3 + 1 + 510 + 1 + 1 = 1627

DCR Swap Contract Redeem

DCR Swap contract txid: 4a14a2d79c1374d286ebd68d2c104343bcf8be44ed54045b5963fbf73667cecc

DCR Swap redeem txid: 4a7948f1eaa589b3e7bb655f44d1ee4daceda7220154ec677e45df708c2e44be

Contract pkScript: OP_HASH160 6d4bc656b3287a0e6b0d38802db6400f70531117 OP_EQUAL

Swap redeem sigScript:

4830450221009fee36700ebcc8728f88907145422e663da8368f56e22577bac59a5e864fe49c022062abc96c0fe83421393eac4f7c6908c041c4408fb089fcd7106af12646d707f10121033c4a91cd93240b1e51dbf73f4791f0ee9224ebcd3477992e4cb4d7b1e035a84e20179581e2e2e8abbaadf0231c52071e4f88588fccb78ad5afc0644f88011fa5d4514c616382012088c020c6de3217594af525fb57eaf1f2aae04c305ddc67d465edd325151685fc5a5e428876a914479eddda81b6ed289515f2dbcc95f05ce80dff466704fe03865eb17576a91498a67ed502adb04173d88fb1ef92d0317711c3816888ac // 240

The sigScript breaks down as:

// begin signatures and push data
48 // OP_DATA_72
30450221009fee36700ebcc8728f88907145422e663da8368f56e22577bac59a5e864fe49c022062abc96c0fe83421393eac4f7c6908c041c4408fb089fcd7106af12646d707f101 // sig
21 // OP_DATA_33
033c4a91cd93240b1e51dbf73f4791f0ee9224ebcd3477992e4cb4d7b1e035a84e // pubkey
20 // OP_DATA_32
179581e2e2e8abbaadf0231c52071e4f88588fccb78ad5afc0644f88011fa5d4 // secret
51 // OP_1
// begin serialized redeem script
4c61 // OP_PUSHDATA1 + 0x61 (push 97 data bytes)
6382012088c020c6de3217594af525fb57eaf1f2aae04c305ddc67d465edd325151685fc5a5e428876a914479eddda81b6ed289515f2dbcc95f05ce80dff466704fe03865eb17576a91498a67ed502adb04173d88fb1ef92d0317711c3816888ac // redeem script a.k.a. the contract

1+72(73 max)+1+33+1+32+1+2+97 = 240(241 max)

decodescript 6382012088c020c6de3217594af525fb57eaf1f2aae04c305ddc67d465edd325151685fc5a5e428876a914479eddda81b6ed289515f2dbcc95f05ce80dff466704fe03865eb17576a91498a67ed502adb04173d88fb1ef92d0317711c3816888ac
{
  "asm": "OP_IF OP_SIZE 20 OP_EQUALVERIFY OP_SHA256 c6de3217594af525fb57eaf1f2aae04c305ddc67d465edd325151685fc5a5e42 OP_EQUALVERIFY OP_DUP OP_HASH160 479eddda81b6ed289515f2dbcc95f05ce80dff46 OP_ELSE fe03865e OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 98a67ed502adb04173d88fb1ef92d0317711c381 OP_ENDIF OP_EQUALVERIFY OP_CHECKSIG",
  "type": "nonstandard",
  "p2sh": "TchUiUNfb96ji35N767BNesdKTe88KP35nf"
}

In this successful swap, the above script is executed with the push data (signature, pubkey, secret, op_1) prefixed as the final stage of P2SH redemption (after the script hash validation). The OP_ELSE portion of the redeem script is used for a refund by the creator with the pubkey corresponding to the pubkey hash 98a67ed502adb04173d88fb1ef92d0317711c381.

Opcode Reference

OP_0                   = 0x00 // 0
OP_FALSE               = 0x00 // 0 - AKA OP_0
OP_DATA_1              = 0x01 // 1
OP_DATA_2              = 0x02 // 2
...
OP_DATA_32             = 0x20 // 32
OP_DATA_33             = 0x21 // 33
...
OP_DATA_71             = 0x47 // 71
OP_DATA_72             = 0x48 // 72
OP_DATA_73             = 0x49 // 73
OP_DATA_74             = 0x4a // 74
OP_DATA_75             = 0x4b // 75 ^  if data (e.g. redeem script) is <76 bytes
OP_PUSHDATA1           = 0x4c // 76 <= if data is 76-255 bytes
OP_PUSHDATA2           = 0x4d // 77 <= if data is 256-65535 bytes
OP_PUSHDATA4           = 0x4e // 78
OP_1NEGATE             = 0x4f // 79
OP_1                   = 0x51 // 81 - AKA OP_TRUE
OP_TRUE                = 0x51 // 81
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment