<p>P2PKH, P2SH, and Segwit are all different address types. Segwit and P2SH addresses are not the same.</p>

<p>P2PKH and P2SH addresses are generated in a similar way. P2PKH takes the hash160 of a public key (RIPMED160 of the SHA256 of the public key), appends the version byte of <code>0x00</code> to the hash160, and Base58 Check encodes it.</p>

<p>P2SH addresses are the Base58 Check encoding of the hash160 of a script (known as the redeemScript). It uses a version byte of <code>0x05</code> instead. The rest of the encoding is the same, just Base58 Check encoding.</p>

<p>For Segwit addresses, there are multiple types. There are native segwit addresses which follow the Bech32 standard. There are also P2SH wrapped segwit addresses.</p>

<p>For a P2WPKH (pay to witness pubkey hash) wrapped in a P2SH address, the redeemScript is <code>0x0014 &lt;hash 160 of the pubkey&gt;</code>. That redeemScript is hashed  and encoded in the typical P2SH way.</p>

<p>For a P2WSH (pay to witness script hash) wrapped in a P2SH address, the witnessScript (redeemScript but for segwit addresses) is first hashed with SHA256. Then the P2SH redeemScript is <code>0x0020 &lt;SHA256 of witnessScript&gt;</code>. The hash160 of this redeemScript is then encoded in the typical P2SH way.</p>

<hr>

<p>As for your code, you are appending <code>0x04</code> to your public key which is simply incorrect. The <code>0x04</code> is not part of the address encoding, it is part of the public key encoding itself. Your public key generator should already be doing this for you. Note that if the public key is compressed that the prefix byte will be either <code>0x02</code> or <code>0x03</code> (depends on the Y value of the public key) instead of <code>0x04</code> which is for uncompressed public keys.</p>

<hr>

<p>[Technical difference - Example solution]</p>

<p>`</p>

<pre><code>    def hash160(self, v):
        r = hashlib.new('ripemd160')
        r.update(hashlib.sha256(v).digest())
        return r


    def doublehash256(self, v):
        return hashlib.sha256(hashlib.sha256(v).digest())


    def ecdsaSECP256k1(self, digest):
        # SECP256k1 - Bitcoin elliptic curve 
        sk = ecdsa.SigningKey.from_string(digest, curve=ecdsa.SECP256k1)                    
        return sk.get_verifying_key()

   def publicaddress1(self):

        prefix_a = b'\x04'
        prefix_b = b'\x00'

        digest = self.privkeyhex.digest()

        p = prefix_a + self.ecdsaSECP256k1(digest).to_string() # 1 + 32 bytes + 32 bytes
        self.pubkey = str(binascii.hexlify(p).decode('utf-8'))

        hash160 = self.hash160(p)

        m = prefix_b + hash160.digest()
        checksum = self.doublehash256(m).digest()[:4]        

        self.pubaddr1 = base58.b58encode(m + checksum)                  


    def publicaddress3(self):

        prefix_even = b'\x02'
        prefix_odd = b'\x03'
        prefix_a = prefix_odd
        prefix_b = b'\x05'
        prefix_redeem = b'\x00\x14'


        digest = self.privkeyhex.digest()

        ecdsa_digest = self.ecdsaSECP256k1(digest).to_string()

        x_coord = ecdsa_digest[:int(len(ecdsa_digest)/2)]
        y_coord = ecdsa_digest[int(len(ecdsa_digest)/2):]            

        if (int(binascii.hexlify(y_coord),16) % 2 == 0): prefix_a = prefix_even

        p = prefix_a + x_coord

        self.pubkeycompressed = str(binascii.hexlify(p).decode('utf-8'))


        redeem_script = self.hash160(prefix_redeem + self.hash160(p).digest()).digest() # 20 bytes

        m = prefix_b + redeem_script
        checksum = self.doublehash256(m).digest()[:4]        

        self.pubaddr3 = base58.b58encode(m + checksum)`
</code></pre>

