From 231fc7add924564460e432b80e9c32bc1dcda774 Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Sun, 6 Jan 2019 06:58:53 +0700 Subject: [PATCH] Initial commit --- .gitignore | 5 +++++ .travis.yml | 8 ++++++++ LICENSE | 21 +++++++++++++++++++++ README.md | 17 +++++++++++++++++ package.json | 39 +++++++++++++++++++++++++++++++++++++++ src/index.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/unit.js | 6 ++++++ 7 files changed, 146 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 package.json create mode 100644 src/index.js create mode 100644 test/unit.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fd69e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +.nyc_output +npm-debug.log +package-lock.json +yarn.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2bde09e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - '8' +script: npm test +after_success: npm run coverage +notifications: + email: + on_success: never diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a4daae1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Luke Childs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4eb938b --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# create-xpub + +> Create a BIP32 extended public key + +[![Build Status](https://travis-ci.com/lukechilds/create-xpub.svg?branch=master)](https://travis-ci.com/lukechilds/create-xpub) +[![Coverage Status](https://coveralls.io/repos/github/lukechilds/create-xpub/badge.svg?branch=master)](https://coveralls.io/github/lukechilds/create-xpub?branch=master) +[![npm](https://img.shields.io/npm/v/create-xpub.svg)](https://www.npmjs.com/package/create-xpub) + +## Install + +```shell +npm install create-xpub +``` + +## License + +MIT © Luke Childs diff --git a/package.json b/package.json new file mode 100644 index 0000000..fd6c773 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "create-xpub", + "version": "0.0.0", + "description": "Create a BIP32 extended public key", + "main": "src/index.js", + "engines": { + "node": ">=8" + }, + "scripts": { + "test": "xo && nyc ava", + "coverage": "nyc report --reporter=text-lcov | coveralls" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lukechilds/create-xpub.git" + }, + "keywords": [ + "xpub", + "bip32", + "bitcoin", + "cryptocurrency" + ], + "author": "Luke Childs (http://lukechilds.co.uk)", + "license": "MIT", + "bugs": { + "url": "https://github.com/lukechilds/create-xpub/issues" + }, + "homepage": "https://github.com/lukechilds/create-xpub#readme", + "devDependencies": { + "ava": "^0.25.0", + "coveralls": "^3.0.2", + "nyc": "^13.1.0", + "xo": "^0.23.0" + }, + "dependencies": { + "bs58check": "^2.1.2", + "hash.js": "^1.1.7" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..2aa4289 --- /dev/null +++ b/src/index.js @@ -0,0 +1,50 @@ +const bs58check = require('bs58check'); +const {sha256, ripemd160} = require('hash.js'); + +const XPUB = 0x0488B21E; + +const compressPublicKey = publicKey => { + if (publicKey.startsWith('02') || publicKey.startsWith('03')) { + return publicKey; + } + + const yIsEven = (parseInt(publicKey.slice(-2), 16) % 2 === 0); + + return (yIsEven ? '02' : '03') + publicKey.slice(2, 66); +}; + +const hash160 = buf => ripemd160().update( + sha256().update(buf).digest() +).digest(); + +const getPublicKeyFingerprint = publicKey => { + publicKey = Buffer.from(publicKey, 'hex'); + + const publicKeyHash = hash160(publicKey); + + return ( + ((publicKeyHash[0] << 24) | + (publicKeyHash[1] << 16) | + (publicKeyHash[2] << 8) | + publicKeyHash[3]) >>> + 0 + ); +}; + +const createXpub = ({network = XPUB, depth, childnum, chainCode, publicKey}) => { + publicKey = compressPublicKey(publicKey); + const fingerprint = getPublicKeyFingerprint(publicKey); + + const xpub = Buffer.from([ + 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 + ].join(''), 'hex'); + + return bs58check.encode(xpub); +}; + +module.exports = createXpub; diff --git a/test/unit.js b/test/unit.js new file mode 100644 index 0000000..40336a7 --- /dev/null +++ b/test/unit.js @@ -0,0 +1,6 @@ +import test from 'ava'; +import createXpub from '..'; + +test('createXpub is exported', t => { + t.not(createXpub, undefined); +});