Created
December 14, 2018 01:01
-
-
Save nscarlson/4106a606e7d609e8e1f29b204ce13f53 to your computer and use it in GitHub Desktop.
Derive btc segwit xpub from Ledger Nano
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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