CC BY-SA 4.0
2018-05-16T16:23:55.563Z
Thank you for your help. So basically i am missing the part where i need to feed a compressed wif private key and to check for the Y value after. The problem now is that the ECDSA is expecting a 32bytes input digest and if i decode base58 compressed WIF  51bytes + x01 and feed into ECDSA is gives me this error:     `assert len(string) == curve.baselen, (len(string), curve.baselen)
AssertionError: (38, 32)` it is expecting a 32 byte size. Should i just input the digest of the private key like the classic P2PKH? I will jump into the Y value part meanwhile.. Thanks a lot.
fortesp
CC BY-SA 4.0
2018-05-16T16:32:02.030Z
Your WIF decoding sounds like it is wrong. You should get a 34 byte object. The first byte is the version number, and the last byte indicates compressedness, but is only relevant to WIF. You should drop those two bytes and you will have a 32 byte object that is the private key. Handling public key compression happens later, so you need to have something else remember whether the public key is compressed or not.
Ava Chow
CC BY-SA 4.0
2018-05-16T21:20:26.197Z
Thank you. What i was missing was the separation of the digest (coordinates) in 32 bytes each. The rest was easy to implement. Going to put the solution up..
fortesp
CC BY-SA 4.0
2018-05-14T05:40:18.887Z
2018-05-16T22:01:02.463Z
2018-05-16T22:01:02.463Z
Ava Chow
<p>Segwit inside P2SH:</p>

<pre><code>redeem_script = hash160(b'\x00\x14' + hash160(public_key))
</code></pre>

<p>0x00 -> Witness version, 0x14 -> 20(or 32)bytes push opcode</p>

<p><code>prefix = b'\x05'</code> -> P2SH main net</p>

<pre><code>checksum = double_sha256(prefix + redeem_script)[:4]
address = base58(prefix + redeem_script + checksum)
</code></pre>

CC BY-SA 4.0
2018-05-13T18:58:54.990Z
Thanks for your help! I notice that those steps are basically what they have here https://bitcoincore.org/en/segwit_wallet_dev/ ? Not able to understand a few things. Where do you get that hash160 function? Are you refering to the ripemd160 ? Are those snipets placed after generating a x00 or in replace of? I don't really understand also what they mention by "the public key used in P2SH-P2WPKH MUST be compressed i.e. 33 bytes in size, and starting with a 0x02 or 0x03"..
fortesp
CC BY-SA 4.0
2018-05-14T09:07:46.160Z
@fortesp hash160(x) is ripemd160(sha256(x)). You can find more information on what a compressed public key is here https://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key
Mike D
CC BY-SA 4.0
2018-05-12T19:27:51.743Z
2018-05-12T19:27:51.743Z
bitaps.com
<p>I  was convinced that the only difference between the generation of addresses starting with '1' and '3' was simply changing the prefix added to the digest from 0x00 to 0x05 after the ripemd160 part. </p>

<p>Although the addresses that i get do not match the addresses from Bitcoin Core wallet, when import the same private key, and also from the <a href="https://segwitaddress.org/" rel="nofollow noreferrer">https://segwitaddress.org/</a>. 
Does the prefix 04 remains the same or also changes? 
There's something i am missing. Could you please help? Thank you.</p>

<p>[EDIT]</p>

<p>This is the method i have at the moment and still does not work. I am surely misinterpreting something..</p>

<pre><code>def getPublicAddress(self, digest):

    oSk = ecdsa.SigningKey.from_string(digest, curve=ecdsa.SECP256k1)                    
    oVk = oSk.get_verifying_key()

    hexlify = codecs.getencoder('hex')             
    self.pubkey = str(hexlify(b'\04' + oVk.to_string())[0].decode('utf-8'))

    ripemd160 = hashlib.new('ripemd160')
    keyhash = hashlib.sha256(codecs.decode(self.pubkey, "hex")).digest()
    ripemd160.update(keyhash)


    redeem_script = hashlib.new('ripemd160')
    redeem_script.update(b'\x00\x14' + ripemd160.digest())

    prefix = b'\x05' 
    m = prefix + redeem_script.digest()
    checksum = hashlib.sha256(hashlib.sha256(m).digest()).digest()[:4]        

    return base58.b58encode(m + checksum)
