<p>Since you can't traverse through hardened paths with xPubs ledger is displaying not the Master xpub but the xpub at the derivation address <code>84/0'/0'</code> or whatever your account number is. From there you need two additional derivations of 0/0 to get the final <code>84/0'/0'/0/0</code> public key.</p>
<p>The resulting public key can be used to derive either a P2PKH address (non-segwit) or a P2WPKH address (segwit). Xpub and Zpub are both encodings of the same key but Zpub additionally instructs the wallet to derive a P2WPKH address from it. Ledger doesn't make use of this standard and prefers to encode it with the more general Xpub encoding (which provides no instruction).</p>
<p>Using my <a href="https://github.com/mcdallas/cryptotools" rel="nofollow noreferrer">toy Python library</a> you can use the following script to derive your addresses:</p>
<pre><code>from cryptotools import Xpub

MY_XPUB = 'xpub-as-shown-in-ledger'

key = Xpub.decode(MY_XPUB)

pubkey0 = key/0/0
print(pubkey0.address('P2WPKH'))  # Tell the wallet that you want a P2WPKH address

</code></pre>
<p>if you want testnet addresses set the envvar CRYPTOTOOLS_NETWOK = 'test'</p>

CC BY-SA 4.0
2021-10-05T17:34:42.667Z
It worked like a charm! Thank you. I took a good look through the source code and I forked it as well. I understand that you have a disclaimer about security. Is there anything I should be aware of?
mike-a
CC BY-SA 4.0
2021-10-04T20:47:30.680Z
2021-10-04T20:47:30.680Z
Mike D
<p>Pycoin now supports segwit xpub after <a href="https://github.com/richardkiss/pycoin/commit/7180aa49878a5a189d99633c474138d547390c3d" rel="nofollow noreferrer">this commit</a>. It is able to parse xpub/ypub/zpub and derive addresses. Ledger is still using <a href="https://www.reddit.com/r/ledgerwallet/comments/o5ijg7/xpubypubzpub_correct_version_prefixes/" rel="nofollow noreferrer">incorrect prefix for segwit xpub</a> and you may have to convert the xpub to ypub/zpub appropriately</p>

CC BY-SA 4.0
2021-11-09T13:36:08.547Z
2021-11-09T13:36:08.547Z
dark knight
<h2>Summary</h2>
<p>I'm pulling my hair out trying to understand a couple of concepts. I would like to use a Segwit wallet in my Ledger Nano S to derive unhardened(?) child public keys (and thus segwit addresses) that match those that my Nano produces. I want to do this using Python 3. I believe creating an address like this is called a &quot;watch wallet&quot;, or at least it is described in the Bip32 docs like this:</p>
<blockquote>
<p>This permits for example a webshop business to let its webserver generate fresh addresses (public key hashes) for each order or for each customer, without giving the webserver access to the corresponding private keys (which are required for spending the received funds).
<a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Motivation" rel="nofollow noreferrer">https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Motivation</a></p>
</blockquote>
<p>This is precisely what I'm trying to do using Python for my Django application. I do not want to use a third party service as I'm told not to trust giving out my extended public key (xPub). I want to use the xPub from my Ledger Nano S. Actually, I'm not entirely sure if my Nano S uses an xpub or a zpub, but I have asked this in a separate question.</p>
<p><a href="https://bitcoin.stackexchange.com/questions/109977/does-ledger-nano-s-have-an-xpub-or-a-zpub-for-bitcoin-wallets">Does Ledger Nano S Have an xPub or a zPub for Bitcoin wallets?</a></p>
<p>Regardless, I have converted the &quot;xpub&quot; key to a &quot;zpub&quot; key and attempted to derive new keys from both using MANY different python modules and with zero success in creating an address that matches or even looks similar to that which my Nano produces.</p>
<h2>What I've Tried</h2>
<p>For the sake of eliminating answers that suggest methods I've already tried here is a complete and exhaustive list of every method I have tried, with links to all similar questions on Stack Exchange.</p>
<p>At first I tried <a href="https://github.com/btclib-org/btclib" rel="nofollow noreferrer">btclib</a> along with <a href="https://github.com/richardkiss/pycoin" rel="nofollow noreferrer">Pycoin</a>.</p>
<p>Note: in all examples I'm attempting to use the Bitcoin Testnet</p>
<pre><code>from btclib import bip32
from pycoin.networks.registry import network_for_netcode

network = network_for_netcode(&quot;XTN&quot;) # XTN for the Testnet, BTC for the Mainnet
xpub = &quot;x(z/t)pub-big-long-key-that-starts-with-tpub-zpub-xpub&quot;

