0

I'm having troubles with understanding how script hash is computed in P2SH transactions.

From BIP-16 documentation (https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki):

scriptSig: [signature] {[pubkey] OP_CHECKSIG}
scriptPubKey: OP_HASH160 [20-byte-hash of {[pubkey] OP_CHECKSIG} ] OP_EQUAL

From Bitcoin Wiki (https://en.bitcoin.it/wiki/Script#Crypto):

OP_HASH160 ... The input is hashed twice: first with SHA-256 and then with RIPEMD-160.

So I've tried to compute script hash from a real transaction. I've randomly chosen this one: https://blockstream.info/tx/00e07f279dd05b9b68c40f21b43c57847e75c35cd3bbc2d80921eb037ef0c9a8?expand.

Next, I will be talking about input 0. I believe that the hash, which I'm supposed to get is

4bf411df4b0004e00006f88a4f83d127195b88c7

And the thing, that I'm supposed to hash is

5221036c3735b2bf370501c3b872498de54b39ab5afa83d8ce7f6aec43f63a812265b421032b03a42faf387dd5c604435cd48d26b8827fa28a5d4d0f9a18b5cefe443bb4102102ebbd4ecea67dd980fc4854cc13b1f10cefafdafe8b1eb8e5ce73939b59a0477c53ae

, as this is hex of the redeem script.

But when I compute HASH160, I get

94b1c88916b7c784b896be91b6924f15c2d4a344

, which is not, what I expect..

SHA256(5221036c3735b2bf370501c3b872498de54b39ab5afa83d8ce7f6aec43f63a812265b421032b03a42faf387dd5c604435cd48d26b8827fa28a5d4d0f9a18b5cefe443bb4102102ebbd4ecea67dd980fc4854cc13b1f10cefafdafe8b1eb8e5ce73939b59a0477c53ae) = a77da07651b8445cc38ff5bb96e1e38977c4efdcc21b767ca3e25b8919514e03

RIPEMD160(a77da07651b8445cc38ff5bb96e1e38977c4efdcc21b767ca3e25b8919514e03) = 94b1c88916b7c784b896be91b6924f15c2d4a344

Please explain to me, where is the mistake and what should I do instead. Am I mistaking in what should be hashed and what the result should be, or am I just computing SHA256 and RIPEMD160 wrong?

Good luck, 0x309.

PS: To compute hashes I run echo"..." | openssl sha256, then I copy the hash (so that there is no "(stdin)= ") and run echo "..." | openssl rmd160.

6
  • 2
    Are you hashing the SHA256 output in hex notation? You need to convert it back to binary first before feeding to ripemd160. Commented Jun 30, 2022 at 12:58
  • @PieterWuille, I don't really understand in what format openssl expects inputs and outputs. Is that ASCII? If yes, then I guess that's not what I need. How do I hash it right?
    – user135349
    Commented Jun 30, 2022 at 13:05
  • 1
    openssl hashes the input as provided in bytes, but outputs the hash encoded in hexadecimal. So if you do what you're doing, it's not hashing the 32-byte SHA256 output itself, but the 64-character hex encoding of the SHA256 output. Commented Jun 30, 2022 at 13:06
  • @PieterWuille, what do you mean by "as provided in bytes"? It has to somehow represent the input string anyway.. And I believe, that representation is not in hex, as ``` echo "hello" | openssl sha256 ``` will work. So how do I specify, that what I'm feeding openssl with is in hex?
    – user135349
    Commented Jun 30, 2022 at 13:25
  • 2
    openssl reads from stdin bytes to hash. You're giving it (in both invocations) hex-encoded bytes. So when you're giving it input "9ac7", you really want to give it byte 0x9a followed by byte 0xc7 instead. A possibility is feeding it through xxd -r -p which will do this conversion for you. Commented Jun 30, 2022 at 14:18

1 Answer 1

1

I've been computing hash wrong. Right way to do it:

echo "hex-encoded script" | xxd -r -p | openssl sha256 | sed "s/[^ ]* //" | xxd -r -p | openssl rmd160

Or in a more elegant way:

echo "hex-encoded script" | xxd -r -p | openssl sha256 --binary | openssl rmd160

Look at the question's comment section, if you are interested why so.

Good luck, 0x309.

PS: you might need to use openssl rmd160 -provider legacy

2
  • If you do the first hash with openssl sha256 -binary you don't need the sed and (second) xxd. Also in some shells instead of piping echo you can do xxd -p -r <<<thehexstring. Commented Jul 3, 2022 at 7:30
  • Thank you for your note @dave_thompson_085! You are right. Added your way to the answer.
    – user135349
    Commented Jul 4, 2022 at 10:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.