</code></pre>

<segregated-witness><ecdsa><p2sh><p2pkh>
Bitcoin - Technical difference between P2PKH and P2SH address generation?
fortesp
# Bitcoin - Technical difference between P2PKH and P2SH address generation?

(Asked by: username_0 on 2018-05-12)

I was convinced that the only difference between the generation of addresses starting with '1' and '3' was simply changing the prefix added to the digest from 0x00 to 0x05 after the ripemd160 part.

Although the addresses that i get do not match the addresses from Bitcoin Core wallet, when import the same private key, and also from the <https://segwitaddress.org/>.
Does the prefix 04 remains the same or also changes?
There's something i am missing. Could you please help? Thank you.

[EDIT]

This is the method i have at the moment and still does not work. I am surely misinterpreting something..

```
def getPublicAddress(self, digest):

    oSk = ecdsa.SigningKey.from_string(digest, curve=ecdsa.SECP256k1)                    
    oVk = oSk.get_verifying_key()

    hexlify = codecs.getencoder('hex')             
    self.pubkey = str(hexlify(b'\04' + oVk.to_string())[0].decode('utf-8'))

    ripemd160 = hashlib.new('ripemd160')
    keyhash = hashlib.sha256(codecs.decode(self.pubkey, "hex")).digest()
    ripemd160.update(keyhash)

    redeem_script = hashlib.new('ripemd160')
    redeem_script.update(b'\x00\x14' + ripemd160.digest())

    prefix = b'\x05' 
    m = prefix + redeem_script.digest()
    checksum = hashlib.sha256(hashlib.sha256(m).digest()).digest()[:4]        

    return base58.b58encode(m + checksum)

```

**Tags:** segregated-witness, ecdsa, p2sh, p2pkh


---

## 2 answers

### Answer by username_1 on 2018-05-14. Score: 1 | Accepted answer

P2PKH, P2SH, and Segwit are all different address types. Segwit and P2SH addresses are not the same.

P2PKH and P2SH addresses are generated in a similar way. P2PKH takes the hash160 of a public key (RIPMED160 of the SHA256 of the public key), appends the version byte of `0x00` to the hash160, and Base58 Check encodes it.

P2SH addresses are the Base58 Check encoding of the hash160 of a script (known as the redeemScript). It uses a version byte of `0x05` instead. The rest of the encoding is the same, just Base58 Check encoding.

For Segwit addresses, there are multiple types. There are native segwit addresses which follow the Bech32 standard. There are also P2SH wrapped segwit addresses.

For a P2WPKH (pay to witness pubkey hash) wrapped in a P2SH address, the redeemScript is `0x0014 <hash 160 of the pubkey>`. That redeemScript is hashed and encoded in the typical P2SH way.

For a P2WSH (pay to witness script hash) wrapped in a P2SH address, the witnessScript (redeemScript but for segwit addresses) is first hashed with SHA256. Then the P2SH redeemScript is `0x0020 <SHA256 of witnessScript>`. The hash160 of this redeemScript is then encoded in the typical P2SH way.

---

As for your code, you are appending `0x04` to your public key which is simply incorrect. The `0x04` is not part of the address encoding, it is part of the public key encoding itself. Your public key generator should already be doing this for you. Note that if the public key is compressed that the prefix byte will be either `0x02` or `0x03` (depends on the Y value of the public key) instead of `0x04` which is for uncompressed public keys.

---

[Technical difference - Example solution]

