hsd
Version:
Cryptocurrency bike-shed
141 lines (107 loc) • 2.87 kB
JavaScript
/*!
* common.js - common functions for hd
* Copyright (c) 2017-2018, Christopher Jeffrey (MIT License).
* https://github.com/handshake-org/hsd
*/
;
const assert = require('bsert');
const LRU = require('blru');
const common = exports;
/** @typedef {import('./private')} HDPrivateKey */
/** @typedef {import('./public')} HDPublicKey */
/**
* Index at which hardening begins.
* @const {Number}
* @default
*/
common.HARDENED = 0x80000000;
/**
* Min entropy bits.
* @const {Number}
* @default
*/
common.MIN_ENTROPY = 128;
/**
* Max entropy bits.
* @const {Number}
* @default
*/
common.MAX_ENTROPY = 512;
/**
* LRU cache to avoid deriving keys twice.
* @type {LRU<String, HDPublicKey|HDPrivateKey>}
*/
common.cache = new LRU(500);
/**
* Parse a derivation path and return an array of indexes.
* @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
* @param {String} path
* @param {Boolean} hard
* @returns {Number[]}
*/
common.parsePath = function parsePath(path, hard) {
assert(typeof path === 'string');
assert(typeof hard === 'boolean');
assert(path.length >= 1);
assert(path.length <= 3062);
const parts = path.split('/');
const root = parts[0];
if (root !== 'm'
&& root !== 'M'
&& root !== 'm\''
&& root !== 'M\'') {
throw new Error('Invalid path root.');
}
const result = [];
for (let i = 1; i < parts.length; i++) {
let part = parts[i];
const hardened = part[part.length - 1] === '\'';
if (hardened)
part = part.slice(0, -1);
if (part.length > 10)
throw new Error('Path index too large.');
if (!/^\d+$/.test(part))
throw new Error('Path index is non-numeric.');
let index = parseInt(part, 10);
if ((index >>> 0) !== index)
throw new Error('Path index out of range.');
if (hardened) {
index |= common.HARDENED;
index >>>= 0;
}
if (!hard && (index & common.HARDENED))
throw new Error('Path index cannot be hardened.');
result.push(index);
}
return result;
};
/**
* Test whether the key is a master key.
* @param {HDPrivateKey|HDPublicKey} key
* @returns {Boolean}
*/
common.isMaster = function isMaster(key) {
return key.depth === 0
&& key.childIndex === 0
&& key.parentFingerPrint === 0;
};
/**
* Test whether the key is (most likely) a BIP44 account key.
* @param {HDPrivateKey|HDPublicKey} key
* @param {Number?} [account]
* @returns {Boolean}
*/
common.isAccount = function isAccount(key, account) {
if (account != null) {
const index = (common.HARDENED | account) >>> 0;
if (key.childIndex !== index)
return false;
}
return key.depth === 3 && (key.childIndex & common.HARDENED) !== 0;
};
/**
* A compressed pubkey of all zeroes.
* @const {Buffer}
* @default
*/
common.ZERO_KEY = Buffer.alloc(33, 0x00);