Files
xo-stack/packages/primitives/src/hd-private-node.ts
T

280 lines
7.2 KiB
TypeScript

import { HDPublicNode } from './hd-public-node.js';
import { PrivateKey } from './private-key.js';
import {
encodeHdPrivateKey,
decodeHdPrivateKey,
deriveHdPath,
deriveHdPathRelative,
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 The created HD Private Node.
*/
public static fromBytes(seed: Uint8Array): HDPrivateNode {
// Return a new HD Private Node from the given seed.
return this.fromSeed(seed);
}
/**
* 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 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 this(deriveResult);
}
/**
* Creates a HD Private Node from the given mnemonic.
*
* @param mnemonic The mnemonic.
*
* @throws {Error} If HD Private Node cannot be created.
*
* @returns 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 this.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 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 this(decodeResult.node);
}
/**
* Creates a HD Private Node from raw node data.
*
* @param node The raw node data.
*
* @returns The created HD Private Node.
*/
public static fromRaw(node: HdPrivateNodeValid) {
return new this(node);
}
/**
* Generates a random HD Private Node.
*
* @throws {Error} If HD Private Node cannot be created.
*
* @returns 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 this(deriveResult);
}
/**
* Checks if the given XPriv string is a valid HD Private Key.
*
* @param xpriv The XPriv string to check.
*
* @returns True if the XPriv string is valid, false otherwise.
*/
public static isXPriv(xpriv: string): boolean {
try {
this.fromXPriv(xpriv);
return true;
} catch (_error) {
return false;
}
}
/**
* Gets the Private Key entity for this node.
*
* @returns 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 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 Private Node from the given relative BIP32 path.
*
* @param path {string} The BIP32 Path (e.g. 0/0).
*
* @throws {Error} If HD Private Node cannot be derived.
*
* @returns The derived HD Private Node
*/
public deriveRelativePath(path: string): HDPrivateNode {
// Attempt to derive the given path.
const derivePathResult = deriveHdPathRelative(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 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);
}
/**
* Returns the Private Key of this node (as a Uint8Array).
*
* @returns The Node's Private Key (as a Uint8Array).
*/
public toBytes(): Uint8Array {
// Encode the XPriv from our node info.
return this.node.privateKey;
}
/**
* Converts this node to an XPriv Key for export.
*
* @param network {HdKeyNetwork} The network to encode for.
*
* @returns The XPriv Key.
*/
public toXPriv(network: HdKeyNetwork = 'mainnet'): string {
// Create our node info structure.
const nodeInfo: DecodedHdKey<HdPrivateNodeValid> = {
network: network,
node: this.node,
};
// Encode the XPriv from our node info.
return encodeHdPrivateKey(nodeInfo).hdPrivateKey;
}
/**
* Returns the XPriv string for this node.
*
* @returns The XPriv string for this node.
*/
public toString(): string {
// Return the Mainnet XPriv.
return this.toXPriv();
}
/**
* Returns the raw node data.
*
* @returns The raw node data.
*/
public toRaw(): HdPrivateNodeValid {
return this.node;
}
}