Created
August 14, 2019 18:11
-
-
Save learntheropes/eedfa2e658851463e3bb379014d7c1a6 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 { map, compose, dropLast, last, length } from 'ramda' | |
import { crypto, HDNode } from 'bitcoinjs-lib' | |
import * as BIP32 from 'bip32' | |
import BIP39 from 'bip39' | |
import Transport from "@ledgerhq/hw-transport-node-hid" | |
import AppBtc from "@ledgerhq/hw-app-btc" | |
import * as bippath from 'bip32-path' | |
const mnemonic = 'deer scout bonus forward rubber rate embrace street tragic know wife tongue photo stool rival century cruise inspire cinnamon before sudden include strong flip' | |
export const compressPublicKey = publicKey => { | |
let prefix = (publicKey[64] & 1) !== 0 ? 0x03 : 0x02 | |
let prefixBuffer = Buffer.alloc(1) | |
prefixBuffer[0] = prefix | |
return Buffer.concat([prefixBuffer, publicKey.slice(1, 1 + 32)]) | |
} | |
export const fingerprint = publickey => { | |
let pkh = compose(crypto.ripemd160, crypto.sha256)(publickey) | |
return ((pkh[0] << 24) | (pkh[1] << 16) | (pkh[2] << 8) | pkh[3]) >>> 0 | |
} | |
const getParentPath = | |
compose( | |
array => bippath.fromPathArray(array).toString(), | |
dropLast(1), | |
path => bippath.fromString(path).toPathArray() | |
) | |
const createXPUB = (path, child, parent) => { | |
let pathArray = bippath.fromString(path).toPathArray() | |
let pkChild = compressPublicKey(Buffer.from(child.publicKey, 'hex')) | |
let pkParent = compressPublicKey(Buffer.from(parent.publicKey, 'hex')) | |
let hdnode = BIP32.fromPublicKey(pkChild, Buffer.from(child.chainCode, 'hex')) | |
hdnode.parentFingerprint = fingerprint(pkParent) | |
hdnode.depth = pathArray.length | |
hdnode.index = last(pathArray) | |
return hdnode.toBase58() | |
} | |
const getXPUB = async (ledger, path) => { | |
let parentPath = getParentPath(path) | |
let child = await ledger.getWalletPublicKey(path) | |
let parent = await ledger.getWalletPublicKey(parentPath) | |
return createXPUB(path, child, parent) | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
const testXPUB = (mnemonic, i) => { | |
// assume bitcoin mainnet for the exercise | |
let seed = BIP39.mnemonicToSeed(mnemonic) | |
let masterNode = HDNode.fromSeedBuffer(seed) | |
return masterNode.deriveHardened(44) | |
.deriveHardened(0) | |
.deriveHardened(i) | |
.neutered() | |
.toBase58() | |
} | |
const connect = async (ledger) => { | |
let transport = await Transport.create() | |
let btc = new AppBtc(transport) | |
return btc | |
} | |
const main = async () => { | |
let ledger = await connect() | |
let xpub = await getXPUB(ledger, "44'/0'/0'") | |
console.log('expected XPUB: ', testXPUB(mnemonic, 0)) | |
console.log('created XPUB: ', xpub) | |
} | |
// IT REQUIRES YOUR LEDGER CONNECTED WITH YOUR BTC APP RUNNING | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment