bitcoinjs-lib icon indicating copy to clipboard operation
bitcoinjs-lib copied to clipboard

Can I parse a zpub key with this library and generate derived keys?

Open meglio opened this issue 2 years ago • 5 comments
trafficstars

Electrum wallet exports a zpub master public key. I need to generate derived public addresses from it. Can I do it with this library?

meglio avatar Mar 22 '23 04:03 meglio

I was just wondering the same. I'm looking at https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts#L16 and it seems the answer may be yes. I'll report back later.

KorbisInc avatar Aug 21 '23 15:08 KorbisInc

Same thing I am wondering. Any luck you had with it so far?

lopotras avatar Oct 10 '23 15:10 lopotras

Yes it's possible. You need to manipulate a particular part.

// Thank you https://github.com/bitcoinjs/bitcoinjs-lib/issues/1238#issuecomment-426880691
const fixNetworkVersionBytes = (xkey: string, network: bitcoin.Network): string => {
  let type = undefined;
  if (xkey.slice(1, 4) == "prv") type = "private";
  if (xkey.slice(1, 4) == "pub") type = "public";
  if (type === undefined) throw new Error("Bad xkey prefix");

  let data = bs58.decode(xkey);
  data = data.slice(4);
  data = Buffer.concat([Buffer.from((network.bip32 as any)[type].toString(16).padStart(8, '0'),'hex'), data]);
  return bs58.encode(data);
};

// Derive a new key-pair
const deriveBitcoinPrivateKey = (xprv: string, account: number, index: number, network: bitcoin.Network): string => {
  const node = bip32.fromBase58(fixNetworkVersionBytes(xprv, network), network);
  return node.derive(account).derive(index).toWIF();
};

KorbisInc avatar Oct 10 '23 16:10 KorbisInc

Beautiful, thank you. Espcially for the typescript example.

I've just found this one as well if that helps anyone any further: https://github.com/bitcoinjs/bitcoinjs-lib/issues/966#issuecomment-356346515

lopotras avatar Oct 10 '23 16:10 lopotras

For reference. an implementation that worked for me for deriving public addresses and making sure that it's not a private key that's used as input:

import * as bitcoinjs from 'bitcoinjs-lib';
import * as ecc from 'tiny-secp256k1';
import b58 from 'bs58check';
import BIP32Factory from 'bip32';

const bip32 = BIP32Factory(ecc);

const fixNetworkVersionBytes = (mpk: string, network: bitcoinjs.Network): string => {
  let type = undefined;
  if (mpk.slice(1, 4) == "pub") type = "public";
  if (type === undefined) throw new Error("Bad MPK prefix");

  let data = b58.decode(mpk);
  data = data.slice(4);
  data = Buffer.concat([Buffer.from((network.bip32 as any)[type].toString(16).padStart(8, '0'),'hex'), data]);
  return b58.encode(data);
};

const deriveBitcoinNativeSegWitAddress = (mpk: string, index: number, network: bitcoinjs.Network): string => {
  const node = bip32.fromBase58(fixNetworkVersionBytes(mpk, network), network);
  const child = node.derive(0).derive(index);
  return bitcoinjs.payments.p2wpkh({ pubkey: child.publicKey, network }).address!;
};

Thanks for the help @LeeKorbisCa

I believe this was the original question.

lopotras avatar Oct 11 '23 12:10 lopotras

These are the examples

https://github.com/bitcoinjs/bitcoinjs-lib/blob/1f92ada3fda587c1c0a6aa93649afa04e8382b93/test/integration/bip32.spec.ts

const bitcoin = require("bitcoinjs-lib");
const ecc = require("tiny-secp256k1");
const { BIP32Factory } = require("bip32");
const bip32 = BIP32Factory(ecc);
const b58 = require("bs58check");

function convert_z(z) {
  let data = b58.decode(z);
  data = data.slice(4);
  data = Buffer.concat([Buffer.from("0488b21e", "hex"), data]);
  return b58.encode(data);
}

const xpub = convert_z("YOUR ZPUB HERE");
const node = bip32.fromBase58(xpub).derivePath("0/0");
const address = bitcoin.payments.p2wpkh({ pubkey: node.publicKey }).address;

I took that function from someone here I can't find that.

vim-wesley avatar Apr 16 '24 21:04 vim-wesley