evtjs
Version:
Javascript API Bindings for the everiToken blockchain.
427 lines (340 loc) • 14.9 kB
JavaScript
;
var _slicedToArray2 = require("babel-runtime/helpers/slicedToArray");
var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
var _typeof2 = require("babel-runtime/helpers/typeof");
var _typeof3 = _interopRequireDefault(_typeof2);
var _regenerator = require("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ecdsa = require("./ecdsa");
var hash = require("./hash");
var curve = require("ecurve").getCurveByName("secp256k1");
var assert = require("assert");
var BigInteger = require("../bigi");
var keyUtils = require("./key_utils");
var PublicKey = require("./key_public");
var ECSignature = require("./ecsignature");
var PrivateKey = require("./key_private");
var secp256k1 = null;
try {
secp256k1 = require("secp256k1");
} catch (e) {/* Do nothing */}
module.exports = Signature;
function Signature(r, s, i) {
assert.equal(r != null, true, "Missing parameter");
assert.equal(s != null, true, "Missing parameter");
assert.equal(i != null, true, "Missing parameter");
/**
Verify signed data.
@arg {String|Buffer} data - full data
@arg {pubkey|PublicKey} pubkey - EOSKey..
@arg {String} [encoding = 'utf8'] - data encoding (if data is a string)
@return {boolean}
*/
function verify(data, pubkey) {
var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "utf8";
if (typeof data === "string") {
data = Buffer.from(data, encoding);
}
assert(Buffer.isBuffer(data), "data is a required String or Buffer");
data = hash.sha256(data);
return verifyHash(data, pubkey);
}
/**
Verify a buffer of exactally 32 bytes in size (sha256(text))
@arg {String|Buffer} dataSha256 - 32 byte buffer or string
@arg {String|PublicKey} pubkey - EOSKey..
@arg {String} [encoding = 'hex'] - dataSha256 encoding (if string)
@return {boolean}
*/
function verifyHash(dataSha256, pubkey) {
var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "hex";
if (typeof dataSha256 === "string") {
dataSha256 = Buffer.from(dataSha256, encoding);
}
if (dataSha256.length !== 32 || !Buffer.isBuffer(dataSha256)) throw new Error("dataSha256: 32 bytes required");
var publicKey = PublicKey(pubkey);
assert(publicKey, "pubkey required");
return ecdsa.verify(curve, dataSha256, { r: r, s: s }, publicKey.Q);
}
/**
Recover the public key used to create this signature using full data.
@arg {String|Buffer} data - full data
@arg {String} [encoding = 'utf8'] - data encoding (if string)
@return {PublicKey}
*/
function recover(data) {
var encoding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "utf8";
if (typeof data === "string") {
data = Buffer.from(data, encoding);
}
assert(Buffer.isBuffer(data), "data is a required String or Buffer");
data = hash.sha256(data);
return recoverHash(data);
}
/**
@arg {String|Buffer} dataSha256 - sha256 hash 32 byte buffer or hex string
@arg {String} [encoding = 'hex'] - dataSha256 encoding (if string)
@return {PublicKey}
*/
function recoverHash(dataSha256) {
var encoding = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "hex";
//let time = new Date().valueOf();
if (typeof dataSha256 === "string") {
dataSha256 = Buffer.from(dataSha256, encoding);
}
if (dataSha256.length !== 32 || !Buffer.isBuffer(dataSha256)) {
throw new Error("dataSha256: 32 byte String or buffer requred");
}
// sign the message
if (secp256k1 != null) {
var buffer = toBuffer();
//console.log("[recoverHash] accelerating supported, length of sign: " + buffer.length);
var ret = PublicKey.fromBuffer(secp256k1.recover(dataSha256, buffer.slice(1), buffer[0] - 4 - 27, true));
//time = (new Date().valueOf()) - time;
//console.log("[+" + time + "ms] recoverHash (c binding)");
return ret;
} else {
//console.log("[recoverHash] accelerating not supported");
var e = BigInteger.fromBuffer(dataSha256);
var i2 = i;
i2 -= 27;
i2 = i2 & 3;
var Q = ecdsa.recoverPubKey(curve, e, { r: r, s: s, i: i }, i2);
// time = (new Date().valueOf()) - time;
//console.log("[+" + time + "ms] recoverHash");
return PublicKey.fromPoint(Q);
}
}
function toBuffer() {
var buf;
buf = new Buffer(65);
buf.writeUInt8(i, 0);
r.toBuffer(32).copy(buf, 1);
s.toBuffer(32).copy(buf, 33);
return buf;
}
function toHex() {
return toBuffer().toString("hex");
}
var signatureCache = void 0;
function toString() {
if (signatureCache) {
return signatureCache;
}
signatureCache = "SIG_K1_" + keyUtils.checkEncode(toBuffer(), "K1");
return signatureCache;
}
return {
r: r, s: s, i: i,
toBuffer: toBuffer,
verify: verify,
verifyHash: verifyHash,
recover: recover,
recoverHash: recoverHash,
toHex: toHex,
toString: toString
};
}
/**
Hash and sign arbitrary data.
@arg {string|Buffer} data - full data
@arg {wif|PrivateKey} privateKey
@arg {String} [encoding = 'utf8'] - data encoding (if string)
@return {Signature}
*/
Signature.sign = function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(data, privateKey) {
var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "utf8";
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (typeof data === "string") {
data = Buffer.from(data, encoding);
}
assert(Buffer.isBuffer(data), "data is a required String or Buffer");
data = hash.sha256(data);
_context.next = 5;
return Signature.signHash(data, privateKey);
case 5:
return _context.abrupt("return", _context.sent);
case 6:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function (_x6, _x7) {
return _ref.apply(this, arguments);
};
}();
function toArrayBuffer(myBuf) {
var myBuffer = new ArrayBuffer(myBuf.length);
var res = new Uint8Array(myBuffer);
for (var i = 0; i < myBuf.length; ++i) {
res[i] = myBuf[i];
}
return res;
}
/**
Sign a buffer of exactally 32 bytes in size (sha256(text))
@arg {string|Buffer} dataSha256 - 32 byte buffer or string
@arg {wif|PrivateKey} privateKey
@arg {String} [encoding = 'hex'] - dataSha256 encoding (if string)
@return {Signature}
*/
Signature.signHash = function () {
var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(dataSha256, privateKey) {
var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "hex";
var _ret, der, e, ecsignature, i, lenR, lenS, nonce;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
//let time = new Date().valueOf();
if (typeof dataSha256 === "string") {
dataSha256 = Buffer.from(dataSha256, encoding);
}
if (!(dataSha256.length !== 32 || !Buffer.isBuffer(dataSha256))) {
_context2.next = 3;
break;
}
throw new Error("dataSha256: 32 byte buffer requred");
case 3:
privateKey = PrivateKey(privateKey);
assert(privateKey, "privateKey required");
// sign the message
if (!(secp256k1 != null)) {
_context2.next = 11;
break;
}
_ret = function () {
// console.log("[signHash] accelerating supported");
var nonce = 0,
canonical = false,
sigObj = void 0,
sigDER = void 0;
while (!canonical) {
sigObj = secp256k1.sign(dataSha256, privateKey.toBuffer(), {
noncefn: function noncefn(message, rivateKey, algo, data, attempt) {
// console.log("[nonce] attempt:" + nonce);
var ret = new Buffer(32);
ret[31] = nonce++;
return ret;
}
});
sigDER = secp256k1.signatureExport(sigObj.signature);
var _lenR = sigDER[3];
var _lenS = sigDER[5 + _lenR];
canonical = _lenR === 32 && _lenS === 32;
}
var ecsig = ECSignature.fromDER(sigDER);
//time = (new Date().valueOf()) - time;
//console.log("[+" + time + "ms] signHash (c binding)");
return {
v: Signature(ecsig.r, ecsig.s, sigObj.recovery + 4 + 27)
};
}();
if (!((typeof _ret === "undefined" ? "undefined" : (0, _typeof3.default)(_ret)) === "object")) {
_context2.next = 9;
break;
}
return _context2.abrupt("return", _ret.v);
case 9:
_context2.next = 28;
break;
case 11:
i = null;
// console.log("[signHash] no accelerating supported");
nonce = 0;
e = BigInteger.fromBuffer(dataSha256);
case 14:
if (!true) {
_context2.next = 27;
break;
}
ecsignature = ecdsa.sign(curve, dataSha256, privateKey.d, nonce++);
der = ecsignature.toDER();
lenR = der[3];
lenS = der[5 + lenR];
if (!(lenR === 32 && lenS === 32)) {
_context2.next = 24;
break;
}
i = ecdsa.calcPubKeyRecoveryParam(curve, e, ecsignature, privateKey.toPublic().Q);
i += 4; // compressed
i += 27; // compact // 24 or 27 :( forcing odd-y 2nd key candidate)
return _context2.abrupt("break", 27);
case 24:
if (nonce % 10 === 0) {
console.log("WARN: " + nonce + " attempts to find canonical signature");
}
_context2.next = 14;
break;
case 27:
return _context2.abrupt("return", Signature(ecsignature.r, ecsignature.s, i));
case 28:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return function (_x9, _x10) {
return _ref2.apply(this, arguments);
};
}();
Signature.fromBuffer = function (buf) {
var i, r, s;
assert(Buffer.isBuffer(buf), "Buffer is required");
assert.equal(buf.length, 65, "Invalid signature length");
i = buf.readUInt8(0);
assert.equal(i - 27, i - 27 & 7, "Invalid signature parameter");
r = BigInteger.fromBuffer(buf.slice(1, 33));
s = BigInteger.fromBuffer(buf.slice(33));
return Signature(r, s, i);
};
Signature.fromHex = function (hex) {
return Signature.fromBuffer(Buffer.from(hex, "hex"));
};
/**
@arg {string} signature - like SIG_K1_base58signature..
@return {Signature} or `null` (invalid)
*/
Signature.fromString = function (signature) {
try {
return Signature.fromStringOrThrow(signature);
} catch (e) {
return null;
}
};
/**
@arg {string} signature - like SIG_K1_base58signature..
@throws {Error} invalid
@return {Signature}
*/
Signature.fromStringOrThrow = function (signature) {
assert.equal(typeof signature === "undefined" ? "undefined" : (0, _typeof3.default)(signature), "string", "signature");
var match = signature.match(/^SIG_([A-Za-z0-9]+)_([A-Za-z0-9]+)$/);
assert(match != null && match.length === 3, "Expecting signature like: SIG_K1_base58signature..");
var _match = (0, _slicedToArray3.default)(match, 3),
keyType = _match[1],
keyString = _match[2];
assert.equal(keyType, "K1", "K1 signature expected");
return Signature.fromBuffer(keyUtils.checkDecode(keyString, keyType));
};
/**
@arg {String|Signature} o - hex string
@return {Signature}
*/
Signature.from = function (o) {
var signature = o ? o.r && o.s && o.i ? o : typeof o === "string" && o.length === 130 ? Signature.fromHex(o) : typeof o === "string" && o.length !== 130 ? Signature.fromStringOrThrow(o) : Buffer.isBuffer(o) ? Signature.fromBuffer(o) : null : o; /*null or undefined*/
if (!signature) {
throw new TypeError("signature should be a hex string or buffer");
}
return signature;
};