Author

Topic: Generating and using P2SH-wrapped-P2WPKH Bitcoin addresses [Tutorial] (Read 723 times)

legendary
Activity: 2618
Merit: 6452
Self-proclaimed Genius
Sorry, wanted to ask. How to distinguish compressed and uncompressed bitcoin addresses?  Huh
For P2PKH, you can't.
The HASH160 will have the same length whether it's derived from uncompressed or compressed public key.

For the topic's examples,
SegWit addresses must be from compressed public key to be standard, else, they wont be able to spend it without the help of a miner that accepts non-standard txns.
So you can assume that most SegWit addresses are based from compressed pubKey.
But there are some cases that it's from uncompressed like this one: https://bitcointalksearch.org/topic/1-btc-bounty-5192454
full member
Activity: 161
Merit: 168
Based on a the single public key from your example I'm able to generate 4 addresses:

Legacy, P2PKH based on non-compressed public key:
1PbEeZisCqZFZvwEY5fnkjMP2R3BLbKJm8

Legacy, P2PKH based on compressed public key
1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu

P2SH wrapped P2WPKH
35PLQyoXs2sk9QDqMv7bBGowxP1pjwXAMe

Bech32 Segwit:
bc1q49afqkyzjstaf3vp44gqfdhydnrgqp3aa4n7m3

Is this a complete list or am I missing something?


These 4 addresses can be generated directly with the CoinAddresGenerator.  https://github.com/MrMaxweII/Bitcoin-Address-Generator


legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
Do you have any idea how many "anyone can spent" outputs there have been in history like the one you linked where it always pushes a 1 to the stack at the end?
No, I haven't done any research in that area, actually I didn't know that address was used before either.
Here is another one on TestNet though: 2MyHxGtCH53AhhWTzqwRRCq3MUZ5DahmhRi
sr. member
Activity: 310
Merit: 727
---------> 1231006505
Thanks, for the link. Very informative!

Do you have any idea how many "anyone can spent" outputs there have been in history like the one you linked where it always pushes a 1 to the stack at the end?
legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
Is this a complete list or am I missing something?
If you think of "addresses" as human readable form of certain scripts then you'll see that there really isn't any cap to the number of addresses you can create, of course some may make no sense and some may be non-standard but for the sake of technical discussion here are some examples:
P2SH-P2PK: 33SjdVkpGHBENVKtYCEDtk4RmAPK7kvJUA
P2SH-P2PKH: 3LyehHxt2uq83FJz9EudBEVQR8mgtsPg8D
P2SH-1of1MultiSig: 3Ly4mSGMWhXq9KTXMnUvwy5rHoLoFBKYq9
P2SH-(locktime): 37TUHj9a2T7ip3m23Z5jX6YHJShZBRoHYv (locktime= e359de5e)
P2WSH(locktime): bc1q7le8nq4pem836mn702n3svx9q82wps9nv3rxhgh69eh2cl84ewrsv6f8t2 (locktime= e359de5e)
...
And here is an address that anyone can spend from: 3MaB7QVq3k4pQx3BhsvEADgzQonLSBwMdj
As an exercise try to guess redeem script of each of the above addresses.
Here is the code I used to create these: https://gist.github.com/Coding-Enthusiast/5e58b3ddc2161c853562bc483beddf69
sr. member
Activity: 310
Merit: 727
---------> 1231006505
Based on a the single public key from your example I'm able to generate 4 addresses:

Legacy, P2PKH based on non-compressed public key:
1PbEeZisCqZFZvwEY5fnkjMP2R3BLbKJm8

Legacy, P2PKH based on compressed public key
1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu

P2SH wrapped P2WPKH
35PLQyoXs2sk9QDqMv7bBGowxP1pjwXAMe

Bech32 Segwit:
bc1q49afqkyzjstaf3vp44gqfdhydnrgqp3aa4n7m3

