<p>I'm not sure about ruby, but here's what's happening in practice.</p>
<p>Take any xpub:</p>
<pre><code>xpub6DBfkACRRWo6B9Fo31Ko6P7M92Yb3rdbuXb81Ls7aDCaZsMr1tyvZWHAHz1exRZuTBspafkPTynwoWL5o3i4WiJX4P3SyGQxNpxQLaUnB2c
</code></pre>
<p>Decoded to hex:</p>
<pre><code>0488b21e03d0888900800000002a2c58c384bf2904e3b251fe5367e21f8acd97f94481709207c7487b9aec159a022ff4a6a6d463c3aadc35366346580f5f95085912d0910c178d2c3d33774ff700a10d285d
</code></pre>
<p>Notice the first 8 characters in the above hex version <code>0488b21e</code>. What you need to do is replace those 8 characters with the version bytes you want and then re-encode back to base58.</p>
<p>For example, if we want to do zpub<code>04b24746</code> we'd change the hex string to:</p>
<pre><code>04b2474603d0888900800000002a2c58c384bf2904e3b251fe5367e21f8acd97f94481709207c7487b9aec159a022ff4a6a6d463c3aadc35366346580f5f95085912d0910c178d2c3d33774ff700a10d285d
</code></pre>
<p>Re-encode to b58:</p>
<pre><code>zpub6rrCMVYFist3sje2hiu3WZJMUxqUw6cbjkdZa8etLDxLg4zJXDK3odbSLPvpxEskGU7S5cwWPJW3a5ZDESY67Bfio4SJ963vvH5h7jFyqw2
</code></pre>
<p>That's it! Regarding the checksum issue see answer: <a href="https://bitcoin.stackexchange.com/a/98816/26873">https://bitcoin.stackexchange.com/a/98816/26873</a></p>
<p>IT IS IMPORTANT to note the account derivation path is already baked into your original extended public key. So let's say you have an ypub that uses BIP49 derivation path, BIP49 will remain even if you change it to xpub, or a zpub. If you're looking to change to BIP84 you need to start from the seed, then derive the path m/84'/0'/0'/0, then change it to a zpub. Simply changing from xpub to ypub or zpub does not change the derivation path.</p>

CC BY-SA 4.0
2021-03-14T21:43:01.997Z
cool thanks, that's what I understood and I can convert it in js and python but not with the ruby library... There isn't much support of Bitcoin adresses in Ruby, I think I'll dive into the technical details to understand where it fails.
jblanche
CC BY-SA 4.0
2021-03-13T16:17:03.010Z
2021-03-13T16:17:03.010Z
m1xolyd1an
<p>I'm looking to convert a Bitcoin extended public key from one format to another in Ruby.<br />
In JS I've found <a href="https://github.com/jlopp/xpub-converter/blob/master/js/xpubConvert.js" rel="nofollow noreferrer">https://github.com/jlopp/xpub-converter/blob/master/js/xpubConvert.js</a> and Python <a href="https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin.rb" rel="nofollow noreferrer">https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin.rb</a>, from which I try to understand how it works.</p>
<p>But in Ruby I can't wrap my head around it. I use the <a href="https://www.rubydoc.info/gems/bitcoin-ruby/Bitcoin/Util" rel="nofollow noreferrer">Bitcoin::Util</a> and my code is as follows:</p>
<pre><code>require 'bitcoin'

include Bitcoin::Util

xpub = 'xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz'
prefixes = {
  xpub: '0488b21e',
  ypub: '049d7cb2',
  zpub: '04b24746'
}

decoded_key = decode_base58(xpub)
zpub_key = encode_base58(prefixes[:zpub] + decoded_key[8..])

puts zpub_key # =&gt; zpub6r8o2p9croV2A7Gh2VZn42iEEv7QCxJrXyqWDUcV7aMapn2nY464gJKzfFTs2Ry4UnCFT1pmvSru6u1KX4GyRs2ti4SYydbtH17TgCSRAgQ
puts base58_checksum?(zpub_key) # =&gt; false