`

```
    def hash160(self, v):
        r = hashlib.new('ripemd160')
        r.update(hashlib.sha256(v).digest())
        return r

    def doublehash256(self, v):
        return hashlib.sha256(hashlib.sha256(v).digest())

    def ecdsaSECP256k1(self, digest):
        # SECP256k1 - Bitcoin elliptic curve 
        sk = ecdsa.SigningKey.from_string(digest, curve=ecdsa.SECP256k1)                    
        return sk.get_verifying_key()

   def publicaddress1(self):

        prefix_a = b'\x04'
        prefix_b = b'\x00'

        digest = self.privkeyhex.digest()

        p = prefix_a + self.ecdsaSECP256k1(digest).to_string() # 1 + 32 bytes + 32 bytes
        self.pubkey = str(binascii.hexlify(p).decode('utf-8'))

        hash160 = self.hash160(p)

        m = prefix_b + hash160.digest()
        checksum = self.doublehash256(m).digest()[:4]        

        self.pubaddr1 = base58.b58encode(m + checksum)                  

    def publicaddress3(self):

        prefix_even = b'\x02'
        prefix_odd = b'\x03'
        prefix_a = prefix_odd
        prefix_b = b'\x05'
        prefix_redeem = b'\x00\x14'

        digest = self.privkeyhex.digest()

        ecdsa_digest = self.ecdsaSECP256k1(digest).to_string()

        x_coord = ecdsa_digest[:int(len(ecdsa_digest)/2)]
        y_coord = ecdsa_digest[int(len(ecdsa_digest)/2):]            

        if (int(binascii.hexlify(y_coord),16) % 2 == 0): prefix_a = prefix_even

        p = prefix_a + x_coord

        self.pubkeycompressed = str(binascii.hexlify(p).decode('utf-8'))

        redeem_script = self.hash160(prefix_redeem + self.hash160(p).digest()).digest() # 20 bytes

        m = prefix_b + redeem_script
        checksum = self.doublehash256(m).digest()[:4]        

        self.pubaddr3 = base58.b58encode(m + checksum)`

```

> **Comments:**
> **username_0**: Thank you for your help. So basically i am missing the part where i need to feed a compressed wif private key and to check for the Y value after. The problem now is that the ECDSA is expecting a 32bytes input digest and if i decode base58 compressed WIF  51bytes + x01 and feed into ECDSA is gives me this error:     `assert len(string) == curve.baselen, (len(string), curve.baselen) AssertionError: (38, 32)` it is expecting a 32 byte size. Should i just input the digest of the private key like the classic P2PKH? I will jump into the Y value part meanwhile.. Thanks a lot.  
> **username_1**: Your WIF decoding sounds like it is wrong. You should get a 34 byte object. The first byte is the version number, and the last byte indicates compressedness, but is only relevant to WIF. You should drop those two bytes and you will have a 32 byte object that is the private key. Handling public key compression happens later, so you need to have something else remember whether the public key is compressed or not.  
> **username_0**: Thank you. What i was missing was the separation of the digest (coordinates) in 32 bytes each. The rest was easy to implement. Going to put the solution up..  

---

### Answer by username_2 on 2018-05-12. Score: 0

Segwit inside P2SH:

```
redeem_script = hash160(b'\x00\x14' + hash160(public_key))

```

0x00 -> Witness version, 0x14 -> 20(or 32)bytes push opcode

`prefix = b'\x05'` -> P2SH main net

```
checksum = double_sha256(prefix + redeem_script)[:4]
address = base58(prefix + redeem_script + checksum)

```

> **Comments:**
> **username_0**: Thanks for your help! I notice that those steps are basically what they have here https://bitcoincore.org/en/segwit_wallet_dev/ ? Not able to understand a few things. Where do you get that hash160 function? Are you refering to the ripemd160 ? Are those snipets placed after generating a x00 or in replace of? I don't really understand also what they mention by "the public key used in P2SH-P2WPKH MUST be compressed i.e. 33 bytes in size, and starting with a 0x02 or 0x03"..  
> **username_3**: @username_0 hash160(x) is ripemd160(sha256(x)). You can find more information on what a compressed public key is here https://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key  

---