child_xpub_key = bip32.derive(xpub, &quot;84'/1'/0'/0/0&quot;)
key = network.parse.bip32(child_xpub_key)

print(str(&quot;Key: {}&quot;).format(child_xpub_key))
print(str(&quot;Address: {}&quot;).format(key.address())) 
</code></pre>
<p>Similar to this question:
<a href="https://bitcoin.stackexchange.com/questions/100646/derive-public-key-from-xpub">Derive public key from xpub?</a>
I get an error using the &quot;hardened&quot; derivation path and in order for the error to go away I can only use the path 84/1/0/0/0. I have even tried path 0 and 0/0. Of course the path my Nano gives me includes the ('). From my understanding this derivation path is for zpub keys but even if I convert to zpub it doesn't give me an address that matches my Nano. I assume this is because I should be using Bip44 or Bip84 to derive addresses? Correct?</p>
<p>The next thing I attempted to use was <a href="https://github.com/ebellocchia/bip_utils" rel="nofollow noreferrer">bip_utils</a></p>
<pre><code>from bip_utils import Bip44, Bip44Coins
key_str = &quot;x(z/t)pub-big-long-key-that-starts-with-tpub-zpub-xpub&quot;
bip44_ctx = Bip44.FromExtendedKey(key_str, Bip44Coins.BITCOIN_TESTNET)
</code></pre>
<p>This code works, however the example code given at the bip_utils github page suggests that the next line of code should be:</p>
<pre><code># Derive account 0 for Bitcoin: m/44'/0'/0'
bip44_acc = bip44_ctx.Purpose().Coin().Account(0)
</code></pre>
<p>Which gives me the error</p>
<pre><code>Bip44DepthError: Current depth (3) is not suitable for deriving purpose
</code></pre>
<p>I already know that I don't want m/44'/0'/0' but the docs give no clue how to change the path and looking at the source code didn't help me either.</p>
<p>Then I tried using <a href="https://github.com/primal100/pybitcointools" rel="nofollow noreferrer">pybitcointools</a> by the famous Vitalik Buterin. He even has a part in the docs about &quot;watch wallets&quot;:</p>
<blockquote>
<p>For security reasons the seed and xprv should ideally be held in cold storage only. If a web application needs to be able to provide addresses on demand, the solution is to use a watch wallet, generated from the xpub. For example, let's take the Dash xpub from a previous example:</p>
</blockquote>
<pre><code>from cryptos import *
coin = Dash()
xpub = 'xpub-some-xpub-key'
wallet = coin.watch_wallet(xpub)
wallet.is_watching_only
wallet.new_receiving_address()
wallet.new_change_address()
</code></pre>
<p>I'm thinking &quot;this is it, Vitalik is my hero! He know's what I'm looking for!&quot; But NO, this sample code only works for Dash, apparently. When I change the class to Bitcoin(), none of the &quot;watch_wallet&quot; methods described in the docs work, or rather they don't exist. No where is an example of how to make this work with Bitcoin.</p>
<h2>Conclusion</h2>
<p>Of all the methods I tried, at least btclib didn't give me any errors. I could be using these python modules incorrectly or perhaps there is a better python module/class that I should be using. Any direction would be helpful. Thank you in advance.</p>

CC BY-SA 4.0
2021-11-09T13:41:50.890Z
You could do that with python-bip32 but you'd need to convert the whatever-pub to a proper xpub before, see https://github.com/darosior/python-bip32/pull/21. EDIT: actually you mentioned xpubs as well, in this case you can checkout the usage here https://github.com/darosior/python-bip32#usage
Antoine Poinsot
<segregated-witness><bip32-hd-wallets><python><xpub><pycoin>
Derive Segwit Addresses From xPub or zPub using PYTHON
mike-a
# Derive Segwit Addresses From xPub or zPub using PYTHON

(Asked by: username_0 on 2021-10-04)

## Summary

I'm pulling my hair out trying to understand a couple of concepts. I would like to use a Segwit wallet in my Ledger Nano S to derive unhardened(?) child public keys (and thus segwit addresses) that match those that my Nano produces. I want to do this using Python 3. I believe creating an address like this is called a "watch wallet", or at least it is described in the Bip32 docs like this:

> This permits for example a webshop business to let its webserver generate fresh addresses (public key hashes) for each order or for each customer, without giving the webserver access to the corresponding private keys (which are required for spending the received funds).
> <https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Motivation>

This is precisely what I'm trying to do using Python for my Django application. I do not want to use a third party service as I'm told not to trust giving out my extended public key (xPub). I want to use the xPub from my Ledger Nano S. Actually, I'm not entirely sure if my Nano S uses an xpub or a zpub, but I have asked this in a separate question.

[Does Ledger Nano S Have an xPub or a zPub for Bitcoin wallets?](https://bitcoin.stackexchange.com/questions/109977/does-ledger-nano-s-have-an-xpub-or-a-zpub-for-bitcoin-wallets)

Regardless, I have converted the "xpub" key to a "zpub" key and attempted to derive new keys from both using MANY different python modules and with zero success in creating an address that matches or even looks similar to that which my Nano produces.

## What I've Tried

For the sake of eliminating answers that suggest methods I've already tried here is a complete and exhaustive list of every method I have tried, with links to all similar questions on Stack Exchange.

At first I tried [btclib](https://github.com/btclib-org/btclib) along with [Pycoin](https://github.com/richardkiss/pycoin).

Note: in all examples I'm attempting to use the Bitcoin Testnet

```
from btclib import bip32
from pycoin.networks.registry import network_for_netcode

network = network_for_netcode("XTN") # XTN for the Testnet, BTC for the Mainnet
xpub = "x(z/t)pub-big-long-key-that-starts-with-tpub-zpub-xpub"

child_xpub_key = bip32.derive(xpub, "84'/1'/0'/0/0")
key = network.parse.bip32(child_xpub_key)

print(str("Key: {}").format(child_xpub_key))
print(str("Address: {}").format(key.address())) 

```

Similar to this question:
[Derive public key from xpub?](https://bitcoin.stackexchange.com/questions/100646/derive-public-key-from-xpub)
I get an error using the "hardened" derivation path and in order for the error to go away I can only use the path 84/1/0/0/0. I have even tried path 0 and 0/0. Of course the path my Nano gives me includes the ('). From my understanding this derivation path is for zpub keys but even if I convert to zpub it doesn't give me an address that matches my Nano. I assume this is because I should be using Bip44 or Bip84 to derive addresses? Correct?

The next thing I attempted to use was [bip\_utils](https://github.com/ebellocchia/bip_utils)

```
from bip_utils import Bip44, Bip44Coins
key_str = "x(z/t)pub-big-long-key-that-starts-with-tpub-zpub-xpub"
bip44_ctx = Bip44.FromExtendedKey(key_str, Bip44Coins.BITCOIN_TESTNET)

```

This code works, however the example code given at the bip\_utils github page suggests that the next line of code should be:

```
# Derive account 0 for Bitcoin: m/44'/0'/0'
bip44_acc = bip44_ctx.Purpose().Coin().Account(0)

```

Which gives me the error

```
Bip44DepthError: Current depth (3) is not suitable for deriving purpose

```

I already know that I don't want m/44'/0'/0' but the docs give no clue how to change the path and looking at the source code didn't help me either.

Then I tried using [pybitcointools](https://github.com/primal100/pybitcointools) by the famous Vitalik Buterin. He even has a part in the docs about "watch wallets":

> For security reasons the seed and xprv should ideally be held in cold storage only. If a web application needs to be able to provide addresses on demand, the solution is to use a watch wallet, generated from the xpub. For example, let's take the Dash xpub from a previous example:

```
from cryptos import *
coin = Dash()
xpub = 'xpub-some-xpub-key'
wallet = coin.watch_wallet(xpub)
wallet.is_watching_only
wallet.new_receiving_address()
wallet.new_change_address()

```

I'm thinking "this is it, Vitalik is my hero! He know's what I'm looking for!" But NO, this sample code only works for Dash, apparently. When I change the class to Bitcoin(), none of the "watch\_wallet" methods described in the docs work, or rather they don't exist. No where is an example of how to make this work with Bitcoin.

## Conclusion

Of all the methods I tried, at least btclib didn't give me any errors. I could be using these python modules incorrectly or perhaps there is a better python module/class that I should be using. Any direction would be helpful. Thank you in advance.

**Tags:** segregated-witness, bip32-hd-wallets, python, xpub, pycoin

> **Comments:**
> **username_1**: You could do that with python-bip32 but you'd need to convert the whatever-pub to a proper xpub before, see https://github.com/darosior/python-bip32/pull/21. EDIT: actually you mentioned xpubs as well, in this case you can checkout the usage here https://github.com/darosior/python-bip32#usage  

---

## 2 answers

### Answer by username_2 on 2021-10-04. Score: 1 | Accepted answer

Since you can't traverse through hardened paths with xPubs ledger is displaying not the Master xpub but the xpub at the derivation address `84/0'/0'` or whatever your account number is. From there you need two additional derivations of 0/0 to get the final `84/0'/0'/0/0` public key.

The resulting public key can be used to derive either a P2PKH address (non-segwit) or a P2WPKH address (segwit). Xpub and Zpub are both encodings of the same key but Zpub additionally instructs the wallet to derive a P2WPKH address from it. Ledger doesn't make use of this standard and prefers to encode it with the more general Xpub encoding (which provides no instruction).

Using my [toy Python library](https://github.com/mcdallas/cryptotools) you can use the following script to derive your addresses:

```
from cryptotools import Xpub

MY_XPUB = 'xpub-as-shown-in-ledger'

key = Xpub.decode(MY_XPUB)

pubkey0 = key/0/0
print(pubkey0.address('P2WPKH'))  # Tell the wallet that you want a P2WPKH address

```

if you want testnet addresses set the envvar CRYPTOTOOLS\_NETWOK = 'test'

> **Comments:**
> **username_0**: It worked like a charm! Thank you. I took a good look through the source code and I forked it as well. I understand that you have a disclaimer about security. Is there anything I should be aware of?  

---

### Answer by username_3 on 2021-11-09. Score: 0

Pycoin now supports segwit xpub after [this commit](https://github.com/richardkiss/pycoin/commit/7180aa49878a5a189d99633c474138d547390c3d). It is able to parse xpub/ypub/zpub and derive addresses. Ledger is still using [incorrect prefix for segwit xpub](https://www.reddit.com/r/ledgerwallet/comments/o5ijg7/xpubypubzpub_correct_version_prefixes/) and you may have to convert the xpub to ypub/zpub appropriately


---

