UNPKG

evtjs

Version:

Javascript API Bindings for the everiToken blockchain.

376 lines (309 loc) 11.4 kB
"use strict"; var _toConsumableArray2 = require("babel-runtime/helpers/toConsumableArray"); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _promise = require("babel-runtime/core-js/promise"); var _promise2 = _interopRequireDefault(_promise); var _slicedToArray2 = require("babel-runtime/helpers/slicedToArray"); var _slicedToArray3 = _interopRequireDefault(_slicedToArray2); var _typeof2 = require("babel-runtime/helpers/typeof"); var _typeof3 = _interopRequireDefault(_typeof2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var ecurve = require("ecurve"); var Point = ecurve.Point; var secp256k1 = ecurve.getCurveByName("secp256k1"); var BigInteger = require("../bigi"); var assert = require("assert"); var hash = require("./hash"); var PublicKey = require("./key_public"); var keyUtils = require("./key_utils"); var createHash = require("create-hash"); var promiseAsync = require("./promise-async"); var publicKeyMemoryCache = new (require("../memoryCache"))(100); var G = secp256k1.G; var n = secp256k1.n; var isNode = false; try { if ((typeof window === "undefined" ? "undefined" : (0, _typeof3.default)(window)) !== "object") { var crypto = require("crypto"); if (crypto && crypto.createECDH) { isNode = true; } } } catch (e) {} module.exports = PrivateKey; /** @typedef {string} wif - https://en.bitcoin.it/wiki/Wallet_import_format @typedef {string} pubkey - EVTKey.. @typedef {ecurve.Point} Point */ /** @param {BigInteger} d */ function PrivateKey(d) { if (typeof d === "string") { return PrivateKey.fromString(d); } else if (Buffer.isBuffer(d)) { return PrivateKey.fromBuffer(d); } else if ((typeof d === "undefined" ? "undefined" : (0, _typeof3.default)(d)) === "object" && BigInteger.isBigInteger(d.d)) { return PrivateKey(d.d); } if (!BigInteger.isBigInteger(d)) { throw new TypeError("Invalid private key"); } /** @return {string} private key like PVT_K1_base58privatekey.. */ function toString() { // todo, use PVT_K1_ // return 'PVT_K1_' + keyUtils.checkEncode(toBuffer(), 'K1') return toWif(); } var wif = void 0; /** @return {wif} */ function toWif() { if (wif) return wif; var private_key = toBuffer(); // checksum includes the version private_key = Buffer.concat([new Buffer([0x80]), private_key]); wif = keyUtils.checkEncode(private_key, "sha256x2"); return wif; } /** @return {Point} */ function toPublic() { var cachedKey = publicKeyMemoryCache.get(toString()); if (cachedKey) { // cache // S L O W return cachedKey; } var public_key = void 0; // In Node, use Native Method if (isNode) { var _require = require('crypto'), createECDH = _require.createECDH; var ecdh = createECDH('secp256k1'); ecdh.setPrivateKey(toBuffer()); public_key = PublicKey.fromBuffer(new Buffer(ecdh.getPublicKey('hex', 'compressed'), 'hex')); } else { var Q = secp256k1.G.multiply(d); public_key = PublicKey.fromPoint(Q); } publicKeyMemoryCache.set(toString(), public_key); return public_key; } function toBuffer() { return d.toBuffer(32); } /** ECIES @arg {string|Object} pubkey wif, PublicKey object @return {Buffer} 64 byte shared secret */ function getSharedSecret(public_key) { public_key = PublicKey(public_key); var KB = public_key.toUncompressed().toBuffer(); var KBP = Point.fromAffine(secp256k1, BigInteger.fromBuffer(KB.slice(1, 33)), // x BigInteger.fromBuffer(KB.slice(33, 65)) // y ); var r = toBuffer(); var P = KBP.multiply(BigInteger.fromBuffer(r)); var S = P.affineX.toBuffer({ size: 32 }); // SHA512 used in ECIES return hash.sha512(S); } // /** ECIES TODO unit test // @arg {string|Object} pubkey wif, PublicKey object // @return {Buffer} 64 byte shared secret // */ // function getSharedSecret(public_key) { // public_key = PublicKey(public_key).toUncompressed() // var P = public_key.Q.multiply( d ); // var S = P.affineX.toBuffer({size: 32}); // // ECIES, adds an extra sha512 // return hash.sha512(S); // } /** @arg {string} name - child key name. @return {PrivateKey} @example activePrivate = masterPrivate.getChildKey('owner').getChildKey('active') @example activePrivate.getChildKey('mycontract').getChildKey('myperm') */ function getChildKey(name) { // console.error('WARNING: getChildKey untested against evtd'); // no evtd impl yet var index = createHash("sha256").update(toBuffer()).update(name).digest(); return PrivateKey(index); } function toHex() { return toBuffer().toString("hex"); } return { d: d, toWif: toWif, toString: toString, toPublic: toPublic, toBuffer: toBuffer, getSharedSecret: getSharedSecret, getChildKey: getChildKey }; } /** @private */ function parseKey(privateStr) { assert.equal(typeof privateStr === "undefined" ? "undefined" : (0, _typeof3.default)(privateStr), "string", "privateStr"); var match = privateStr.match(/^PVT_([A-Za-z0-9]+)_([A-Za-z0-9]+)$/); if (match === null) { // legacy WIF - checksum includes the version var versionKey = keyUtils.checkDecode(privateStr, "sha256x2"); var version = versionKey.readUInt8(0); assert.equal(0x80, version, "Expected version " + 0x80 + ", instead got " + version); var _privateKey = PrivateKey.fromBuffer(versionKey.slice(1)); var _keyType = "K1"; var format = "WIF"; return { privateKey: _privateKey, format: format, keyType: _keyType }; } assert(match.length === 3, "Expecting private key like: PVT_K1_base58privateKey.."); var _match = (0, _slicedToArray3.default)(match, 3), keyType = _match[1], keyString = _match[2]; assert.equal(keyType, "K1", "K1 private key expected"); var privateKey = PrivateKey.fromBuffer(keyUtils.checkDecode(keyString, keyType)); return { privateKey: privateKey, format: "PVT", keyType: keyType }; } PrivateKey.fromHex = function (hex) { return PrivateKey.fromBuffer(new Buffer(hex, "hex")); }; PrivateKey.fromBuffer = function (buf) { if (!Buffer.isBuffer(buf)) { throw new Error("Expecting parameter to be a Buffer type"); } if (buf.length === 33 && buf[32] === 1) { // remove compression flag buf = buf.slice(0, -1); } if (32 !== buf.length) { throw new Error("Expecting 32 bytes, instead got " + buf.length); } return PrivateKey(BigInteger.fromBuffer(buf)); }; /** @arg {string} seed - any length string. This is private, the same seed produces the same private key every time. @return {PrivateKey} */ PrivateKey.fromSeed = function (seed) { // generate_private_key if (!(typeof seed === "string")) { throw new Error("seed must be of type string"); } return PrivateKey.fromBuffer(hash.sha256(seed)); }; /** @arg {wif} key @return {boolean} true if key is in the Wallet Import Format */ PrivateKey.isWif = function (text) { try { assert(parseKey(text).format === "WIF"); return true; } catch (e) { return false; } }; /** @arg {wif|Buffer|PrivateKey} key @return {boolean} true if key is convertable to a private key object. */ PrivateKey.isValid = function (key) { try { PrivateKey(key); return true; } catch (e) { return false; } }; /** @deprecated */ PrivateKey.fromWif = function (str) { console.log("PrivateKey.fromWif is deprecated, please use PrivateKey.fromString"); return PrivateKey.fromString(str); }; /** @throws {AssertError|Error} parsing key @arg {string} privateStr Wallet Import Format (wif) -- a secret */ PrivateKey.fromString = function (privateStr) { return parseKey(privateStr).privateKey; }; /** Create a new random private key. Call initialize() first to run some self-checking code and gather some CPU entropy. @arg {number} [cpuEntropyBits = 0] - additional CPU entropy, this already happens once so it should not be needed again. @return {Promise<PrivateKey>} - random private key */ PrivateKey.randomKey = function () { var cpuEntropyBits = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return PrivateKey.initialize().then(function () { return PrivateKey.fromBuffer(keyUtils.random32ByteBuffer({ cpuEntropyBits: cpuEntropyBits })); }); }; /** @return {Promise<PrivateKey>} for testing, does not require initialize(). */ PrivateKey.unsafeRandomKey = function () { return _promise2.default.resolve(PrivateKey.fromBuffer(keyUtils.random32ByteBuffer({ safe: false }))); }; var initialized = false, unitTested = false; /** Run self-checking code and gather CPU entropy. Initialization happens once even if called multiple times. @return {Promise} */ function initialize() { if (initialized) { return; } unitTest(); keyUtils.addEntropy.apply(keyUtils, (0, _toConsumableArray3.default)(keyUtils.cpuEntropy())); assert(keyUtils.entropyCount() >= 128, "insufficient entropy"); initialized = true; } PrivateKey.initialize = promiseAsync(initialize); /** Unit test basic private and public key functionality. @throws {AssertError} */ function unitTest() { var pvt = PrivateKey(hash.sha256("")); var pvtError = "key comparison test failed on a known private key"; assert.equal(pvt.toWif(), "5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss", pvtError); assert.equal(pvt.toString(), "5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss", pvtError); // assert.equal(pvt.toString(), 'PVT_K1_2jH3nnhxhR3zPUcsKaWWZC9ZmZAnKm3GAnFD1xynGJE1Znuvjd', pvtError) var pub = pvt.toPublic(); var pubError = "pubkey string comparison test failed on a known public key"; assert.equal(pub.toString(), "EVT859gxfnXyUriMgUeThh1fWv3oqcpLFyHa3TfFYC4PK2HqhToVM", pubError); // assert.equal(pub.toString(), 'PUB_K1_859gxfnXyUriMgUeThh1fWv3oqcpLFyHa3TfFYC4PK2Ht7beeX', pubError) // assert.equal(pub.toStringLegacy(), 'EVT859gxfnXyUriMgUeThh1fWv3oqcpLFyHa3TfFYC4PK2HqhToVM', pubError) doesNotThrow(function () { return PrivateKey.fromString(pvt.toWif()); }, "converting known wif from string"); doesNotThrow(function () { return PrivateKey.fromString(pvt.toString()); }, "converting known pvt from string"); doesNotThrow(function () { return PublicKey.fromString(pub.toString()); }, "converting known public key from string"); // doesNotThrow(() => PublicKey.fromString(pub.toStringLegacy()), 'converting known public key from string') unitTested = true; } /** @private */ var doesNotThrow = function doesNotThrow(cb, msg) { try { cb(); } catch (error) { error.message = msg + " ==> " + error.message; throw error; } };