@muirglacier/jellyfish-wallet-mnemonic
Version:
A collection of TypeScript + JavaScript tools and libraries for DeFi Blockchain developers to build decentralized finance for Bitcoin
193 lines • 8.01 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MnemonicHdNodeProvider = exports.MnemonicHdNode = void 0;
const create_hmac_1 = __importDefault(require("create-hmac"));
const bip32 = __importStar(require("bip32"));
const jellyfish_crypto_1 = require("@muirglacier/jellyfish-crypto");
const jellyfish_transaction_1 = require("@muirglacier/jellyfish-transaction");
const jellyfish_transaction_signature_1 = require("@muirglacier/jellyfish-transaction-signature");
const mnemonic_1 = require("./mnemonic");
/**
* MnemonicHdNode implements the WalletHdNode from jellyfish-wallet.
* MnemonicHdNode implementations is purpose and derivation agnostic.
*
* Prior-art:
* - BIP32 Hierarchical Deterministic Wallets
* - BIP39 Mnemonic code for generating deterministic keys
* - BIP44 Multi-Account Hierarchy for Deterministic Wallets
*/
class MnemonicHdNode {
constructor(path, rootPrivKey, chainCode, options) {
this.path = path;
this.rootPrivKey = rootPrivKey;
this.chainCode = chainCode;
this.options = options;
}
deriveNode() {
return __awaiter(this, void 0, void 0, function* () {
return bip32.fromPrivateKey(this.rootPrivKey, this.chainCode, this.options)
.derivePath(this.path);
});
}
/**
* @return Promise<Buffer> compressed public key
*/
publicKey() {
return __awaiter(this, void 0, void 0, function* () {
const node = yield this.deriveNode();
return node.publicKey;
});
}
/**
* @return Promise<Buffer> privateKey of the WalletHdNode
*/
privateKey() {
return __awaiter(this, void 0, void 0, function* () {
const node = yield this.deriveNode();
return node.privateKey;
});
}
/**
* Sign a transaction with all prevout belong to this HdNode with SIGHASH.ALL
* This implementation can only sign a P2WPKH, hence the implementing WalletAccount should only
* recognize P2WPKH addresses encoded in bech32 format.
*
* @param {Transaction} transaction to sign
* @param {Vout[]} prevouts of transaction to sign, ellipticPair will be mapped to current node
* @return TransactionSegWit signed transaction ready to broadcast
*/
signTx(transaction, prevouts) {
return __awaiter(this, void 0, void 0, function* () {
return yield jellyfish_transaction_signature_1.TransactionSigner.signPrevoutsWithEllipticPairs(transaction, prevouts, prevouts.map(() => this), {
sigHashType: jellyfish_transaction_1.SIGHASH.ALL
});
});
}
/**
* @param {Buffer} hash to sign
* @return {Buffer} signature in DER format, SIGHASHTYPE not included
*/
sign(hash) {
return __awaiter(this, void 0, void 0, function* () {
const node = yield this.deriveNode();
const signature = node.sign(hash, true);
return jellyfish_crypto_1.DERSignature.encode(signature);
});
}
/**
* @param {Buffer} hash to verify with signature
* @param {Buffer} derSignature of the hash in encoded with DER, SIGHASHTYPE must not be included
* @return Promise<boolean> validity of signature of the hash
*/
verify(hash, derSignature) {
return __awaiter(this, void 0, void 0, function* () {
const node = yield this.deriveNode();
const signature = jellyfish_crypto_1.DERSignature.decode(derSignature);
return node.verify(hash, signature);
});
}
}
exports.MnemonicHdNode = MnemonicHdNode;
/**
* Provider that derive MnemonicHdNode from root. Uses a lite on demand derivation.
*/
class MnemonicHdNodeProvider {
constructor(data, options) {
this.data = data;
this.options = options;
}
derive(path) {
const rootPrivKey = Buffer.from(this.data.privKey, 'hex');
const chainCode = Buffer.from(this.data.chainCode, 'hex');
return new MnemonicHdNode(path, rootPrivKey, chainCode, this.options);
}
/**
* @param {MnemonicProviderData} data to init MnemonicHdNodeProvider
* @param {Bip32Options} options
*/
static fromData(data, options) {
return new MnemonicHdNodeProvider(data, options);
}
/**
* @param {string[]} words to init MnemonicHdNodeProvider
* @param {Bip32Options} options
*/
static fromWords(words, options) {
const data = this.wordsToData(words, options);
return this.fromData(data, options);
}
/**
* @param {string[]} words to convert into MnemonicProviderData
* @param {Bip32Options} options
* @return MnemonicProviderData
*/
static wordsToData(words, options) {
const node = fromWordsToSeed(words, options);
const privKey = node.privateKey.toString('hex');
const chainCode = node.chainCode.toString('hex');
return { words, chainCode, privKey };
}
/**
* Generate a random mnemonic code of length, uses crypto.randomBytes under the hood.
*
* @param {number} length the sentence length of the mnemonic code
* @param {(number) => Buffer} rng random number generation, generate random num of bytes buffer
* @return {string[]} generated mnemonic word list, (COLD STORAGE)
*/
static generateWords(length = 24, rng) {
return mnemonic_1.generateMnemonicWords(length, rng);
}
}
exports.MnemonicHdNodeProvider = MnemonicHdNodeProvider;
/**
* Derive from mnemonic words using our own seed called '@muirglacier/jellyfish-wallet-mnemonic'.
*
* @param {string[]} words to convert into Bip32Interface
* @param {Bip32Options} options
*/
function fromWordsToSeed(words, options) {
const seed = mnemonic_1.mnemonicToSeed(words);
if (seed.length < 16) {
throw new TypeError('Seed should be at least 128 bits');
}
if (seed.length > 64) {
throw new TypeError('Seed should be at most 512 bits');
}
const key = Buffer.from('@muirglacier/jellyfish-wallet-mnemonic', 'utf8');
const I = create_hmac_1.default('sha512', key).update(seed).digest();
const IL = I.slice(0, 32);
const IR = I.slice(32);
return bip32.fromPrivateKey(IL, IR, options);
}
//# sourceMappingURL=hd_node.js.map