Merged master into feature-unicode-strings

This commit is contained in:
n1474335 2018-01-12 23:57:02 +00:00
commit fff188eb30
20 changed files with 336 additions and 147 deletions

View file

@ -1,4 +1,5 @@
import Utils from "../Utils.js";
import BigNumber from "bignumber.js";
/**
@ -24,11 +25,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runSum: function(input, args) {
const val = Arithmetic._sum(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -37,11 +38,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runSub: function(input, args) {
let val = Arithmetic._sub(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -50,11 +51,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMulti: function(input, args) {
let val = Arithmetic._multi(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -63,11 +64,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runDiv: function(input, args) {
let val = Arithmetic._div(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -76,11 +77,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMean: function(input, args) {
let val = Arithmetic._mean(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -89,11 +90,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMedian: function(input, args) {
let val = Arithmetic._median(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -102,11 +103,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runStdDev: function(input, args) {
let val = Arithmetic._stdDev(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@ -116,7 +117,7 @@ const Arithmetic = {
* @private
* @param {string[]} input
* @param {string} delim
* @returns {number[]}
* @returns {BigNumber[]}
*/
_createNumArray: function(input, delim) {
delim = Utils.charRep[delim || "Space"];
@ -125,13 +126,13 @@ const Arithmetic = {
num;
for (let i = 0; i < splitNumbers.length; i++) {
if (splitNumbers[i].indexOf(".") >= 0) {
num = parseFloat(splitNumbers[i].trim());
} else {
num = parseInt(splitNumbers[i].trim(), 0);
}
if (!isNaN(num)) {
numbers.push(num);
try {
num = BigNumber(splitNumbers[i].trim());
if (!num.isNaN()) {
numbers.push(num);
}
} catch (err) {
// This line is not a valid number
}
}
return numbers;
@ -142,12 +143,12 @@ const Arithmetic = {
* Adds an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_sum: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc + curr);
return data.reduce((acc, curr) => acc.plus(curr));
}
},
@ -156,12 +157,12 @@ const Arithmetic = {
* Subtracts an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_sub: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc - curr);
return data.reduce((acc, curr) => acc.minus(curr));
}
},
@ -170,12 +171,12 @@ const Arithmetic = {
* Multiplies an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_multi: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc * curr);
return data.reduce((acc, curr) => acc.times(curr));
}
},
@ -184,12 +185,12 @@ const Arithmetic = {
* Divides an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_div: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc / curr);
return data.reduce((acc, curr) => acc.div(curr));
}
},
@ -198,12 +199,12 @@ const Arithmetic = {
* Computes mean of a number array and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_mean: function(data) {
if (data.length > 0) {
return Arithmetic._sum(data) / data.length;
return Arithmetic._sum(data).div(data.length);
}
},
@ -212,14 +213,14 @@ const Arithmetic = {
* Computes median of a number array and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_median: function (data) {
if ((data.length % 2) === 0) {
if ((data.length % 2) === 0 && data.length > 0) {
let first, second;
data.sort(function(a, b){
return a - b;
return a.minus(b);
});
first = data[Math.floor(data.length / 2)];
second = data[Math.floor(data.length / 2) - 1];
@ -234,17 +235,17 @@ const Arithmetic = {
* Computes standard deviation of a number array and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_stdDev: function (data) {
if (data.length > 0) {
let avg = Arithmetic._mean(data);
let devSum = 0;
let devSum = new BigNumber(0);
for (let i = 0; i < data.length; i++) {
devSum += (data[i] - avg) ** 2;
devSum = devSum.plus(data[i].minus(avg).pow(2));
}
return Math.sqrt(devSum / data.length);
return devSum.div(data.length).sqrt();
}
},
};

View file

@ -1,4 +1,5 @@
import Utils from "../Utils.js";
import BigNumber from "bignumber.js";
/**
@ -61,14 +62,14 @@ const BCD = {
/**
* To BCD operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {string}
*/
runToBCD: function(input, args) {
if (isNaN(input))
if (input.isNaN())
return "Invalid input";
if (Math.floor(input) !== input)
if (!input.floor().equals(input))
return "Fractional values are not supported by BCD";
const encoding = BCD.ENCODING_LOOKUP[args[0]],
@ -77,7 +78,7 @@ const BCD = {
outputFormat = args[3];
// Split input number up into separate digits
const digits = input.toString().split("");
const digits = input.toFixed().split("");
if (digits[0] === "-" || digits[0] === "+") {
digits.shift();
@ -152,7 +153,7 @@ const BCD = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runFromBCD: function(input, args) {
const encoding = BCD.ENCODING_LOOKUP[args[0]],
@ -206,7 +207,7 @@ const BCD = {
output += val.toString();
});
return parseInt(output, 10);
return new BigNumber(output);
},
};

View file

@ -1,3 +1,5 @@
import BigNumber from "bignumber.js";
/**
* Numerical base operations.
*
@ -18,7 +20,7 @@ const Base = {
/**
* To Base operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {string}
*/
@ -39,7 +41,7 @@ const Base = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runFrom: function(input, args) {
const radix = args[0] || Base.DEFAULT_RADIX;
@ -48,14 +50,14 @@ const Base = {
}
let number = input.replace(/\s/g, "").split("."),
result = parseInt(number[0], radix) || 0;
result = new BigNumber(number[0], radix) || 0;
if (number.length === 1) return result;
// Fractional part
for (let i = 0; i < number[1].length; i++) {
const digit = parseInt(number[1][i], radix);
result += digit / Math.pow(radix, i+1);
const digit = new BigNumber(number[1][i], radix);
result += digit.div(Math.pow(radix, i+1));
}
return result;

View file

@ -2,6 +2,7 @@ import Utils from "../Utils.js";
import CryptoJS from "crypto-js";
import forge from "imports-loader?jQuery=>null!node-forge/dist/forge.min.js";
import {blowfish as Blowfish} from "sladex-blowfish";
import BigNumber from "bignumber.js";
/**
@ -520,7 +521,11 @@ DES uses a key length of 8 bytes (64 bits).`;
* @default
*/
PRNG_BYTES: 32,
PRNG_OUTPUT: ["Hex", "Number", "Byte array", "Raw"],
/**
* @constant
* @default
*/
PRNG_OUTPUT: ["Hex", "Integer", "Byte array", "Raw"],
/**
* Pseudo-Random Number Generator operation.
@ -542,17 +547,17 @@ DES uses a key length of 8 bytes (64 bits).`;
bytes = forge.random.getBytesSync(numBytes);
}
let value = 0,
let value = new BigNumber(0),
i;
switch (outputAs) {
case "Hex":
return forge.util.bytesToHex(bytes);
case "Number":
case "Integer":
for (i = bytes.length - 1; i >= 0; i--) {
value = (value * 256) + bytes.charCodeAt(i);
value = value.mul(256).plus(bytes.charCodeAt(i));
}
return value.toString();
return value.toFixed();
case "Byte array":
return JSON.stringify(Utils.strToCharcode(bytes));
case "Raw":

View file

@ -60,17 +60,16 @@ const Convert = {
/**
* Convert distance operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runDistance: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.DISTANCE_FACTOR[inputUnits];
return input / Convert.DISTANCE_FACTOR[outputUnits];
// TODO Remove rounding errors (e.g. 1.000000000001)
input = input.mul(Convert.DISTANCE_FACTOR[inputUnits]);
return input.div(Convert.DISTANCE_FACTOR[outputUnits]);
},
@ -141,16 +140,16 @@ const Convert = {
/**
* Convert data units operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runDataSize: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.DATA_FACTOR[inputUnits];
return input / Convert.DATA_FACTOR[outputUnits];
input = input.mul(Convert.DATA_FACTOR[inputUnits]);
return input.div(Convert.DATA_FACTOR[outputUnits]);
},
@ -221,16 +220,16 @@ const Convert = {
/**
* Convert area operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runArea: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.AREA_FACTOR[inputUnits];
return input / Convert.AREA_FACTOR[outputUnits];
input = input.mul(Convert.AREA_FACTOR[inputUnits]);
return input.div(Convert.AREA_FACTOR[outputUnits]);
},
@ -332,16 +331,16 @@ const Convert = {
/**
* Convert mass operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMass: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.MASS_FACTOR[inputUnits];
return input / Convert.MASS_FACTOR[outputUnits];
input = input.mul(Convert.MASS_FACTOR[inputUnits]);
return input.div(Convert.MASS_FACTOR[outputUnits]);
},
@ -397,16 +396,16 @@ const Convert = {
/**
* Convert speed operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runSpeed: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.SPEED_FACTOR[inputUnits];
return input / Convert.SPEED_FACTOR[outputUnits];
input = input.mul(Convert.SPEED_FACTOR[inputUnits]);
return input.div(Convert.SPEED_FACTOR[outputUnits]);
},
};

View file

@ -329,6 +329,75 @@ const StrUtils = {
})
.join(delimiter);
},
/**
* @constant
* @default
*/
HAMMING_DELIM: "\\n\\n",
/**
* @constant
* @default
*/
HAMMING_INPUT_TYPE: ["Raw string", "Hex"],
/**
* @constant
* @default
*/
HAMMING_UNIT: ["Byte", "Bit"],
/**
* Hamming Distance operation.
*
* @author GCHQ Contributor [2]
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runHamming: function(input, args) {
const delim = args[0],
byByte = args[1] === "Byte",
inputType = args[2],
samples = input.split(delim);
if (samples.length !== 2) {
return "Error: You can only calculae the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.";
}
if (samples[0].length !== samples[1].length) {
return "Error: Both inputs must be of the same length.";
}
if (inputType === "Hex") {
samples[0] = Utils.fromHex(samples[0]);
samples[1] = Utils.fromHex(samples[1]);
} else {
samples[0] = Utils.strToByteArray(samples[0]);
samples[1] = Utils.strToByteArray(samples[1]);
}
let dist = 0;
for (let i = 0; i < samples[0].length; i++) {
const lhs = samples[0][i],
rhs = samples[1][i];
if (byByte && lhs !== rhs) {
dist++;
} else if (!byByte) {
let xord = lhs ^ rhs;
while (xord) {
dist++;
xord &= xord - 1;
}
}
}
return dist.toString();
},
};
export default StrUtils;