</code></pre>
<p>The checksum is invalid and I don't understand how to make it work</p>

<public-key><xpub><base58><ruby><base58check>
How to convert xpub ypub and zpub in Ruby
jblanche
# How to convert xpub ypub and zpub in Ruby

(Asked by: username_0 on 2021-03-12)

I'm looking to convert a Bitcoin extended public key from one format to another in Ruby.  
In JS I've found <https://github.com/jlopp/xpub-converter/blob/master/js/xpubConvert.js> and Python <https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin.rb>, from which I try to understand how it works.

But in Ruby I can't wrap my head around it. I use the [Bitcoin::Util](https://www.rubydoc.info/gems/bitcoin-ruby/Bitcoin/Util) and my code is as follows:

```
require 'bitcoin'

include Bitcoin::Util

xpub = 'xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz'
prefixes = {
  xpub: '0488b21e',
  ypub: '049d7cb2',
  zpub: '04b24746'
}

decoded_key = decode_base58(xpub)
zpub_key = encode_base58(prefixes[:zpub] + decoded_key[8..])

puts zpub_key # => zpub6r8o2p9croV2A7Gh2VZn42iEEv7QCxJrXyqWDUcV7aMapn2nY464gJKzfFTs2Ry4UnCFT1pmvSru6u1KX4GyRs2ti4SYydbtH17TgCSRAgQ
puts base58_checksum?(zpub_key) # => false

```

The checksum is invalid and I don't understand how to make it work

**Tags:** public-key, xpub, base58, ruby, base58check


---

## 1 answers

### Answer by username_1 on 2021-03-13. Score: 2

I'm not sure about ruby, but here's what's happening in practice.

Take any xpub:

```
xpub6DBfkACRRWo6B9Fo31Ko6P7M92Yb3rdbuXb81Ls7aDCaZsMr1tyvZWHAHz1exRZuTBspafkPTynwoWL5o3i4WiJX4P3SyGQxNpxQLaUnB2c

```

Decoded to hex:

```
0488b21e03d0888900800000002a2c58c384bf2904e3b251fe5367e21f8acd97f94481709207c7487b9aec159a022ff4a6a6d463c3aadc35366346580f5f95085912d0910c178d2c3d33774ff700a10d285d

```

Notice the first 8 characters in the above hex version `0488b21e`. What you need to do is replace those 8 characters with the version bytes you want and then re-encode back to base58.

For example, if we want to do zpub`04b24746` we'd change the hex string to:

```
04b2474603d0888900800000002a2c58c384bf2904e3b251fe5367e21f8acd97f94481709207c7487b9aec159a022ff4a6a6d463c3aadc35366346580f5f95085912d0910c178d2c3d33774ff700a10d285d

```

Re-encode to b58:

```
zpub6rrCMVYFist3sje2hiu3WZJMUxqUw6cbjkdZa8etLDxLg4zJXDK3odbSLPvpxEskGU7S5cwWPJW3a5ZDESY67Bfio4SJ963vvH5h7jFyqw2

```

That's it! Regarding the checksum issue see answer: <https://bitcoin.stackexchange.com/a/98816/26873>

IT IS IMPORTANT to note the account derivation path is already baked into your original extended public key. So let's say you have an ypub that uses BIP49 derivation path, BIP49 will remain even if you change it to xpub, or a zpub. If you're looking to change to BIP84 you need to start from the seed, then derive the path m/84'/0'/0'/0, then change it to a zpub. Simply changing from xpub to ypub or zpub does not change the derivation path.

> **Comments:**
> **username_0**: cool thanks, that's what I understood and I can convert it in js and python but not with the ruby library... There isn't much support of Bitcoin adresses in Ruby, I think I'll dive into the technical details to understand where it fails.  

---

