UNPKG

@bajetech/digitalbits-hd-wallet

Version:

Key derivation for the DigitalBits blockchain (based on Stellar's SEP-0005)

123 lines (122 loc) 4.47 kB
import has from "lodash.has"; import * as bip39 from "bip39"; import { derivePath } from "./hd-key"; import { Keypair } from "xdb-digitalbits-base"; const ENTROPY_BITS = 256; // = 24 word mnemonic const INVALID_SEED = "Invalid seed (must be a Buffer or hex string)"; const INVALID_MNEMONIC = "Invalid mnemonic (see bip39)"; /** * Class for SEP-0005 key derivation. * * This code is copied and adapted from: * https://github.com/chatch/stellar-hd-wallet/blob/b529d5ad19e9cc31029fd9fbae724856adf4b953/src/stellar-hd-wallet.js * * to use with the DigitalBits blockchain network and ecosystem. * * @see {@link https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md|SEP-0005} */ class DigitalBitsHDWallet { /** * New instance from seed hex string * @param seedHex - Hex string */ constructor(seedHex) { this.seedHex = seedHex; } /** * Instance from a BIP39 mnemonic string. * @param mnemonic - A BIP39 mnemonic * @param password - Optional mnemonic password. * Defaults to undefined * @param language - Optional language of mnemonic. * Defaults to 'english' * @throws {Error} Invalid Mnemonic */ static fromMnemonic(mnemonic, password = undefined, language = "english") { if (!DigitalBitsHDWallet.validateMnemonic(mnemonic, language)) { throw new Error(INVALID_MNEMONIC); } return new DigitalBitsHDWallet(bip39.mnemonicToSeedSync(mnemonic, password).toString("hex")); } /** * Instance from a seed * @param seed - binary seed * @throws {TypeError} Invalid seed */ static fromSeed(seed) { let seedHex; if (Buffer.isBuffer(seed)) seedHex = seed.toString("hex"); else if (typeof seed === "string") seedHex = seed; else throw new TypeError(INVALID_SEED); return new DigitalBitsHDWallet(seedHex); } /** * Generate a mnemonic using BIP39 * @param options - Options defining how to generate the mnemonic * @throws {TypeError} Language not supported by bip39 module * @throws {TypeError} Invalid entropy */ static generateMnemonic({ entropyBits = ENTROPY_BITS, language = "english", rngFn = undefined, } = {}) { if (language && !has(bip39.wordlists, language)) throw new TypeError(`Language ${language} does not have a wordlist in the bip39 module`); const wordlist = bip39.wordlists[language]; return bip39.generateMnemonic(entropyBits, rngFn, wordlist); } /** * Validate a mnemonic using BIP39 * @param mnemonic - A BIP39 mnemonic * @param language - name of a language wordlist as * defined in the 'bip39' npm module. See module.exports.wordlists: * here https://github.com/bitcoinjs/bip39/blob/master/index.js * * Defaults to 'english' * @throws {TypeError} Language not supported by bip39 module */ static validateMnemonic(mnemonic, language = "english") { if (language && !has(bip39.wordlists, language)) throw new TypeError(`Language ${language} does not have a wordlist in the bip39 module`); const wordlist = bip39.wordlists[language]; return bip39.validateMnemonic(mnemonic, wordlist); } /** * Derive key given a full BIP44 path * * @param path - BIP44 path string (eg. m/44'/148'/8') * @return Key binary as Buffer */ derive(path) { const data = derivePath(path, this.seedHex); return data.key; } /** * Get DigitalBits account keypair for child key at given index * * @param index - Account index into path m/44'/148'/{index} * @return Keypair instance for the account */ getKeypair(index) { const key = this.derive(`m/44'/148'/${index}'`); return Keypair.fromRawEd25519Seed(key); } /** * Get public key for account at * * @param index - Account index into path m/44'/148'/{index} * @return Public key */ getPublicKey(index) { return this.getKeypair(index).publicKey(); } /** * Get secret for account at index * @param index - Account index into path m/44'/148'/{index} * @return Secret */ getSecret(index) { return this.getKeypair(index).secret(); } } export default DigitalBitsHDWallet;