Skip to content

Instantly share code, notes, and snippets.

@nscarlson
Created December 14, 2018 01:01
Show Gist options
  • Save nscarlson/4106a606e7d609e8e1f29b204ce13f53 to your computer and use it in GitHub Desktop.
Save nscarlson/4106a606e7d609e8e1f29b204ce13f53 to your computer and use it in GitHub Desktop.
Derive btc segwit xpub from Ledger Nano
import '@babel/polyfill'
import bitcoin from 'bitcoinjs-lib'
import bs58check from 'bs58check'
import Bitcoin from '@ledgerhq/hw-app-btc'
import Transport from '@ledgerhq/hw-transport-u2f'
const getCompressPublicKey = (publicKey) => {
let compressedKeyIndex
if (parseInt(publicKey.substring(128, 130), 16) % 2 !== 0) {
compressedKeyIndex = '03'
} else {
compressedKeyIndex = '02'
}
const result = compressedKeyIndex + publicKey.substring(2, 66)
return result
}
const createXpub = ({
depth,
fingerprint,
childnum,
chainCode,
publicKey,
network,
}) => {
const array = [
network.toString(16).padStart(8, '0'),
depth.toString(16).padStart(2, '0'),
fingerprint.toString(16).padStart(8, '0'),
childnum.toString(16).padStart(8, '0'),
chainCode,
publicKey,
]
return array.join('')
}
const getXpub58 = ({ node, account, fingerprint, network }) => {
const { publicKey, chainCode } = node
const compressPublicKey = getCompressPublicKey(publicKey)
const childnum = (0x80000000 | account) >>> 0
const xpub = createXpub({
depth: 3,
fingerprint,
childnum,
chainCode,
publicKey: compressPublicKey,
network,
})
const xpub58 = bs58check.encode(Buffer.from(parseHexString(xpub)))
return xpub58
}
function parseHexString(str) {
const result = []
while (str.length >= 2) {
result.push(parseInt(str.substring(0, 2), 16))
str = str.substring(2, str.length)
}
return result
}
const getFingerprint = ({ publicKey }) => {
let result = bitcoin.crypto.ripemd160(
bitcoin.crypto.sha256(
new Uint8Array(parseHexString(getCompressPublicKey(publicKey))),
),
)
return (
((result[0] << 24) |
(result[1] << 16) |
(result[2] << 8) |
result[3]) >>>
0
)
}
const connect = async () => {
try {
const transport = await Transport.open(null)
await transport.setExchangeTimeout(5000) // 5 seconds
const btc = new Bitcoin(transport)
const node = await btc.getWalletPublicKey("m/49'/0'/0'")
const fingerprint = getFingerprint({ publicKey: node.publicKey })
const xpub = getXpub58({
node,
fingerprint,
account: 0,
network: 0x0488b21e,
})
console.log('xpub:', xpub)
} catch (err) {
throw err
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment