UNPKG

@safeheron/master-key-derive

Version:
317 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.extendedPubSharesAgg = exports.mnemonicToExtendedPub = exports.Mnemonics = exports.MasterKeyShare = exports.MasterKeyPair = exports.SigAlg = exports.Purpose = void 0; const BN = require("bn.js"); const crypto_bip32_1 = require("@safeheron/crypto-bip32"); const crypto_utils_1 = require("@safeheron/crypto-utils"); const elliptic = require("elliptic"); const cryptoJS = require("crypto-js"); const bip39 = require("bip39"); const assert = require("assert"); const Ed25519 = new elliptic.eddsa('ed25519'); const Secp256k1 = new elliptic.ec('secp256k1'); const P256 = new elliptic.ec('p256'); const ZERO = new BN('0', 16); const POW2_256 = new BN('1', 10).shln(256); const MASTER_SECRET = cryptoJS.enc.Utf8.parse('MPC seed'); var Purpose; (function (Purpose) { Purpose[Purpose["MASTER_KEY_DERIVE"] = 0] = "MASTER_KEY_DERIVE"; Purpose[Purpose["AUTH_KEY_DERIVE"] = 1] = "AUTH_KEY_DERIVE"; Purpose[Purpose["POLICY_ENGINE"] = 2] = "POLICY_ENGINE"; })(Purpose = exports.Purpose || (exports.Purpose = {})); var SigAlg; (function (SigAlg) { SigAlg[SigAlg["ECDSA_SECP256K1"] = 0] = "ECDSA_SECP256K1"; SigAlg[SigAlg["EDDSA_ED25519"] = 1] = "EDDSA_ED25519"; SigAlg[SigAlg["BLS_BN12_381"] = 2] = "BLS_BN12_381"; SigAlg[SigAlg["SCHNORR_SECP256K1"] = 3] = "SCHNORR_SECP256K1"; SigAlg[SigAlg["ECDSA_P256"] = 4] = "ECDSA_P256"; SigAlg[SigAlg["SCHNORR_P256"] = 5] = "SCHNORR_P256"; })(SigAlg = exports.SigAlg || (exports.SigAlg = {})); function getOrderOfCurve(sigAlg) { switch (sigAlg) { case SigAlg.ECDSA_SECP256K1: return Secp256k1.n; case SigAlg.EDDSA_ED25519: return Ed25519.curve.n; case SigAlg.BLS_BN12_381: throw "Unsupported sigAlg:" + sigAlg; case SigAlg.SCHNORR_SECP256K1: return Secp256k1.n; case SigAlg.ECDSA_P256: case SigAlg.SCHNORR_P256: return P256.n; default: throw "Unsupported sigAlg:" + sigAlg; } } function getHDKeyClass(sigAlg) { switch (sigAlg) { case SigAlg.ECDSA_SECP256K1: return crypto_bip32_1.Secp256k1HDKey; case SigAlg.EDDSA_ED25519: return crypto_bip32_1.Ed25519HDKey; case SigAlg.BLS_BN12_381: throw "Can't get a HDKeyClass because of unsupported sigAlg: " + sigAlg; case SigAlg.SCHNORR_SECP256K1: return crypto_bip32_1.Secp256k1HDKey; case SigAlg.ECDSA_P256: case SigAlg.SCHNORR_P256: return crypto_bip32_1.P256HDKey; default: throw "Can't get a HDKeyClass because of unsupported sigAlg: " + sigAlg; } } function getPurposeHex(purpose) { switch (purpose) { case Purpose.MASTER_KEY_DERIVE: return "00000000"; case Purpose.AUTH_KEY_DERIVE: return "00000001"; case Purpose.POLICY_ENGINE: return "00000002"; default: throw "Unsupported purpose: " + purpose; } } function getSigAlgHex(sigAlg) { switch (sigAlg) { case SigAlg.ECDSA_SECP256K1: return "00000000"; case SigAlg.EDDSA_ED25519: return "00000001"; case SigAlg.BLS_BN12_381: return "00000002"; case SigAlg.SCHNORR_SECP256K1: return "00000003"; case SigAlg.ECDSA_P256: return "00000004"; case SigAlg.SCHNORR_P256: return "00000005"; default: throw "Unsupported sigAlg:" + sigAlg; } } function getAlternativeHex(alter) { return crypto_utils_1.Hex.pad8(alter.toString(16)); } class MasterKeyPair { constructor(xprv, xpub) { this.xprv = xprv; this.xpub = xpub; } static _checkIsValidChainCode(masterKeyShares) { assert(masterKeyShares.length > 1); // Check the state of 'isFullChainCode' let flagFullChainCode = masterKeyShares[0].isFullChainCode; for (let i = 1; i < masterKeyShares.length; i++) { if (masterKeyShares[i].isFullChainCode !== flagFullChainCode) { return false; } } return true; } static _checkIsFullChainCode(masterKeyShares) { assert(masterKeyShares.length > 1); let c = masterKeyShares[0].chainCodeShare; for (let i = 1; i < masterKeyShares.length; i++) { if (!masterKeyShares[i].chainCodeShare.eq(c)) { return false; } } return true; } /** * Recover master key pair from all the MasterKeyShares * @param masterKeyShares * @param sigAlg */ static recoverFromMasterKeyShares(masterKeyShares, sigAlg) { assert(masterKeyShares.length > 1); let n = getOrderOfCurve(sigAlg); let c = new BN(0); let k = new BN(0); for (let mks of masterKeyShares) { c = c.add(mks.chainCodeShare).umod(POW2_256); k = k.add(mks.keyShare).umod(n); } if (k.eqn(0)) throw "Invalid master key!"; if (MasterKeyPair._checkIsFullChainCode(masterKeyShares)) { c = masterKeyShares[0].chainCodeShare; } let HDKeyClass = getHDKeyClass(sigAlg); let hdKey = HDKeyClass.fromPrivateKeyAndChainCode(k, c); return new MasterKeyPair(hdKey.xprv, hdKey.xpub); } static _recoverFromMnemonics(mnemonics, sigAlg, alt) { let masterKeyShares = []; for (let i = 0; i < mnemonics.length; i++) { masterKeyShares.push(mnemonics[i].derive(Purpose.MASTER_KEY_DERIVE, sigAlg, alt)); } if (!MasterKeyPair._checkIsValidChainCode(masterKeyShares)) throw 'Invalid chain code!'; try { return MasterKeyPair.recoverFromMasterKeyShares(masterKeyShares, sigAlg); } catch (err) { return MasterKeyPair._recoverFromMnemonics(mnemonics, sigAlg, alt + 1); } } /** * Recover master key pair from all the Mnemonics * @param mnemonics * @param sigAlg */ static recoverFromMnemonics(mnemonics, sigAlg) { return MasterKeyPair._recoverFromMnemonics(mnemonics, sigAlg, 0); } } exports.MasterKeyPair = MasterKeyPair; class MasterKeyShare { constructor(keyShare, chainCodeShare, isFullChainCode) { this.keyShare = keyShare; this.chainCodeShare = chainCodeShare; this.isFullChainCode = isFullChainCode; } } exports.MasterKeyShare = MasterKeyShare; class Mnemonics { constructor(mnemo, extraMnemo) { assert(mnemo.length > 0); this.mnemo = mnemo; this.extraMnemo = extraMnemo; } /*** * Create Mnemonics from key share and chain code. * * Warn: only invoked by the old user of mpc wallet * * @param keyShare * @param chainCode */ static createMnemonics(keyShare, chainCode) { assert(chainCode.lt(POW2_256)); assert(keyShare.lt(Secp256k1.n)); let mnemo = bip39.entropyToMnemonic(crypto_utils_1.Hex.pad64(keyShare.toString(16))); let extraMnemo = bip39.entropyToMnemonic(crypto_utils_1.Hex.pad64(chainCode.toString(16))); return new Mnemonics(mnemo, extraMnemo); } /** * Create a new Mnemonic */ static generateMnemonic() { let mnemo = bip39.generateMnemonic(256); return new Mnemonics(mnemo, ""); } _derive(purpose, sigAlg, alg) { let seedHex = bip39.mnemonicToEntropy(this.mnemo); let purposeHex = getPurposeHex(purpose); let sigAlgHex = getSigAlgHex(sigAlg); let alternativeHex = getAlternativeHex(alg); // Derivation 0 let keyBytes = MASTER_SECRET; let dataBytes = cryptoJS.enc.Hex.parse(seedHex); let IHex = cryptoJS.enc.Hex.stringify(cryptoJS.HmacSHA512(dataBytes, keyBytes)); let IL_hex = IHex.substr(0, 64); let IR_hex = IHex.substr(64); // Derivation 1 keyBytes = cryptoJS.enc.Hex.parse(IL_hex); dataBytes = cryptoJS.enc.Hex.parse(IR_hex + purposeHex); IHex = cryptoJS.enc.Hex.stringify(cryptoJS.HmacSHA512(dataBytes, keyBytes)); IL_hex = IHex.substr(0, 64); IR_hex = IHex.substr(64); // Derivation 2 keyBytes = cryptoJS.enc.Hex.parse(IL_hex); dataBytes = cryptoJS.enc.Hex.parse(IR_hex + sigAlgHex); IHex = cryptoJS.enc.Hex.stringify(cryptoJS.HmacSHA512(dataBytes, keyBytes)); IL_hex = IHex.substr(0, 64); IR_hex = IHex.substr(64); // Derivation 3 keyBytes = cryptoJS.enc.Hex.parse(IL_hex); dataBytes = cryptoJS.enc.Hex.parse(IR_hex + alternativeHex); IHex = cryptoJS.enc.Hex.stringify(cryptoJS.HmacSHA512(dataBytes, keyBytes)); IL_hex = IHex.substr(0, 64); IR_hex = IHex.substr(64); let IL = new BN(0); let IR = new BN(0); if (sigAlg === SigAlg.EDDSA_ED25519) { // IL: little-endian IL = new BN(crypto_utils_1.Hex.reverseHex(IL_hex), 16); // It doesn't matter for iR's encode. IR = new BN(IR_hex, 16); } else { IL = new BN(IL_hex, 16); IR = new BN(IR_hex, 16); } let n = getOrderOfCurve(sigAlg); let k = IL.umod(n); let c = IR; if (k.eqn(0)) { return this._derive(purpose, sigAlg, alg + 1); } return new MasterKeyShare(k, c, false); } _derive_old_secp256k1() { let n = getOrderOfCurve(SigAlg.ECDSA_SECP256K1); let k = new BN(bip39.mnemonicToEntropy(this.mnemo), 16); k = k.umod(n); let c = new BN(bip39.mnemonicToEntropy(this.extraMnemo), 16); return new MasterKeyShare(k, c, true); } /** * Derive function * @param purpose * @param sigAlg * @param alg */ derive(purpose, sigAlg, alg) { if (this.extraMnemo === undefined || this.extraMnemo === "") { return this._derive(purpose, sigAlg, alg); } else { return this._derive_old_secp256k1(); } } } exports.Mnemonics = Mnemonics; function mnemonicToExtendedPub(sigAlg, alt, mnemo, chaincode = "") { let HDKeyClass = getHDKeyClass(sigAlg); let extraMnemo = ""; if (chaincode !== "") { if (sigAlg !== SigAlg.ECDSA_SECP256K1) throw 'Invalid sign algorithm!'; extraMnemo = bip39.entropyToMnemonic(crypto_utils_1.Hex.pad64(chaincode)); } let mnemoObj = new Mnemonics(mnemo, extraMnemo); let masterKeyShare = mnemoObj.derive(Purpose.MASTER_KEY_DERIVE, sigAlg, alt); let hdKey = HDKeyClass.fromPrivateKeyAndChainCode(masterKeyShare.keyShare, masterKeyShare.chainCodeShare); return hdKey.xpub; } exports.mnemonicToExtendedPub = mnemonicToExtendedPub; function extendedPubSharesAgg(sigAlg, extendedPubShares, isFullChainCode) { assert(extendedPubShares.length > 1); let HDKeyClass = getHDKeyClass(sigAlg); let hdKey = HDKeyClass.fromExtendedKey(extendedPubShares[0]); let chaincode = hdKey.chainCode; let pub = hdKey.publicKey; for (let i = 1; i < extendedPubShares.length; i++) { hdKey = HDKeyClass.fromExtendedKey(extendedPubShares[i]); pub = pub.add(hdKey.publicKey); if (isFullChainCode) { if (!chaincode.eq(hdKey.chainCode)) throw "Invalid chaincode!"; } else { chaincode = chaincode.add(hdKey.chainCode).umod(POW2_256); } } if (pub.isInfinity()) throw "Invalid master public key!"; hdKey = HDKeyClass.fromPublicKeyAndChainCode(pub, chaincode); return hdKey.xpub; } exports.extendedPubSharesAgg = extendedPubSharesAgg; //# sourceMappingURL=keyDerive.js.map