As a developer who prefers documentation I've always liked these step-by-step guides with actual values that could also be used in tests. Since my previous topic on the subject (Bech32 P2WPKH addresses)[1] was bumped I thought about creating a new one here maybe it could help other developers spend less time trying to understand how it works or for debugging their code,...
Read more about details in[2].
Pre-requirementA P2SH address is the human readable form of a pay-to-script-hash pubkey script and as the name suggests it is a payment to hash of a script. In other words in order to create a P2SH address all we need is a script. This script can be anything from an empty script or a single OP code to complex smart contracts. You usually see it as a multi-signature redeem script (OP_m Pub1 Pub2 ... Pubn OP_n OP_CheckMultiSig).
In a P2SH-P2WPKH address this script is a special redeem script created by using the hash of the public key.
Steps for creating a P2SH-P2WPKH address:1. Having a compressed[3] public key (0x02 or 0x03 followed by 32 byte X coordinate):
02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c
2. Compute SHA-256 hash of the public key:
fecf7bb8fef0756dedfaf16fcdbe7b38f15a1edf29a621ad6c9189c24f0ce959
3. Compute RIPEMD-160 hash of the result of SHA-256:
d9351dcbad5b8f3b8bfa2f2cdc85c28118ca9326
4. Build the redeem script that is
OP_0 PushData0014d9351dcbad5b8f3b8bfa2f2cdc85c28118ca9326
(This redeem script also goes in signature script of a transaction while spending)
Now we use the script from step 4 to create the address (the following steps are similar to creating a P2SH address for a multi-signature redeem script)5. Compute SHA-256 of the script (step 4)
1ecdf8533accbb86c5d264adfa0d9af869a37386b9e8733b55bef753db486981
6. Compute RIPEMD-160 hash of the result of step 5
7db6766dce18d816eaac1198391e8bdcf70b253a
7. Add P2SH version byte at the beginning of the result from step 6 and encode the result using Base-58 encoding with a checksum[4][5]
057db6766dce18d816eaac1198391e8bdcf70b253a
=> Final result
3D9iyFHi1Zs9KoyynUfrL82rGhJfYTfSG4
How about P2SH-P2WSH?It is very similar to this but instead of starting from a public key we start from having a "script" (step 1) and instead of 2 hashes (step 2 and 3) only one hash is performed on it and that is a single SHA-256. The rest is the same.
1.
OP_1 PushData(02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c) PushData(02588d202afcc1ee4ab5254c7847ec25b9a135bbda0f2bc69ee1a714749fd77dc9) OP_2 OP_CheckMultiSig
512102d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c2102588d202afcc1ee4ab5254c7847ec25b9a135bbda0f2bc69ee1a714749fd77dc952ae
2&3. A single SHA256
773ab29f89711d3211ced9978c70539c2f078e3e1e83c985c6b24f6f7c4ba917
4. Build the redeem script that is OP_0 PushData
0020773ab29f89711d3211ced9978c70539c2f078e3e1e83c985c6b24f6f7c4ba917
5. Compute SHA-256 of the script (step 4)
8f61e1b2eb81d5176379bdab2bd7075c6de384a4b01fac6976f9913a2dbd94b5
6. Compute RIPEMD-160 hash of the result of step 5
87cff96494678aaf63d568dcec99e125b4455619
7. Add P2SH version byte at the beginning of the result from step 6 and encode the result using Base-58 encoding with a checksum
3E58HjvumxkQVk9KeY9Kw69pfBSEDPnmEd
[1] Step by step guide to go from public key to a Bech32 encoded address
[2] https://bitcoincore.org/en/segwit_wallet_dev/
[3] Using uncompressed public keys would make the script non-standard and will practically lead to fund loss
[4] https://en.bitcoin.it/wiki/List_of_address_prefixes
[5] https://en.bitcoin.it/wiki/Base58Check_encoding