blockkeeper / blockkeeper-frontend-web

blockkeeper.io - Your blockchain book keeping app
GNU General Public License v3.0
25 stars 12 forks source link

Add ypub and zpub support #38

Closed stepansnigirev closed 6 years ago

stepansnigirev commented 6 years ago

It would be nice to have ypub/zpub support as it is commonly used in Trezor and electrum wallets. Bitcoinjs-lib doesn't support it but these types of keys are different from xpubs only by a prefix.

Unfortunately, I am not a javascript programmer and I don't know the architecture of the project, so I can't really create a reasonable pull request, but I can provide a function that converts ypub, zpub and all other stuff to standard xpub keys using bitcoinjs-lib.

const bitcoin = require('bitcoinjs-lib');
const bs58check = require('bs58check');

/* ypub and zpub are not standard, it is an extension of the bip32 created by Trezor team
 * and adopted by the community. Currently, it has a pretty wide support in multiple wallets
 * including electrum. The only difference comparing to xpub is a prefix, but as it is
 * a base58 encoded string with a checksum, checksum is also different
 *
 * The easiest way to fix it is to decode from base58check, replace the prefix to 
 * standard xpub or tpub and then to encode back to base58check. Then one can use this xpub
 * as normal bip32 master key.
 *
 * It may make sense to remember the type of the public key as it tells what type of script
 * is used in the wallet.
 * 
 */

const pub_types = [
    // mainnet
    '0488b21e', // xpub
    '049d7cb2', // ypub
    '04b24746', // zpub
    '0295b43f', // Ypub
    '02aa7ed3', // Zpub
]
const xpub = Buffer.from('0488b21e','hex');

function to_xpub(pub){
    // decoded from base58check
    const payload = bs58check.decode(pub);
    // prefix
    const version = payload.slice(0,4);
    // key
    const key = payload.slice(4);
    if(!pub_types.includes(version.toString('hex'))){
        throw new Error('prefix is not supported')
    }
    // converting to xpub that bitcoinjs-lib understands
    let buf = Buffer.concat([xpub, key]);
    return bs58check.encode(buf);
}

const examples = [ 
    "ypub6YrkQpbFR2Mu9xGKc2pTd7RyGHTdJ4P9DSBkEegM9yu3Txrv92gE8ezF9NoL7ZVZCo1ZUpPN9RsuSEYwrNAzBDPBTvCEjNSuoWtbjLQqUNg",
    "zpub6saSr7EjQkNXMPVpAv7LQwRHLRvNsQAh7JeQKDTsKbYtfpohL1LtY8eJ4YBwXGYe6WcxFKZzWvS5tbC9f38PA3aJJYwTdri1voaYUEgra6A",
];

examples.forEach( pub => {
    // master public key:
    console.log("\n\nOriginal: " + pub);

    // converting to standard xpub:
    let normalized_pub = to_xpub(pub);
    console.log(normalized_pub);

    // and here is an HD wallet:
    hd = bitcoin.HDNode.fromBase58(normalized_pub);
    console.log(hd);
})

References

DanielSanW commented 6 years ago

https://jlopp.github.io/xpub-converter/ this might also be helpful when introducing extended keys for bitcoin testnet.

d3ck-org commented 6 years ago

Done. Tests are welcome :)