Is this a complete list or am I missing something?
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
9. Have fun and stay safe with your new "3-addresses"!
Is that address safe? You own the private key that corresponds to this address, but will all wallets generate the same address? AFAIK, trying to send any transactions to this address may not appear in your wallet, and therefore it will not be easy for you to spend.
Have you tried importing them in serval wallets? Especially with the Blockchain Info API/wallet[1]


What is the difference between the first part and the use of https://www.bitaddress.org/?


[1] https://gist.github.com/matthewdowney/998e6cfc750d286b3e2cca1aac7ca0ed

Yes, they are as safe as can be. One compressed private key (starts with K or L) corresponds to exactly one P2SH-wrapped-P2WPKH address.

If you're not convinced feel free to try (BUT DO NOT USE THIS EXAMPLE FOR AS A SERIOUS ACCOUNT)

Code:
Hex: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Private key compressed (WIF): KwFvTne98E1t3mTNAr8pKx67eUzFJWdSNPqPSfxMEtrueW7PcQzL
Compressed legacy address: 1M8Qk46ERsPrEtWLBRSET5NUH2Ck5wwREU
P2SH-P2WPKH address: 31khcn4aNFxMdvcVUCHj8Z1u1A7CqBqyAr

In Bitcoin Core, in the console just type: importprivkey "KwFvTne98E1t3mTNAr8pKx67eUzFJWdSNPqPSfxMEtrueW7PcQzL" "my-test-key"
and it should give you 31khcn4aNFxMdvcVUCHj8Z1u1A7CqBqyAr

In Electrum, which is much faster for testing, simply import private key (including the prefix!) "p2wpkh-p2sh:KwFvTne98E1t3mTNAr8pKx67eUzFJWdSNPqPSfxMEtrueW7PcQzL" and it should show you the public address 31khcn4aNFxMdvcVUCHj8Z1u1A7CqBqyAr

As for addresses from bitaddress.org, well.... if you use their script offline, you'll get the same result. I would personally discourage from generating or using private keys online. My script runs offline. (And no, it's not unique in any way, I just figured it was nice with a step-by-step explanation of the process.

"Why bother with segwit addresses at all?" is a valid question. A short answer would be: much lower transaction fees.

For your information, I have a new script for converting from legacy (1....) to bech32 too, i.e. "bc1..."-addresses, will post it here if people are interested.

We good?
legendary
Activity: 2702
Merit: 4002
9. Have fun and stay safe with your new "3-addresses"!
Is that address safe? You own the private key that corresponds to this address, but will all wallets generate the same address? AFAIK, trying to send any transactions to this address may not appear in your wallet, and therefore it will not be easy for you to spend.
Have you tried importing them in serval wallets? Especially with the Blockchain Info API/wallet[1]


What is the difference between the first part and the use of https://www.bitaddress.org/?


[1] https://gist.github.com/matthewdowney/998e6cfc750d286b3e2cca1aac7ca0ed
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
... and here goes the same script, but in Python, which is orders of magnitude faster than bash.

For one simple calculation, you won't notice any speed difference, but for batch conversions, changing over to Python makes all the difference.

Python is a rather picky language, and getting every step to work took some trial and error. Converting back and forth between hexadecimal strings and binary outputs when hashing is, in my opinion, the trickiest part.

Nevertheless, here it is confirmed fully functional; feel free to copy and paste (relevant parts of) it into your own scripts and applications. Enjoy!

Code:
#!/usr/bin/python

import hashlib
import binascii
import base58

pubadd = '1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu' #Must be a COMPRESSED legacy address!
output1 = binascii.hexlify(base58.b58decode_check(pubadd))[2:]
output2 = hashlib.sha256(binascii.a2b_hex('0014'+output1)).hexdigest()
output3 = hashlib.new('ripemd160', binascii.a2b_hex(output2)).hexdigest()
newadd = base58.b58encode_check(binascii.a2b_hex('05'+output3))
print '\n\n'
print '======================================================================'
print 'Legacy/P2PKH address:               '+pubadd
print 'P2SH-P2WPKH  address:               '+newadd
print '======================================================================'
print '\n\n'


copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
Thank you for your kind feedback! I corrected a spelling mistake that two of you noticed (and a few more that you haven't complained about yet Smiley )

I would like to add a few things:

Firstly, there are a number of users who ask about P2SH-P2WPKH Bitcoin addresses in Electrum specifically, and I showed you how easy such addresses can be imported with the "p2wpkh-p2sh:" prefix.

Secondly, I demonstrated how easy it is in simple bash to take a compressed legacy Bitcoin address, and convert it into its P2SH-P2WPKH "twin" address; wrapped up and controlled by the same private key. And what's even cooler is that you don't even need the private key in the process; just start at step 4 with your legacy address.

Thirdly, I should for the sake of clarity mention that even though these addresses are "twins", it is only the holder of the private key who can know this. Therefore, live and on the blockchain, 1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu and 35PLQyoXs2sk9QDqMv7bBGowxP1pjwXAMe are treated as two separate entities without any known connections between them. (No, you cannot send coins to the legacy address and spend them with the P2SH-P2WPKH address - or the other way around - they are completely separated.)

Fourthly, I will keep calling these "pseudo-segwit" addresses, since the script is only 2 bytes long and more importantly: they are controlled by one (1) and not several private keys; there is no segregation, in my opinion. Not a big deal, technicalities.  

Fifthly, maybe I should have summarized the steps into one bash script, so here we go. You only need to change the string pubadd to your own, to derive the corresponding P2SH-P2WPKH address. A word of caution before you try it! This script will accept uncompressed legacy addresses (there is no way to test compression in a script with the public address as the only input) and thus create dysfunctional P2SH-P2WPKH addresses. In fact, this proof-of-concept script contains no error checking at all; your scripts should have. Use only with compressed legacy addresses!

Code:
#!/bin/bash

pubadd="1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu" #Must be a COMPRESSED legacy address!
output1=$(echo -n "$pubadd" | base58 -d | xxd -p | cut -c3-42)
output2=$(echo -n "0014"+"$output1" | xxd -r -p | openssl sha256 | tail -c65)
output3=$(echo -n "$output2" | xxd -r -p | openssl ripemd160 | tail -c41)
newadd=$(echo -n "05"+"$output3" | xxd -r -p | base58 -c)

echo -e "\n\n"
echo "======================================================================"
echo "Legacy/P2PKH address:               $pubadd"
echo "P2SH-P2WPKH  address:               $newadd"
echo "======================================================================"
echo -e "\n\n"


P.S. Of course, you can skip all of this and let your wallet handle it, as suggested. But then you will learn nothing new. Also, you must trust your wallet software entirely. After all, this is the Development & Technical Discussion.
legendary
Activity: 2618
Merit: 6452
Self-proclaimed Genius
If you want to use Bitcoin Core instead, the command you are looking for is
Code:
importmulti
It's simpler to use importprivkey:
Code:
importprivkey "Private_Key" "Label"
Current version will derive all of the address types from the imported private key (if compressed).

But the simplest method (if the user will use Core) was already suggested by HCP that will skip the whole process in the OP.
Because why not?
legendary
Activity: 3472
Merit: 10611
"pseudo-segwit"
you can't call them that because "pseudo" means "not real" and there is nothing unreal about these scripts. they are still a real SegWit script but it is wrapped inside a hash (in P2SH) so they don't show the type of the script until spent.

Quote
For the record, they are always compressed (legacy Bitcoin addresses may be both uncompressed and compressed; others have written in length about that).
and for the record they can use any type of public key there is which happens to be 3 types! compressed, uncompressed and hybrid. but since almost all the bitcoin network is bitcoin core nodes and by default (without an option to change this) they use certain standard rules, they will reject any pubkeys that are not compressed.

Quote
What do you think of this guide?
it was good but i think before you start a topic like this you have to think about whom you want to be your audience. right now the guide seems to be confused between two groups.
if it is for regular users then it is not at all a good idea to use this method. regular users must choose a wallet and with minimal effort (eg. clicking a button or selecting from a dropdown list) set their desired address type.
if it is for developers then focusing too much on commands and using a certain library (eg. Open SSL) is not good. it must be generalized and only steps and results of those steps must be written. also certain steps are extra such as creating a random key or converting it to a WIF. they are off-topic here.
HCP
legendary
Activity: 2086
Merit: 4363
Or, if you're going to end using Bitcoin Core anyway... you can save yourself a lot of hassle and simply use the Bitcoin Core console/cli and do: getnewaddress "" "p2sh-segwit" and it will automagically create a new P2SH-P2WPKH address for you. Tongue


ps. there was a slight typo in your 3rd paragraph:
A P2SH-wrapped-P2WPKH Bitcoin address is a pseudo*-segmented witness (segwit) address
Should be "segregated witness".

Otherwise a comprehensive guide.
copper member
Activity: 193
Merit: 255
Click "+Merit" top-right corner
If you need "a new Bitcoin address that begins with a 3", and want to know how to create them relatively fast and use them safely, then this is for you.

You need access to a Linux machine, such as a desktop or laptop computer running Ubuntu or some other common distribution, or an online or offline virtual machine. (If someone wants to translate this to Windows, be my guest.)

A P2SH-wrapped-P2WPKH Bitcoin address is a pseudo*-segregated witness (segwit) address, in other words, a Bitcoin address beginning with a "3", compared to legacy addresses (a.k.a P2PKH addresses) that always begin with a "1". They are sometimes referred to as "wrapped". Example (DO NOT USE THESE EXACT ADDRESSES SINCE THEIR PRIVATE KEY IS EXPOSED; YOU WILL BE ROBBED):

Code:
Legacy/P2PKH address: 1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu
P2SH-wrapped-P2WPKH address: 35PLQyoXs2sk9QDqMv7bBGowxP1pjwXAMe
Private key (for controlling both): KzLvnctuw7tMdg5hv1NXj4X515rbweDsgoyigtDgGgsqV9dW2kNo

Until P2SH-wrapped-P2WPKH addresses and spent from, they are indistinguishable from "real" segwit addresses, but as with legacy addresses they rely on only one (1) private key, which I why I call them "pseudo-segwit". For the record, they are always compressed (legacy Bitcoin addresses may be both uncompressed and compressed; others have written in length about that).

P2SH-wrapped-P2WPKH Bitcoin addresses several advantages over legacy addresses, such as low transaction fees, but also several considerations. Even though it is not absolutely necessary, I recommend that you take a few minutes and read up on the basics. Two decent starting point are:

https://bitcoincore.org/en/segwit_wallet_dev/
https://medium.com/@buddhasource/bitcoin-legacy-vs-segwit-wallet-address-what-is-the-difference-cb2e71ab8381

According to numerous sources, it is extremely easy to create and use P2SH-wrapped-P2WPKH Bitcoin addresses, but I couldn't find a simple step-by-step guide, so here we go. I'm looking forward to hearing your feedback!

GUIDE (the code is not explained in depth)

1. You need to is to create a safe 32-byte private key. There are a million different articles, scripts, codes, and so forth published about this topic. The shortest possible version is that you need to produce 32 bytes that are as close to true randomness as possible. This can actually be achieved with only one line of code (yes, it is considered safe, google it):

Code:
openssl rand -hex 32

an example output is (again - do NOT re-use my example numbers)

Code:
5d399c02e9642adb56a334b69898032747edbac8e038c6ba7adbc658bf3f53d9

2. You must convert these 32 bytes (here in hexadecimal format) into its corresponding compressed Bitcoin private key. There are many tools for this; one of my personal favorites is (avoid online conversion tools, you NEVER want to expose your private key on a webpage):

https://github.com/matja/bitcoin-tool

and the command is (using the numbers generated in step 1)

Code:
./bitcoin-tool --input-type private-key --input-format hex --output-type private-key-wif --output-format base58check --network bitcoin --public-key-compression compressed --input  5d399c02e9642adb56a334b69898032747edbac8e038c6ba7adbc658bf3f53d9

which will output the private key (guard your real private keys with your life)

Code:
KzLvnctuw7tMdg5hv1NXj4X515rbweDsgoyigtDgGgsqV9dW2kNo

3. You need to find out the corresponding legacy public address. This can be achieved in many ways, such as importing the private key into a wallet (more on that later), but for now, let's stick to code and use the same tool again, so that

Code:
./bitcoin-tool --input-type private-key --input-format hex --output-type address --output-format base58check --network bitcoin --public-key-compression compressed --input 5d399c02e9642adb56a334b69898032747edbac8e038c6ba7adbc658bf3f53d9

which will output

Code:
1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu

4. A public Bitcoin address is, such as the one above, base58check-encoded (google it), and in order to move on, we need to convert it to RIPEMD-160 (a.k.a. Hash160). This too can be achieved with a single line of code (using the public key from the step above):

Code:
echo -n '1GT82JgvX7WDtwHzRMRg2xGi6v5hGoJbDu' | base58 -d | xxd -p | cut -c3-42

which will output

Code:
a97a9058829417d4c581ad5004b6e46cc680063d

5. We now have everything we need to convert this to a P2SH-wrapped-P2WPKH address. First, we need to add a certain prefix and produce a single SHA256 hash of the combination (using the numbers from above):

Code:
echo '0014'+'a97a9058829417d4c581ad5004b6e46cc680063d' | xxd -r -p | openssl sha256 | tail -c65

which will output
Code:
15d62f464163bb0f6edafd421b83356fef88682b727a1e318ce633ccf1651d4d

6. The above SHA256 hash needs to be hashed once with RIPEMD-160, so:

Code:
echo '15d62f464163bb0f6edafd421b83356fef88682b727a1e318ce633ccf1651d4d' | xxd -r -p | openssl ripemd160 | tail -c41

will output

Code:
288873634ae24a3c9b6792cc7e2a084ec79ef68b

7. Hang in there, we now need to pad this with another prefix, using the numbers from above, and convert all of it to base58check (the &&-part may be omitted, but it is there to create a nice linebreak in the terminal):

Code:
echo '05'+'288873634ae24a3c9b6792cc7e2a084ec79ef68b' | xxd -r -p | base58 -c && echo ''

which will output

Code:
35PLQyoXs2sk9QDqMv7bBGowxP1pjwXAMe

And what do you know, there is your new and super-safe P2SH-wrapped-P2WPKH Bitcoin address!

8. You may now use your new P2SH-wrapped-P2WPKH Bitcoin keypair

Code:
35PLQyoXs2sk9QDqMv7bBGowxP1pjwXAMe
KzLvnctuw7tMdg5hv1NXj4X515rbweDsgoyigtDgGgsqV9dW2kNo

in all wallet software and online wallets that support segwit (all of them in 2020?). Tell people to fill your new "3-address" to the rim!

I personally like Electrum: https://electrum.org/

Create a new wallet, on the second page choose "Import Bitcoin address or private keys" and in order to get it working in this splendid wallet, you need to specify a prefix, so enter

Code:
p2wpkh-p2sh:KzLvnctuw7tMdg5hv1NXj4X515rbweDsgoyigtDgGgsqV9dW2kNo

and click "Next". When all is complete, move over to the address tab, right-click and show private key, and you should see your new address and its private key like so:



If you want to use Bitcoin Core instead, the command you are looking for is

Code:
importmulti

More information here: https://bitcoincore.org/en/doc/0.18.0/rpc/wallet/importmulti/

9. Have fun and stay safe with your new "3-addresses"!

In summary

I was surprised not to find a tutorial like this online. I hope you liked it and will find it useful. It should be really straight-forward to turn all of the above into a bash script (or python, if you're cocky). In fact, please do!

Remember: Never use private keys found online, especially not from educational examples like this, and never submit your private keys to online conversion tools (most of them exist to scam you). All of the above can and should be performed offline.

What do you think of this guide?
Jump to: