UNPKG

@ecash/lib

Version:

Library for eCash transaction building

148 lines 4.89 kB
"use strict"; // Copyright (c) 2025 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. Object.defineProperty(exports, "__esModule", { value: true }); exports.HdNode = void 0; const hmac_js_1 = require("./hmac.js"); const hash_js_1 = require("./hash.js"); const bytes_js_1 = require("./io/bytes.js"); const str_js_1 = require("./io/str.js"); const writerbytes_js_1 = require("./io/writerbytes.js"); const HIGHEST_BIT = 0x80000000; class HdNode { constructor(params) { this._ecc = params.ecc; this._seckey = params.seckey; this._pubkey = params.pubkey; this._chainCode = params.chainCode; this._depth = params.depth; this._index = params.index; this._parentFingerprint = params.parentFingerprint; } seckey() { return this._seckey; } pubkey() { return this._pubkey; } pkh() { return (0, hash_js_1.shaRmd160)(this._pubkey); } fingerprint() { return this.pkh().slice(0, 4); } index() { return this._index; } depth() { return this._depth; } parentFingerprint() { return this._parentFingerprint; } chainCode() { return this._chainCode; } derive(index) { const isHardened = index >= HIGHEST_BIT; const data = new writerbytes_js_1.WriterBytes(1 + 32 + 4); if (isHardened) { if (this._seckey === undefined) { throw new Error('Missing private key for hardened child key'); } data.putU8(0); data.putBytes(this._seckey); } else { data.putBytes(this._pubkey); } data.putU32(index, 'BE'); const hashed = (0, hmac_js_1.hmacSha512)(this._chainCode, data.data); const hashedLeft = hashed.slice(0, 32); const hashedRight = hashed.slice(32); // In case the secret key doesn't lie on the curve, we proceed with the // next index. This is astronomically unlikely but part of the specification. if (!this._ecc.isValidSeckey(hashedLeft)) { return this.derive(index + 1); } let seckey; let pubkey; if (this._seckey !== undefined) { try { seckey = this._ecc.seckeyAdd(this._seckey, hashedLeft); } catch (ex) { console.log('Skipping index', index, ':', ex); return this.derive(index + 1); } pubkey = this._ecc.derivePubkey(seckey); } else { try { pubkey = this._ecc.pubkeyAdd(this._pubkey, hashedLeft); } catch (ex) { console.log('Skipping index', index, ':', ex); return this.derive(index + 1); } seckey = undefined; } return new HdNode({ ecc: this._ecc, seckey: seckey, pubkey: pubkey, chainCode: hashedRight, depth: this._depth + 1, index, parentFingerprint: new bytes_js_1.Bytes(this.fingerprint()).readU32('BE'), }); } deriveHardened(index) { if (index < 0 || index >= HIGHEST_BIT) { throw new TypeError(`index must be between 0 and ${HIGHEST_BIT}, got ${index}`); } return this.derive(index + HIGHEST_BIT); } derivePath(path) { let splitPath = path.split('/'); if (splitPath[0] === 'm') { if (this._parentFingerprint) { throw new TypeError('Expected master, got child'); } splitPath = splitPath.slice(1); } let hd = this; for (const step of splitPath) { if (step.slice(-1) === `'`) { hd = hd.deriveHardened(parseInt(step.slice(0, -1), 10)); } else { hd = hd.derive(parseInt(step, 10)); } } return hd; } static fromPrivateKey(ecc, seckey, chainCode) { return new HdNode({ ecc, seckey: seckey, pubkey: ecc.derivePubkey(seckey), chainCode, depth: 0, index: 0, parentFingerprint: 0, }); } static fromSeed(ecc, seed) { if (seed.length < 16 || seed.length > 64) { throw new TypeError('Seed must be between 16 and 64 bytes long'); } const hashed = (0, hmac_js_1.hmacSha512)((0, str_js_1.strToBytes)('Bitcoin seed'), seed); const hashedLeft = hashed.slice(0, 32); const hashedRight = hashed.slice(32); return HdNode.fromPrivateKey(ecc, hashedLeft, hashedRight); } } exports.HdNode = HdNode; //# sourceMappingURL=hdwallet.js.map