import { HDPublicNode } from './hd-public-node.js'; import { PrivateKey } from './private-key.js'; import { encodeHdPrivateKey, decodeHdPrivateKey, deriveHdPath, deriveHdPublicNode, deriveHdPrivateNodeFromSeed, deriveSeedFromBip39Mnemonic, generateRandomBytes, } from '@bitauth/libauth'; import type { DecodedHdKey, HdKeyNetwork, HdPrivateNodeValid, } from '@bitauth/libauth'; /** * Hierarchically Deterministic Private Node Entity. */ export class HDPrivateNode { // The HD Private Node. public readonly node: HdPrivateNodeValid; /** * Construct a new HD Private Node. * * @param node The HD Private Node. */ constructor(node: HdPrivateNodeValid) { this.node = node; } /** * Creates a HD Private Node from a raw seed. * * @param seed The raw seed bytes. * * @throws {Error} If HD Private Node cannot be created. * * @returns {HDPrivateNode} The created HD Private Node. */ public static fromSeed(seed: Uint8Array): HDPrivateNode { // If the seed is not 32 bytes, throw an error. /*if (seed.length !== 32) { throw new Error( `Failed to derive Private Node from seed: Seed must be 32 bytes (${seed.length} given)` ); }*/ // Attempt to derive HD Private Node from the given seed. const deriveResult = deriveHdPrivateNodeFromSeed(seed); // If a string is returned, this indicates an error... if (typeof deriveResult === 'string') { throw new Error(deriveResult); } // Return a new HD Private Node from the given seed. return new HDPrivateNode(deriveResult); } /** * Creates a HD Private Node from the given mnemonic. * * @param mnemonic The mnemonic. * * @throws {Error} If HD Private Node cannot be created. * * @returns {HDPrivateNode} The created HD Private Node. */ public static fromMnemonic(mnemonic: string): HDPrivateNode { // Derive the seed from the mnemonic. const seed = deriveSeedFromBip39Mnemonic(mnemonic); // Return a new HDPrivateNode from the given seed. return HDPrivateNode.fromSeed(seed); } /** * Creates a HD Private Node from the given XPriv Key. * * @param xpriv The XPriv Key. * * @throws {Error} If HD Private Node cannot be created. * * @returns {HDPrivateNode} The created HD Private Node. */ public static fromXPriv(xpriv: string): HDPrivateNode { // Attempt to decode the XPriv Key. const decodeResult = decodeHdPrivateKey(xpriv); // If a string is returned, this indicates an error... if (typeof decodeResult === 'string') { throw new Error(decodeResult); } // Return a new HD Private Node from the given XPriv. return new HDPrivateNode(decodeResult.node); } /** * Generates a random HD Private Node. * * @throws {Error} If HD Private Node cannot be created. * * @returns {HDPrivateNode} The created HD Private Node. */ public static generateRandom(): HDPrivateNode { // Attempt to derive HD Private Node from randomly generated bytes. const deriveResult = deriveHdPrivateNodeFromSeed(generateRandomBytes(32)); // If a string is returned, this indicates an error... if (typeof deriveResult === 'string') { throw new Error(deriveResult); } // Return the new HD Private Node from the random bytes. return new HDPrivateNode(deriveResult); } /** * Returns the XPriv string for this node. * * @returns {string} The XPriv string for this node. */ public toString(): string { // Return the Mainnet XPriv. return this.toXPriv(); } /** * Gets the Private Key entity for this node. * * @returns {PrivateKey} The Private Key Entity for this node. */ public privateKey(): PrivateKey { // Return a Private Key Entity from the private key of our node. return new PrivateKey(this.node.privateKey); } /** * Derives a HD Private Node from the given BIP32 path. * * @param path {string} The BIP32 Path (e.g. m/44'/145'/0'/0/1). * * @throws {Error} If HD Private Node cannot be derived. * * @returns {HDPrivateNode} The derived HD Private Node */ public derivePath(path: string): HDPrivateNode { // Attempt to derive the given path. const derivePathResult = deriveHdPath(this.node, path); // If a string is returned, this indicates an error... if (typeof derivePathResult === 'string') { throw new Error(derivePathResult); } // Return a new HD Private Node Entity derived from the given path. return new HDPrivateNode(derivePathResult); } /** * Derives a HD Public Node from this Private Node. * * @returns {HDPublicNode} The derived HD Public Node */ public deriveHDPublicNode(): HDPublicNode { // Derive a HD Public Node from this HD Private Node. const publicNode = deriveHdPublicNode(this.node); // Return a new HD Public Node entity from our derived Public Node. return new HDPublicNode(publicNode); } /** * Converts this node to an XPriv Key for export. * * @param network {HdKeyNetwork} The network to encode for. * * @returns {string} The XPriv Key. */ public toXPriv(network: HdKeyNetwork = 'mainnet'): string { // Create our node info structure. const nodeInfo: DecodedHdKey = { network: network, node: this.node, }; // Encode the XPriv from our node info. return encodeHdPrivateKey(nodeInfo).hdPrivateKey; } }