2018-06-17 16:47:28 -04:00
|
|
|
"use strict";
|
2017-02-24 14:57:46 -05:00
|
|
|
/**
|
|
|
|
* Conversion Utilities
|
|
|
|
*
|
|
|
|
*/
|
2018-07-30 18:59:52 -04:00
|
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
|
var result = {};
|
|
|
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
|
|
result["default"] = mod;
|
|
|
|
return result;
|
|
|
|
};
|
2018-06-17 16:47:28 -04:00
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
2018-09-24 16:07:14 -04:00
|
|
|
var errors = __importStar(require("../errors"));
|
2018-07-30 18:59:52 -04:00
|
|
|
///////////////////////////////
|
|
|
|
function isHexable(value) {
|
|
|
|
return !!(value.toHexString);
|
|
|
|
}
|
|
|
|
exports.isHexable = isHexable;
|
2018-06-17 16:47:28 -04:00
|
|
|
function addSlice(array) {
|
|
|
|
if (array.slice) {
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
array.slice = function () {
|
2017-11-08 20:19:41 -05:00
|
|
|
var args = Array.prototype.slice.call(arguments);
|
2019-02-04 16:09:35 -05:00
|
|
|
return addSlice(new Uint8Array(Array.prototype.slice.apply(array, args)));
|
2018-06-17 16:47:28 -04:00
|
|
|
};
|
2017-11-08 20:19:41 -05:00
|
|
|
return array;
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
function isArrayish(value) {
|
2018-06-22 20:30:50 -04:00
|
|
|
if (!value || parseInt(String(value.length)) != value.length || typeof (value) === 'string') {
|
2017-02-24 14:57:46 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (var i = 0; i < value.length; i++) {
|
|
|
|
var v = value[i];
|
2018-06-22 20:30:50 -04:00
|
|
|
if (v < 0 || v >= 256 || parseInt(String(v)) != v) {
|
2017-02-24 14:57:46 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.isArrayish = isArrayish;
|
|
|
|
function arrayify(value) {
|
2018-04-12 15:18:11 -04:00
|
|
|
if (value == null) {
|
|
|
|
errors.throwError('cannot convert null value to array', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
|
|
}
|
2018-07-30 18:59:52 -04:00
|
|
|
if (isHexable(value)) {
|
2017-02-24 14:57:46 -05:00
|
|
|
value = value.toHexString();
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
if (typeof (value) === 'string') {
|
|
|
|
var match = value.match(/^(0x)?[0-9a-fA-F]*$/);
|
2018-06-13 15:39:39 -04:00
|
|
|
if (!match) {
|
|
|
|
errors.throwError('invalid hexidecimal string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
|
|
}
|
|
|
|
if (match[1] !== '0x') {
|
2018-06-17 16:47:28 -04:00
|
|
|
errors.throwError('hex string must have 0x prefix', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
2018-06-13 15:39:39 -04:00
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
value = value.substring(2);
|
2018-06-17 16:47:28 -04:00
|
|
|
if (value.length % 2) {
|
|
|
|
value = '0' + value;
|
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
var result = [];
|
|
|
|
for (var i = 0; i < value.length; i += 2) {
|
|
|
|
result.push(parseInt(value.substr(i, 2), 16));
|
|
|
|
}
|
2017-11-08 20:19:41 -05:00
|
|
|
return addSlice(new Uint8Array(result));
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
|
|
|
if (isArrayish(value)) {
|
2017-11-08 20:19:41 -05:00
|
|
|
return addSlice(new Uint8Array(value));
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
errors.throwError('invalid arrayify value', null, { arg: 'value', value: value, type: typeof (value) });
|
2018-06-13 15:39:39 -04:00
|
|
|
return null;
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.arrayify = arrayify;
|
|
|
|
function concat(objects) {
|
2017-02-24 14:57:46 -05:00
|
|
|
var arrays = [];
|
|
|
|
var length = 0;
|
|
|
|
for (var i = 0; i < objects.length; i++) {
|
2018-06-17 16:47:28 -04:00
|
|
|
var object = arrayify(objects[i]);
|
2017-02-24 14:57:46 -05:00
|
|
|
arrays.push(object);
|
|
|
|
length += object.length;
|
|
|
|
}
|
|
|
|
var result = new Uint8Array(length);
|
|
|
|
var offset = 0;
|
|
|
|
for (var i = 0; i < arrays.length; i++) {
|
|
|
|
result.set(arrays[i], offset);
|
|
|
|
offset += arrays[i].length;
|
|
|
|
}
|
2017-11-08 20:19:41 -05:00
|
|
|
return addSlice(result);
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.concat = concat;
|
|
|
|
function stripZeros(value) {
|
|
|
|
var result = arrayify(value);
|
|
|
|
if (result.length === 0) {
|
|
|
|
return result;
|
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
// Find the first non-zero entry
|
|
|
|
var start = 0;
|
2018-06-17 16:47:28 -04:00
|
|
|
while (result[start] === 0) {
|
|
|
|
start++;
|
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
// If we started with zeros, strip them
|
|
|
|
if (start) {
|
2018-06-13 15:39:39 -04:00
|
|
|
result = result.slice(start);
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-13 15:39:39 -04:00
|
|
|
return result;
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.stripZeros = stripZeros;
|
|
|
|
function padZeros(value, length) {
|
2017-04-04 17:22:53 -04:00
|
|
|
value = arrayify(value);
|
2018-06-17 16:47:28 -04:00
|
|
|
if (length < value.length) {
|
|
|
|
throw new Error('cannot pad');
|
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
var result = new Uint8Array(length);
|
|
|
|
result.set(value, length - value.length);
|
2017-11-08 20:19:41 -05:00
|
|
|
return addSlice(result);
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.padZeros = padZeros;
|
|
|
|
function isHexString(value, length) {
|
|
|
|
if (typeof (value) !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (length && value.length !== 2 + 2 * length) {
|
|
|
|
return false;
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.isHexString = isHexString;
|
|
|
|
var HexCharacters = '0123456789abcdef';
|
|
|
|
function hexlify(value) {
|
2018-07-30 18:59:52 -04:00
|
|
|
if (isHexable(value)) {
|
2017-02-24 14:57:46 -05:00
|
|
|
return value.toHexString();
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
if (typeof (value) === 'number') {
|
2017-02-24 14:57:46 -05:00
|
|
|
if (value < 0) {
|
2018-06-13 15:39:39 -04:00
|
|
|
errors.throwError('cannot hexlify negative value', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2019-02-08 19:58:41 -05:00
|
|
|
// @TODO: Roll this into the above error as a numeric fault (overflow); next version, not backward compatible
|
|
|
|
// We can about (value == MAX_INT) to as well, since that may indicate we underflowed already
|
|
|
|
if (value >= 9007199254740991) {
|
|
|
|
errors.throwError("out-of-range", errors.NUMERIC_FAULT, {
|
|
|
|
operartion: "hexlify",
|
|
|
|
fault: "out-of-safe-range"
|
|
|
|
});
|
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
var hex = '';
|
|
|
|
while (value) {
|
|
|
|
hex = HexCharacters[value & 0x0f] + hex;
|
2018-06-22 20:30:50 -04:00
|
|
|
value = Math.floor(value / 16);
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
|
|
|
if (hex.length) {
|
2018-06-17 16:47:28 -04:00
|
|
|
if (hex.length % 2) {
|
|
|
|
hex = '0' + hex;
|
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
return '0x' + hex;
|
|
|
|
}
|
|
|
|
return '0x00';
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
if (typeof (value) === 'string') {
|
|
|
|
var match = value.match(/^(0x)?[0-9a-fA-F]*$/);
|
2018-06-13 15:39:39 -04:00
|
|
|
if (!match) {
|
|
|
|
errors.throwError('invalid hexidecimal string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
|
|
}
|
|
|
|
if (match[1] !== '0x') {
|
2018-06-17 16:47:28 -04:00
|
|
|
errors.throwError('hex string must have 0x prefix', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
2018-06-13 15:39:39 -04:00
|
|
|
}
|
2017-02-24 14:57:46 -05:00
|
|
|
if (value.length % 2) {
|
|
|
|
value = '0x0' + value.substring(2);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
if (isArrayish(value)) {
|
|
|
|
var result = [];
|
|
|
|
for (var i = 0; i < value.length; i++) {
|
2018-06-17 16:47:28 -04:00
|
|
|
var v = value[i];
|
|
|
|
result.push(HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f]);
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
|
|
|
return '0x' + result.join('');
|
|
|
|
}
|
2018-06-13 15:39:39 -04:00
|
|
|
errors.throwError('invalid hexlify value', null, { arg: 'value', value: value });
|
|
|
|
return 'never';
|
2017-02-24 14:57:46 -05:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.hexlify = hexlify;
|
|
|
|
function hexDataLength(data) {
|
2018-06-17 16:32:57 -04:00
|
|
|
if (!isHexString(data) || (data.length % 2) !== 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return (data.length - 2) / 2;
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.hexDataLength = hexDataLength;
|
2018-09-27 16:55:40 -04:00
|
|
|
function hexDataSlice(data, offset, endOffset) {
|
2018-06-17 16:32:57 -04:00
|
|
|
if (!isHexString(data)) {
|
|
|
|
errors.throwError('invalid hex data', errors.INVALID_ARGUMENT, { arg: 'value', value: data });
|
|
|
|
}
|
|
|
|
if ((data.length % 2) !== 0) {
|
|
|
|
errors.throwError('hex data length must be even', errors.INVALID_ARGUMENT, { arg: 'value', value: data });
|
|
|
|
}
|
|
|
|
offset = 2 + 2 * offset;
|
2018-09-27 16:55:40 -04:00
|
|
|
if (endOffset != null) {
|
|
|
|
return '0x' + data.substring(offset, 2 + 2 * endOffset);
|
2018-06-17 16:32:57 -04:00
|
|
|
}
|
|
|
|
return '0x' + data.substring(offset);
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.hexDataSlice = hexDataSlice;
|
|
|
|
function hexStripZeros(value) {
|
2018-06-13 15:39:39 -04:00
|
|
|
if (!isHexString(value)) {
|
|
|
|
errors.throwError('invalid hex string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
|
|
}
|
2018-03-04 19:31:09 -05:00
|
|
|
while (value.length > 3 && value.substring(0, 3) === '0x0') {
|
|
|
|
value = '0x' + value.substring(3);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.hexStripZeros = hexStripZeros;
|
|
|
|
function hexZeroPad(value, length) {
|
2018-06-13 15:39:39 -04:00
|
|
|
if (!isHexString(value)) {
|
|
|
|
errors.throwError('invalid hex string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
|
|
|
|
}
|
2018-03-04 19:31:09 -05:00
|
|
|
while (value.length < 2 * length + 2) {
|
|
|
|
value = '0x0' + value.substring(2);
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.hexZeroPad = hexZeroPad;
|
2018-07-12 02:42:46 -04:00
|
|
|
function isSignature(value) {
|
|
|
|
return (value && value.r != null && value.s != null);
|
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
function splitSignature(signature) {
|
2018-07-12 02:42:46 -04:00
|
|
|
var v = 0;
|
|
|
|
var r = '0x', s = '0x';
|
|
|
|
if (isSignature(signature)) {
|
2018-07-17 15:36:14 -04:00
|
|
|
if (signature.v == null && signature.recoveryParam == null) {
|
|
|
|
errors.throwError('at least on of recoveryParam or v must be specified', errors.INVALID_ARGUMENT, { argument: 'signature', value: signature });
|
|
|
|
}
|
2018-07-12 02:42:46 -04:00
|
|
|
r = hexZeroPad(signature.r, 32);
|
|
|
|
s = hexZeroPad(signature.s, 32);
|
2018-07-12 20:14:04 -04:00
|
|
|
v = signature.v;
|
|
|
|
if (typeof (v) === 'string') {
|
|
|
|
v = parseInt(v, 16);
|
|
|
|
}
|
2018-07-12 02:42:46 -04:00
|
|
|
var recoveryParam = signature.recoveryParam;
|
|
|
|
if (recoveryParam == null && signature.v != null) {
|
2018-07-12 20:14:04 -04:00
|
|
|
recoveryParam = 1 - (v % 2);
|
2018-07-12 02:42:46 -04:00
|
|
|
}
|
|
|
|
v = 27 + recoveryParam;
|
2018-04-12 15:18:11 -04:00
|
|
|
}
|
2018-07-12 02:42:46 -04:00
|
|
|
else {
|
|
|
|
var bytes = arrayify(signature);
|
|
|
|
if (bytes.length !== 65) {
|
|
|
|
throw new Error('invalid signature');
|
|
|
|
}
|
|
|
|
r = hexlify(bytes.slice(0, 32));
|
|
|
|
s = hexlify(bytes.slice(32, 64));
|
|
|
|
v = bytes[64];
|
|
|
|
if (v !== 27 && v !== 28) {
|
|
|
|
v = 27 + (v % 2);
|
|
|
|
}
|
2018-04-12 15:18:11 -04:00
|
|
|
}
|
|
|
|
return {
|
2018-07-12 02:42:46 -04:00
|
|
|
r: r,
|
|
|
|
s: s,
|
2018-06-17 16:32:57 -04:00
|
|
|
recoveryParam: (v - 27),
|
2018-04-12 15:18:11 -04:00
|
|
|
v: v
|
2018-06-17 16:47:28 -04:00
|
|
|
};
|
2018-04-12 15:18:11 -04:00
|
|
|
}
|
2018-06-17 16:47:28 -04:00
|
|
|
exports.splitSignature = splitSignature;
|
2018-06-18 05:42:41 -04:00
|
|
|
function joinSignature(signature) {
|
2018-07-12 02:42:46 -04:00
|
|
|
signature = splitSignature(signature);
|
2018-06-18 05:42:41 -04:00
|
|
|
return hexlify(concat([
|
2018-07-12 02:42:46 -04:00
|
|
|
signature.r,
|
|
|
|
signature.s,
|
2018-06-18 05:42:41 -04:00
|
|
|
(signature.recoveryParam ? '0x1c' : '0x1b')
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
exports.joinSignature = joinSignature;
|