@unification-com/und-js-v2
Version:
Unification Mainchain Wallet SDK v2
229 lines (216 loc) • 10.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getPublicKeyFromPrivateKey = exports.getPrivateKeyFromMnemonic = exports.getPrivateKeyFromKeyStore = exports.getAddressFromPublicKey = exports.getAddressFromPrivateKey = exports.generateMnemonic = exports.generateKeyStore = exports.encodeAddress = exports.decodeAddress = exports.checkAddress = void 0;
var _cryptoBrowserify = _interopRequireDefault(require("crypto-browserify"));
var _uuid = require("uuid");
var _is_js = _interopRequireDefault(require("is_js"));
var bip39 = _interopRequireWildcard(require("bip39"));
var _elliptic = _interopRequireDefault(require("elliptic"));
var bip32 = _interopRequireWildcard(require("bip32"));
var bech32 = _interopRequireWildcard(require("bech32"));
var _utils = require("../utils");
var _config = _interopRequireDefault(require("../config"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/**
* @module crypto
*/
// secp256k1 privkey is 32 bytes
var PRIVKEY_LEN = 32;
var MNEMONIC_LEN = 256;
var DECODED_ADDRESS_LEN = 20;
var CURVE = "secp256k1";
var EC = _elliptic["default"].ec;
var elliptic = new EC(CURVE);
/**
* Decodes an address in bech32 format.
* @param {string} value the bech32 address to decode
*/
var decodeAddress = function decodeAddress(value) {
var decodeAddress = bech32.decode(value);
return Buffer.from(bech32.fromWords(decodeAddress.words));
};
/**
* Checks whether an address is valid.
* @param {string} address the bech32 address to decode
* @param {string} hrp the prefix to check for the bech32 address
* @return {boolean}
*/
exports.decodeAddress = decodeAddress;
var checkAddress = function checkAddress(address, hrp) {
try {
if (!address.startsWith(hrp)) {
return false;
}
var decodedAddress = bech32.decode(address);
var decodedAddressLength = decodeAddress(address).length;
if (decodedAddressLength === DECODED_ADDRESS_LEN && decodedAddress.prefix === hrp) {
return true;
}
return false;
} catch (err) {
return false;
}
};
/**
* Encodes an address from input data bytes.
* @param {string} value the public key to encode
* @param {*} prefix the address prefix
* @param {*} type the output type (default: hex)
*/
exports.checkAddress = checkAddress;
var encodeAddress = function encodeAddress(value) {
var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "und";
var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "hex";
var words = bech32.toWords(Buffer.from(value, type));
return bech32.encode(prefix, words);
};
/**
* Calculates the public key from a given private key.
* @param {string} privateKeyHex the private key hexstring
* @return {string} public key hexstring
*/
exports.encodeAddress = encodeAddress;
var getPublicKeyFromPrivateKey = function getPublicKeyFromPrivateKey(privateKeyHex) {
if (!privateKeyHex || privateKeyHex.length !== PRIVKEY_LEN * 2) {
throw new Error("invalid privateKey");
}
var curve = new EC(CURVE);
var keypair = curve.keyFromPrivate(privateKeyHex, "hex");
var unencodedPubKey = keypair.getPublic().encode("hex");
return unencodedPubKey;
};
/**
* Gets an address from a public key hex.
* @param {string} publicKeyHex the public key hexstring
* @param {string} prefix the address prefix
*/
exports.getPublicKeyFromPrivateKey = getPublicKeyFromPrivateKey;
var getAddressFromPublicKey = function getAddressFromPublicKey(publicKeyHex, prefix) {
var pubKey = elliptic.keyFromPublic(publicKeyHex, "hex");
var pubPoint = pubKey.getPublic();
var compressed = pubPoint.encodeCompressed();
var hexed = (0, _utils.ab2hexstring)(compressed);
var hash = (0, _utils.sha256ripemd160)(hexed); // https://git.io/fAn8N
var address = encodeAddress(hash, prefix);
return address;
};
/**
* Gets an address from a private key.
* @param {string} privateKeyHex the private key hexstring
*/
exports.getAddressFromPublicKey = getAddressFromPublicKey;
var getAddressFromPrivateKey = function getAddressFromPrivateKey(privateKeyHex, prefix) {
return getAddressFromPublicKey(getPublicKeyFromPrivateKey(privateKeyHex), prefix);
};
/**
* Generates a keystore object (web3 secret storage format) given a private key to store and a password.
* @param {string} privateKeyHex the private key hexstring.
* @param {string} password the password.
* @return {object} the keystore object.
*/
exports.getAddressFromPrivateKey = getAddressFromPrivateKey;
var generateKeyStore = function generateKeyStore(privateKeyHex, password) {
var salt = _cryptoBrowserify["default"].randomBytes(32);
var iv = _cryptoBrowserify["default"].randomBytes(16);
var cipherAlg = "aes-256-ctr";
var kdf = "pbkdf2";
var kdfparams = {
dklen: 32,
salt: salt.toString("hex"),
c: 262144,
prf: "hmac-sha256"
};
var derivedKey = _cryptoBrowserify["default"].pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, "sha256");
var cipher = _cryptoBrowserify["default"].createCipheriv(cipherAlg, derivedKey.slice(0, 32), iv);
if (!cipher) {
throw new Error("Unsupported cipher");
}
var ciphertext = Buffer.concat([cipher.update(Buffer.from(privateKeyHex, "hex")), cipher["final"]()]);
var bufferValue = Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, "hex")]);
return {
version: 1,
id: (0, _uuid.v4)({
random: _cryptoBrowserify["default"].randomBytes(16)
}),
crypto: {
ciphertext: ciphertext.toString("hex"),
cipherparams: {
iv: iv.toString("hex")
},
cipher: cipherAlg,
kdf: kdf,
kdfparams: kdfparams,
// mac must use sha3 according to web3 secret storage spec
mac: (0, _utils.sha3)(bufferValue.toString("hex"))
}
};
};
/**
* Gets a private key from a keystore given its password.
* @param {string} keystore the keystore in json format
* @param {string} password the password.
*/
exports.generateKeyStore = generateKeyStore;
var getPrivateKeyFromKeyStore = function getPrivateKeyFromKeyStore(keystore, password) {
if (!_is_js["default"].string(password)) {
throw new Error("No password given.");
}
var json = _is_js["default"].object(keystore) ? keystore : JSON.parse(keystore);
var kdfparams = json.crypto.kdfparams;
if (kdfparams.prf !== "hmac-sha256") {
throw new Error("Unsupported parameters to PBKDF2");
}
var derivedKey = _cryptoBrowserify["default"].pbkdf2Sync(Buffer.from(password), Buffer.from(kdfparams.salt, "hex"), kdfparams.c, kdfparams.dklen, "sha256");
var ciphertext = Buffer.from(json.crypto.ciphertext, "hex");
var bufferValue = Buffer.concat([derivedKey.slice(16, 32), ciphertext]);
// try sha3 (new / ethereum keystore) mac first
var mac = (0, _utils.sha3)(bufferValue.toString("hex"));
if (mac !== json.crypto.mac) {
// the legacy (sha256) mac is next to be checked. pre-testnet keystores used a sha256 digest for the mac.
// the sha256 mac was not compatible with ethereum keystores, so it was changed to sha3 for mainnet.
var macLegacy = (0, _utils.sha256)(bufferValue.toString("hex"));
if (macLegacy !== json.crypto.mac) {
throw new Error("Keystore mac check failed (sha3 & sha256) - wrong password?");
}
}
var decipher = _cryptoBrowserify["default"].createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 32), Buffer.from(json.crypto.cipherparams.iv, "hex"));
var privateKey = Buffer.concat([decipher.update(ciphertext), decipher["final"]()]).toString("hex");
return privateKey;
};
/**
* Generates mnemonic phrase words using random entropy.
*/
exports.getPrivateKeyFromKeyStore = getPrivateKeyFromKeyStore;
var generateMnemonic = function generateMnemonic() {
return bip39.generateMnemonic(MNEMONIC_LEN);
};
/**
* Get a private key from mnemonic words.
* @param {string} mnemonic the mnemonic phrase words
* @param {Boolean} derive derive a private key using the default HD path (default: true)
* @param {number} index the bip44 address index (default: 0)
* @param {string} password according to bip39
* @return {Buffer} hexstring
*/
exports.generateMnemonic = generateMnemonic;
var getPrivateKeyFromMnemonic = function getPrivateKeyFromMnemonic(mnemonic) {
var derive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var password = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "";
if (!bip39.validateMnemonic(mnemonic)) {
throw new Error("wrong mnemonic format");
}
var seed = bip39.mnemonicToSeed(mnemonic, password);
if (derive) {
var master = bip32.fromSeed(seed);
var child = master.derivePath(_config["default"].HD_PATH + index);
return child.privateKey;
}
return seed;
};
exports.getPrivateKeyFromMnemonic = getPrivateKeyFromMnemonic;