179 lines
4.9 KiB
TypeScript
179 lines
4.9 KiB
TypeScript
import { HDPublicNode } from './hd-public-node.js';
|
|
import { PrivateKey } from './private-key.js';
|
|
|
|
import {
|
|
encodeHdPrivateKey,
|
|
decodeHdPrivateKey,
|
|
deriveHdPath,
|
|
deriveHdPublicNode,
|
|
deriveHdPrivateNodeFromSeed,
|
|
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 {HdPrivateNodeValid} The HD Private Node.
|
|
*/
|
|
constructor(node: HdPrivateNodeValid) {
|
|
this.node = node;
|
|
}
|
|
|
|
/**
|
|
* Creates a HD Private Node from the given XPriv Key.
|
|
*
|
|
* @param xpriv {string} 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);
|
|
}
|
|
|
|
/**
|
|
* Creates a HD Private Node from a raw seed.
|
|
*
|
|
* @param seed {Uint8Array} 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);
|
|
}
|
|
|
|
/**
|
|
* 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<HdPrivateNodeValid> = {
|
|
network: network,
|
|
node: this.node,
|
|
};
|
|
|
|
// Encode the XPriv from our node info.
|
|
return encodeHdPrivateKey(nodeInfo).hdPrivateKey;
|
|
}
|
|
}
|