evtjs
Version:
Javascript API Bindings for the everiToken blockchain.
376 lines (309 loc) • 11.4 kB
JavaScript
;
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;
}
};