1

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 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

1 Answer 1

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 zpub04b24746 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.

2
  • 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
    Commented Mar 14, 2021 at 21:43
  • Where is python link? You have mentioned 2 links in question: JS and Ruby
    – user103136
    Commented Mar 21, 2021 at 18:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.